[BLUE] Add IOCTL buffers validation. Addendum to commit bfd8a848. 2172/head
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 24 Dec 2019 12:27:15 +0000 (13:27 +0100)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Fri, 3 Jan 2020 16:17:03 +0000 (17:17 +0100)
Also convert all sizes and positions of CONSOLE_DRAW to USHORT since
this is the standard type for all console buffer positions & sizes
(minimum value 0, maximum value 0xFFFF == 65535).

drivers/setup/blue/blue.c
sdk/include/reactos/drivers/blue/ntddblue.h

index 2558506..def5049 100644 (file)
@@ -292,7 +292,7 @@ ScrInbvCleanup(VOID)
     ThreadHandle = InterlockedExchangePointer((PVOID*)&InbvThreadHandle, NULL);
     if (ThreadHandle)
     {
-        KeWaitForSingleObject(&ThreadHandle, Executive, KernelMode, FALSE, NULL);
+        ZwWaitForSingleObject(ThreadHandle, Executive, KernelMode, FALSE, NULL);
         /* Close its handle */
         ObCloseHandle(ThreadHandle, KernelMode);
     }
@@ -658,14 +658,21 @@ ScrResetScreen(
     return TRUE; // STATUS_SUCCESS;
 }
 
-static DRIVER_DISPATCH ScrCreate;
+static DRIVER_DISPATCH ScrCreateClose;
 static NTSTATUS
 NTAPI
