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; }
static NTSTATUS FspFsvolLockControlRetry( PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, BOOLEAN CanWait) { PAGED_CODE(); NTSTATUS Result; PFILE_OBJECT FileObject = IrpSp->FileObject; FSP_FILE_NODE *FileNode = FileObject->FsContext; BOOLEAN Success; /* try to acquire the FileNode shared Main */ Success = DEBUGTEST(90) && FspFileNodeTryAcquireSharedF(FileNode, FspFileNodeAcquireMain, CanWait); if (!Success) return FspWqRepostIrpWorkItem(Irp, FspFsvolLockControlRetry, 0); /* perform oplock check; we are only implementing Win7 behavior */ Result = FspFileNodeOplockCheckAsync( FileNode, FspFileNodeAcquireMain, FspFsvolLockControlRetry, Irp); if (STATUS_PENDING == Result) return Result; if (!NT_SUCCESS(Result)) { FspFileNodeRelease(FileNode, Main); return Result; } ULONG IrpFlags = FspIrpFlags(Irp); IoSetTopLevelIrp(0); /* let the FSRTL package handle this one! */ Result = FspFileNodeProcessLockIrp(FileNode, Irp); FspFileNodeReleaseF(FileNode, IrpFlags); return Result | FSP_STATUS_IGNORE_BIT; }
static NTSTATUS FspFsvolWriteCached( PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, BOOLEAN CanWait) { PAGED_CODE(); /* assert: must be top-level IRP */ ASSERT(0 == FspIrpTopFlags(Irp)); NTSTATUS Result; BOOLEAN Retrying = 0 != FspIrpRequest(Irp); PFILE_OBJECT FileObject = IrpSp->FileObject; FSP_FILE_NODE *FileNode = FileObject->FsContext; LARGE_INTEGER WriteOffset = IrpSp->Parameters.Write.ByteOffset; ULONG WriteLength = IrpSp->Parameters.Write.Length; BOOLEAN WriteToEndOfFile = FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart; BOOLEAN SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); FSP_FSCTL_FILE_INFO FileInfo; CC_FILE_SIZES FileSizes; FILE_END_OF_FILE_INFORMATION EndOfFileInformation; UINT64 WriteEndOffset; BOOLEAN ExtendingFile; BOOLEAN Success; /* should we defer the write? */ Success = DEBUGTEST(90) && CcCanIWrite(FileObject, WriteLength, CanWait, Retrying); if (!Success) { Result = FspWqCreateIrpWorkItem(Irp, FspFsvolWriteCached, 0); if (NT_SUCCESS(Result)) { IoMarkIrpPending(Irp); CcDeferWrite(FileObject, FspFsvolWriteCachedDeferred, Irp, 0, WriteLength, Retrying); return STATUS_PENDING; } /* if we are unable to defer we will go ahead and (try to) service the IRP now! */ } /* try to acquire the FileNode Main exclusive */ Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireMain, CanWait); if (!Success) return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteCached, 0); /* perform oplock check */ Result = FspFileNodeOplockCheckAsync( FileNode, FspFileNodeAcquireMain, FspFsvolWriteCached, Irp); if (STATUS_PENDING == Result) return Result; if (!NT_SUCCESS(Result)) { FspFileNodeRelease(FileNode, Main); return Result; } /* check the file locks */ if (!FsRtlCheckLockForWriteAccess(&FileNode->FileLock, Irp)) { FspFileNodeRelease(FileNode, Main); return STATUS_FILE_LOCK_CONFLICT; } /* compute new file size */ ASSERT(FspTimeoutInfinity32 == FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FileInfoTimeout); FspFileNodeGetFileInfo(FileNode, &FileInfo); if (WriteToEndOfFile) WriteOffset.QuadPart = FileInfo.FileSize; WriteEndOffset = WriteOffset.QuadPart + WriteLength; ExtendingFile = FileInfo.FileSize < WriteEndOffset; if (ExtendingFile && !CanWait) { /* need CanWait==TRUE for FspSendSetInformationIrp */ FspFileNodeRelease(FileNode, Main); return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteCached, 0); } /* initialize cache if not already initialized! */ if (0 == FileObject->PrivateCacheMap) { FileSizes.AllocationSize.QuadPart = FileInfo.AllocationSize; FileSizes.FileSize.QuadPart = FileInfo.FileSize; FileSizes.ValidDataLength.QuadPart = MAXLONGLONG; Result = FspCcInitializeCacheMap(FileObject, &FileSizes, FALSE, &FspCacheManagerCallbacks, FileNode); if (!NT_SUCCESS(Result)) { FspFileNodeRelease(FileNode, Main); return Result; } } /* are we extending the file? */ if (ExtendingFile) { ASSERT(CanWait); /* send EndOfFileInformation IRP; this will also set TruncateOnClose, etc. */ EndOfFileInformation.EndOfFile.QuadPart = WriteEndOffset; Result = FspSendSetInformationIrp(FsvolDeviceObject/* bypass filters */, FileObject, FileEndOfFileInformation, &EndOfFileInformation, sizeof EndOfFileInformation); if (!NT_SUCCESS(Result)) { FspFileNodeRelease(FileNode, Main); return Result; } /* double-check that the cache still exists in case CcSetFileSizes failed */ if (0 == FileObject->SectionObjectPointer->SharedCacheMap) { FspFileNodeRelease(FileNode, Main); return STATUS_INSUFFICIENT_RESOURCES; // or STATUS_SECTION_TOO_BIG? } } /* * From this point forward we must jump to the CLEANUP label on failure. */ /* are we using the copy or MDL interface? */ if (!FlagOn(IrpSp->MinorFunction, IRP_MN_MDL)) { PVOID Buffer; Buffer = 0 == Irp->MdlAddress ? Irp->UserBuffer : MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); if (0 == Buffer) { Result = STATUS_INSUFFICIENT_RESOURCES; goto cleanup; } Result = FspCcCopyWrite(FileObject, &WriteOffset, WriteLength, CanWait, Buffer); if (!NT_SUCCESS(Result) || STATUS_PENDING == Result) goto cleanup; Irp->IoStatus.Information = WriteLength; } else { Result = FspCcPrepareMdlWrite(FileObject, &WriteOffset, WriteLength, &Irp->MdlAddress, &Irp->IoStatus); if (!NT_SUCCESS(Result)) goto cleanup; ASSERT(STATUS_PENDING != Result); } /* update the current file offset if synchronous I/O */ if (SynchronousIo) FileObject->CurrentByteOffset.QuadPart = WriteEndOffset; /* mark the file object as modified (if not paging I/O) */ SetFlag(FileObject->Flags, FO_FILE_MODIFIED); FspFileNodeRelease(FileNode, Main); return STATUS_SUCCESS; cleanup: FspFileNodeRelease(FileNode, Main); if (STATUS_PENDING == Result) return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteCached, 0); return Result; }
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); }