From 5be25657583ea91b09025c858b4785834c20f59c Mon Sep 17 00:00:00 2001
From: Francesco Bertolaccini <francesco.bertolaccini@trailofbits.com>
Date: Tue, 3 Mar 2026 16:41:43 +0100
Subject: [PATCH] Fix NULL function-pointer dereference for empty external
 parameter entities

When an external parameter entity with empty text is referenced inside
an entity declaration value, the sub-parser created to handle it receives
0 bytes of input.  Processing enters entityValueInitProcessor which calls
storeEntityValue() with the parser's encoding; since no bytes were ever
processed, encoding detection has not yet occurred and the encoding is
still the initial probing encoding set up by XmlInitEncoding().  That
encoding only populates scanners[] (for prolog and content), not
literalScanners[].  XmlEntityValueTok() calls through
literalScanners[XML_ENTITY_VALUE_LITERAL] which is NULL, causing a
SEGV.

Skip the tokenization loop entirely when entityTextPtr >= entityTextEnd,
and initialize the `next` pointer before the early exit so that callers
(callStoreEntityValue) receive a valid value through nextPtr.
---
diff -urp firefox-115.4.0.orig/parser/expat/lib/xmlparse.c firefox-115.4.0/parser/expat/lib/xmlparse.c
--- firefox-115.4.0.orig/parser/expat/lib/xmlparse.c	2023-10-16 21:48:57.000000000 -0500
+++ firefox-115.4.0/parser/expat/lib/xmlparse.c	2026-04-25 04:55:34.512578221 -0500
@@ -5875,8 +5875,18 @@ storeEntityValue(XML_Parser parser,
       return XML_ERROR_NO_MEMORY;
   }
 
+  const char *next = entityTextPtr;
+
+  /* Nothing to tokenize. */
+  if (entityTextPtr >= entityTextEnd) {
+    result = XML_ERROR_NONE;
+    goto endEntityValue;
+  }
+
   for (;;) {
-    const char *next;
+    next
+        = entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */
+
     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
     switch (tok) {
     case XML_TOK_PARAM_ENTITY_REF:
