[NPFS-NEW]: Fix pool corruption and crashing bugs in NpPeek, which was using sizeof...
authorAlex Ionescu <aionescu@gmail.com>
Fri, 13 Sep 2013 07:49:42 +0000 (07:49 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Fri, 13 Sep 2013 07:49:42 +0000 (07:49 +0000)
[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

reactos/drivers/filesystems/npfs_new/create.c
reactos/drivers/filesystems/npfs_new/fsctrl.c
reactos/drivers/filesystems/npfs_new/main.c
reactos/drivers/filesystems/npfs_new/npfs.h
reactos/drivers/filesystems/npfs_new/strucsup.c
reactos/drivers/filesystems/npfs_new/waitsup.c

index 0450f25..d18c027 100644 (file)
@@ -551,7 +551,7 @@ NpCreateNewNamedPipe(IN PNP_DCB Dcb,
                          Parameters->NamedPipeType & 0xFFFF,
                          &Fcb);
     if (!NT_SUCCESS(Status)) goto Quickie;
-    
+
     Status = NpCreateCcb(Fcb,
                          FileObject,
                          FILE_PIPE_LISTENING_STATE,
index daf85fb..346141b 100644 (file)
@@ -206,7 +206,7 @@ NpPeek(IN PDEVICE_OBJECT DeviceObject,
 {
     PIO_STACK_LOCATION IoStack;
     NODE_TYPE_CODE Type;
-    ULONG InputLength;
+    ULONG OutputLength;
     ULONG NamedPipeEnd;
     PNP_CCB Ccb;
     PFILE_PIPE_PEEK_BUFFER PeekBuffer;
@@ -218,7 +218,7 @@ NpPeek(IN PDEVICE_OBJECT DeviceObject,
     PAGED_CODE();
 
     IoStack = IoGetCurrentIrpStackLocation(Irp);
-    InputLength = IoStack->Parameters.FileSystemControl.OutputBufferLength;
+    OutputLength = IoStack->Parameters.FileSystemControl.OutputBufferLength;
     Type = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);
 
     if (!Type)
@@ -226,7 +226,8 @@ NpPeek(IN PDEVICE_OBJECT DeviceObject,
         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;
     }
@@ -264,7 +265,7 @@ NpPeek(IN PDEVICE_OBJECT DeviceObject,
     PeekBuffer->NumberOfMessages = 0;
     PeekBuffer->MessageLength = 0;
     PeekBuffer->NamedPipeState = Ccb->NamedPipeState;
-    BytesPeeked = sizeof(*PeekBuffer);
+    BytesPeeked = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data);
 
     if (DataQueue->QueueState == WriteEntries)
     {
@@ -279,7 +280,8 @@ NpPeek(IN PDEVICE_OBJECT DeviceObject,
             PeekBuffer->NumberOfMessages = DataQueue->EntriesInQueue;
             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;
         }
@@ -289,12 +291,12 @@ NpPeek(IN PDEVICE_OBJECT DeviceObject,
                                        TRUE,
                                        FALSE,
                                        PeekBuffer->Data,
-                                       InputLength - sizeof(*PeekBuffer),
+                                       OutputLength - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data),
                                        Ccb->Fcb->NamedPipeType == FILE_PIPE_MESSAGE_TYPE,
                                        Ccb,
                                        List);
             Status = IoStatus.Status;
-            BytesPeeked = IoStatus.Information + sizeof(*PeekBuffer);
+            BytesPeeked += IoStatus.Information;
         }
     }
     else
@@ -523,14 +525,18 @@ NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject,
     NODE_TYPE_CODE NodeTypeCode;
     PLIST_ENTRY NextEntry;
     PNP_FCB Fcb;
+    PWCHAR OriginalBuffer;
     PAGED_CODE();
 
     IoStack = IoGetCurrentIrpStackLocation(Irp);
-    InLength = IoStack->Parameters.DeviceIoControl.InputBufferLength;
+    InLength = IoStack->Parameters.FileSystemControl.InputBufferLength;
 
     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;
         goto Quickie;
@@ -544,14 +550,17 @@ NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject,
     }
 
     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;
         goto Quickie;
     }
 
     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)
     {
         Status = STATUS_INSUFFICIENT_RESOURCES;
@@ -562,6 +571,7 @@ NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject,
     RtlCopyMemory(&SourceString.Buffer[1], Buffer->Name, Buffer->NameLength);
 
     Status = STATUS_SUCCESS;
+    OriginalBuffer = SourceString.Buffer;
     //Status = NpTranslateAlias(&SourceString);
     if (!NT_SUCCESS(Status)) goto Quickie;
 
@@ -583,7 +593,7 @@ NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject,
         if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) break;
     }
 
