Author: mjmartin Date: Sun Jan 11 08:28:45 2009 New Revision: 38699
URL: http://svn.reactos.org/svn/reactos?rev=38699&view=rev Log: - Last implementation was failing to charge the QuotaAvailable for the message length proceeding the message in the buffer, causing overwriting of the pool. See bug 4018 for more info.
Modified: trunk/reactos/drivers/filesystems/npfs/rw.c
Modified: trunk/reactos/drivers/filesystems/npfs/rw.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/npfs/rw... ============================================================================== --- trunk/reactos/drivers/filesystems/npfs/rw.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/npfs/rw.c [iso-8859-1] Sun Jan 11 08:28:45 2009 @@ -438,6 +438,7 @@ break; } ExReleaseFastMutex(&Ccb->DataListLock); + if (IoIsOperationSynchronous(Irp)) { /* Wait for ReadEvent to become signaled */ @@ -448,8 +449,7 @@ Irp->RequestorMode, FALSE, NULL); - DPRINT("Finished waiting (%wZ)! Status: %x\n", &Ccb->Fcb->PipeName, Status); - ExAcquireFastMutex(&Ccb->DataListLock); + DPRINT("Finished waiting (%wZ)! Status: %x\n", &Ccb->Fcb->PipeName, Status);
if ((Status == STATUS_USER_APC) || (Status == STATUS_KERNEL_APC)) { @@ -460,6 +460,7 @@ { ASSERT(FALSE); } + ExAcquireFastMutex(&Ccb->DataListLock); } else { @@ -526,26 +527,25 @@ DPRINT("Message mode\n");
/* For Message mode, the Message length will be stored in the buffer preceeding the Message. */ - if (Ccb->ReadDataAvailable) { ULONG NextMessageLength=0; //HexDump(Ccb->Data, (ULONG)Ccb->WritePtr - (ULONG)Ccb->Data); - /*First get the size of the message */ memcpy(&NextMessageLength, Ccb->Data, sizeof(NextMessageLength)); - - if (NextMessageLength == 0) + if ((NextMessageLength == 0) || (NextMessageLength > Ccb->ReadDataAvailable)) { DPRINT1("This should never happen! Possible memory corruption.\n"); #ifndef NDEBUG HexDump(Ccb->Data, (ULONG)Ccb->WritePtr - (ULONG)Ccb->Data); #endif - break; + ASSERT(FALSE); }
/* Use the smaller value */ + CopyLength = min(NextMessageLength, Length); + /* retrieve the message from the buffer */ memcpy(Buffer, (PVOID)((ULONG)Ccb->Data + sizeof(NextMessageLength)), CopyLength);
@@ -558,6 +558,7 @@
/* Calculate the remaining message new size */ ULONG NewMessageSize = NextMessageLength-CopyLength; + /* Write a new Message size to buffer for the part of the message still there */ memcpy(Ccb->Data, &NewMessageSize, sizeof(NewMessageSize));
@@ -568,10 +569,15 @@
/* Update the write pointer */ Ccb->WritePtr = (PVOID)((ULONG)Ccb->WritePtr - CopyLength); + + /* Add CopyLength only to WriteQuotaAvailable as the + Message Size was replaced in the buffer */ + Ccb->WriteQuotaAvailable += CopyLength; } else { /* Client wanted the entire message */ + /* Move the memory starting from the next Message just retrieved */ memmove(Ccb->Data, (PVOID)((ULONG_PTR) Ccb->Data + NextMessageLength + sizeof(NextMessageLength)), @@ -579,14 +585,24 @@
/* Update the write pointer */ Ccb->WritePtr = (PVOID)((ULONG)Ccb->WritePtr - NextMessageLength); + + /* Add both the message length and the header to the WriteQuotaAvailable + as they both were removed */ + Ccb->WriteQuotaAvailable += (CopyLength + sizeof(NextMessageLength)); } } else { /* This was the last Message, so just zero this messages for safety sake */ memset(Ccb->Data,0,NextMessageLength + sizeof(NextMessageLength)); - /* reset the write pointer */ + + /* reset the write pointer to beginning of buffer */ Ccb->WritePtr = Ccb->Data; + + /* Add both the message length and the header to the WriteQuotaAvailable + as they both were removed */ + Ccb->WriteQuotaAvailable += (CopyLength + sizeof(ULONG)); + KeResetEvent(&Ccb->ReadEvent); if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE) { @@ -599,8 +615,10 @@ #endif
Information += CopyLength; - Ccb->WriteQuotaAvailable +=CopyLength; + Ccb->ReadDataAvailable -= CopyLength; + + if ((ULONG)Ccb->WriteQuotaAvailable > (ULONG)Ccb->MaxDataLength) ASSERT(FALSE); }
if (Information > 0) @@ -700,7 +718,7 @@
if (Irp->MdlAddress == NULL) { - DPRINT("Irp->MdlAddress == NULL\n"); + DPRINT1("Irp->MdlAddress == NULL\n"); Status = STATUS_UNSUCCESSFUL; Length = 0; goto done; @@ -708,7 +726,7 @@
if (ReaderCcb == NULL) { - DPRINT("Pipe is NOT connected!\n"); + DPRINT1("Pipe is NOT connected!\n"); if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE) Status = STATUS_PIPE_LISTENING; else if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE) @@ -721,7 +739,7 @@
if (ReaderCcb->Data == NULL) { - DPRINT("Pipe is NOT writable!\n"); + DPRINT1("Pipe is NOT writable!\n"); Status = STATUS_UNSUCCESSFUL; Length = 0; goto done; @@ -738,7 +756,7 @@
while(1) { - if (ReaderCcb->WriteQuotaAvailable == 0) + if ((ReaderCcb->WriteQuotaAvailable == 0)) { KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE); if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE) @@ -749,14 +767,14 @@ } ExReleaseFastMutex(&ReaderCcb->DataListLock);
- DPRINT("Waiting for buffer space (%S)\n", Fcb->PipeName.Buffer); + DPRINT("Write Waiting for buffer space (%S)\n", Fcb->PipeName.Buffer); Status = KeWaitForSingleObject(&Ccb->WriteEvent, UserRequest, Irp->RequestorMode, FALSE, NULL); - DPRINT("Finished waiting (%S)! Status: %x\n", Fcb->PipeName.Buffer, Status); - + DPRINT("Write Finished waiting (%S)! Status: %x\n", Fcb->PipeName.Buffer, Status); + ExAcquireFastMutex(&ReaderCcb->DataListLock); if ((Status == STATUS_USER_APC) || (Status == STATUS_KERNEL_APC)) { Status = STATUS_CANCELLED; @@ -777,8 +795,6 @@ // ExReleaseFastMutex(&ReaderCcb->DataListLock); goto done; } - - ExAcquireFastMutex(&ReaderCcb->DataListLock); }
if (Fcb->WriteMode == FILE_PIPE_BYTE_STREAM_MODE) @@ -825,21 +841,41 @@ { /* For Message Type Pipe, the Pipes memory will be used to store the size of each message */ /* FIXME: Check and verify ReadMode ByteStream */ - DPRINT("Message mode\n"); + if (Length > 0) { - CopyLength = min(Length, ReaderCcb->WriteQuotaAvailable); + /* Verify the WritePtr is still inside the buffer */ + if (((ULONG)ReaderCcb->WritePtr > ((ULONG)ReaderCcb->Data + (ULONG)ReaderCcb->MaxDataLength)) || + ((ULONG)ReaderCcb->WritePtr < (ULONG)ReaderCcb->Data)) + { + DPRINT1("NPFS is writing out of its buffer. Report to developer!\n"); + DPRINT1("ReaderCcb->WritePtr %x, ReaderCcb->Data %x, ReaderCcb->MaxDataLength%d\n", + ReaderCcb->WritePtr,ReaderCcb->Data,ReaderCcb->MaxDataLength); + ASSERT(FALSE); + } + + CopyLength = min(Length, ReaderCcb->WriteQuotaAvailable - sizeof(ULONG)); + /* First Copy the Length of the message into the pipes buffer */ memcpy(ReaderCcb->WritePtr, &CopyLength, sizeof(CopyLength)); + /* Now the user buffer itself */ memcpy((PVOID)((ULONG)ReaderCcb->WritePtr+ sizeof(CopyLength)), Buffer, CopyLength); + /* Update the write pointer */ ReaderCcb->WritePtr = (PVOID)((ULONG)ReaderCcb->WritePtr + sizeof(CopyLength) + CopyLength);
Information += CopyLength;
ReaderCcb->ReadDataAvailable += CopyLength; - ReaderCcb->WriteQuotaAvailable -= CopyLength; + + ReaderCcb->WriteQuotaAvailable -= (CopyLength + sizeof(ULONG)); + + if ((ULONG)ReaderCcb->WriteQuotaAvailable > (ULONG)ReaderCcb->MaxDataLength) + { + DPRINT1("QuotaAvailable is greater than buffer size!\n"); + ASSERT(FALSE); + } }
if (Information > 0)