-ScrCreate(
+ScrCreateClose(
     _In_ PDEVICE_OBJECT DeviceObject,
     _In_ PIRP Irp)
 {
-    // Irp->IoStatus.Information = FILE_OPENED;
+    PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
+
+    UNREFERENCED_PARAMETER(DeviceObject);
+
+    if (stk->MajorFunction == IRP_MJ_CREATE)
+        Irp->IoStatus.Information = FILE_OPENED;
+    // else: IRP_MJ_CLOSE
+
     Irp->IoStatus.Status = STATUS_SUCCESS;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
     return STATUS_SUCCESS;
@@ -824,7 +831,7 @@ ScrWrite(
     Status = STATUS_SUCCESS;
 
     Irp->IoStatus.Status = Status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    IoCompleteRequest(Irp, IO_VIDEO_INCREMENT);
 
     return Status;
 }
@@ -838,29 +845,48 @@ ScrIoControl(
 {
     NTSTATUS Status;
     PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
-    PDEVICE_EXTENSION DeviceExtension;
+    PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
 
-    DeviceExtension = DeviceObject->DeviceExtension;
     switch (stk->Parameters.DeviceIoControl.IoControlCode)
     {
         case IOCTL_CONSOLE_RESET_SCREEN:
         {
-            BOOLEAN Enable = !!*(PULONG)Irp->AssociatedIrp.SystemBuffer;
+            BOOLEAN Enable;
+
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            Enable = !!*(PULONG)Irp->AssociatedIrp.SystemBuffer;
 
             /* Fully enable or disable the screen */
             Status = (ScrResetScreen(DeviceExtension, TRUE, Enable)
                         ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
-
             Irp->IoStatus.Information = 0;
             break;
         }
 
         case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO:
         {
-            PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
+            PCONSOLE_SCREEN_BUFFER_INFO pcsbi;
             USHORT rows = DeviceExtension->Rows;
             USHORT columns = DeviceExtension->Columns;
 
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_SCREEN_BUFFER_INFO))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
+            RtlZeroMemory(pcsbi, sizeof(CONSOLE_SCREEN_BUFFER_INFO));
+
             pcsbi->dwSize.X = columns;
             pcsbi->dwSize.Y = rows;
 
@@ -884,7 +910,17 @@ ScrIoControl(
 
         case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO:
         {
-            PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
+            PCONSOLE_SCREEN_BUFFER_INFO pcsbi;
+
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONSOLE_SCREEN_BUFFER_INFO))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
 
             if ( pcsbi->dwCursorPosition.X < 0 || pcsbi->dwCursorPosition.X >= DeviceExtension->Columns ||
                  pcsbi->dwCursorPosition.Y < 0 || pcsbi->dwCursorPosition.Y >= DeviceExtension->Rows )
@@ -911,7 +947,18 @@ ScrIoControl(
 
         case IOCTL_CONSOLE_GET_CURSOR_INFO:
         {
-            PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
+            PCONSOLE_CURSOR_INFO pcci;
+
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_CURSOR_INFO))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
+            RtlZeroMemory(pcci, sizeof(CONSOLE_CURSOR_INFO));
 
             pcci->dwSize = DeviceExtension->CursorSize;
             pcci->bVisible = DeviceExtension->CursorVisible;
@@ -923,7 +970,17 @@ ScrIoControl(
 
         case IOCTL_CONSOLE_SET_CURSOR_INFO:
         {
-            PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
+            PCONSOLE_CURSOR_INFO pcci;
+
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONSOLE_CURSOR_INFO))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
 
             DeviceExtension->CursorSize = pcci->dwSize;
             DeviceExtension->CursorVisible = pcci->bVisible;
@@ -937,7 +994,18 @@ ScrIoControl(
 
         case IOCTL_CONSOLE_GET_MODE:
         {
-            PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
+            PCONSOLE_MODE pcm;
+
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_MODE))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
+            RtlZeroMemory(pcm, sizeof(CONSOLE_MODE));
 
             pcm->dwMode = DeviceExtension->Mode;
 
@@ -948,8 +1016,17 @@ ScrIoControl(
 
         case IOCTL_CONSOLE_SET_MODE:
         {
-            PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
+            PCONSOLE_MODE pcm;
 
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONSOLE_MODE))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
             DeviceExtension->Mode = pcm->dwMode;
 
             Irp->IoStatus.Information = 0;
@@ -959,17 +1036,31 @@ ScrIoControl(
 
         case IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE:
         {
-            POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
+            POUTPUT_ATTRIBUTE Buf;
             PUCHAR vidmem;
             ULONG offset;
             ULONG dwCount;
-            ULONG nMaxLength = Buf->nLength;
+            ULONG nMaxLength;
+
+            /* Validate input and output buffers */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength  < sizeof(OUTPUT_ATTRIBUTE) ||
+                stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(OUTPUT_ATTRIBUTE))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
+            nMaxLength = Buf->nLength;
+
+            Buf->dwTransfered = 0;
+            Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
 
             if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
-                 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
+                 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows    ||
+                 nMaxLength == 0 )
             {
-                Buf->dwTransfered = 0;
-                Irp->IoStatus.Information = 0;
                 Status = STATUS_SUCCESS;
                 break;
             }
@@ -987,39 +1078,63 @@ ScrIoControl(
                 {
                     vidmem[offset + (dwCount * 2)] = (char)Buf->wAttribute;
                 }
+                Buf->dwTransfered = dwCount;
             }
 
-            Buf->dwTransfered = nMaxLength;
-
-            Irp->IoStatus.Information = 0;
             Status = STATUS_SUCCESS;
             break;
         }
 
         case IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE:
         {
-            POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
-            PUSHORT pAttr = (PUSHORT)MmGetSystemAddressForMdl(Irp->MdlAddress);
+            POUTPUT_ATTRIBUTE Buf;
+            PUSHORT pAttr;
             PUCHAR vidmem;
             ULONG offset;
             ULONG dwCount;
             ULONG nMaxLength;
 
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(OUTPUT_ATTRIBUTE))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
+            Irp->IoStatus.Information = 0;
+
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength == 0)
+            {
+                Status = STATUS_SUCCESS;
+                break;
+            }
+            ASSERT(Irp->MdlAddress);
+            pAttr = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+            if (pAttr == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+
             if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
                  Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
             {
-                Buf->dwTransfered = 0;
-                Irp->IoStatus.Information = 0;
                 Status = STATUS_SUCCESS;
                 break;
             }
 
+            nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength;
+            nMaxLength /= sizeof(USHORT);
+
             if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
             {
                 vidmem = DeviceExtension->VideoMemory;
                 offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2 + 1;
 
-                nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength,
+                nMaxLength = min(nMaxLength,
                                  (DeviceExtension->Rows - Buf->dwCoord.Y)
                                     * DeviceExtension->Columns - Buf->dwCoord.X);
 
@@ -1027,75 +1142,123 @@ ScrIoControl(
                 {
                     *((PCHAR)pAttr) = vidmem[offset + (dwCount * 2)];
                 }
-
-                Buf->dwTransfered = dwCount;
-            }
-            else
-            {
-                Buf->dwTransfered = 0;
+                Irp->IoStatus.Information = dwCount * sizeof(USHORT);
             }
 
-            Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
             Status = STATUS_SUCCESS;
             break;
         }
 
         case IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE:
         {
-            PCOORD pCoord = (PCOORD)MmGetSystemAddressForMdl(Irp->MdlAddress);
-            PCHAR pAttr = (PCHAR)(pCoord + 1);
+            COORD dwCoord;
+            PCOORD pCoord;
+            PUSHORT pAttr;
             PUCHAR vidmem;
             ULONG offset;
             ULONG dwCount;
             ULONG nMaxLength;
 
-            if ( pCoord->X < 0 || pCoord->X >= DeviceExtension->Columns ||
-                 pCoord->Y < 0 || pCoord->Y >= DeviceExtension->Rows )
+            //
+            // NOTE: For whatever reason no OUTPUT_ATTRIBUTE structure
+            // is used for this IOCTL.
+            //
+
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(COORD))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->MdlAddress);
+            pCoord = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+            if (pCoord == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+            /* Capture the input info data */
+            dwCoord = *pCoord;
+
+            nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD);
+            nMaxLength /= sizeof(USHORT);
+
+            Irp->IoStatus.Information = 0;
+
+            if ( dwCoord.X < 0 || dwCoord.X >= DeviceExtension->Columns ||
+                 dwCoord.Y < 0 || dwCoord.Y >= DeviceExtension->Rows    ||
+                 nMaxLength == 0 )
             {
-                Irp->IoStatus.Information = 0;
                 Status = STATUS_SUCCESS;
                 break;
             }
 
+            pAttr = (PUSHORT)(pCoord + 1);
+
             if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
             {
                 vidmem = DeviceExtension->VideoMemory;
-                offset = (pCoord->X + pCoord->Y * DeviceExtension->Columns) * 2 + 1;
+                offset = (dwCoord.X + dwCoord.Y * DeviceExtension->Columns) * 2 + 1;
 
-                nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD),
-                                 (DeviceExtension->Rows - pCoord->Y)
-                                    * DeviceExtension->Columns - pCoord->X);
+                nMaxLength = min(nMaxLength,
+                                 (DeviceExtension->Rows - dwCoord.Y)
+                                    * DeviceExtension->Columns - dwCoord.X);
 
                 for (dwCount = 0; dwCount < nMaxLength; dwCount++, pAttr++)
                 {
-                    vidmem[offset + (dwCount * 2)] = *pAttr;
+                    vidmem[offset + (dwCount * 2)] = *((PCHAR)pAttr);
                 }
+                Irp->IoStatus.Information = dwCount * sizeof(USHORT);
             }
 
-            Irp->IoStatus.Information = 0;
             Status = STATUS_SUCCESS;
             break;
         }
 
         case IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE:
