mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-02 17:02:57 -05:00
sys: FspFastIoQueryOpen: access control
Extend the WinFsp kernel-user mode protocol to allow passing security descriptors that can then be used for access control during FastIoQueryOpen.
This commit is contained in:
@ -96,7 +96,11 @@ enum
|
||||
RequestFileObject = 2,
|
||||
RequestState = 3,
|
||||
|
||||
/* RequestState */
|
||||
/* TryOpen RequestState */
|
||||
RequestFlushImage = 1,
|
||||
RequestAcceptsSecurityDescriptor = 2,
|
||||
|
||||
/* Overwrite RequestState */
|
||||
RequestPending = 0,
|
||||
RequestProcessing = 1,
|
||||
};
|
||||
@ -602,6 +606,9 @@ static NTSTATUS FspFsvolCreateNoLock(
|
||||
Request->Req.Create.HasTrailingBackslash = HasTrailingBackslash;
|
||||
Request->Req.Create.NamedStream = MainFileName.Length;
|
||||
|
||||
Request->Req.Create.AcceptsSecurityDescriptor = 0 == Request->Req.Create.NamedStream &&
|
||||
!!FsvolDeviceExtension->VolumeParams.AllowOpenInKernelMode;
|
||||
|
||||
ASSERT(
|
||||
0 == StreamPart.Length && 0 == MainFileName.Length ||
|
||||
0 != StreamPart.Length && 0 != MainFileName.Length);
|
||||
@ -1110,7 +1117,8 @@ NTSTATUS FspFsvolCreateComplete(
|
||||
* A Reserved request is a special request used when retrying a file open.
|
||||
*/
|
||||
|
||||
BOOLEAN FlushImage = 0 != FspIopRequestContext(Request, RequestState);
|
||||
BOOLEAN FlushImage =
|
||||
0 != (RequestFlushImage & (UINT_PTR)FspIopRequestContext(Request, RequestState));
|
||||
|
||||
Result = FspFsvolCreateTryOpen(Irp, Response, FileNode, FileDesc, FileObject, FlushImage);
|
||||
}
|
||||
@ -1178,7 +1186,9 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
|
||||
FspIopRequestContext(Request, RequestDeviceObject) = RequestDeviceObjectValue;
|
||||
FspIopRequestContext(Request, RequestFileDesc) = FileDesc;
|
||||
FspIopRequestContext(Request, RequestFileObject) = FileObject;
|
||||
FspIopRequestContext(Request, RequestState) = (PVOID)(UINT_PTR)FlushImage;
|
||||
FspIopRequestContext(Request, RequestState) = (PVOID)(UINT_PTR)(
|
||||
(FlushImage ? RequestFlushImage : 0) |
|
||||
(Request->Req.Create.AcceptsSecurityDescriptor ? RequestAcceptsSecurityDescriptor : 0));
|
||||
}
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
@ -1199,8 +1209,28 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
|
||||
return Result;
|
||||
}
|
||||
|
||||
PSECURITY_DESCRIPTOR OpenDescriptor = 0;
|
||||
ULONG OpenDescriptorSize = 0;
|
||||
if (0 != (RequestAcceptsSecurityDescriptor &
|
||||
(UINT_PTR)FspIopRequestContext(Request, RequestState)) &&
|
||||
Response->Rsp.Create.Opened.HasSecurityDescriptor &&
|
||||
0 < Response->Rsp.Create.Opened.SecurityDescriptor.Size &&
|
||||
Response->Buffer +
|
||||
Response->Rsp.Create.Opened.SecurityDescriptor.Offset +
|
||||
Response->Rsp.Create.Opened.SecurityDescriptor.Size <=
|
||||
(PUINT8)Response + Response->Size &&
|
||||
RtlValidRelativeSecurityDescriptor(
|
||||
(PUINT8)Response->Buffer +
|
||||
Response->Rsp.Create.Opened.SecurityDescriptor.Offset,
|
||||
Response->Rsp.Create.Opened.SecurityDescriptor.Size, 0))
|
||||
{
|
||||
OpenDescriptor = (PSECURITY_DESCRIPTOR)(Response->Buffer +
|
||||
Response->Rsp.Create.Opened.SecurityDescriptor.Offset);
|
||||
OpenDescriptorSize = Response->Rsp.Create.Opened.SecurityDescriptor.Size;
|
||||
}
|
||||
|
||||
/*
|
||||
* FspFileNodeTrySetFileInfoOnOpen sets the FileNode's metadata to values reported
|
||||
* FspFileNodeTrySetFileInfoAndSecurityOnOpen sets the FileNode's metadata to values reported
|
||||
* by the user mode file system. It does so only if the file is not already open; the
|
||||
* reason is that there is a subtle race condition otherwise.
|
||||
*
|
||||
@ -1231,12 +1261,13 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
|
||||
* example, Explorer often opens files to get information about them and may inappropriately
|
||||
* update the FSD view of the file size during WRITE's.
|
||||
*
|
||||
* FspFileNodeTrySetFileInfoOnOpen attempts to mitigate this problem by only updating the
|
||||
* FileInfo if the file is not already open. This avoids placing stale information in the
|
||||
* FspFileNodeTrySetFileInfoAndSecurityOnOpen attempts to mitigate this problem by only updating
|
||||
* the FileInfo if the file is not already open. This avoids placing stale information in the
|
||||
* FileNode.
|
||||
*/
|
||||
|
||||
FspFileNodeTrySetFileInfoOnOpen(FileNode, FileObject, &Response->Rsp.Create.Opened.FileInfo,
|
||||
FspFileNodeTrySetFileInfoAndSecurityOnOpen(FileNode, FileObject,
|
||||
&Response->Rsp.Create.Opened.FileInfo, OpenDescriptor, OpenDescriptorSize,
|
||||
FILE_CREATED == Response->IoStatus.Information);
|
||||
|
||||
if (FlushImage)
|
||||
|
@ -1386,12 +1386,14 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp
|
||||
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
|
||||
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
BOOLEAN FspFileNodeTryGetFileInfoByName(PDEVICE_OBJECT FsvolDeviceObject,
|
||||
BOOLEAN FspFileNodeTryGetFileInfoByName(PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp,
|
||||
PUNICODE_STRING FileName, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
||||
BOOLEAN FspFileNodeTrySetFileInfoOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
||||
BOOLEAN FspFileNodeTrySetFileInfoAndSecurityOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo,
|
||||
const PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG SecurityDescriptorSize,
|
||||
BOOLEAN TruncateOnClose);
|
||||
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
|
||||
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
|
||||
|
@ -61,12 +61,14 @@ NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp
|
||||
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
|
||||
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
BOOLEAN FspFileNodeTryGetFileInfoByName(PDEVICE_OBJECT FsvolDeviceObject,
|
||||
BOOLEAN FspFileNodeTryGetFileInfoByName(PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp,
|
||||
PUNICODE_STRING FileName, FSP_FSCTL_FILE_INFO *FileInfo);
|
||||
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
||||
BOOLEAN FspFileNodeTrySetFileInfoOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose);
|
||||
BOOLEAN FspFileNodeTrySetFileInfoAndSecurityOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo,
|
||||
const PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG SecurityDescriptorSize,
|
||||
BOOLEAN TruncateOnClose);
|
||||
BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber);
|
||||
VOID FspFileNodeInvalidateFileInfo(FSP_FILE_NODE *FileNode);
|
||||
@ -140,7 +142,7 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp);
|
||||
#pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo)
|
||||
#pragma alloc_text(PAGE, FspFileNodeTryGetFileInfoByName)
|
||||
#pragma alloc_text(PAGE, FspFileNodeSetFileInfo)
|
||||
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfoOnOpen)
|
||||
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfoAndSecurityOnOpen)
|
||||
#pragma alloc_text(PAGE, FspFileNodeTrySetFileInfo)
|
||||
#pragma alloc_text(PAGE, FspFileNodeInvalidateFileInfo)
|
||||
#pragma alloc_text(PAGE, FspFileNodeReferenceSecurity)
|
||||
@ -1643,14 +1645,33 @@ BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN FspFileNodeTryGetFileInfoByName(PDEVICE_OBJECT FsvolDeviceObject,
|
||||
BOOLEAN FspFileNodeTryGetFileInfoByName(PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp,
|
||||
PUNICODE_STRING FileName, FSP_FSCTL_FILE_INFO *FileInfo)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
|
||||
ACCESS_MASK DesiredAccess = AccessState->RemainingDesiredAccess;
|
||||
ACCESS_MASK GrantedAccess = AccessState->PreviouslyGrantedAccess;
|
||||
KPROCESSOR_MODE RequestorMode =
|
||||
FlagOn(IrpSp->Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode;
|
||||
BOOLEAN HasTraversePrivilege =
|
||||
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE);
|
||||
FSP_FILE_NODE *FileNode;
|
||||
PVOID SecurityBuffer;
|
||||
BOOLEAN Result;
|
||||
|
||||
if (UserMode == RequestorMode)
|
||||
{
|
||||
/* user mode: allow only FILE_READ_ATTRIBUTES with traverse privilege */
|
||||
if (FILE_READ_ATTRIBUTES != DesiredAccess || !HasTraversePrivilege)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
/* kernel mode: anything goes! */
|
||||
DesiredAccess = 0;
|
||||
|
||||
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||
FileNode = FspFsvolDeviceLookupContextByName(FsvolDeviceObject, FileName);
|
||||
if (0 != FileNode)
|
||||
@ -1661,7 +1682,34 @@ BOOLEAN FspFileNodeTryGetFileInfoByName(PDEVICE_OBJECT FsvolDeviceObject,
|
||||
if (0 != FileNode)
|
||||
{
|
||||
FspFileNodeAcquireShared(FileNode, Main);
|
||||
Result = FspFileNodeTryGetFileInfo(FileNode, FileInfo);
|
||||
|
||||
if (0 != DesiredAccess)
|
||||
{
|
||||
ASSERT(FILE_READ_ATTRIBUTES == DesiredAccess);
|
||||
|
||||
if (FspFileNodeReferenceSecurity(FileNode, &SecurityBuffer, 0))
|
||||
{
|
||||
NTSTATUS AccessStatus;
|
||||
Result = SeAccessCheck(
|
||||
SecurityBuffer,
|
||||
&AccessState->SubjectSecurityContext,
|
||||
TRUE,
|
||||
DesiredAccess,
|
||||
GrantedAccess,
|
||||
0,
|
||||
IoGetFileObjectGenericMapping(),
|
||||
RequestorMode,
|
||||
&GrantedAccess,
|
||||
&AccessStatus);
|
||||
|
||||
FspFileNodeDereferenceSecurity(SecurityBuffer);
|
||||
|
||||
Result = Result && FspFileNodeTryGetFileInfo(FileNode, FileInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
Result = FspFileNodeTryGetFileInfo(FileNode, FileInfo);
|
||||
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
FspFileNodeDereference(FileNode);
|
||||
}
|
||||
@ -1779,8 +1827,10 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN FspFileNodeTrySetFileInfoOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo, BOOLEAN TruncateOnClose)
|
||||
BOOLEAN FspFileNodeTrySetFileInfoAndSecurityOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
|
||||
const FSP_FSCTL_FILE_INFO *FileInfo,
|
||||
const PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG SecurityDescriptorSize,
|
||||
BOOLEAN TruncateOnClose)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
@ -1813,6 +1863,8 @@ BOOLEAN FspFileNodeTrySetFileInfoOnOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT Cc
|
||||
}
|
||||
|
||||
FspFileNodeSetFileInfo(FileNode, CcFileObject, FileInfo, TruncateOnClose);
|
||||
if (0 != SecurityDescriptor)
|
||||
FspFileNodeSetSecurity(FileNode, SecurityDescriptor, SecurityDescriptorSize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1910,7 +1910,7 @@ BOOLEAN FspFastIoQueryOpen(
|
||||
if (0 != FileObject->RelatedFileObject)
|
||||
FSP_RETURN(Result = FALSE);
|
||||
|
||||
Result = FspFileNodeTryGetFileInfoByName(DeviceObject, &FileObject->FileName, &FileInfoBuf);
|
||||
Result = FspFileNodeTryGetFileInfoByName(DeviceObject, Irp, &FileObject->FileName, &FileInfoBuf);
|
||||
if (Result)
|
||||
{
|
||||
PVOID Buffer = Info;
|
||||
|
Reference in New Issue
Block a user