1
0
Fork 0
mirror of https://github.com/reactos/reactos.git synced 2025-06-18 20:25:21 +00:00

[NPFS-NEW]: Fix pool corruption and crashing bugs in NpPeek, which was using sizeof instead of FIELD_OFFSET.

[NPFS-NEW]: Actually implement NpCancelWaiter instead of making it ASSERT.
[NPFS-NEW]: Critical fixes to NpAddWaiter and NpWaitForNamedPipe to fix logic flaws.
NPFS-NEW now behaves without any visible regressions, and exhibits only 2 failures in the kernel32 pipe winetest -- vs 120+ failures with the current NPFS driver. It has 0 ntdll pipe failures, and 0 kmtest pipe failures.

svn path=/trunk/; revision=60070
This commit is contained in:
Alex Ionescu 2013-09-13 07:49:42 +00:00
parent f9cb414f74
commit f2ca6ff5d0
6 changed files with 179 additions and 84 deletions
reactos/drivers/filesystems/npfs_new

View file

@ -551,7 +551,7 @@ NpCreateNewNamedPipe(IN PNP_DCB Dcb,
Parameters->NamedPipeType & 0xFFFF, Parameters->NamedPipeType & 0xFFFF,
&Fcb); &Fcb);
if (!NT_SUCCESS(Status)) goto Quickie; if (!NT_SUCCESS(Status)) goto Quickie;
Status = NpCreateCcb(Fcb, Status = NpCreateCcb(Fcb,
FileObject, FileObject,
FILE_PIPE_LISTENING_STATE, FILE_PIPE_LISTENING_STATE,

View file

@ -206,7 +206,7 @@ NpPeek(IN PDEVICE_OBJECT DeviceObject,
{ {
PIO_STACK_LOCATION IoStack; PIO_STACK_LOCATION IoStack;
NODE_TYPE_CODE Type; NODE_TYPE_CODE Type;
ULONG InputLength; ULONG OutputLength;
ULONG NamedPipeEnd; ULONG NamedPipeEnd;
PNP_CCB Ccb; PNP_CCB Ccb;
PFILE_PIPE_PEEK_BUFFER PeekBuffer; PFILE_PIPE_PEEK_BUFFER PeekBuffer;
@ -218,7 +218,7 @@ NpPeek(IN PDEVICE_OBJECT DeviceObject,
PAGED_CODE(); PAGED_CODE();
IoStack = IoGetCurrentIrpStackLocation(Irp); IoStack = IoGetCurrentIrpStackLocation(Irp);
InputLength = IoStack->Parameters.FileSystemControl.OutputBufferLength; OutputLength = IoStack->Parameters.FileSystemControl.OutputBufferLength;
Type = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd); Type = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);
if (!Type) if (!Type)
@ -226,7 +226,8 @@ NpPeek(IN PDEVICE_OBJECT DeviceObject,
return STATUS_PIPE_DISCONNECTED; return STATUS_PIPE_DISCONNECTED;
} }
if ((Type != NPFS_NTC_CCB) && (InputLength < sizeof(*PeekBuffer))) if ((Type != NPFS_NTC_CCB) &&
(OutputLength < FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data)))
{ {
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
} }
@ -264,7 +265,7 @@ NpPeek(IN PDEVICE_OBJECT DeviceObject,
PeekBuffer->NumberOfMessages = 0; PeekBuffer->NumberOfMessages = 0;
PeekBuffer->MessageLength = 0; PeekBuffer->MessageLength = 0;
PeekBuffer->NamedPipeState = Ccb->NamedPipeState; PeekBuffer->NamedPipeState = Ccb->NamedPipeState;
BytesPeeked = sizeof(*PeekBuffer); BytesPeeked = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data);
if (DataQueue->QueueState == WriteEntries) if (DataQueue->QueueState == WriteEntries)
{ {
@ -279,7 +280,8 @@ NpPeek(IN PDEVICE_OBJECT DeviceObject,
PeekBuffer->NumberOfMessages = DataQueue->EntriesInQueue; PeekBuffer->NumberOfMessages = DataQueue->EntriesInQueue;
PeekBuffer->MessageLength = DataEntry->DataSize - DataQueue->ByteOffset; PeekBuffer->MessageLength = DataEntry->DataSize - DataQueue->ByteOffset;
} }
if (InputLength == sizeof(*PeekBuffer))
if (OutputLength == FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data))
{ {
Status = PeekBuffer->ReadDataAvailable ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS; Status = PeekBuffer->ReadDataAvailable ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
} }
@ -289,12 +291,12 @@ NpPeek(IN PDEVICE_OBJECT DeviceObject,
TRUE, TRUE,
FALSE, FALSE,
PeekBuffer->Data, PeekBuffer->Data,
InputLength - sizeof(*PeekBuffer), OutputLength - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data),
Ccb->Fcb->NamedPipeType == FILE_PIPE_MESSAGE_TYPE, Ccb->Fcb->NamedPipeType == FILE_PIPE_MESSAGE_TYPE,
Ccb, Ccb,
List); List);
Status = IoStatus.Status; Status = IoStatus.Status;
BytesPeeked = IoStatus.Information + sizeof(*PeekBuffer); BytesPeeked += IoStatus.Information;
} }
} }
else else
@ -523,14 +525,18 @@ NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject,
NODE_TYPE_CODE NodeTypeCode; NODE_TYPE_CODE NodeTypeCode;
PLIST_ENTRY NextEntry; PLIST_ENTRY NextEntry;
PNP_FCB Fcb; PNP_FCB Fcb;
PWCHAR OriginalBuffer;
PAGED_CODE(); PAGED_CODE();
IoStack = IoGetCurrentIrpStackLocation(Irp); IoStack = IoGetCurrentIrpStackLocation(Irp);
InLength = IoStack->Parameters.DeviceIoControl.InputBufferLength; InLength = IoStack->Parameters.FileSystemControl.InputBufferLength;
SourceString.Buffer = NULL; SourceString.Buffer = NULL;
if (NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd) != NPFS_NTC_ROOT_DCB) if (NpDecodeFileObject(IoStack->FileObject,
NULL,
&Ccb,
&NamedPipeEnd) != NPFS_NTC_ROOT_DCB)
{ {
Status = STATUS_ILLEGAL_FUNCTION; Status = STATUS_ILLEGAL_FUNCTION;
goto Quickie; goto Quickie;
@ -544,14 +550,17 @@ NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject,
} }
NameLength = Buffer->NameLength; NameLength = Buffer->NameLength;
if ((NameLength > 0xFFFD) || ((NameLength + sizeof(*Buffer)) > InLength)) if ((NameLength > (0xFFFF - sizeof(UNICODE_NULL))) ||
((NameLength + FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name)) > InLength))
{ {
Status = STATUS_INVALID_PARAMETER; Status = STATUS_INVALID_PARAMETER;
goto Quickie; goto Quickie;
} }
SourceString.Length = (USHORT)NameLength + sizeof(OBJ_NAME_PATH_SEPARATOR); SourceString.Length = (USHORT)NameLength + sizeof(OBJ_NAME_PATH_SEPARATOR);
SourceString.Buffer = ExAllocatePoolWithTag(PagedPool, SourceString.Length, NPFS_WRITE_BLOCK_TAG); SourceString.Buffer = ExAllocatePoolWithTag(PagedPool,
SourceString.Length,
NPFS_WRITE_BLOCK_TAG);
if (!SourceString.Buffer) if (!SourceString.Buffer)
{ {
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
@ -562,6 +571,7 @@ NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject,
RtlCopyMemory(&SourceString.Buffer[1], Buffer->Name, Buffer->NameLength); RtlCopyMemory(&SourceString.Buffer[1], Buffer->Name, Buffer->NameLength);
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
OriginalBuffer = SourceString.Buffer;
//Status = NpTranslateAlias(&SourceString); //Status = NpTranslateAlias(&SourceString);
if (!NT_SUCCESS(Status)) goto Quickie; if (!NT_SUCCESS(Status)) goto Quickie;
@ -583,7 +593,7 @@ NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject,
if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) break; if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) break;
} }
if (NextEntry == &Fcb->CcbList) if (NextEntry != &Fcb->CcbList)
{ {
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
} }
@ -592,7 +602,8 @@ NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject,
Status = NpAddWaiter(&NpVcb->WaitQueue, Status = NpAddWaiter(&NpVcb->WaitQueue,
Fcb->Timeout, Fcb->Timeout,
Irp, Irp,
&SourceString); OriginalBuffer == SourceString.Buffer ?
NULL : &SourceString);
} }
Quickie: Quickie:

