some fixes in NtReadFile and NtWrite file for (a)synchronous pipe handling and parameter checks Modified: trunk/reactos/ntoskrnl/io/file.c _____
Modified: trunk/reactos/ntoskrnl/io/file.c --- trunk/reactos/ntoskrnl/io/file.c 2006-01-17 03:00:21 UTC (rev 20930) +++ trunk/reactos/ntoskrnl/io/file.c 2006-01-17 03:25:55 UTC (rev 20931) @@ -531,6 +531,8 @@
PIO_STACK_LOCATION StackPtr; PKEVENT EventObject = NULL; BOOLEAN LocalEvent = FALSE; + ULONG AccessType; + OBJECT_HANDLE_INFORMATION HandleInformation; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
DPRINT("IopDeviceFsIoControl(DeviceHandle 0x%p Event 0x%p UserApcRoutine 0x%p " @@ -541,17 +543,84 @@ IoControlCode,InputBuffer,InputBufferLength,OutputBuffer, OutputBufferLength);
- if (IoStatusBlock == NULL) return STATUS_ACCESS_VIOLATION; + AccessType = IO_METHOD_FROM_CTL_CODE(IoControlCode);
- /* Check granted access against the access rights from IoContolCode */ + if (PreviousMode != KernelMode) + { + _SEH_TRY + { + ProbeForWrite(IoStatusBlock, + sizeof(IO_STATUS_BLOCK), + sizeof(ULONG)); + + /* probe the input and output buffers if needed */ + if (AccessType == METHOD_BUFFERED) + { + if (OutputBuffer != NULL) + { + ProbeForWrite(OutputBuffer, + OutputBufferLength, + 1); + } + else + { + /* make sure the caller can't fake this as we depend on this */ + OutputBufferLength = 0; + } + } + + if (AccessType != METHOD_NEITHER) + { + if (InputBuffer != NULL) + { + ProbeForRead(InputBuffer, + InputBufferLength, + 1); + } + else + { + /* make sure the caller can't fake this as we depend on this */ + InputBufferLength = 0; + } + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if (!NT_SUCCESS(Status)) + { + DPRINT("Probing the buffers failed!\n"); + return Status; + } + } + + /* Don't check for access rights right now, KernelMode can do anything */ Status = ObReferenceObjectByHandle(DeviceHandle, - (IoControlCode >> 14) & 0x3, + 0, IoFileObjectType, PreviousMode, (PVOID *) &FileObject, - NULL); + &HandleInformation); if (!NT_SUCCESS(Status)) return Status;
+ /* Check for sufficient access rights */ + if (PreviousMode != KernelMode) + { + ACCESS_MASK DesiredAccess = (ACCESS_MASK)((IoControlCode >> 14) & 3); + if (DesiredAccess != FILE_ANY_ACCESS && + !RtlAreAllAccessesGranted(HandleInformation.GrantedAccess, + (ACCESS_MASK)((IoControlCode >> 14) & 3))) + { + DPRINT1("Insufficient access rights! Granted: 0x%x Desired: 0x%x\n", + HandleInformation.GrantedAccess, (ACCESS_MASK)((IoControlCode >> 14) & 3)); + ObDereferenceObject (FileObject); + return STATUS_ACCESS_DENIED; + } + } + /* Check for an event */ if (Event) { @@ -605,6 +674,19 @@ EventObject, IoStatusBlock);
+ if (Irp == NULL) + { + DPRINT1("IoBuildDeviceIoControlRequest failed!\n"); + + if (EventObject != NULL) + { + ObDereferenceObject (EventObject); + } + + ObDereferenceObject (FileObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + /* Set some extra settings */ Irp->Tail.Overlay.OriginalFileObject = FileObject; Irp->RequestorMode = PreviousMode; @@ -2917,9 +2999,10 @@ PDEVICE_OBJECT DeviceObject; PIO_STACK_LOCATION StackPtr; KPROCESSOR_MODE PreviousMode; - BOOLEAN LocalEvent = FALSE; PKEVENT EventObject = NULL; LARGE_INTEGER CapturedByteOffset; + ULONG CapturedKey = 0; + BOOLEAN Synchronous = FALSE;
DPRINT("NtReadFile(FileHandle 0x%p Buffer 0x%p Length %x ByteOffset 0x%p, " "IoStatusBlock 0x%p)\n", FileHandle, Buffer, Length, ByteOffset, @@ -2945,6 +3028,10 @@ { CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); } + if (Key != NULL) + { + CapturedKey = ProbeForReadUlong(Key); + } /* FIXME - probe other pointers and capture information */ } _SEH_HANDLE @@ -2961,6 +3048,10 @@ { CapturedByteOffset = *ByteOffset; } + if (Key != NULL) + { + CapturedKey = *Key; + } }
/* Get File Object */ @@ -2972,23 +3063,29 @@ NULL); if (!NT_SUCCESS(Status)) return Status;
- /* Check the Byte Offset */ - if (ByteOffset == NULL || - (CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION && - CapturedByteOffset.u.HighPart == -1)) + /* Check if we should use Sync IO or not */ + if (FileObject->Flags & FO_SYNCHRONOUS_IO) { - /* a valid ByteOffset is required if asynch. op. */ - if (!(FileObject->Flags & FO_SYNCHRONOUS_IO)) + if (ByteOffset == NULL || + (CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION && + CapturedByteOffset.u.HighPart == -1)) { - DPRINT1("NtReadFile: missing ByteOffset for asynch. op\n"); - ObDereferenceObject(FileObject); - return STATUS_INVALID_PARAMETER; + /* Use the Current Byte OFfset */ + CapturedByteOffset = FileObject->CurrentByteOffset; }
- /* Use the Current Byte OFfset */ - CapturedByteOffset = FileObject->CurrentByteOffset; + Synchronous = TRUE; } + else if (ByteOffset == NULL && !(FileObject->Flags & FO_NAMED_PIPE)) + { + /* a valid ByteOffset is required if asynch. op. */ + DPRINT1("NtReadFile: missing ByteOffset for asynch. op (0x%p)\n", + ByteOffset);
+ ObDereferenceObject(FileObject); + return STATUS_INVALID_PARAMETER; + } + /* Check for event */ if (Event) { @@ -3017,16 +3114,7 @@ DeviceObject = IoGetRelatedDeviceObject(FileObject); }
- /* Check if we should use Sync IO or not */ - if (FileObject->Flags & FO_SYNCHRONOUS_IO) - { - /* Use File Object event */ - KeClearEvent(&FileObject->Event); - } - else - { - LocalEvent = TRUE; - } + KeClearEvent(&FileObject->Event);
/* Create the IRP */ _SEH_TRY @@ -3038,6 +3126,7 @@ &CapturedByteOffset, EventObject, IoStatusBlock); + if (Irp == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; @@ -3073,13 +3162,13 @@ /* Setup Stack Data */ StackPtr = IoGetNextIrpStackLocation(Irp); StackPtr->FileObject = FileObject; - StackPtr->Parameters.Read.Key = Key ? *Key : 0; + StackPtr->Parameters.Read.Key = CapturedKey;
/* Call the Driver */ Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { - if (!LocalEvent) + if (Synchronous) { KeWaitForSingleObject(&FileObject->Event, Executive, @@ -3679,7 +3768,7 @@ PDEVICE_OBJECT DeviceObject; PIO_STACK_LOCATION StackPtr; KPROCESSOR_MODE PreviousMode; - BOOLEAN LocalEvent = FALSE; + BOOLEAN Synchronous = FALSE; PKEVENT EventObject = NULL; LARGE_INTEGER CapturedByteOffset; ULONG CapturedKey = 0; @@ -3694,9 +3783,32 @@ PreviousMode = KeGetPreviousMode(); CapturedByteOffset.QuadPart = 0;
+ /* Get File Object */ + Status = ObReferenceObjectByHandle(FileHandle, + 0, + IoFileObjectType, + PreviousMode, + (PVOID*)&FileObject, + &ObjectHandleInfo); + if (!NT_SUCCESS(Status)) return Status; + + /* If this is a named pipe, make sure we don't ask for FILE_APPEND_DATA as it + overlaps with the FILE_CREATE_PIPE_INSTANCE access right! */ + if (!(FileObject->Flags & FO_NAMED_PIPE)) + DesiredAccess |= FILE_APPEND_DATA; + /* Validate User-Mode Buffers */ if(PreviousMode != KernelMode) { + /* check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was + granted. */ + if (!RtlAreAnyAccessesGranted(ObjectHandleInfo.GrantedAccess, + DesiredAccess)) + { + ObDereferenceObject(FileObject); + return STATUS_ACCESS_DENIED; + } + _SEH_TRY { ProbeForWrite(IoStatusBlock, @@ -3736,62 +3848,35 @@ } }
- /* Get File Object */ - Status = ObReferenceObjectByHandle(FileHandle, - 0, - IoFileObjectType, - PreviousMode, - (PVOID*)&FileObject, - &ObjectHandleInfo); - if (!NT_SUCCESS(Status)) return Status; - - /* check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was - granted. However, if this is a named pipe, make sure we don't ask for - FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE - access right! */ - if (!(FileObject->Flags & FO_NAMED_PIPE)) - DesiredAccess |= FILE_APPEND_DATA; - if (!RtlAreAnyAccessesGranted(ObjectHandleInfo.GrantedAccess, - DesiredAccess)) + /* check if this is an append operation */ + if ((ObjectHandleInfo.GrantedAccess & DesiredAccess) == FILE_APPEND_DATA) { - ObDereferenceObject(FileObject); - return STATUS_ACCESS_DENIED; + /* Give the drivers something to understand */ + CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE; + CapturedByteOffset.u.HighPart = -1; }
- /* Check if we got write Access */ - if (ObjectHandleInfo.GrantedAccess & FILE_WRITE_DATA) + /* Check if we should use Sync IO or not */ + if (FileObject->Flags & FO_SYNCHRONOUS_IO) { - /* Check the Byte Offset */ if (ByteOffset == NULL || (CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION && CapturedByteOffset.u.HighPart == -1)) { - /* a valid ByteOffset is required if asynch. op. */ - if (!(FileObject->Flags & FO_SYNCHRONOUS_IO)) - { - DPRINT1("NtReadFile: missing ByteOffset for asynch. op\n"); - ObDereferenceObject(FileObject); - return STATUS_INVALID_PARAMETER; - } - /* Use the Current Byte OFfset */ CapturedByteOffset = FileObject->CurrentByteOffset; } + + Synchronous = TRUE; } - else if ((ObjectHandleInfo.GrantedAccess & FILE_APPEND_DATA) && - !(FileObject->Flags & FO_NAMED_PIPE)) + else if (ByteOffset == NULL && !(FileObject->Flags & FO_NAMED_PIPE)) { /* a valid ByteOffset is required if asynch. op. */ - if (!(FileObject->Flags & FO_SYNCHRONOUS_IO)) - { - DPRINT1("NtWriteFile: missing ByteOffset for asynch. op\n"); - ObDereferenceObject(FileObject); - return STATUS_INVALID_PARAMETER; - } + DPRINT1("NtReadFile: missing ByteOffset for asynch. op (0x%p)\n", + ByteOffset);
- /* Give the drivers somethign to understand */ - CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE; - CapturedByteOffset.u.HighPart = 0xffffffff; + ObDereferenceObject(FileObject); + return STATUS_INVALID_PARAMETER; }
/* Check if we got an event */ @@ -3822,16 +3907,7 @@ DeviceObject = IoGetRelatedDeviceObject(FileObject); }
- /* Check if we should use Sync IO or not */ - if (FileObject->Flags & FO_SYNCHRONOUS_IO) - { - /* Use File Object event */ - KeClearEvent(&FileObject->Event); - } - else - { - LocalEvent = TRUE; - } + KeClearEvent(&FileObject->Event);
/* Build the IRP */ _SEH_TRY @@ -3888,7 +3964,7 @@ Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { - if (!LocalEvent) + if (Synchronous) { KeWaitForSingleObject(&FileObject->Event, Executive,