From fbe686c008d5c0373188b3738dfe3e75250d3cd7 Mon Sep 17 00:00:00 2001
From: Tu Dinh <ngoc-tu.dinh@vates.tech>
Date: Tue, 1 Apr 2025 10:36:12 +0000
Subject: Properly limit xenstore write lengths

Xenbus's write interface only checks write data sizes using asserts.
The size of overly-large writes (e.g. through Xeniface IOCTLs) is not
checked in release builds.

Verify write lengths using full checks instead of asserts to fix this
issue.

This is XSA-468 / CVE-2025-27464.

Signed-off-by: Tu Dinh <ngoc-tu.dinh@vates.tech>
Acked-by: Paul Durrant <paul@xen.org>
Reviewed-by: Owen Smith <owen.smith@cloud.com>
---
 src/xenbus/store.c | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/src/xenbus/store.c b/src/xenbus/store.c
index 02d3cc27b5cc..02cdd179ead1 100644
--- a/src/xenbus/store.c
+++ b/src/xenbus/store.c
@@ -32,6 +32,7 @@
 
 #include <ntddk.h>
 #include <ntstrsafe.h>
+#include <ntintsafe.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <xen.h>
@@ -210,6 +211,7 @@ StorePrepareRequest(
     Segment->Length = sizeof (struct xsd_sockmsg);
 
     va_start(Arguments, Type);
+    status = STATUS_UNSUCCESSFUL;
     for (;;) {
         PCHAR   Data;
         ULONG   Length;
@@ -222,14 +224,19 @@ StorePrepareRequest(
             break;
         }
 
+        if (Request->Count >= XENBUS_STORE_REQUEST_SEGMENT_COUNT)
+            goto fail2;
         Segment = &Request->Segment[Request->Count++];
-        ASSERT3U(Request->Count, <, XENBUS_STORE_REQUEST_SEGMENT_COUNT);
 
         Segment->Data = Data;
         Segment->Offset = 0;
         Segment->Length = Length;
 
-        Request->Header.len += Segment->Length;
+        if (!NT_SUCCESS(RtlULongAdd(Request->Header.len,
+                                    Segment->Length,
+                                    &Request->Header.len)) ||
+            Request->Header.len > XENSTORE_PAYLOAD_MAX)
+            goto fail3;
     }
     va_end(Arguments);
 
@@ -237,6 +244,10 @@ StorePrepareRequest(
 
     return STATUS_SUCCESS;
 
+fail3:
+fail2:
+    RtlZeroMemory(Request, sizeof (XENBUS_STORE_REQUEST));
+
 fail1:
     return status;
 }
@@ -1272,10 +1283,12 @@ StoreVPrintf(
         if (status != STATUS_BUFFER_OVERFLOW)
             goto fail2;
 
-        __StoreFree(Buffer);
+        status = STATUS_INVALID_BUFFER_SIZE;
         Length <<= 1;
+        if (Length > 1024)
+            goto fail3;
 
-        ASSERT3U(Length, <=, 1024);
+        __StoreFree(Buffer);
     }
 
     status = StoreWrite(Context,
@@ -1284,12 +1297,13 @@ StoreVPrintf(
                           Node,
                           Buffer);
     if (!NT_SUCCESS(status))
-        goto fail3;
+        goto fail4;
 
     __StoreFree(Buffer);
 
     return STATUS_SUCCESS;
 
+fail4:
 fail3:
 fail2:
     __StoreFree(Buffer);
-- 
2.47.1

