[NTOSKRNL]: Fix a literal metric fuckton of missing parameter checks in IoCreateFile. I know for a fact this fixes two ntdll pipe tests, it probably fixes a bunch of other tests too.

[NTOSKRNL]: Fix OPEN_PACKET definition. Also, allocate it from the pool in IoCreateFile, instead of the stack (Windows does too).
[NTOSKRNL]: IoCreateFile should only be setting IO_STATUS_BLOCK Information/Status if EA Buffer validation *Fails*, not if it succeeds!

svn path=/trunk/; revision=60038
This commit is contained in:
Alex Ionescu 2013-09-11 18:50:28 +00:00
parent 14fc5d4748
commit e4b198bc97
2 changed files with 204 additions and 90 deletions

View file

@ -368,14 +368,15 @@ typedef struct _OPEN_PACKET
PFILE_BASIC_INFORMATION BasicInformation;
PFILE_NETWORK_OPEN_INFORMATION NetworkInformation;
CREATE_FILE_TYPE CreateFileType;
PVOID MailslotOrPipeParameters;
PVOID ExtraCreateParameters;
BOOLEAN Override;
BOOLEAN QueryOnly;
BOOLEAN DeleteOnly;
BOOLEAN FullAttributes;
PDUMMY_FILE_OBJECT DummyFileObject;
PDUMMY_FILE_OBJECT LocalFileObject;
BOOLEAN TraversedMountPoint;
ULONG InternalFlags;
//PIO_DRIVER_CREATE_CONTEXT DriverCreateContext; Vista only, needs ROS DDK Update
PDEVICE_OBJECT TopDeviceObjectHint;
} OPEN_PACKET, *POPEN_PACKET;
//

View file