-            DeviceExtension->CharAttribute = (USHORT)*(PUSHORT)Irp->AssociatedIrp.SystemBuffer;
+        {
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(USHORT))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            DeviceExtension->CharAttribute = *(PUSHORT)Irp->AssociatedIrp.SystemBuffer;
+
             Irp->IoStatus.Information = 0;
             Status = STATUS_SUCCESS;
             break;
+        }
 
         case IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER:
         {
-            POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
+            POUTPUT_CHARACTER Buf;
             PUCHAR vidmem;
             ULONG offset;
             ULONG dwCount;
-            ULONG nMaxLength = Buf->nLength;
+            ULONG nMaxLength;
+
+            /* Validate input and output buffers */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength  < sizeof(OUTPUT_CHARACTER) ||
+                stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(OUTPUT_CHARACTER))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
+            nMaxLength = Buf->nLength;
+
+            Buf->dwTransfered = 0;
+            Irp->IoStatus.Information = sizeof(OUTPUT_CHARACTER);
 
             if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
-                 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
+                 Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows    ||
+                 nMaxLength == 0 )
             {
-                Buf->dwTransfered = 0;
-                Irp->IoStatus.Information = 0;
                 Status = STATUS_SUCCESS;
                 break;
             }
@@ -1113,39 +1276,62 @@ ScrIoControl(
                 {
                     vidmem[offset + (dwCount * 2)] = (char)Buf->cCharacter;
                 }
+                Buf->dwTransfered = dwCount;
             }
 