-    if (NextEntry == &Fcb->CcbList)
+    if (NextEntry != &Fcb->CcbList)
     {
         Status = STATUS_SUCCESS;
     }
@@ -592,7 +602,8 @@ NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject,
         Status = NpAddWaiter(&NpVcb->WaitQueue,
                              Fcb->Timeout,
                              Irp,
-                             &SourceString);
+                             OriginalBuffer == SourceString.Buffer ?
+                             NULL : &SourceString);
     }
 
 Quickie:
index d903975..449cfc4 100644 (file)
@@ -62,7 +62,7 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
 
     DriverObject->DriverUnload = NULL;
 
-    RtlInitUnicodeString(&DeviceName, L"\\Device\\NamedPipe2");
+    RtlInitUnicodeString(&DeviceName, L"\\Device\\NamedPipe");
     Status = IoCreateDevice(DriverObject,
                             sizeof(NP_VCB),
                             &DeviceName,
index e7160dd..0206f0a 100644 (file)
@@ -178,7 +178,7 @@ typedef struct _NP_WAIT_QUEUE_ENTRY
     KDPC Dpc;
     KTIMER Timer;
     PNP_WAIT_QUEUE WaitQueue;
-    UNICODE_STRING String;
+    UNICODE_STRING AliasName;
     PFILE_OBJECT FileObject;
 } NP_WAIT_QUEUE_ENTRY, *PNP_WAIT_QUEUE_ENTRY;
 
@@ -590,7 +590,7 @@ NTAPI
 NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue,
             IN LARGE_INTEGER WaitTime,
             IN PIRP Irp, 
-            IN PUNICODE_STRING Name);
+            IN PUNICODE_STRING AliasName);
 
 NTSTATUS
 NTAPI
index 51f4565..f8d83d0 100644 (file)
@@ -66,7 +66,6 @@ NpDeleteFcb(IN PNP_FCB Fcb,
             IN PLIST_ENTRY ListEntry)
 {
     PNP_DCB Dcb;
-
     PAGED_CODE();
 
     Dcb = Fcb->ParentDcb;
@@ -76,7 +75,7 @@ NpDeleteFcb(IN PNP_FCB Fcb,
                    &Fcb->FullName,
                    STATUS_OBJECT_NAME_NOT_FOUND,
                    ListEntry);
-    
+
     RemoveEntryList(&Fcb->DcbEntry);
 
     if (Fcb->SecurityDescriptor)
index 52d67f9..ac3af79 100644 (file)
@@ -45,7 +45,7 @@ NpCancelWaitQueueIrp(IN PDEVICE_OBJECT DeviceObject,
 
     if (WaitEntry)
     {
-        ObfDereferenceObject(WaitEntry->FileObject);
+        ObDereferenceObject(WaitEntry->FileObject);
         ExFreePool(WaitEntry);
     }
 
@@ -66,23 +66,28 @@ NpTimerDispatch(IN PKDPC Dpc,
     PNP_WAIT_QUEUE_ENTRY WaitEntry = Context;
 
     OldIrql = KfAcquireSpinLock(&WaitEntry->WaitQueue->WaitLock);
+
     Irp = WaitEntry->Irp;
     if (Irp)
     {
         RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+
         if (!IoSetCancelRoutine(Irp, NULL))
         {
             Irp->Tail.Overlay.DriverContext[1] = NULL;
             Irp = NULL;
         }
     }
+
     KfReleaseSpinLock(&WaitEntry->WaitQueue->WaitLock, OldIrql);
+
     if (Irp)
     {
         Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
         IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
     }
-    ObfDereferenceObject(WaitEntry->FileObject);
+
+    ObDereferenceObject(WaitEntry->FileObject);
     ExFreePool(WaitEntry);
 }
 
@@ -99,13 +104,22 @@ NTAPI
 NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue,
                IN PUNICODE_STRING PipeName,
                IN NTSTATUS Status,
-               IN PLIST_ENTRY ListEntry)
+               IN PLIST_ENTRY List)
 {
     UNICODE_STRING DestinationString;
     KIRQL OldIrql;
     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;
 
     RtlInitEmptyUnicodeString(&DestinationString, Buffer, PipeName->Length);
@@ -113,10 +127,78 @@ NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue,
 
     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);
+
     ExFreePool(DestinationString.Buffer);
+
+    while (Linkage)
+    {
+        WaitEntry = Linkage;
+        Linkage = (PNP_WAIT_QUEUE_ENTRY)Linkage->WaitQueue;
+        ObDereferenceObject(WaitEntry->FileObject);
+        ExFreePool(WaitEntry);
+    }
+
     return STATUS_SUCCESS;
 }
 