View file

@ -62,7 +62,7 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
DriverObject->DriverUnload = NULL; DriverObject->DriverUnload = NULL;
RtlInitUnicodeString(&DeviceName, L"\\Device\\NamedPipe2"); RtlInitUnicodeString(&DeviceName, L"\\Device\\NamedPipe");
Status = IoCreateDevice(DriverObject, Status = IoCreateDevice(DriverObject,
sizeof(NP_VCB), sizeof(NP_VCB),
&DeviceName, &DeviceName,

View file

@ -178,7 +178,7 @@ typedef struct _NP_WAIT_QUEUE_ENTRY
KDPC Dpc; KDPC Dpc;
KTIMER Timer; KTIMER Timer;
PNP_WAIT_QUEUE WaitQueue; PNP_WAIT_QUEUE WaitQueue;
UNICODE_STRING String; UNICODE_STRING AliasName;
PFILE_OBJECT FileObject; PFILE_OBJECT FileObject;
} NP_WAIT_QUEUE_ENTRY, *PNP_WAIT_QUEUE_ENTRY; } NP_WAIT_QUEUE_ENTRY, *PNP_WAIT_QUEUE_ENTRY;
@ -590,7 +590,7 @@ NTAPI
NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue, NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue,
IN LARGE_INTEGER WaitTime, IN LARGE_INTEGER WaitTime,
IN PIRP Irp, IN PIRP Irp,
IN PUNICODE_STRING Name); IN PUNICODE_STRING AliasName);
NTSTATUS NTSTATUS
NTAPI NTAPI