-            Buf->dwTransfered = nMaxLength;
-
-            Irp->IoStatus.Information = 0;
             Status = STATUS_SUCCESS;
             break;
         }
 
         case IOCTL_CONSOLE_READ_OUTPUT_CHARACTER:
         {
-            POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
-            PCHAR pChar = (PCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress);
+            POUTPUT_CHARACTER Buf;
+            PCHAR pChar;
             PUCHAR vidmem;
             ULONG offset;
             ULONG dwCount;
             ULONG nMaxLength;
 
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(OUTPUT_CHARACTER))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
+            Irp->IoStatus.Information = 0;
+
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength == 0)
+            {
+                Status = STATUS_SUCCESS;
+                break;
+            }
+            ASSERT(Irp->MdlAddress);
+            pChar = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+            if (pChar == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+
             if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
                  Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
             {
-                Buf->dwTransfered = 0;
-                Irp->IoStatus.Information = 0;
                 Status = STATUS_SUCCESS;
                 break;
             }
 
+            nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength;
+
             if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
             {
                 vidmem = DeviceExtension->VideoMemory;
                 offset = (Buf->dwCoord.X + Buf->dwCoord.Y * DeviceExtension->Columns) * 2;
 
-                nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength,
+                nMaxLength = min(nMaxLength,
                                  (DeviceExtension->Rows - Buf->dwCoord.Y)
                                     * DeviceExtension->Columns - Buf->dwCoord.X);
 
@@ -1153,72 +1339,135 @@ ScrIoControl(
                 {
                     *pChar = vidmem[offset + (dwCount * 2)];
                 }
-
-                Buf->dwTransfered = dwCount;
-            }
-            else
-            {
-                Buf->dwTransfered = 0;
+                Irp->IoStatus.Information = dwCount * sizeof(CHAR);
             }
 
-            Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
             Status = STATUS_SUCCESS;
             break;
         }
 
         case IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER:
         {
-            PCOORD pCoord = (PCOORD)MmGetSystemAddressForMdl(Irp->MdlAddress);
-            PCHAR pChar = (PCHAR)(pCoord + 1);
+            COORD dwCoord;
+            PCOORD pCoord;
+            PCHAR pChar;
             PUCHAR vidmem;
             ULONG offset;
             ULONG dwCount;
             ULONG nMaxLength;
 
-            if ( pCoord->X < 0 || pCoord->X >= DeviceExtension->Columns ||
-                 pCoord->Y < 0 || pCoord->Y >= DeviceExtension->Rows )
+            //
+            // NOTE: For whatever reason no OUTPUT_CHARACTER structure
+            // is used for this IOCTL.
+            //
+
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(COORD))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->MdlAddress);
+            pCoord = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+            if (pCoord == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+            /* Capture the input info data */
+            dwCoord = *pCoord;
+
+            nMaxLength = stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD);
+            Irp->IoStatus.Information = 0;
+
+            if ( dwCoord.X < 0 || dwCoord.X >= DeviceExtension->Columns ||
+                 dwCoord.Y < 0 || dwCoord.Y >= DeviceExtension->Rows    ||
+                 nMaxLength == 0 )
             {
-                Irp->IoStatus.Information = 0;
                 Status = STATUS_SUCCESS;
                 break;
             }
 
+            pChar = (PCHAR)(pCoord + 1);
+
             if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
             {
                 vidmem = DeviceExtension->VideoMemory;
-                offset = (pCoord->X + pCoord->Y * DeviceExtension->Columns) * 2;
+                offset = (dwCoord.X + dwCoord.Y * DeviceExtension->Columns) * 2;
 
-                nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD),
-                                 (DeviceExtension->Rows - pCoord->Y)
-                                    * DeviceExtension->Columns - pCoord->X);
+                nMaxLength = min(nMaxLength,
+                                 (DeviceExtension->Rows - dwCoord.Y)
+                                    * DeviceExtension->Columns - dwCoord.X);
 
                 for (dwCount = 0; dwCount < nMaxLength; dwCount++, pChar++)
                 {
                     vidmem[offset + (dwCount * 2)] = *pChar;
                 }
+                Irp->IoStatus.Information = dwCount * sizeof(CHAR);
             }
 
