[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 3/4] Fix buffer handling of MapForeignPages and PermitForeignAccess


  • To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Tu Dinh <ngoc-tu.dinh@xxxxxxxxxx>
  • Date: Tue, 13 Oct 2026 14:32:37 +0200
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=vates.tech header.i="@vates.tech" header.h="From:Subject:Date:Message-ID:To:Cc:MIME-Version:Content-Type:In-Reply-To:References:Feedback-ID"
  • Cc: Tu Dinh <ngoc-tu.dinh@xxxxxxxxxx>
  • Delivery-date: Tue, 13 Oct 2026 12:32:48 +0000
  • Feedback-id: default:8631fc262581453bbf619ec5b2062170:Sweego
  • List-id: Developer list for the Windows PV Drivers subproject <win-pv-devel.lists.xenproject.org>

MapForeignPages:
* In is used directly to store the references coming from In1, so we
  must allocate its entire size rather than just the header.
* As a result, the input size must be bound before allocating In.
* Relax the input buffer size restriction so that an input with
  fewer NumberPages than provided by the IOCTL buffer size will be
  accepted.

PermitForeignAccess:
* Relax the output buffer size restriction so that an output with
  fewer NumberPages than provided by the IOCTL buffer size will be
  accepted.

Signed-off-by: Tu Dinh <ngoc-tu.dinh@xxxxxxxxxx>
---
 src/xeniface/ioctl_gnttab.c | 45 ++++++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 20 deletions(-)

