From e7cef945073e0e04496a035b3a35e497826f1d3d Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Thu, 18 Feb 2016 15:54:52 -0800 Subject: [PATCH] sys: IRP_MJ_QUERY_SECURITY --- src/sys/driver.h | 20 ++++++-- src/sys/file.c | 41 ++++++++++++++++ src/sys/fileinfo.c | 3 +- src/sys/meta.c | 15 +++--- src/sys/security.c | 118 ++++++++++++++++++++++++++++++++++++++++++++- src/sys/util.c | 33 +++++++++++++ 6 files changed, 218 insertions(+), 12 deletions(-) diff --git a/src/sys/driver.h b/src/sys/driver.h index 19cc0b7e..17db4c85 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -203,6 +203,9 @@ extern __declspec(selectany) int fsp_bp = 1; goto fsp_leave_label; \ } while (0,0) +/* missing typedef */ +typedef const void *PCVOID; + /* driver major functions */ _Function_class_(DRIVER_DISPATCH) _IRQL_requires_max_(APC_LEVEL) @@ -318,6 +321,9 @@ BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams); VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix); NTSTATUS FspCreateGuid(GUID *Guid); NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes); +NTSTATUS FspQuerySecurityDescriptorInfo(SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR SecurityDescriptor, PULONG PLength, + PSECURITY_DESCRIPTOR ObjectsSecurityDescriptor); /* utility: synchronous work queue */ typedef struct @@ -401,9 +407,10 @@ NTSTATUS FspMetaCacheCreate( FSP_META_CACHE **PMetaCache); VOID FspMetaCacheDelete(FSP_META_CACHE *MetaCache); VOID FspMetaCacheInvalidateExpired(FSP_META_CACHE *MetaCache, UINT64 ExpirationTime); -PVOID FspMetaCacheReferenceItemBuffer(FSP_META_CACHE *MetaCache, UINT64 ItemIndex, PULONG PSize); -VOID FspMetaCacheDereferenceItemBuffer(PVOID Buffer); -UINT64 FspMetaCacheAddItem(FSP_META_CACHE *MetaCache, PVOID Buffer, ULONG Size); +BOOLEAN FspMetaCacheReferenceItemBuffer(FSP_META_CACHE *MetaCache, UINT64 ItemIndex, + PCVOID *PBuffer, PULONG PSize); +VOID FspMetaCacheDereferenceItemBuffer(PCVOID Buffer); +UINT64 FspMetaCacheAddItem(FSP_META_CACHE *MetaCache, PCVOID Buffer, ULONG Size); VOID FspMetaCacheInvalidateItem(FSP_META_CACHE *MetaCache, UINT64 ItemIndex); /* I/O processing */ @@ -624,6 +631,8 @@ typedef struct UINT64 ChangeTime; ULONG InfoChangeNumber; NTSTATUS CcStatus; + UINT64 Security; + ULONG SecurityChangeNumber; /* read-only after creation (and insertion in the ContextTable) */ PDEVICE_OBJECT FsvolDeviceObject; UINT64 UserContext; @@ -671,6 +680,10 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject, const FSP_FSCTL_FILE_INFO *FileInfo); BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject, const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber); +BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize); +VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size); +BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size, + ULONG SecurityChangeNumber); NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc); VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc); #define FspFileNodeAcquireShared(N,F) FspFileNodeAcquireSharedF(N, FspFileNodeAcquire ## F) @@ -680,6 +693,7 @@ VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc); #define FspFileNodeSetOwner(N,F,P) FspFileNodeSetOwnerF(N, FspFileNodeAcquire ## F, P) #define FspFileNodeRelease(N,F) FspFileNodeReleaseF(N, FspFileNodeAcquire ## F) #define FspFileNodeReleaseOwner(N,F,P) FspFileNodeReleaseOwnerF(N, FspFileNodeAcquire ## F, P) +#define FspFileNodeDereferenceSecurity(P) FspMetaCacheDereferenceItemBuffer(P) /* debug */ #if DBG diff --git a/src/sys/file.c b/src/sys/file.c index 2431c4eb..70b64c88 100644 --- a/src/sys/file.c +++ b/src/sys/file.c @@ -27,6 +27,10 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject, const FSP_FSCTL_FILE_INFO *FileInfo); BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject, const FSP_FSCTL_FILE_INFO *FileInfo, ULONG InfoChangeNumber); +BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize); +VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size); +BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size, + ULONG SecurityChangeNumber); NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc); VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc); @@ -47,6 +51,9 @@ VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc); #pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo) #pragma alloc_text(PAGE, FspFileNodeSetFileInfo) #pragma alloc_text(PAGE, FspFileNodeTrySetFileInfo) +#pragma alloc_text(PAGE, FspFileNodeReferenceSecurity) +#pragma alloc_text(PAGE, FspFileNodeSetSecurity) +#pragma alloc_text(PAGE, FspFileNodeTrySetSecurity) #pragma alloc_text(PAGE, FspFileDescCreate) #pragma alloc_text(PAGE, FspFileDescDelete) #endif @@ -471,6 +478,40 @@ BOOLEAN FspFileNodeTrySetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileOb return TRUE; } +BOOLEAN FspFileNodeReferenceSecurity(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize) +{ + PAGED_CODE(); + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = + FspFsvolDeviceExtension(FileNode->FsvolDeviceObject); + + return FspMetaCacheReferenceItemBuffer(FsvolDeviceExtension->SecurityCache, + FileNode->Security, PBuffer, PSize); +} + +VOID FspFileNodeSetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size) +{ + PAGED_CODE(); + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = + FspFsvolDeviceExtension(FileNode->FsvolDeviceObject); + + FspMetaCacheInvalidateItem(FsvolDeviceExtension->SecurityCache, FileNode->Security); + FileNode->Security = FspMetaCacheAddItem(FsvolDeviceExtension->SecurityCache, Buffer, Size); +} + +BOOLEAN FspFileNodeTrySetSecurity(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size, + ULONG SecurityChangeNumber) +{ + PAGED_CODE(); + + if (FileNode->SecurityChangeNumber != SecurityChangeNumber) + return FALSE; + + FspFileNodeSetSecurity(FileNode, Buffer, Size); + return TRUE; +} + NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc) { PAGED_CODE(); diff --git a/src/sys/fileinfo.c b/src/sys/fileinfo.c index 987b5a5d..741d66d4 100644 --- a/src/sys/fileinfo.c +++ b/src/sys/fileinfo.c @@ -501,8 +501,7 @@ NTSTATUS FspFsvolQueryInformationComplete( if (!Success) { FspIopRetryCompleteIrp(Irp, Response, &Result); - - return Result; + FSP_RETURN(); } if (!FspFileNodeTrySetFileInfo(FileNode, FileObject, &Response->Rsp.QueryInformation.FileInfo, diff --git a/src/sys/meta.c b/src/sys/meta.c index da4c4822..98147b80 100644 --- a/src/sys/meta.c +++ b/src/sys/meta.c @@ -148,12 +148,14 @@ VOID FspMetaCacheInvalidateExpired(FSP_META_CACHE *MetaCache, UINT64 ExpirationT } } -PVOID FspMetaCacheReferenceItemBuffer(FSP_META_CACHE *MetaCache, UINT64 ItemIndex, PULONG PSize) +BOOLEAN FspMetaCacheReferenceItemBuffer(FSP_META_CACHE *MetaCache, UINT64 ItemIndex, + PCVOID *PBuffer, PULONG PSize) { + *PBuffer = 0; if (0 != PSize) *PSize = 0; if (0 == MetaCache || 0 == ItemIndex) - return 0; + return FALSE; FSP_META_CACHE_ITEM *Item = 0; FSP_META_CACHE_ITEM_BUFFER *ItemBuffer; KIRQL Irql; @@ -162,23 +164,24 @@ PVOID FspMetaCacheReferenceItemBuffer(FSP_META_CACHE *MetaCache, UINT64 ItemInde if (0 == Item) { KeReleaseSpinLock(&MetaCache->SpinLock, Irql); - return 0; + return FALSE; } InterlockedIncrement(&Item->RefCount); KeReleaseSpinLock(&MetaCache->SpinLock, Irql); ItemBuffer = Item->ItemBuffer; + *PBuffer = ItemBuffer->Buffer; if (0 != PSize) *PSize = ItemBuffer->Size; - return ItemBuffer->Buffer; + return TRUE; } -VOID FspMetaCacheDereferenceItemBuffer(PVOID Buffer) +VOID FspMetaCacheDereferenceItemBuffer(PCVOID Buffer) { FSP_META_CACHE_ITEM_BUFFER *ItemBuffer = (PVOID)((PUINT8)Buffer - sizeof *ItemBuffer); FspMetaCacheDereferenceItem(ItemBuffer->Item); } -UINT64 FspMetaCacheAddItem(FSP_META_CACHE *MetaCache, PVOID Buffer, ULONG Size) +UINT64 FspMetaCacheAddItem(FSP_META_CACHE *MetaCache, PCVOID Buffer, ULONG Size) { if (0 == MetaCache) return 0; diff --git a/src/sys/security.c b/src/sys/security.c index 150185bd..550b9940 100644 --- a/src/sys/security.c +++ b/src/sys/security.c @@ -12,6 +12,7 @@ FSP_IOCMPL_DISPATCH FspFsvolQuerySecurityComplete; static NTSTATUS FspFsvolSetSecurity( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); FSP_IOCMPL_DISPATCH FspFsvolSetSecurityComplete; +static FSP_IOP_REQUEST_FINI FspFsvolSecurityRequestFini; FSP_DRIVER_DISPATCH FspQuerySecurity; FSP_DRIVER_DISPATCH FspSetSecurity; @@ -20,16 +21,72 @@ FSP_DRIVER_DISPATCH FspSetSecurity; #pragma alloc_text(PAGE, FspFsvolQuerySecurityComplete) #pragma alloc_text(PAGE, FspFsvolSetSecurity) #pragma alloc_text(PAGE, FspFsvolSetSecurityComplete) +#pragma alloc_text(PAGE, FspFsvolSecurityRequestFini) #pragma alloc_text(PAGE, FspQuerySecurity) #pragma alloc_text(PAGE, FspSetSecurity) #endif +enum +{ + /* QuerySecurity */ + RequestFileNode = 0, + RequestSecurityChangeNumber = 1, + + /* SetSecurity */ + //RequestFileNode = 0, +}; + static NTSTATUS FspFsvolQuerySecurity( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { PAGED_CODE(); - return STATUS_INVALID_DEVICE_REQUEST; + /* is this a valid FileObject? */ + if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext)) + return STATUS_INVALID_DEVICE_REQUEST; + + NTSTATUS Result; + PFILE_OBJECT FileObject = IrpSp->FileObject; + FSP_FILE_NODE *FileNode = FileObject->FsContext; + FSP_FILE_DESC *FileDesc = FileObject->FsContext2; + SECURITY_INFORMATION SecurityInformation = IrpSp->Parameters.QuerySecurity.SecurityInformation; + PVOID Buffer = Irp->UserBuffer; + ULONG Length = IrpSp->Parameters.QuerySecurity.Length; + PVOID SecurityBuffer; + + ASSERT(FileNode == FileDesc->FileNode); + + FspFileNodeAcquireShared(FileNode, Main); + if (FspFileNodeReferenceSecurity(FileNode, &SecurityBuffer, 0)) + { + FspFileNodeRelease(FileNode, Main); + + Result = FspQuerySecurityDescriptorInfo(SecurityInformation, Buffer, &Length, SecurityBuffer); + FspFileNodeDereferenceSecurity(SecurityBuffer); + + Irp->IoStatus.Information = Length; + return Result; + } + + FspFileNodeAcquireShared(FileNode, Pgio); + + FSP_FSCTL_TRANSACT_REQ *Request; + + Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolSecurityRequestFini, &Request); + if (!NT_SUCCESS(Result)) + { + FspFileNodeRelease(FileNode, Full); + return Result; + } + + Request->Kind = FspFsctlTransactQuerySecurityKind; + Request->Req.QuerySecurity.UserContext = FileNode->UserContext; + Request->Req.QuerySecurity.UserContext2 = FileDesc->UserContext2; + + FspFileNodeSetOwner(FileNode, Full, Request); + FspIopRequestContext(Request, RequestFileNode) = FileNode; + + return FSP_STATUS_IOQ_POST; } NTSTATUS FspFsvolQuerySecurityComplete( @@ -37,6 +94,55 @@ NTSTATUS FspFsvolQuerySecurityComplete( { FSP_ENTER_IOC(PAGED_CODE()); + if (!NT_SUCCESS(Response->IoStatus.Status)) + { + Irp->IoStatus.Information = 0; + Result = Response->IoStatus.Status; + FSP_RETURN(); + } + + PFILE_OBJECT FileObject = IrpSp->FileObject; + FSP_FILE_NODE *FileNode = FileObject->FsContext; + SECURITY_INFORMATION SecurityInformation = IrpSp->Parameters.QuerySecurity.SecurityInformation; + PVOID Buffer = Irp->UserBuffer; + ULONG Length = IrpSp->Parameters.QuerySecurity.Length; + PVOID SecurityBuffer = 0; + FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); + BOOLEAN Success; + + if (0 != FspIopRequestContext(Request, RequestFileNode)) + { + FspIopRequestContext(Request, RequestSecurityChangeNumber) = (PVOID)FileNode->SecurityChangeNumber; + FspIopRequestContext(Request, RequestFileNode) = 0; + + FspFileNodeReleaseOwner(FileNode, Full, Request); + } + + Success = DEBUGRANDTEST(90, TRUE) && FspFileNodeTryAcquireExclusive(FileNode, Main); + if (!Success) + { + FspIopRetryCompleteIrp(Irp, Response, &Result); + FSP_RETURN(); + } + + Success = !FspFileNodeTrySetSecurity(FileNode, + Response->Buffer, Response->Rsp.QuerySecurity.SecurityDescriptor.Size, + (ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestSecurityChangeNumber)); + Success = Success && FspFileNodeReferenceSecurity(FileNode, &SecurityBuffer, 0); + FspFileNodeRelease(FileNode, Main); + if (Success) + { + Result = FspQuerySecurityDescriptorInfo(SecurityInformation, Buffer, &Length, SecurityBuffer); + FspFileNodeDereferenceSecurity(SecurityBuffer); + } + else + { + SecurityBuffer = (PVOID)Response->Buffer; + Result = FspQuerySecurityDescriptorInfo(SecurityInformation, Buffer, &Length, SecurityBuffer); + } + + Irp->IoStatus.Information = Length; + FSP_LEAVE_IOC("FileObject=%p, SecurityInformation=%x", IrpSp->FileObject, IrpSp->Parameters.QuerySecurity.SecurityInformation); } @@ -58,6 +164,16 @@ NTSTATUS FspFsvolSetSecurityComplete( IrpSp->FileObject, IrpSp->Parameters.SetSecurity.SecurityInformation); } +static VOID FspFsvolSecurityRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4]) +{ + PAGED_CODE(); + + FSP_FILE_NODE *FileNode = Context[RequestFileNode]; + + if (0 != FileNode) + FspFileNodeReleaseOwner(FileNode, Full, Request); +} + NTSTATUS FspQuerySecurity( PDEVICE_OBJECT DeviceObject, PIRP Irp) { diff --git a/src/sys/util.c b/src/sys/util.c index 99dfeda6..6c4c76cd 100644 --- a/src/sys/util.c +++ b/src/sys/util.c @@ -9,6 +9,10 @@ BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams); VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix); NTSTATUS FspCreateGuid(GUID *Guid); +NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes); +NTSTATUS FspQuerySecurityDescriptorInfo(SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR SecurityDescriptor, PULONG PLength, + PSECURITY_DESCRIPTOR ObjectsSecurityDescriptor); VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem, PWORKER_THREAD_ROUTINE Routine, PVOID Context); VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem); @@ -22,6 +26,8 @@ static KDEFERRED_ROUTINE FspQueueDelayedWorkItemDPC; #pragma alloc_text(PAGE, FspUnicodePathIsValid) #pragma alloc_text(PAGE, FspUnicodePathSuffix) #pragma alloc_text(PAGE, FspCreateGuid) +#pragma alloc_text(PAGE, FspCcSetFileSizes) +#pragma alloc_text(PAGE, FspQuerySecurityDescriptorInfo) #pragma alloc_text(PAGE, FspInitializeSynchronousWorkItem) #pragma alloc_text(PAGE, FspExecuteSynchronousWorkItem) #pragma alloc_text(PAGE, FspExecuteSynchronousWorkItemRoutine) @@ -41,6 +47,8 @@ static const LONG Delays[] = PVOID FspAllocMustSucceed(SIZE_T Size) { + // !PAGED_CODE(); + PVOID Result; LARGE_INTEGER Delay; @@ -57,6 +65,8 @@ PVOID FspAllocMustSucceed(SIZE_T Size) PVOID FspAllocateIrpMustSucceed(CCHAR StackSize) { + // !PAGED_CODE(); + PIRP Result; LARGE_INTEGER Delay; @@ -145,6 +155,8 @@ NTSTATUS FspCreateGuid(GUID *Guid) NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes) { + PAGED_CODE(); + try { CcSetFileSizes(FileObject, FileSizes); @@ -156,6 +168,27 @@ NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes) } } +NTSTATUS FspQuerySecurityDescriptorInfo(SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR SecurityDescriptor, PULONG PLength, + PSECURITY_DESCRIPTOR ObjectsSecurityDescriptor) +{ + PAGED_CODE(); + + NTSTATUS Result; + + try + { + Result = SeQuerySecurityDescriptorInfo(&SecurityInformation, + SecurityDescriptor, PLength, &ObjectsSecurityDescriptor); + } + except (EXCEPTION_EXECUTE_HANDLER) + { + Result = STATUS_INVALID_USER_BUFFER; + } + + return STATUS_BUFFER_TOO_SMALL == Result ? STATUS_BUFFER_OVERFLOW : Result; +} + VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem, PWORKER_THREAD_ROUTINE Routine, PVOID Context) {