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:
Bill Zissimopoulos
2018-10-04 13:21:29 -07:00
parent fd9eccbe8b
commit 4d49039abe
6 changed files with 175 additions and 33 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -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;