diff --git a/src/xeniface/ioctl_gnttab.c b/src/xeniface/ioctl_gnttab.c
index c018cd3..dd1f4bb 100644
--- a/src/xeniface/ioctl_gnttab.c
+++ b/src/xeniface/ioctl_gnttab.c
@@ -358,6 +358,7 @@ IoctlGnttabPermitForeignAccess(
     PXENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS_OUT Out = Irp->UserBuffer;
     PXENIFACE_GNTTAB_CONTEXT Context;
     ULONG Page;
+    ULONG OutputSize;
     ULONG ControlCode = 
IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode;
 
     Status = STATUS_INVALID_BUFFER_SIZE;
@@ -400,7 +401,9 @@ IoctlGnttabPermitForeignAccess(
     }
 
     Status = STATUS_INVALID_BUFFER_SIZE;
-    if (OutLen != 
(ULONG)FIELD_OFFSET(XENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS_OUT, 
References[In->NumberPages]))
+    OutputSize = 
(ULONG)FIELD_OFFSET(XENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS_OUT, References)
+        + In->NumberPages * sizeof(ULONG);
+    if (OutLen < OutputSize)
         goto fail6;
 
     Status = STATUS_NO_MEMORY;
@@ -442,7 +445,7 @@ IoctlGnttabPermitForeignAccess(
     // Pass the result to user mode.
 #pragma prefast(suppress: 6320) // we want to catch all exceptions
     try {
-        ProbeForWrite(Out, OutLen, 1);
+        ProbeForWrite(Out, OutputSize, 1);
         Out->Address = Context->UserVa;
 
         for (Page = 0; Page < Context->NumberPages; Page++) {
@@ -452,7 +455,7 @@ IoctlGnttabPermitForeignAccess(
         }
     } except(EXCEPTION_EXECUTE_HANDLER) {
         Status = GetExceptionCode();
-        Error("Exception 0x%lx while probing/writing output buffer at %p, size 
0x%lx\n", Status, Out, OutLen);
+        Error("Exception 0x%lx while probing/writing output buffer at %p, size 
0x%lx\n", Status, Out, OutputSize);
         goto fail9;
     }
 
@@ -633,7 +636,7 @@ IoctlGnttabMapForeignPages(
     PXENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN_V2    In = NULL;
     // XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_OUT_V2 is the same as 
XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_OUT
     PXENIFACE_GNTTAB_MAP_FOREIGN_PAGES_OUT Out = Irp->UserBuffer;
-    ULONG NumberPages;
+    ULONG ReferenceSize;
     PXENIFACE_GNTTAB_CONTEXT Context;
     ULONG ControlCode = 
IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode;
 
@@ -656,26 +659,30 @@ IoctlGnttabMapForeignPages(
             goto fail2;
 
         In1 = Buffer;
-        NumberPages = (InLen - 
(ULONG)FIELD_OFFSET(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN, References)) / 
sizeof(ULONG);
+        ReferenceSize = InLen - 
(ULONG)FIELD_OFFSET(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN, References);
+        if (ReferenceSize > 1024 * 1024 * sizeof(ULONG))
+            goto fail3;
         status = __CaptureUserBuffer(Buffer, InLen, &In1);
         if (!NT_SUCCESS(status))
-            goto fail3;
+            goto fail4;
 
         Context->UseRequestId = TRUE;
         Context->RequestId = In1->RequestId;
 
         // legacy IOCTL, convert the input to v2
         status = STATUS_NO_MEMORY;
-        In = __AllocatePoolWithTag(NonPagedPool, sizeof(*In), 
XENIFACE_POOL_TAG);
+        In = __AllocatePoolWithTag(NonPagedPool,
+                                   
(ULONG)FIELD_OFFSET(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN, References) + 
ReferenceSize,
+                                   XENIFACE_POOL_TAG);
         if (In == NULL)
-            goto fail4;
+            goto fail5;
 
         In->RemoteDomain = In1->RemoteDomain;
         In->NumberPages = In1->NumberPages;
         In->NotifyOffset = In1->NotifyOffset;
         In->NotifyPort = In1->NotifyPort;
         In->Flags = In1->Flags;
-        memcpy(&In->References, &In1->References, NumberPages * sizeof(ULONG));
+        memcpy(&In->References, &In1->References, ReferenceSize);
 
         __FreeCapturedBuffer(In1);
         In1 = NULL;
@@ -686,10 +693,12 @@ IoctlGnttabMapForeignPages(
             goto fail2;
 
         In = Buffer;
-        NumberPages = (InLen - 
(ULONG)FIELD_OFFSET(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN_V2, References)) / 
sizeof(ULONG);
+        ReferenceSize = InLen - 
(ULONG)FIELD_OFFSET(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN_V2, References);
+        if (ReferenceSize > 1024 * 1024 * sizeof(ULONG))
+            goto fail3;
         status = __CaptureUserBuffer(Buffer, InLen, &In);
         if (!NT_SUCCESS(status))
-            goto fail3;
+            goto fail4;
 
         Context->UseRequestId = FALSE;
         Context->RequestId = 0;
@@ -699,18 +708,14 @@ IoctlGnttabMapForeignPages(
     status = STATUS_INVALID_PARAMETER;
     if (In->NumberPages == 0 ||
         In->NumberPages > 1024 * 1024 ||
-        In->NumberPages != NumberPages) {
-        goto fail5;
+        In->NumberPages * sizeof(ULONG) > ReferenceSize) {
+        goto fail6;
     }
 
     if ((In->Flags & XENIFACE_GNTTAB_USE_NOTIFY_OFFSET) &&
         (In->NotifyOffset >= In->NumberPages * PAGE_SIZE)) {
-        goto fail6;
-    }
-
-    status = STATUS_INVALID_BUFFER_SIZE;
-    if (InLen != (ULONG)FIELD_OFFSET(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN_V2, 
References[In->NumberPages]))
         goto fail7;
+    }
 
     Context->RemoteDomain = In->RemoteDomain;
     Context->NumberPages = In->NumberPages;
@@ -837,14 +842,14 @@ fail7:
 
 fail6:
     Error("Fail6\n");
+    __FreeCapturedBuffer(In);
 
 fail5:
     Error("Fail5\n");
-    __FreeCapturedBuffer(In);
+    __FreeCapturedBuffer(In1);
 
 fail4:
     Error("Fail4\n");
-    __FreeCapturedBuffer(In1);
 
 fail3:
     Error("Fail3\n");
-- 
2.55.0.windows.3



--
Ngoc Tu Dinh | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.