NTSTATUS FspFsvolWritePrepare( PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request) { PAGED_CODE(); if (FspWriteIrpShouldUseProcessBuffer(Irp, Request->Req.Write.Length)) { NTSTATUS Result; PVOID Cookie; PVOID Address; PEPROCESS Process; PVOID SystemAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); if (0 == SystemAddress) return STATUS_INSUFFICIENT_RESOURCES; /* something is seriously screwy! */ Result = FspProcessBufferAcquire(Request->Req.Write.Length, &Cookie, &Address); if (!NT_SUCCESS(Result)) return Result; ASSERT(0 != Address); try { RtlCopyMemory(Address, SystemAddress, Request->Req.Write.Length); } except (EXCEPTION_EXECUTE_HANDLER) { Result = GetExceptionCode(); Result = FsRtlIsNtstatusExpected(Result) ? STATUS_INVALID_USER_BUFFER : Result; FspProcessBufferRelease(Cookie, Address); return Result; } /* get a pointer to the current process so that we can release the buffer later */ Process = PsGetCurrentProcess(); ObReferenceObject(Process); Request->Req.Write.Address = (UINT64)(UINT_PTR)Address; FspIopRequestContext(Request, RequestCookie) = (PVOID)((UINT_PTR)Cookie | 1); FspIopRequestContext(Request, RequestAddress) = Address; FspIopRequestContext(Request, RequestProcess) = Process; return STATUS_SUCCESS; }
NTSTATUS FspFsvolSetSecurityPrepare( PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request) { PAGED_CODE(); NTSTATUS Result; SECURITY_SUBJECT_CONTEXT SecuritySubjectContext; SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService; SECURITY_CLIENT_CONTEXT SecurityClientContext; HANDLE UserModeAccessToken; PEPROCESS Process; /* duplicate the subject context access token into an impersonation token */ SecurityQualityOfService.Length = sizeof SecurityQualityOfService; SecurityQualityOfService.ImpersonationLevel = SecurityIdentification; SecurityQualityOfService.ContextTrackingMode = SECURITY_STATIC_TRACKING; SecurityQualityOfService.EffectiveOnly = FALSE; SeCaptureSubjectContext(&SecuritySubjectContext); SeLockSubjectContext(&SecuritySubjectContext); Result = SeCreateClientSecurityFromSubjectContext(&SecuritySubjectContext, &SecurityQualityOfService, FALSE, &SecurityClientContext); SeUnlockSubjectContext(&SecuritySubjectContext); SeReleaseSubjectContext(&SecuritySubjectContext); if (!NT_SUCCESS(Result)) return Result; ASSERT(TokenImpersonation == SeTokenType(SecurityClientContext.ClientToken)); /* get a user-mode handle to the impersonation token */ Result = ObOpenObjectByPointer(SecurityClientContext.ClientToken, 0, 0, TOKEN_QUERY, *SeTokenObjectType, UserMode, &UserModeAccessToken); SeDeleteClientSecurity(&SecurityClientContext); if (!NT_SUCCESS(Result)) return Result; /* get a pointer to the current process so that we can close the impersonation token later */ Process = PsGetCurrentProcess(); ObReferenceObject(Process); /* send the user-mode handle to the user-mode file system */ FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken; FspIopRequestContext(Request, RequestProcess) = Process; Request->Req.SetSecurity.AccessToken = (UINT_PTR)UserModeAccessToken; return STATUS_SUCCESS; }
static NTSTATUS FspFsvolQuerySecurity( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { PAGED_CODE(); /* 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; FSP_FSCTL_TRANSACT_REQ *Request; 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); Result = FspBufferUserBuffer(Irp, Length, IoWriteAccess); if (!NT_SUCCESS(Result)) { FspFileNodeRelease(FileNode, Full); return Result; } Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolQuerySecurityRequestFini, &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; }
static NTSTATUS FspFsvolSetSecurity( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { PAGED_CODE(); /* 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.SetSecurity.SecurityInformation; PSECURITY_DESCRIPTOR SecurityDescriptor = IrpSp->Parameters.SetSecurity.SecurityDescriptor; ULONG SecurityDescriptorSize = 0; ASSERT(FileNode == FileDesc->FileNode); #if 0 /* captured security descriptor is always valid */ if (0 == SecurityDescriptor || !RtlValidSecurityDescriptor(SecurityDescriptor)) return STATUS_INVALID_PARAMETER; #endif SecurityDescriptorSize = RtlLengthSecurityDescriptor(SecurityDescriptor); FspFileNodeAcquireExclusive(FileNode, Full); FSP_FSCTL_TRANSACT_REQ *Request; Result = FspIopCreateRequestEx(Irp, 0, SecurityDescriptorSize, FspFsvolSetSecurityRequestFini, &Request); if (!NT_SUCCESS(Result)) { FspFileNodeRelease(FileNode, Full); return Result; } Request->Kind = FspFsctlTransactSetSecurityKind; Request->Req.SetSecurity.UserContext = FileNode->UserContext; Request->Req.SetSecurity.UserContext2 = FileDesc->UserContext2; Request->Req.SetSecurity.SecurityInformation = SecurityInformation; Request->Req.SetSecurity.SecurityDescriptor.Offset = 0; Request->Req.SetSecurity.SecurityDescriptor.Size = (UINT16)SecurityDescriptorSize; RtlCopyMemory(Request->Buffer, SecurityDescriptor, SecurityDescriptorSize); FspFileNodeSetOwner(FileNode, Full, Request); FspIopRequestContext(Request, RequestFileNode) = FileNode; return FSP_STATUS_IOQ_POST; }
NTSTATUS FspFsvolSetSecurityComplete( PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) { 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; FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); /* if the security descriptor that we got back is valid */ if (0 < Response->Rsp.SetSecurity.SecurityDescriptor.Size && Response->Buffer + Response->Rsp.SetSecurity.SecurityDescriptor.Size <= (PUINT8)Response + Response->Size && RtlValidRelativeSecurityDescriptor((PVOID)Response->Buffer, Response->Rsp.SetSecurity.SecurityDescriptor.Size, 0)) { /* update the cached security */ FspFileNodeSetSecurity(FileNode, Response->Buffer, Response->Rsp.SetSecurity.SecurityDescriptor.Size); } else { /* invalidate the cached security */ FspFileNodeSetSecurity(FileNode, 0, 0); } FspIopRequestContext(Request, RequestFileNode) = 0; FspFileNodeReleaseOwner(FileNode, Full, Request); Irp->IoStatus.Information = 0; Result = STATUS_SUCCESS; FSP_LEAVE_IOC("FileObject=%p, SecurityInformation=%x", IrpSp->FileObject, IrpSp->Parameters.SetSecurity.SecurityInformation); }
static NTSTATUS FspFsvolWriteNonCached( PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, BOOLEAN CanWait) { PAGED_CODE(); /* assert: either a top-level IRP or Paging I/O */ ASSERT(0 == FspIrpTopFlags(Irp) || FlagOn(Irp->Flags, IRP_PAGING_IO)); NTSTATUS Result; PFILE_OBJECT FileObject = IrpSp->FileObject; FSP_FILE_NODE *FileNode = FileObject->FsContext; FSP_FILE_DESC *FileDesc = FileObject->FsContext2; LARGE_INTEGER WriteOffset = IrpSp->Parameters.Write.ByteOffset; ULONG WriteLength = IrpSp->Parameters.Write.Length; ULONG WriteKey = IrpSp->Parameters.Write.Key; BOOLEAN WriteToEndOfFile = FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart; BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); FSP_FSCTL_TRANSACT_REQ *Request; BOOLEAN Success; ASSERT(FileNode == FileDesc->FileNode); /* no MDL requests on the non-cached path */ if (FlagOn(IrpSp->MinorFunction, IRP_MN_MDL)) return STATUS_INVALID_PARAMETER; /* paging I/O cannot change the file size */ if (PagingIo && WriteToEndOfFile) return STATUS_INVALID_PARAMETER; /* stop CcWriteBehind from calling me! */ if (FspIoqStopped(FspFsvolDeviceExtension(FsvolDeviceObject)->Ioq)) return FspFsvolDeviceStoppedStatus(FsvolDeviceObject); /* probe and lock the user buffer */ Result = FspLockUserBuffer(Irp, WriteLength, IoReadAccess); if (!NT_SUCCESS(Result)) return Result; /* acquire FileNode exclusive Full */ Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, CanWait); if (!Success) return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteNonCached, 0); /* perform oplock check */ if (!PagingIo) { Result = FspFileNodeOplockCheckAsync( FileNode, FspFileNodeAcquireFull, FspFsvolWriteNonCached, Irp); if (STATUS_PENDING == Result) return Result; if (!NT_SUCCESS(Result)) { FspFileNodeRelease(FileNode, Full); return Result; } } /* check the file locks */ if (!PagingIo && !FsRtlCheckLockForWriteAccess(&FileNode->FileLock, Irp)) { FspFileNodeRelease(FileNode, Full); return STATUS_FILE_LOCK_CONFLICT; } /* if this is a non-cached transfer on a cached file then flush and purge the file */ if (!PagingIo && 0 != FileObject->SectionObjectPointer->DataSectionObject) { if (!CanWait) { FspFileNodeRelease(FileNode, Full); return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteNonCached, 0); } Result = FspFileNodeFlushAndPurgeCache(FileNode, IrpSp->Parameters.Write.ByteOffset.QuadPart, IrpSp->Parameters.Write.Length, TRUE); if (!NT_SUCCESS(Result)) { FspFileNodeRelease(FileNode, Full); return Result; } } Request = FspIrpRequest(Irp); if (0 == Request) { /* create request */ Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolWriteNonCachedRequestFini, &Request); if (!NT_SUCCESS(Result)) { FspFileNodeRelease(FileNode, Full); return Result; } } else { /* reuse existing request */ ASSERT(Request->Size == sizeof *Request); ASSERT(Request->Hint == (UINT_PTR)Irp); FspIopResetRequest(Request, FspFsvolWriteNonCachedRequestFini); RtlZeroMemory(&Request->Req, sizeof *Request - FIELD_OFFSET(FSP_FSCTL_TRANSACT_REQ, Req)); } Request->Kind = FspFsctlTransactWriteKind; Request->Req.Write.UserContext = FileNode->UserContext; Request->Req.Write.UserContext2 = FileDesc->UserContext2; Request->Req.Write.Offset = WriteOffset.QuadPart; Request->Req.Write.Length = WriteLength; Request->Req.Write.Key = WriteKey; Request->Req.Write.ConstrainedIo = !!PagingIo; FspFileNodeSetOwner(FileNode, Full, Request); FspIopRequestContext(Request, RequestIrp) = Irp; FSP_STATISTICS *Statistics = FspFsvolDeviceStatistics(FsvolDeviceObject); if (PagingIo) { FspStatisticsInc(Statistics, Base.UserFileWrites); FspStatisticsAdd(Statistics, Base.UserFileWriteBytes, WriteLength); FspStatisticsInc(Statistics, Base.UserDiskWrites); } else { FspStatisticsInc(Statistics, Specific.NonCachedWrites); FspStatisticsAdd(Statistics, Specific.NonCachedWriteBytes, WriteLength); FspStatisticsInc(Statistics, Specific.NonCachedDiskWrites); } return FSP_STATUS_IOQ_POST; }
NTSTATUS FspFsvolQuerySecurityComplete( PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) { 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->AssociatedIrp.SystemBuffer; ULONG Length = IrpSp->Parameters.QuerySecurity.Length; PVOID SecurityBuffer = 0; FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); BOOLEAN Success; if (0 != FspIopRequestContext(Request, RequestFileNode)) { /* check that the security descriptor we got back is valid */ if (Response->Buffer + Response->Rsp.QuerySecurity.SecurityDescriptor.Size > (PUINT8)Response + Response->Size || !RtlValidRelativeSecurityDescriptor((PVOID)Response->Buffer, Response->Rsp.QuerySecurity.SecurityDescriptor.Size, 0)) { Irp->IoStatus.Information = 0; Result = STATUS_INVALID_SECURITY_DESCR; FSP_RETURN(); } FspIopRequestContext(Request, RequestSecurityChangeNumber) = (PVOID)FileNode->SecurityChangeNumber; FspIopRequestContext(Request, RequestFileNode) = 0; FspFileNodeReleaseOwner(FileNode, Full, Request); } Success = DEBUGTEST(90) && 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); }