View file

@ -66,7 +66,6 @@ NpDeleteFcb(IN PNP_FCB Fcb,
IN PLIST_ENTRY ListEntry) IN PLIST_ENTRY ListEntry)
{ {
PNP_DCB Dcb; PNP_DCB Dcb;
PAGED_CODE(); PAGED_CODE();
Dcb = Fcb->ParentDcb; Dcb = Fcb->ParentDcb;
@ -76,7 +75,7 @@ NpDeleteFcb(IN PNP_FCB Fcb,
&Fcb->FullName, &Fcb->FullName,
STATUS_OBJECT_NAME_NOT_FOUND, STATUS_OBJECT_NAME_NOT_FOUND,
ListEntry); ListEntry);
RemoveEntryList(&Fcb->DcbEntry); RemoveEntryList(&Fcb->DcbEntry);
if (Fcb->SecurityDescriptor) if (Fcb->SecurityDescriptor)

View file

@ -45,7 +45,7 @@ NpCancelWaitQueueIrp(IN PDEVICE_OBJECT DeviceObject,
if (WaitEntry) if (WaitEntry)
{ {
ObfDereferenceObject(WaitEntry->FileObject); ObDereferenceObject(WaitEntry->FileObject);
ExFreePool(WaitEntry); ExFreePool(WaitEntry);
} }
@ -66,23 +66,28 @@ NpTimerDispatch(IN PKDPC Dpc,
PNP_WAIT_QUEUE_ENTRY WaitEntry = Context; PNP_WAIT_QUEUE_ENTRY WaitEntry = Context;
OldIrql = KfAcquireSpinLock(&WaitEntry->WaitQueue->WaitLock); OldIrql = KfAcquireSpinLock(&WaitEntry->WaitQueue->WaitLock);
Irp = WaitEntry->Irp; Irp = WaitEntry->Irp;
if (Irp) if (Irp)
{ {
RemoveEntryList(&Irp->Tail.Overlay.ListEntry); RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
if (!IoSetCancelRoutine(Irp, NULL)) if (!IoSetCancelRoutine(Irp, NULL))
{ {
Irp->Tail.Overlay.DriverContext[1] = NULL; Irp->Tail.Overlay.DriverContext[1] = NULL;
Irp = NULL; Irp = NULL;
} }
} }
KfReleaseSpinLock(&WaitEntry->WaitQueue->WaitLock, OldIrql); KfReleaseSpinLock(&WaitEntry->WaitQueue->WaitLock, OldIrql);
if (Irp) if (Irp)
{ {
Irp->IoStatus.Status = STATUS_IO_TIMEOUT; Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT); IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
} }
ObfDereferenceObject(WaitEntry->FileObject);
ObDereferenceObject(WaitEntry->FileObject);
ExFreePool(WaitEntry); ExFreePool(WaitEntry);
} }
@ -99,13 +104,22 @@ NTAPI
NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue, NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue,
IN PUNICODE_STRING PipeName, IN PUNICODE_STRING PipeName,
IN NTSTATUS Status, IN NTSTATUS Status,
IN PLIST_ENTRY ListEntry) IN PLIST_ENTRY List)
{ {
UNICODE_STRING DestinationString; UNICODE_STRING DestinationString;
KIRQL OldIrql; KIRQL OldIrql;
PWCHAR Buffer; PWCHAR Buffer;
PLIST_ENTRY NextEntry;
PNP_WAIT_QUEUE_ENTRY WaitEntry, Linkage;
PIRP WaitIrp;
PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer;
ULONG i, NameLength;
Buffer = ExAllocatePoolWithTag(NonPagedPool, PipeName->Length, NPFS_WAIT_BLOCK_TAG); Linkage = NULL;
Buffer = ExAllocatePoolWithTag(NonPagedPool,
PipeName->Length,
NPFS_WAIT_BLOCK_TAG);
if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
RtlInitEmptyUnicodeString(&DestinationString, Buffer, PipeName->Length); RtlInitEmptyUnicodeString(&DestinationString, Buffer, PipeName->Length);
@ -113,10 +127,78 @@ NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue,
OldIrql = KfAcquireSpinLock(&WaitQueue->WaitLock); OldIrql = KfAcquireSpinLock(&WaitQueue->WaitLock);
ASSERT(IsListEmpty(&WaitQueue->WaitList) == TRUE); for (NextEntry = WaitQueue->WaitList.Flink;
NextEntry != &WaitQueue->WaitList;
NextEntry = NextEntry->Flink)
{
WaitIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
WaitEntry = WaitIrp->Tail.Overlay.DriverContext[1];
if (WaitEntry->AliasName.Length)
{
ASSERT(FALSE);
if (DestinationString.Length == WaitEntry->AliasName.Length)
{
if (RtlCompareMemory(WaitEntry->AliasName.Buffer,
DestinationString.Buffer,
DestinationString.Length) ==
DestinationString.Length)
{
CancelWait:
RemoveEntryList(&WaitIrp->Tail.Overlay.ListEntry);
if (KeCancelTimer(&WaitEntry->Timer))
{
WaitEntry->WaitQueue = (PNP_WAIT_QUEUE)Linkage;
Linkage = WaitEntry;
}
else
{
WaitEntry->Irp = NULL;
WaitIrp->Tail.Overlay.DriverContext[1] = NULL;
}
if (IoSetCancelRoutine(WaitIrp, NULL))
{
WaitIrp->IoStatus.Information = 0;
WaitIrp->IoStatus.Status = Status;
InsertTailList(List, &WaitIrp->Tail.Overlay.ListEntry);
}
else
{
WaitIrp->Tail.Overlay.DriverContext[1] = NULL;
}
}
}
}
else
{
WaitBuffer = WaitIrp->AssociatedIrp.SystemBuffer;
if (WaitBuffer->NameLength + sizeof(WCHAR) == DestinationString.Length)
{
NameLength = WaitBuffer->NameLength / sizeof(WCHAR);
for (i = 0; i < NameLength; i++)
{
if (WaitBuffer->Name[i] != DestinationString.Buffer[i + 1]) break;
}
if (i >= NameLength) goto CancelWait;
}
}
}
KfReleaseSpinLock(&WaitQueue->WaitLock, OldIrql); KfReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
ExFreePool(DestinationString.Buffer); ExFreePool(DestinationString.Buffer);
while (Linkage)
{
WaitEntry = Linkage;
Linkage = (PNP_WAIT_QUEUE_ENTRY)Linkage->WaitQueue;
ObDereferenceObject(WaitEntry->FileObject);
ExFreePool(WaitEntry);
}
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -124,8 +206,8 @@ NTSTATUS
NTAPI NTAPI
NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue, NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue,
IN LARGE_INTEGER WaitTime, IN LARGE_INTEGER WaitTime,
IN PIRP Irp, IN PIRP Irp,
IN PUNICODE_STRING Name) IN PUNICODE_STRING AliasName)
{ {
PIO_STACK_LOCATION IoStack; PIO_STACK_LOCATION IoStack;
KIRQL OldIrql; KIRQL OldIrql;
@ -137,71 +219,74 @@ NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue,
IoStack = IoGetCurrentIrpStackLocation(Irp); IoStack = IoGetCurrentIrpStackLocation(Irp);
WaitEntry = ExAllocatePoolWithQuotaTag(NonPagedPool, sizeof(*WaitEntry), NPFS_WRITE_BLOCK_TAG); WaitEntry = ExAllocatePoolWithQuotaTag(NonPagedPool,
if (WaitEntry) sizeof(*WaitEntry),
NPFS_WRITE_BLOCK_TAG);
if (!WaitEntry)
{ {
KeInitializeDpc(&WaitEntry->Dpc, NpTimerDispatch, WaitEntry); return STATUS_INSUFFICIENT_RESOURCES;
KeInitializeTimer(&WaitEntry->Timer); }
if (Name) KeInitializeDpc(&WaitEntry->Dpc, NpTimerDispatch, WaitEntry);
{ KeInitializeTimer(&WaitEntry->Timer);
WaitEntry->String = *Name;
}
else
{
WaitEntry->String.Length = 0;
WaitEntry->String.Buffer = 0;
}
WaitEntry->WaitQueue = WaitQueue; if (AliasName)
WaitEntry->Irp = Irp; {
WaitEntry->AliasName = *AliasName;
WaitBuffer = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
if (WaitBuffer->TimeoutSpecified)
{
DueTime = WaitBuffer->Timeout;
}
else
{
DueTime = WaitTime;
}
for (i = 0; i < WaitBuffer->NameLength / sizeof(WCHAR); i++)
{
WaitBuffer->Name[i] = RtlUpcaseUnicodeChar(WaitBuffer->Name[i]);
}
Irp->Tail.Overlay.DriverContext[0] = WaitQueue;
Irp->Tail.Overlay.DriverContext[1] = WaitEntry;
OldIrql = KfAcquireSpinLock(&WaitQueue->WaitLock);
IoSetCancelRoutine(Irp, NpCancelWaitQueueIrp);
if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
{
Status = STATUS_CANCELLED;
}
else
{
InsertTailList(&WaitQueue->WaitList, &Irp->Tail.Overlay.ListEntry);
IoMarkIrpPending(Irp);
Status = STATUS_PENDING;
WaitEntry->FileObject = IoStack->FileObject;
ObfReferenceObject(WaitEntry->FileObject);
KeSetTimer(&WaitEntry->Timer, DueTime, &WaitEntry->Dpc);
WaitEntry = NULL;
}
KfReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
if (WaitEntry) ExFreePool(WaitEntry);
} }
else else
{ {
Status = STATUS_INSUFFICIENT_RESOURCES; WaitEntry->AliasName.Length = 0;
WaitEntry->AliasName.Buffer = NULL;
} }
WaitEntry->WaitQueue = WaitQueue;
WaitEntry->Irp = Irp;
WaitBuffer = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
if (WaitBuffer->TimeoutSpecified)
{
DueTime = WaitBuffer->Timeout;
}
else
{
DueTime = WaitTime;
}
for (i = 0; i < WaitBuffer->NameLength / sizeof(WCHAR); i++)
{
WaitBuffer->Name[i] = RtlUpcaseUnicodeChar(WaitBuffer->Name[i]);
}
Irp->Tail.Overlay.DriverContext[0] = WaitQueue;
Irp->Tail.Overlay.DriverContext[1] = WaitEntry;
OldIrql = KfAcquireSpinLock(&WaitQueue->WaitLock);
IoSetCancelRoutine(Irp, NpCancelWaitQueueIrp);
if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
{
Status = STATUS_CANCELLED;
}
else
{
InsertTailList(&WaitQueue->WaitList, &Irp->Tail.Overlay.ListEntry);
IoMarkIrpPending(Irp);
Status = STATUS_PENDING;
WaitEntry->FileObject = IoStack->FileObject;
ObReferenceObject(WaitEntry->FileObject);
KeSetTimer(&WaitEntry->Timer, DueTime, &WaitEntry->Dpc);
WaitEntry = NULL;
}
KfReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
if (WaitEntry) ExFreePool(WaitEntry);
return Status; return Status;
} }