-            Irp->IoStatus.Information = 0;
             Status = STATUS_SUCCESS;
             break;
         }
 
         case IOCTL_CONSOLE_DRAW:
         {
-            PCONSOLE_DRAW ConsoleDraw;
+            CONSOLE_DRAW ConsoleDraw;
+            PCONSOLE_DRAW pConsoleDraw;
             PUCHAR Src, Dest;
             UINT32 SrcDelta, DestDelta, i;
 
+            /* Validate output buffer */
+            if (stk->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CONSOLE_DRAW))
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+            ASSERT(Irp->MdlAddress);
+            pConsoleDraw = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+            if (pConsoleDraw == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+            /* Capture the input info data */
+            ConsoleDraw = *pConsoleDraw;
+
+            /* Check whether we have the size for the header plus the data area */
+            if ((stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(CONSOLE_DRAW)) / 2
+                    < ((ULONG)ConsoleDraw.SizeX * (ULONG)ConsoleDraw.SizeY))
+            {
+                Status = STATUS_INVALID_BUFFER_SIZE;
+                break;
+            }
+
+            // TODO: For the moment if the ConsoleDraw rectangle has borders
+            // out of the screen-buffer we just bail out. Would it be better
+            // to actually clip the rectangle within its borders instead?
+            if ( ConsoleDraw.X < 0 || ConsoleDraw.X >= DeviceExtension->Columns ||
+                 ConsoleDraw.Y < 0 || ConsoleDraw.Y >= DeviceExtension->Rows )
+            {
+                Status = STATUS_SUCCESS;
+                break;
+            }
+            if ( ConsoleDraw.SizeX >= DeviceExtension->Columns - ConsoleDraw.X ||
+                 ConsoleDraw.SizeY >= DeviceExtension->Rows    - ConsoleDraw.Y )
+            {
+                Status = STATUS_SUCCESS;
+                break;
+            }
+
             if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
             {
-                ConsoleDraw = (PCONSOLE_DRAW) MmGetSystemAddressForMdl(Irp->MdlAddress);
-                Src = (PUCHAR) (ConsoleDraw + 1);
-                SrcDelta = ConsoleDraw->SizeX * 2;
+                Src = (PUCHAR)(pConsoleDraw + 1);
+                SrcDelta = ConsoleDraw.SizeX * 2;
                 Dest = DeviceExtension->VideoMemory +
-                        (ConsoleDraw->X + ConsoleDraw->Y * DeviceExtension->Columns) * 2;
+                        (ConsoleDraw.X + ConsoleDraw.Y * DeviceExtension->Columns) * 2;
                 DestDelta = DeviceExtension->Columns * 2;
+                /* 2 == sizeof(CHAR) + sizeof(BYTE) */
 
-                for (i = 0; i < ConsoleDraw->SizeY; i++)
+                /* Copy each line */
+                for (i = 0; i < ConsoleDraw.SizeY; i++)
                 {
                     RtlCopyMemory(Dest, Src, SrcDelta);
                     Src += SrcDelta;
@@ -1227,8 +1476,8 @@ ScrIoControl(
             }
 
             /* Set the cursor position, clipping it to the screen */
-            DeviceExtension->CursorX = min(max(ConsoleDraw->CursorX, 0), DeviceExtension->Columns - 1);
-            DeviceExtension->CursorY = min(max(ConsoleDraw->CursorY, 0), DeviceExtension->Rows - 1);
+            DeviceExtension->CursorX = min(max(ConsoleDraw.CursorX, 0), DeviceExtension->Columns - 1);
+            DeviceExtension->CursorY = min(max(ConsoleDraw.CursorY, 0), DeviceExtension->Rows    - 1);
             if (DeviceExtension->Enabled)
                 ScrSetCursor(DeviceExtension);
 
@@ -1239,14 +1488,19 @@ ScrIoControl(
 
         case IOCTL_CONSOLE_LOADFONT:
         {
-            ULONG CodePage = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
-            DeviceExtension->CodePage = CodePage;
-
-            if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
+            /* Validate input buffer */
+            if (stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
             {
-                /* Upload a font for the codepage if needed */
-                ScrLoadFontTable(CodePage);
+                Status = STATUS_INVALID_PARAMETER;
+                break;
             }
+            ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+            DeviceExtension->CodePage = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
+
+            /* Upload a font for the codepage if needed */
+            if (DeviceExtension->Enabled && DeviceExtension->VideoMemory)
+                ScrLoadFontTable(DeviceExtension->CodePage);
 
             Irp->IoStatus.Information = 0;
             Status = STATUS_SUCCESS;
@@ -1258,7 +1512,7 @@ ScrIoControl(
     }
 
     Irp->IoStatus.Status = Status;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    IoCompleteRequest(Irp, IO_VIDEO_INCREMENT);
 
     return Status;
 }
@@ -1270,23 +1524,16 @@ ScrDispatch(
     _In_ PDEVICE_OBJECT DeviceObject,
     _In_ PIRP Irp)
 {
-    NTSTATUS Status;
     PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
 
-    switch (stk->MajorFunction)
-    {
-        case IRP_MJ_CLOSE:
-            Status = STATUS_SUCCESS;
-            break;
+    UNREFERENCED_PARAMETER(DeviceObject);
 
-        default:
-            Status = STATUS_NOT_IMPLEMENTED;
-            break;
-    }
+    DPRINT1("ScrDispatch(0x%p): stk->MajorFunction = %lu UNIMPLEMENTED\n",
+            DeviceObject, stk->MajorFunction);
 
-    Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
-    return Status;
+    return STATUS_NOT_IMPLEMENTED;
 }
 
 /*
@@ -1305,8 +1552,8 @@ DriverEntry(
 
     DPRINT("Screen Driver 0.0.6\n");
 
-    DriverObject->MajorFunction[IRP_MJ_CREATE] = ScrCreate;
-    DriverObject->MajorFunction[IRP_MJ_CLOSE]  = ScrDispatch;
+    DriverObject->MajorFunction[IRP_MJ_CREATE] = ScrCreateClose;
+    DriverObject->MajorFunction[IRP_MJ_CLOSE]  = ScrCreateClose;
     DriverObject->MajorFunction[IRP_MJ_READ]   = ScrDispatch;
     DriverObject->MajorFunction[IRP_MJ_WRITE]  = ScrWrite;
     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScrIoControl;
index 5c6df7b..0d41d0f 100644 (file)
 #define IOCTL_CONSOLE_SET_MODE                  CTL_CODE(FILE_DEVICE_SCREEN, 0x806, METHOD_BUFFERED, FILE_WRITE_ACCESS)
 
 #define IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE     CTL_CODE(FILE_DEVICE_SCREEN, 0x810, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE     CTL_CODE(FILE_DEVICE_SCREEN, 0x811, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
-#define IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE    CTL_CODE(FILE_DEVICE_SCREEN, 0x812, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+#define IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE     CTL_CODE(FILE_DEVICE_SCREEN, 0x811, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#define IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE    CTL_CODE(FILE_DEVICE_SCREEN, 0x812, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
 #define IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE        CTL_CODE(FILE_DEVICE_SCREEN, 0x813, METHOD_BUFFERED, FILE_WRITE_ACCESS)
 
 #define IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER     CTL_CODE(FILE_DEVICE_SCREEN, 0x820, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_CONSOLE_READ_OUTPUT_CHARACTER     CTL_CODE(FILE_DEVICE_SCREEN, 0x821, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
-#define IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER    CTL_CODE(FILE_DEVICE_SCREEN, 0x822, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+#define IOCTL_CONSOLE_READ_OUTPUT_CHARACTER     CTL_CODE(FILE_DEVICE_SCREEN, 0x821, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#define IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER    CTL_CODE(FILE_DEVICE_SCREEN, 0x822, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
 
 #define IOCTL_CONSOLE_DRAW                      CTL_CODE(FILE_DEVICE_SCREEN, 0x830, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
 
@@ -48,12 +48,12 @@ typedef struct tagOUTPUT_CHARACTER
 
 typedef struct tagCONSOLE_DRAW
 {
-    ULONG X;       /* Origin */
-    ULONG Y;
-    ULONG SizeX;   /* Size of the screen buffer (chars) */
-    ULONG SizeY;
-    ULONG CursorX; /* New cursor position (screen-relative) */
-    ULONG CursorY;
+    USHORT X;       /* Origin */
+    USHORT Y;
+    USHORT SizeX;   /* Size of the screen buffer (chars) */
+    USHORT SizeY;
+    USHORT CursorX; /* New cursor position (screen-relative) */
+    USHORT CursorY;
     /* Followed by screen buffer in char/attrib format */
 } CONSOLE_DRAW, *PCONSOLE_DRAW;