- Fix IopQueryNameFile to properly validate and calculate lengths at each step of the way and to support incomplete buffers. Previously, dangerous assumptions were made about the buffers and the actual required length was never returned.

svn path=/trunk/; revision=22853
This commit is contained in:
Alex Ionescu 2006-07-04 23:31:42 +00:00
parent 0342a00bde
commit ef41fc2623

View file

@ -463,61 +463,97 @@ IopSecurityFile(IN PVOID ObjectBody,
} }
NTSTATUS NTSTATUS
STDCALL NTAPI
IopQueryNameFile(PVOID ObjectBody, IopQueryNameFile(IN PVOID ObjectBody,
IN BOOLEAN HasName, IN BOOLEAN HasName,
POBJECT_NAME_INFORMATION ObjectNameInfo, OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
ULONG Length, IN ULONG Length,
PULONG ReturnLength, OUT PULONG ReturnLength,
IN KPROCESSOR_MODE PreviousMode) IN KPROCESSOR_MODE PreviousMode)
{ {
POBJECT_NAME_INFORMATION LocalInfo; POBJECT_NAME_INFORMATION LocalInfo;
PFILE_OBJECT FileObject; PFILE_NAME_INFORMATION LocalFileInfo;
ULONG LocalReturnLength; PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
ULONG LocalReturnLength, FileLength;
NTSTATUS Status; NTSTATUS Status;
PWCHAR p;
DPRINT1("IopQueryNameFile() called\n"); /* Validate length */
if (Length < sizeof(OBJECT_NAME_INFORMATION))
FileObject = (PFILE_OBJECT)ObjectBody; {
/* Wrong length, fail */
return STATUS_INFO_LENGTH_MISMATCH;
}
/* Allocate Buffer */ /* Allocate Buffer */
LocalInfo = ExAllocatePool(PagedPool, LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, TAG_IO);
sizeof(OBJECT_NAME_INFORMATION) + if (!LocalInfo) return STATUS_INSUFFICIENT_RESOURCES;
MAX_PATH * sizeof(WCHAR));
if (LocalInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES;
/* Query the name */ /* Query the name */
Status = ObQueryNameString(FileObject->DeviceObject, Status = ObQueryNameString(FileObject->DeviceObject,
LocalInfo, LocalInfo,
MAX_PATH * sizeof(WCHAR), Length,
&LocalReturnLength); &LocalReturnLength);
if (!NT_SUCCESS (Status)) if (!NT_SUCCESS (Status))
{ {
ExFreePool (LocalInfo); /* Free the buffer and fail */
return Status;
}
DPRINT ("Device path: %wZ\n", &LocalInfo->Name);
/* Write Device Path */
Status = RtlAppendUnicodeStringToString(&ObjectNameInfo->Name,
&(LocalInfo)->Name);
/* Query the File name */
Status = IoQueryFileInformation(FileObject,
FileNameInformation,
LocalReturnLength,
LocalInfo,
NULL);
if (Status != STATUS_SUCCESS)
{
ExFreePool(LocalInfo); ExFreePool(LocalInfo);
return Status; return Status;
} }
/* Write the Name */ /* Copy the information */
Status = RtlAppendUnicodeToString(&ObjectNameInfo->Name, RtlCopyMemory(ObjectNameInfo,
((PFILE_NAME_INFORMATION)LocalInfo)->FileName); LocalInfo,
DPRINT ("Total path: %wZ\n", &ObjectNameInfo->Name); LocalReturnLength > Length ?
Length : LocalReturnLength);
/* Set buffer pointer */
p = (PWCHAR)(ObjectNameInfo + 1);
ObjectNameInfo->Name.Buffer = p;
/* Advance in buffer */
p += (LocalInfo->Name.Length / sizeof(WCHAR));
/* Now get the file name buffer and check the length needed */
LocalFileInfo = (PFILE_NAME_INFORMATION)LocalInfo;
FileLength = Length -
LocalReturnLength +
FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
/* Query the File name */
Status = IoQueryFileInformation(FileObject,
FileNameInformation,
Length,
LocalFileInfo,
&LocalReturnLength);
if (NT_ERROR(Status))
{
/* Fail on errors only, allow warnings */
ExFreePool(LocalInfo);
return Status;
}
/* Now calculate the new lenghts left */
FileLength = LocalReturnLength -
FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
LocalReturnLength = (ULONG_PTR)p -
(ULONG_PTR)ObjectNameInfo +
LocalFileInfo->FileNameLength;
/* Write the Name and null-terminate it */
RtlMoveMemory(p, LocalFileInfo->FileName, FileLength);
p += (FileLength / sizeof(WCHAR));
*p = UNICODE_NULL;
LocalReturnLength += sizeof(UNICODE_NULL);
/* Return the length needed */
*ReturnLength = LocalReturnLength;
/* Setup the length and maximum length */
FileLength = (ULONG_PTR)p - (ULONG_PTR)ObjectNameInfo;
ObjectNameInfo->Name.Length = Length - sizeof(OBJECT_NAME_INFORMATION);
ObjectNameInfo->Name.MaximumLength = ObjectNameInfo->Name.Length +
sizeof(UNICODE_NULL);
/* Free buffer and return */ /* Free buffer and return */
ExFreePool(LocalInfo); ExFreePool(LocalInfo);