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/r…
==============================================================================
--- 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)