@@ -124,8 +206,8 @@ NTSTATUS
 NTAPI
 NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue,
             IN LARGE_INTEGER WaitTime,
-            IN PIRP Irp, 
-            IN PUNICODE_STRING Name)
+            IN PIRP Irp,
+            IN PUNICODE_STRING AliasName)
 {
     PIO_STACK_LOCATION IoStack;
     KIRQL OldIrql;
@@ -137,71 +219,74 @@ NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue,
 
     IoStack = IoGetCurrentIrpStackLocation(Irp);
 
-    WaitEntry = ExAllocatePoolWithQuotaTag(NonPagedPool, sizeof(*WaitEntry), NPFS_WRITE_BLOCK_TAG);
-    if (WaitEntry)
+    WaitEntry = ExAllocatePoolWithQuotaTag(NonPagedPool,
+                                           sizeof(*WaitEntry),
+                                           NPFS_WRITE_BLOCK_TAG);
+    if (!WaitEntry)
     {
-        KeInitializeDpc(&WaitEntry->Dpc, NpTimerDispatch, WaitEntry);
-        KeInitializeTimer(&WaitEntry->Timer);
-
-        if (Name)
-        {
-            WaitEntry->String = *Name;
-        }
-        else
-        {
-            WaitEntry->String.Length = 0;
-            WaitEntry->String.Buffer = 0;
-        }
-
-        WaitEntry->WaitQueue = WaitQueue;
-        WaitEntry->Irp = Irp;
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
 
-        WaitBuffer = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
-        if (WaitBuffer->TimeoutSpecified)
-        {
-            DueTime = WaitBuffer->Timeout;
-        }
-        else
-        {
-            DueTime = WaitTime;
-        }
+    KeInitializeDpc(&WaitEntry->Dpc, NpTimerDispatch, WaitEntry);
+    KeInitializeTimer(&WaitEntry->Timer);
 
-        for (i = 0; i < WaitBuffer->NameLength / sizeof(WCHAR); i++)
-        {
-            WaitBuffer->Name[i] = RtlUpcaseUnicodeChar(WaitBuffer->Name[i]);
-        }
+    if (AliasName)
+    {
+        WaitEntry->AliasName = *AliasName;
+    }
+    else
+    {
+        WaitEntry->AliasName.Length = 0;
+        WaitEntry->AliasName.Buffer = NULL;
+    }
 
-        Irp->Tail.Overlay.DriverContext[0] = WaitQueue;
-        Irp->Tail.Overlay.DriverContext[1] = WaitEntry;
-        OldIrql = KfAcquireSpinLock(&WaitQueue->WaitLock);
+    WaitEntry->WaitQueue = WaitQueue;
+    WaitEntry->Irp = Irp;
 
-        IoSetCancelRoutine(Irp, NpCancelWaitQueueIrp);
+    WaitBuffer = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
+    if (WaitBuffer->TimeoutSpecified)
+    {
+        DueTime = WaitBuffer->Timeout;
+    }
+    else
+    {
+        DueTime = WaitTime;
+    }
 
-        if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
-        {
-            Status = STATUS_CANCELLED;
-        }
-        else
-        {
-            InsertTailList(&WaitQueue->WaitList, &Irp->Tail.Overlay.ListEntry);
+    for (i = 0; i < WaitBuffer->NameLength / sizeof(WCHAR); i++)
+    {
+        WaitBuffer->Name[i] = RtlUpcaseUnicodeChar(WaitBuffer->Name[i]);
+    }
 
-            IoMarkIrpPending(Irp);
-            Status = STATUS_PENDING;
+    Irp->Tail.Overlay.DriverContext[0] = WaitQueue;
+    Irp->Tail.Overlay.DriverContext[1] = WaitEntry;
 
-            WaitEntry->FileObject = IoStack->FileObject;
-            ObfReferenceObject(WaitEntry->FileObject);
+    OldIrql = KfAcquireSpinLock(&WaitQueue->WaitLock);
 
-            KeSetTimer(&WaitEntry->Timer, DueTime, &WaitEntry->Dpc);
-            WaitEntry = NULL;
+    IoSetCancelRoutine(Irp, NpCancelWaitQueueIrp);
 
-        }
-        KfReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
-        if (WaitEntry) ExFreePool(WaitEntry);
+    if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
+    {
+        Status = STATUS_CANCELLED;
     }
     else
     {
-        Status = STATUS_INSUFFICIENT_RESOURCES;
+        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;
 }