@ -188,7 +188,7 @@ IopParseDevice(IN PVOID ParseObject,
BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile;
OBJECT_ATTRIBUTES ObjectAttributes;
KIRQL OldIrql;
PDUMMY_FILE_OBJECT DummyFileObject;
PDUMMY_FILE_OBJECT LocalFileObject;
PFILE_BASIC_INFORMATION FileBasicInfo;
ULONG ReturnLength;
KPROCESSOR_MODE CheckMode;
@ -503,9 +503,7 @@ IopParseDevice(IN PVOID ParseObject,
/* Now set the IRP data */
Irp->RequestorMode = AccessMode;
Irp->Flags = IRP_CREATE_OPERATION |
IRP_SYNCHRONOUS_API |
IRP_DEFER_IO_COMPLETION;
Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->UserIosb = &IoStatusBlock;
Irp->MdlAddress = NULL;
@ -537,8 +535,7 @@ IopParseDevice(IN PVOID ParseObject,
/* Set the flags */
StackLoc->Flags = (UCHAR)OpenPacket->Options;
StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ?
SL_CASE_SENSITIVE: 0;
StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0;
break;
/* Named pipe */
@ -546,8 +543,7 @@ IopParseDevice(IN PVOID ParseObject,
/* Set the named pipe MJ and set the parameters */
StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
StackLoc->Parameters.CreatePipe.Parameters =
OpenPacket->MailslotOrPipeParameters;
StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters;
break;
/* Mailslot */
@ -555,8 +551,7 @@ IopParseDevice(IN PVOID ParseObject,
/* Set the mailslot MJ and set the parameters */
StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
StackLoc->Parameters.CreateMailslot.Parameters =
OpenPacket->MailslotOrPipeParameters;
StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters;
break;
}
@ -658,13 +653,13 @@ IopParseDevice(IN PVOID ParseObject,
else
{
/* Use the dummy object instead */
DummyFileObject = OpenPacket->DummyFileObject;
RtlZeroMemory(DummyFileObject, sizeof(DUMMY_FILE_OBJECT));
LocalFileObject = OpenPacket->LocalFileObject;
RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT));
/* Set it up */
FileObject = (PFILE_OBJECT)&DummyFileObject->ObjectHeader.Body;
DummyFileObject->ObjectHeader.Type = IoFileObjectType;
DummyFileObject->ObjectHeader.PointerCount = 1;
FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body;
LocalFileObject->ObjectHeader.Type = IoFileObjectType;
LocalFileObject->ObjectHeader.PointerCount = 1;
}
/* Setup the file header */
@ -1541,7 +1536,7 @@ IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
{
NTSTATUS Status;
KPROCESSOR_MODE AccessMode = ExGetPreviousMode();
DUMMY_FILE_OBJECT DummyFileObject;
DUMMY_FILE_OBJECT LocalFileObject;
FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo;
HANDLE Handle;
OPEN_PACKET OpenPacket;
@ -1582,7 +1577,7 @@ IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
&NetworkOpenInfo : FileInformation;
OpenPacket.QueryOnly = TRUE;
OpenPacket.FullAttributes = IsBasic ? FALSE : TRUE;
OpenPacket.DummyFileObject = &DummyFileObject;
OpenPacket.LocalFileObject = &LocalFileObject;
/* Update the operation count */
IopUpdateOperationCount(IopOtherTransfer);
@ -1717,14 +1712,18 @@ IoCreateFile(OUT PHANDLE FileHandle,
KPROCESSOR_MODE AccessMode;
HANDLE LocalHandle = 0;
LARGE_INTEGER SafeAllocationSize;
volatile PVOID SystemEaBuffer = NULL;
NTSTATUS Status = STATUS_SUCCESS;
OPEN_PACKET OpenPacket;
PNAMED_PIPE_CREATE_PARAMETERS NamedPipeCreateParameters;
POPEN_PACKET OpenPacket;
ULONG EaErrorOffset;
PAGED_CODE();
IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
/* Allocate the open packet */
OpenPacket = ExAllocatePoolWithTag(NonPagedPool, sizeof(*OpenPacket), 'pOoI');
if (!OpenPacket) return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(OpenPacket, sizeof(*OpenPacket));
/* Check if we have no parameter checking to do */
if (Options & IO_NO_PARAMETER_CHECKING)
{
@ -1738,12 +1737,112 @@ IoCreateFile(OUT PHANDLE FileHandle,
}
/* Check if the call came from user mode */
if (AccessMode != KernelMode)
if ((AccessMode != KernelMode) || (Options & IO_CHECK_CREATE_PARAMETERS))
{
/* Validate parameters */
if ((FileAttributes & ~FILE_ATTRIBUTE_VALID_FLAGS) ||
(ShareAccess & ~FILE_SHARE_VALID_FLAGS) ||
(Disposition > FILE_MAXIMUM_DISPOSITION) ||
(CreateOptions & ~FILE_VALID_OPTION_FLAGS) ||
((CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) &&
(!(DesiredAccess & SYNCHRONIZE))) ||
((CreateOptions & FILE_DELETE_ON_CLOSE) && (!(DesiredAccess & DELETE))) ||
((CreateOptions & (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT)) ==
(FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT)) ||
((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
((CreateOptions & ~(FILE_DIRECTORY_FILE |
FILE_SYNCHRONOUS_IO_ALERT |
FILE_SYNCHRONOUS_IO_NONALERT |
FILE_WRITE_THROUGH |
FILE_COMPLETE_IF_OPLOCKED |
FILE_OPEN_FOR_BACKUP_INTENT |
FILE_DELETE_ON_CLOSE |
FILE_OPEN_FOR_FREE_SPACE_QUERY |
FILE_OPEN_BY_FILE_ID |
FILE_NO_COMPRESSION |
FILE_OPEN_REPARSE_POINT)) ||
((Disposition != FILE_CREATE) && (Disposition != FILE_OPEN) && (Disposition != FILE_OPEN_IF)))) ||
((CreateOptions & FILE_COMPLETE_IF_OPLOCKED) && (CreateOptions & FILE_RESERVE_OPFILTER)) ||
((CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) && (DesiredAccess & FILE_APPEND_DATA)))
{
/*
* Parameter failure. We'll be as unspecific as NT as to
* why this happened though, to make debugging a pain!
*/
DPRINT1("File Create Parameter Failure!\n");
ExFreePool(OpenPacket);
return STATUS_INVALID_PARAMETER;
}
/* Now check if this is a named pipe */
if (CreateFileType == CreateFileTypeNamedPipe)
{
/* Make sure we have extra parameters */
if (!ExtraCreateParameters)
{
ExFreePool(OpenPacket);
return STATUS_INVALID_PARAMETER;
}
/* Get the parameters and validate them */
NamedPipeCreateParameters = ExtraCreateParameters;
if ((NamedPipeCreateParameters->NamedPipeType > FILE_PIPE_MESSAGE_TYPE) ||
(NamedPipeCreateParameters->ReadMode > FILE_PIPE_MESSAGE_MODE) ||
(NamedPipeCreateParameters->CompletionMode > FILE_PIPE_COMPLETE_OPERATION) ||
(ShareAccess & FILE_SHARE_DELETE) ||
((Disposition < FILE_OPEN) || (Disposition > FILE_OPEN_IF)) ||
(CreateOptions & ~FILE_VALID_PIPE_OPTION_FLAGS))
{
/* Invalid named pipe create */
ExFreePool(OpenPacket);
return STATUS_INVALID_PARAMETER;
}
}
else if (CreateFileType == CreateFileTypeMailslot)
{
/* Make sure we have extra parameters */
if (!ExtraCreateParameters)
{
ExFreePool(OpenPacket);
return STATUS_INVALID_PARAMETER;
}
/* Get the parameters and validate them */
if ((ShareAccess & FILE_SHARE_DELETE) ||
!(ShareAccess & ~FILE_SHARE_WRITE) ||
(Disposition != FILE_CREATE) ||
(CreateOptions & ~FILE_VALID_MAILSLOT_OPTION_FLAGS))
{
/* Invalid mailslot create */
ExFreePool(OpenPacket);
return STATUS_INVALID_PARAMETER;
}
}
_SEH2_TRY
{
/* Probe the output parameters */
ProbeForWriteHandle(FileHandle);
ProbeForWriteIoStatusBlock(IoStatusBlock);
/* Probe the allocation size if one was passed in */
if (AllocationSize)
{
SafeAllocationSize = ProbeForReadLargeInteger(AllocationSize);
@ -1753,32 +1852,44 @@ IoCreateFile(OUT PHANDLE FileHandle,
SafeAllocationSize.QuadPart = 0;
}
if ((EaBuffer) && (EaLength))
/* Make sure it's valid */
if (SafeAllocationSize.QuadPart < 0)
{
ProbeForRead(EaBuffer, EaLength, sizeof(ULONG));
/* marshal EaBuffer */
SystemEaBuffer = ExAllocatePoolWithTag(NonPagedPool,
EaLength,
TAG_EA);
if (!SystemEaBuffer)
{
_SEH2_YIELD(return STATUS_INSUFFICIENT_RESOURCES);
RtlRaiseStatus(STATUS_INVALID_PARAMETER);
}
RtlCopyMemory(SystemEaBuffer, EaBuffer, EaLength);
/* Check if EA was passed in */
if ((EaBuffer) && (EaLength))
{
/* Probe it */
ProbeForRead(EaBuffer, EaLength, sizeof(ULONG));
/* And marshall it */
OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
EaLength,
TAG_EA);
OpenPacket->EaLength = EaLength;
RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
/* Validate the buffer */
Status = IoCheckEaBufferValidity(SystemEaBuffer,
Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
EaLength,
&EaErrorOffset);
if (!NT_SUCCESS(Status))
{
/* Undo everything if it's invalid */
DPRINT1("Invalid EA buffer\n");
IoStatusBlock->Status = Status;
IoStatusBlock->Information = EaErrorOffset;
RtlRaiseStatus(Status);
}
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
if (OpenPacket->EaBuffer != NULL) ExFreePool(OpenPacket->EaBuffer);
ExFreePool(OpenPacket);
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
@ -1809,47 +1920,47 @@ IoCreateFile(OUT PHANDLE FileHandle,
if ((EaBuffer) && (EaLength))
{
/* Allocate the kernel copy */
SystemEaBuffer = ExAllocatePoolWithTag(NonPagedPool,
OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
EaLength,
TAG_EA);
if (!SystemEaBuffer) return STATUS_INSUFFICIENT_RESOURCES;
if (!OpenPacket->EaBuffer)
{
ExFreePool(OpenPacket);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Copy the data */
RtlCopyMemory(SystemEaBuffer, EaBuffer, EaLength);
OpenPacket->EaLength = EaLength;
RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
/* Validate the buffer */
Status = IoCheckEaBufferValidity(SystemEaBuffer,
Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
EaLength,
&EaErrorOffset);
IoStatusBlock->Status = Status;
IoStatusBlock->Information = EaErrorOffset;
}
}
if (!NT_SUCCESS(Status))
{
DPRINT1("FIXME: IoCheckEaBufferValidity() failed with Status: %lx\n",
Status);
/* Free SystemEaBuffer if needed and return the error */
if (SystemEaBuffer) ExFreePoolWithTag(SystemEaBuffer, TAG_EA);
/* Undo everything if it's invalid */
DPRINT1("Invalid EA buffer\n");
ExFreePool(OpenPacket->EaBuffer);
IoStatusBlock->Status = Status;
IoStatusBlock->Information = EaErrorOffset;
ExFreePool(OpenPacket);
return Status;
}
}
}
/* Setup the Open Packet */
RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
OpenPacket.Type = IO_TYPE_OPEN_PACKET;
OpenPacket.Size = sizeof(OPEN_PACKET);
OpenPacket.AllocationSize = SafeAllocationSize;
OpenPacket.CreateOptions = CreateOptions;
OpenPacket.FileAttributes = (USHORT)FileAttributes;
OpenPacket.ShareAccess = (USHORT)ShareAccess;
OpenPacket.EaBuffer = SystemEaBuffer;
OpenPacket.EaLength = EaLength;
OpenPacket.Options = Options;
OpenPacket.Disposition = Disposition;
OpenPacket.CreateFileType = CreateFileType;
OpenPacket.MailslotOrPipeParameters = ExtraCreateParameters;
OpenPacket->Type = IO_TYPE_OPEN_PACKET;
OpenPacket->Size = sizeof(*OpenPacket);
OpenPacket->AllocationSize = SafeAllocationSize;
OpenPacket->CreateOptions = CreateOptions;
OpenPacket->FileAttributes = (USHORT)FileAttributes;
OpenPacket->ShareAccess = (USHORT)ShareAccess;
OpenPacket->Options = Options;
OpenPacket->Disposition = Disposition;
OpenPacket->CreateFileType = CreateFileType;
OpenPacket->ExtraCreateParameters = ExtraCreateParameters;
/* Update the operation count */
IopUpdateOperationCount(IopOtherTransfer);
@ -1867,14 +1978,14 @@ IoCreateFile(OUT PHANDLE FileHandle,
AccessMode,
NULL,
DesiredAccess,
&OpenPacket,
OpenPacket,
&LocalHandle);
/* Free the EA Buffer */
if (OpenPacket.EaBuffer) ExFreePool(OpenPacket.EaBuffer);
if (OpenPacket->EaBuffer) ExFreePool(OpenPacket->EaBuffer);
/* Now check for Ob or Io failure */
if (!(NT_SUCCESS(Status)) || (OpenPacket.ParseCheck != TRUE))
if (!(NT_SUCCESS(Status)) || (OpenPacket->ParseCheck != TRUE))
{
/* Check if Ob thinks well went well */
if (NT_SUCCESS(Status))
@ -1888,10 +1999,10 @@ IoCreateFile(OUT PHANDLE FileHandle,
}
/* Now check the Io status */
if (!NT_SUCCESS(OpenPacket.FinalStatus))
if (!NT_SUCCESS(OpenPacket->FinalStatus))
{
/* Use this status instead of Ob's */
Status = OpenPacket.FinalStatus;
Status = OpenPacket->FinalStatus;
/* Check if it was only a warning */
if (NT_WARNING(Status))
@ -1900,8 +2011,8 @@ IoCreateFile(OUT PHANDLE FileHandle,
_SEH2_TRY
{
/* In this case, we copy the I/O Status back */
IoStatusBlock->Information = OpenPacket.Information;
IoStatusBlock->Status = OpenPacket.FinalStatus;
IoStatusBlock->Information = OpenPacket->Information;
IoStatusBlock->Status = OpenPacket->FinalStatus;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
@ -1911,39 +2022,40 @@ IoCreateFile(OUT PHANDLE FileHandle,
_SEH2_END;
}
}
else if ((OpenPacket.FileObject) && (OpenPacket.ParseCheck != 1))
else if ((OpenPacket->FileObject) && (OpenPacket->ParseCheck != 1))
{
/*
* This can happen in the very bizarre case where the parse routine
* actually executed more then once (due to a reparse) and ended
* up failing after already having created the File Object.
*/
if (OpenPacket.FileObject->FileName.Length)
if (OpenPacket->FileObject->FileName.Length)
{
/* It had a name, free it */
ExFreePoolWithTag(OpenPacket.FileObject->FileName.Buffer, TAG_IO_NAME);
ExFreePoolWithTag(OpenPacket->FileObject->FileName.Buffer, TAG_IO_NAME);
}
/* Clear the device object to invalidate the FO, and dereference */
OpenPacket.FileObject->DeviceObject = NULL;
ObDereferenceObject(OpenPacket.FileObject);
OpenPacket->FileObject->DeviceObject = NULL;
ObDereferenceObject(OpenPacket->FileObject);
}
}
else
{
/* We reached success and have a valid file handle */
OpenPacket.FileObject->Flags |= FO_HANDLE_CREATED;
OpenPacket->FileObject->Flags |= FO_HANDLE_CREATED;
ASSERT(OpenPacket->FileObject->Type == IO_TYPE_FILE);
/* Enter SEH for write back */
_SEH2_TRY
{
/* Write back the handle and I/O Status */
*FileHandle = LocalHandle;
IoStatusBlock->Information = OpenPacket.Information;
IoStatusBlock->Status = OpenPacket.FinalStatus;
IoStatusBlock->Information = OpenPacket->Information;
IoStatusBlock->Status = OpenPacket->FinalStatus;
/* Get the Io status */
Status = OpenPacket.FinalStatus;
Status = OpenPacket->FinalStatus;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
@ -1954,13 +2066,14 @@ IoCreateFile(OUT PHANDLE FileHandle,
}
/* Check if we were 100% successful */
if ((OpenPacket.ParseCheck == TRUE) && (OpenPacket.FileObject))
if ((OpenPacket->ParseCheck == TRUE) && (OpenPacket->FileObject))
{
/* Dereference the File Object */
ObDereferenceObject(OpenPacket.FileObject);
ObDereferenceObject(OpenPacket->FileObject);
}
/* Return status */
ExFreePool(OpenPacket);
return Status;
}
@ -2190,7 +2303,7 @@ IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PFILE_NETWORK_OPEN_INFORMATION Buffer)
{
NTSTATUS Status;
DUMMY_FILE_OBJECT DummyFileObject;
DUMMY_FILE_OBJECT LocalFileObject;
HANDLE Handle;
OPEN_PACKET OpenPacket;
PAGED_CODE();
@ -2207,7 +2320,7 @@ IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
OpenPacket.NetworkInformation = Buffer;
OpenPacket.QueryOnly = TRUE;
OpenPacket.FullAttributes = TRUE;
OpenPacket.DummyFileObject = &DummyFileObject;
OpenPacket.LocalFileObject = &LocalFileObject;
/*
* Attempt opening the file. This will call the I/O Parse Routine for
@ -3000,7 +3113,7 @@ NTAPI
NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
{
NTSTATUS Status;
DUMMY_FILE_OBJECT DummyFileObject;
DUMMY_FILE_OBJECT LocalFileObject;
HANDLE Handle;
KPROCESSOR_MODE AccessMode = KeGetPreviousMode();
OPEN_PACKET OpenPacket;
@ -3017,7 +3130,7 @@ NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
FILE_SHARE_DELETE;
OpenPacket.Disposition = FILE_OPEN;
OpenPacket.DeleteOnly = TRUE;
OpenPacket.DummyFileObject = &DummyFileObject;
OpenPacket.LocalFileObject = &LocalFileObject;
/* Update the operation counts */
IopUpdateOperationCount(IopOtherTransfer);