Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: [email protected], [email protected]
Control: affects -1 + src:libxml2.9
User: [email protected]
Usertags: pu

[ Reason ]

Fix <no-dsa> issue CVE-2025-9714 and improve existing mitigation for
CVE-2025-7425.

[ Impact ]

Users will remain vulnerable to CVE-2025-9714, and will regress when
upgrading (a fix was uploaded to Bullseye LTS).

[ Tests ]

1/ PoC (from libxslt) at https://gitlab.gnome.org/GNOME/libxslt/-/issues/140
and https://gitlab.gnome.org/GNOME/libxslt/-/issues/148 .

2/ Autopkgtests for reverse (build-)dependencies.

[ Risks ]

The upstream fix for CVE-2025-9714 trivially applies to
2.9.14+dfsg-1.3~deb12u4.

Backporting the mitigation for CVE-2025-7425 from
https://gitlab.gnome.org/-/project/1762/uploads/302ecfda701895ebd0fa438a66d1a7a4/gnome-libxslt-bug-140-apple-fix.diff
was more involved.  Improvements over the existing
d/p/CVE-2025-7425.patch were discussed offlist with Aron Xu; a version
containing the resulting patch was uploaded to Bullseye LTS.

[ Checklist ]

  [*] *all* changes are documented in the d/changelog
  [*] I reviewed all changes and I approve them
  [*] attach debdiff against the package in oldstable
  [*] the issue is verified as fixed in unstable

[ Changes ]

  * Fix CVE-2025-9714: Denial of service vulnerability via uncontrolled
    recursion in XPath evaluation.
  * Amend d/p/CVE-2025-7425.patch to better reflect the original fix.

-- 
Guilhem.
diffstat for libxml2-2.9.14+dfsg libxml2-2.9.14+dfsg

 changelog                   |    9 
 patches/CVE-2025-7425.patch |  441 +++++++++++++++-----------------------------
 patches/CVE-2025-9714.patch |  113 +++++++++++
 patches/series              |    1 
 4 files changed, 277 insertions(+), 287 deletions(-)

diff -Nru libxml2-2.9.14+dfsg/debian/changelog 
libxml2-2.9.14+dfsg/debian/changelog
--- libxml2-2.9.14+dfsg/debian/changelog        2025-08-25 13:30:10.000000000 
+0200
+++ libxml2-2.9.14+dfsg/debian/changelog        2025-10-11 14:41:17.000000000 
+0200
@@ -1,3 +1,12 @@
+libxml2 (2.9.14+dfsg-1.3~deb12u5) bookworm; urgency=high
+
+  * Non-maintainer upload.
+  * Fix CVE-2025-9714: Denial of service vulnerability via uncontrolled
+    recursion in XPath evaluation.
+  * Amend d/p/CVE-2025-7425.patch to better reflect the original fix.
+
+ -- Guilhem Moulin <[email protected]>  Sat, 11 Oct 2025 14:41:17 +0200
+
 libxml2 (2.9.14+dfsg-1.3~deb12u4) bookworm-security; urgency=high
 
   * CVE-2025-7425: heap-use-after-free in xmlFreeID caused by `atype`
diff -Nru libxml2-2.9.14+dfsg/debian/patches/CVE-2025-7425.patch 
libxml2-2.9.14+dfsg/debian/patches/CVE-2025-7425.patch
--- libxml2-2.9.14+dfsg/debian/patches/CVE-2025-7425.patch      2025-08-25 
13:29:44.000000000 +0200
+++ libxml2-2.9.14+dfsg/debian/patches/CVE-2025-7425.patch      2025-10-11 
14:41:17.000000000 +0200
@@ -59,35 +59,42 @@
 (xmlSchemaValAtomicType):
 - Adopt macros by renaming the struct fields, recompiling and fixing
   compiler failures, then changing the struct field names back.
+
+Origin: 
https://gitlab.gnome.org/-/project/1762/uploads/302ecfda701895ebd0fa438a66d1a7a4/gnome-libxslt-bug-140-apple-fix.diff
+Bug: https://gitlab.gnome.org/GNOME/libxslt/-/issues/140
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=2379274
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-7425
+Bug-Debian: https://bugs.debian.org/1109122
 ---
- HTMLparser.c          |  1 +
- SAX2.c                |  6 ++--
- include/libxml/tree.h | 14 ++++++++-
- parser.c              |  8 ++---
- runxmlconf.c          |  4 +--
- tree.c                | 20 ++++++-------
- valid.c               | 68 +++++++++++++++++++++----------------------
- xmlreader.c           | 30 +++++++++----------
- xmlschemas.c          |  4 +--
- xmlschemastypes.c     | 12 ++++----
- 10 files changed, 90 insertions(+), 77 deletions(-)
+ HTMLparser.c          |  2 +-
+ SAX2.c                |  6 +++---
+ include/libxml/tree.h | 14 +++++++++++++-
+ parser.c              | 26 +++++++++++++-------------
+ runxmlconf.c          |  4 ++--
+ tree.c                | 20 ++++++++++----------
+ valid.c               | 16 ++++++++--------
+ xmlreader.c           | 30 +++++++++++++++---------------
+ xmlschemas.c          |  4 ++--
+ xmlschemastypes.c     | 12 ++++++------
+ 10 files changed, 73 insertions(+), 61 deletions(-)
 
-Index: libxml2-2.9.14+dfsg/HTMLparser.c
-===================================================================
---- libxml2-2.9.14+dfsg.orig/HTMLparser.c
-+++ libxml2-2.9.14+dfsg/HTMLparser.c
-@@ -2514,6 +2514,7 @@ htmlNewDocNoDtD(const xmlChar *URI, cons
+diff --git a/HTMLparser.c b/HTMLparser.c
+index 4a56fb1..eabca3a 100644
+--- a/HTMLparser.c
++++ b/HTMLparser.c
+@@ -2514,7 +2514,7 @@ htmlNewDocNoDtD(const xmlChar *URI, const xmlChar 
*ExternalID) {
      cur->refs = NULL;
      cur->_private = NULL;
      cur->charset = XML_CHAR_ENCODING_UTF8;
+-    cur->properties = XML_DOC_HTML | XML_DOC_USERBUILT;
 +    XML_DOC_SET_PROPERTIES(cur, XML_DOC_HTML | XML_DOC_USERBUILT);
-     cur->properties = XML_DOC_HTML | XML_DOC_USERBUILT;
      if ((ExternalID != NULL) ||
        (URI != NULL))
-Index: libxml2-2.9.14+dfsg/SAX2.c
-===================================================================
---- libxml2-2.9.14+dfsg.orig/SAX2.c
-+++ libxml2-2.9.14+dfsg/SAX2.c
+       xmlCreateIntSubset(cur, BAD_CAST "html", ExternalID, URI);
+diff --git a/SAX2.c b/SAX2.c
+index f7c77c2..0d8e84a 100644
+--- a/SAX2.c
++++ b/SAX2.c
 @@ -970,7 +970,7 @@ xmlSAX2StartDocument(void *ctx)
            xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
            return;
@@ -109,10 +116,10 @@
            doc->parseFlags = ctxt->options;
            if (ctxt->encoding != NULL)
                doc->encoding = xmlStrdup(ctxt->encoding);
-Index: libxml2-2.9.14+dfsg/include/libxml/tree.h
-===================================================================
---- libxml2-2.9.14+dfsg.orig/include/libxml/tree.h
-+++ libxml2-2.9.14+dfsg/include/libxml/tree.h
+diff --git a/include/libxml/tree.h b/include/libxml/tree.h
+index 1e79be9..61178b2 100644
+--- a/include/libxml/tree.h
++++ b/include/libxml/tree.h
 @@ -365,7 +365,6 @@ struct _xmlElement {
  #endif
  };
@@ -155,11 +162,11 @@
  
  typedef struct _xmlDOMWrapCtxt xmlDOMWrapCtxt;
  typedef xmlDOMWrapCtxt *xmlDOMWrapCtxtPtr;
-Index: libxml2-2.9.14+dfsg/parser.c
-===================================================================
---- libxml2-2.9.14+dfsg.orig/parser.c
-+++ libxml2-2.9.14+dfsg/parser.c
-@@ -5523,7 +5523,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt
+diff --git a/parser.c b/parser.c
+index 603c0b3..f859296 100644
+--- a/parser.c
++++ b/parser.c
+@@ -5523,7 +5523,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
                            xmlErrMemory(ctxt, "New Doc failed");
                            return;
                        }
@@ -168,7 +175,7 @@
                    }
                    if (ctxt->myDoc->intSubset == NULL)
                        ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc,
-@@ -5594,7 +5594,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt
+@@ -5594,7 +5594,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
                                xmlErrMemory(ctxt, "New Doc failed");
                                return;
                            }
@@ -177,7 +184,7 @@
                        }
  
                        if (ctxt->myDoc->intSubset == NULL)
-@@ -7035,7 +7035,7 @@ xmlParseExternalSubset(xmlParserCtxtPtr
+@@ -7035,7 +7035,7 @@ xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const 
xmlChar *ExternalID,
            xmlErrMemory(ctxt, "New Doc failed");
            return;
        }
@@ -186,7 +193,7 @@
      }
      if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL))
          xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID);
-@@ -7419,7 +7419,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt)
+@@ -7419,7 +7419,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
                            (nw != NULL) &&
                            (nw->type == XML_ELEMENT_NODE) &&
                            (nw->children == NULL))
@@ -195,11 +202,74 @@
  
                        break;
                    }
-Index: libxml2-2.9.14+dfsg/runxmlconf.c
-===================================================================
---- libxml2-2.9.14+dfsg.orig/runxmlconf.c
-+++ libxml2-2.9.14+dfsg/runxmlconf.c
-@@ -197,7 +197,7 @@ xmlconfTestInvalid(const char *id, const
+@@ -10858,13 +10858,13 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) {
+     }
+ 
+     if ((ctxt->wellFormed) && (ctxt->myDoc != NULL)) {
+-        ctxt->myDoc->properties |= XML_DOC_WELLFORMED;
++        XML_DOC_ADD_PROPERTIES(ctxt->myDoc, XML_DOC_WELLFORMED);
+       if (ctxt->valid)
+-          ctxt->myDoc->properties |= XML_DOC_DTDVALID;
++          XML_DOC_ADD_PROPERTIES(ctxt->myDoc, XML_DOC_DTDVALID);
+       if (ctxt->nsWellFormed)
+-          ctxt->myDoc->properties |= XML_DOC_NSVALID;
++          XML_DOC_ADD_PROPERTIES(ctxt->myDoc, XML_DOC_NSVALID);
+       if (ctxt->options & XML_PARSE_OLD10)
+-          ctxt->myDoc->properties |= XML_DOC_OLD10;
++          XML_DOC_ADD_PROPERTIES(ctxt->myDoc, XML_DOC_OLD10);
+     }
+     if (! ctxt->wellFormed) {
+       ctxt->valid = 0;
+@@ -12748,7 +12748,7 @@ xmlIOParseDTD(xmlSAXHandlerPtr sax, 
xmlParserInputBufferPtr input,
+       xmlErrMemory(ctxt, "New Doc failed");
+       return(NULL);
+     }
+-    ctxt->myDoc->properties = XML_DOC_INTERNAL;
++    XML_DOC_SET_PROPERTIES(ctxt->myDoc, XML_DOC_INTERNAL);
+     ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none",
+                                      BAD_CAST "none", BAD_CAST "none");
+ 
+@@ -12897,7 +12897,7 @@ xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar 
*ExternalID,
+       xmlFreeParserCtxt(ctxt);
+       return(NULL);
+     }
+-    ctxt->myDoc->properties = XML_DOC_INTERNAL;
++    XML_DOC_SET_PROPERTIES(ctxt->myDoc, XML_DOC_INTERNAL);
+     ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none",
+                                      ExternalID, SystemID);
+     xmlParseExternalSubset(ctxt, ExternalID, SystemID);
+@@ -13047,7 +13047,7 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, 
xmlParserCtxtPtr oldctxt,
+       xmlFreeParserCtxt(ctxt);
+       return(XML_ERR_INTERNAL_ERROR);
+     }
+-    newDoc->properties = XML_DOC_INTERNAL;
++    XML_DOC_SET_PROPERTIES(newDoc, XML_DOC_INTERNAL);
+     if (doc) {
+         newDoc->intSubset = doc->intSubset;
+         newDoc->extSubset = doc->extSubset;
+@@ -13366,7 +13366,7 @@ xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr 
oldctxt,
+           xmlFreeParserCtxt(ctxt);
+           return(XML_ERR_INTERNAL_ERROR);
+       }
+-      newDoc->properties = XML_DOC_INTERNAL;
++      XML_DOC_SET_PROPERTIES(newDoc, XML_DOC_INTERNAL);
+       newDoc->dict = ctxt->dict;
+       xmlDictReference(newDoc->dict);
+       ctxt->myDoc = newDoc;
+@@ -13768,7 +13768,7 @@ xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, 
xmlSAXHandlerPtr sax,
+       xmlFreeParserCtxt(ctxt);
+       return(-1);
+     }
+-    newDoc->properties = XML_DOC_INTERNAL;
++    XML_DOC_SET_PROPERTIES(newDoc, XML_DOC_INTERNAL);
+     if ((doc != NULL) && (doc->dict != NULL)) {
+         xmlDictFree(ctxt->dict);
+       ctxt->dict = doc->dict;
+diff --git a/runxmlconf.c b/runxmlconf.c
+index 8a37aa8..601a0af 100644
+--- a/runxmlconf.c
++++ b/runxmlconf.c
+@@ -197,7 +197,7 @@ xmlconfTestInvalid(const char *id, const char *filename, 
int options) {
                 id, filename);
      } else {
      /* invalidity should be reported both in the context and in the document 
*/
@@ -208,7 +278,7 @@
            test_log("test %s : %s failed to detect invalid document\n",
                     id, filename);
            nb_errors++;
-@@ -229,7 +229,7 @@ xmlconfTestValid(const char *id, const c
+@@ -229,7 +229,7 @@ xmlconfTestValid(const char *id, const char *filename, int 
options) {
        ret = 0;
      } else {
      /* validity should be reported both in the context and in the document */
@@ -217,10 +287,10 @@
            test_log("test %s : %s failed to validate a valid document\n",
                     id, filename);
            nb_errors++;
-Index: libxml2-2.9.14+dfsg/tree.c
-===================================================================
---- libxml2-2.9.14+dfsg.orig/tree.c
-+++ libxml2-2.9.14+dfsg/tree.c
+diff --git a/tree.c b/tree.c
+index 60cc6f4..2ce9f7e 100644
+--- a/tree.c
++++ b/tree.c
 @@ -1192,7 +1192,7 @@ xmlNewDoc(const xmlChar *version) {
      cur->compression = -1; /* not initialized */
      cur->doc = cur;
@@ -239,7 +309,7 @@
            xmlRemoveID(cur->doc, cur);
      }
      if (cur->children != NULL) xmlFreeNodeList(cur->children);
-@@ -2838,7 +2838,7 @@ xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr
+@@ -2838,7 +2838,7 @@ xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
        if(tree->type == XML_ELEMENT_NODE) {
            prop = tree->properties;
            while (prop != NULL) {
@@ -248,7 +318,7 @@
                      xmlRemoveID(tree->doc, prop);
                  }
  
-@@ -6952,9 +6952,9 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr n
+@@ -6952,9 +6952,9 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar 
*name,
        /*
        * Modify the attribute's value.
        */
@@ -260,7 +330,7 @@
        }
        if (prop->children != NULL)
            xmlFreeNodeList(prop->children);
-@@ -6974,7 +6974,7 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr n
+@@ -6974,7 +6974,7 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar 
*name,
                tmp = tmp->next;
            }
        }
@@ -292,7 +362,7 @@
                    ((xmlAttrPtr) cur)->psvi = NULL;
                }
                break;
-@@ -9991,7 +9991,7 @@ xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ct
+@@ -9991,7 +9991,7 @@ xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
      }
  
      XML_TREE_ADOPT_STR(attr->name);
@@ -301,20 +371,11 @@
      attr->psvi = NULL;
      /*
      * Walk content.
-Index: libxml2-2.9.14+dfsg/valid.c
-===================================================================
---- libxml2-2.9.14+dfsg.orig/valid.c
-+++ libxml2-2.9.14+dfsg/valid.c
-@@ -1906,7 +1906,7 @@ xmlScanIDAttributeDecl(xmlValidCtxtPtr c
-     if (elem == NULL) return(0);
-     cur = elem->attributes;
-     while (cur != NULL) {
--        if (cur->atype == XML_ATTRIBUTE_ID) {
-+        if (XML_ATTR_GET_ATYPE(cur) == XML_ATTRIBUTE_ID) {
-           ret ++;
-           if ((ret > 1) && (err))
-               xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
-@@ -2279,7 +2279,7 @@ xmlDumpAttributeDecl(xmlBufferPtr buf, x
+diff --git a/valid.c b/valid.c
+index 36a0435..28822a2 100644
+--- a/valid.c
++++ b/valid.c
+@@ -2279,7 +2279,7 @@ xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr 
attr) {
        xmlBufferWriteChar(buf, ":");
      }
      xmlBufferWriteCHAR(buf, attr->name);
@@ -323,7 +384,7 @@
        case XML_ATTRIBUTE_CDATA:
            xmlBufferWriteChar(buf, " CDATA");
            break;
-@@ -2758,7 +2758,7 @@ xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr
+@@ -2758,7 +2758,7 @@ xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const 
xmlChar *value,
        return(NULL);
      }
      if (attr != NULL)
@@ -332,16 +393,7 @@
      return(ret);
  }
  
-@@ -2837,7 +2837,7 @@ xmlIsID(xmlDocPtr doc, xmlNodePtr elem,
-       if ((fullelemname != felem) && (fullelemname != elem->name))
-           xmlFree(fullelemname);
- 
--        if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
-+        if ((attrDecl != NULL) && (XML_ATTR_GET_ATYPE(attrDecl) == 
XML_ATTRIBUTE_ID))
-           return(1);
-     }
-     return(0);
-@@ -2878,7 +2878,7 @@ xmlRemoveID(xmlDocPtr doc, xmlAttrPtr at
+@@ -2878,7 +2878,7 @@ xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
  
      xmlHashRemoveEntry(table, ID, xmlFreeIDTableEntry);
      xmlFree(ID);
@@ -350,18 +402,7 @@
      return(0);
  }
  
-@@ -3157,8 +3157,8 @@ xmlIsRef(xmlDocPtr doc, xmlNodePtr elem,
-                                        elem->name, attr->name);
- 
-       if ((attrDecl != NULL) &&
--          (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
--           attrDecl->atype == XML_ATTRIBUTE_IDREFS))
-+          (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_IDREF ||
-+           XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_IDREFS))
-       return(1);
-     }
-     return(0);
-@@ -3532,7 +3532,7 @@ xmlIsMixedElement(xmlDocPtr doc, const x
+@@ -3532,7 +3532,7 @@ xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
  
  static int
  xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
@@ -370,7 +411,7 @@
          /*
         * Use the new checks of production [4] [4a] amd [5] of the
         * Update 5 of XML-1.0
-@@ -3562,7 +3562,7 @@ xmlIsDocNameStartChar(xmlDocPtr doc, int
+@@ -3562,7 +3562,7 @@ xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
  
  static int
  xmlIsDocNameChar(xmlDocPtr doc, int c) {
@@ -379,155 +420,16 @@
          /*
         * Use the new checks of production [4] [4a] amd [5] of the
         * Update 5 of XML-1.0
-@@ -4112,7 +4112,7 @@ xmlValidCtxtNormalizeAttributeValue(xmlV
- 
-     if (attrDecl == NULL)
-       return(NULL);
--    if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
-+    if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_CDATA)
-       return(NULL);
- 
-     ret = xmlStrdup(value);
-@@ -4174,7 +4174,7 @@ xmlValidNormalizeAttributeValue(xmlDocPt
- 
-     if (attrDecl == NULL)
-       return(NULL);
--    if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
-+    if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_CDATA)
-       return(NULL);
- 
-     ret = xmlStrdup(value);
-@@ -4189,7 +4189,7 @@ xmlValidateAttributeIdCallback(void *pay
-                              const xmlChar *name ATTRIBUTE_UNUSED) {
-     xmlAttributePtr attr = (xmlAttributePtr) payload;
-     int *count = (int *) data;
--    if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
-+    if (XML_ATTR_GET_ATYPE(attr) == XML_ATTRIBUTE_ID) (*count)++;
- }
- 
- /**
-@@ -4221,7 +4221,7 @@ xmlValidateAttributeDecl(xmlValidCtxtPtr
-     /* Attribute Default Legal */
-     /* Enumeration */
-     if (attr->defaultValue != NULL) {
--      val = xmlValidateAttributeValueInternal(doc, attr->atype,
-+      val = xmlValidateAttributeValueInternal(doc, XML_ATTR_GET_ATYPE(attr),
-                                               attr->defaultValue);
-       if (val == 0) {
-           xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
-@@ -4232,7 +4232,7 @@ xmlValidateAttributeDecl(xmlValidCtxtPtr
-     }
- 
-     /* ID Attribute Default */
--    if ((attr->atype == XML_ATTRIBUTE_ID)&&
-+    if ((XML_ATTR_GET_ATYPE(attr) == XML_ATTRIBUTE_ID)&&
-         (attr->def != XML_ATTRIBUTE_IMPLIED) &&
-       (attr->def != XML_ATTRIBUTE_REQUIRED)) {
-       xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
-@@ -4242,7 +4242,7 @@ xmlValidateAttributeDecl(xmlValidCtxtPtr
-     }
- 
-     /* One ID per Element Type */
--    if (attr->atype == XML_ATTRIBUTE_ID) {
-+    if (XML_ATTR_GET_ATYPE(attr) == XML_ATTRIBUTE_ID) {
-         int nbId;
- 
-       /* the trick is that we parse DtD as their own internal subset */
-@@ -4501,9 +4501,9 @@ xmlValidateOneAttribute(xmlValidCtxtPtr
+@@ -4501,7 +4501,7 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr 
doc,
               attr->name, elem->name, NULL);
        return(0);
      }
 -    attr->atype = attrDecl->atype;
 +    XML_ATTR_SET_ATYPE(attr, attrDecl->atype);
  
--    val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
-+    val = xmlValidateAttributeValueInternal(doc, 
XML_ATTR_GET_ATYPE(attrDecl), value);
+     val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
      if (val == 0) {
-           xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
-          "Syntax of value for attribute %s of %s is not valid\n",
-@@ -4522,19 +4522,19 @@ xmlValidateOneAttribute(xmlValidCtxtPtr
-     }
- 
-     /* Validity Constraint: ID uniqueness */
--    if (attrDecl->atype == XML_ATTRIBUTE_ID) {
-+    if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_ID) {
-         if (xmlAddID(ctxt, doc, value, attr) == NULL)
-           ret = 0;
-     }
- 
--    if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
--      (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
-+    if ((XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_IDREF) ||
-+      (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_IDREFS)) {
-         if (xmlAddRef(ctxt, doc, value, attr) == NULL)
-           ret = 0;
-     }
- 
-     /* Validity Constraint: Notation Attributes */
--    if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
-+    if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_NOTATION) {
-         xmlEnumerationPtr tree = attrDecl->tree;
-         xmlNotationPtr nota;
- 
-@@ -4564,7 +4564,7 @@ xmlValidateOneAttribute(xmlValidCtxtPtr
-     }
- 
-     /* Validity Constraint: Enumeration */
--    if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
-+    if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_ENUMERATION) {
-         xmlEnumerationPtr tree = attrDecl->tree;
-       while (tree != NULL) {
-           if (xmlStrEqual(tree->name, value)) break;
-@@ -4589,7 +4589,7 @@ xmlValidateOneAttribute(xmlValidCtxtPtr
- 
-     /* Extra check for the attribute value */
-     ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
--                                    attrDecl->atype, value);
-+                                    XML_ATTR_GET_ATYPE(attrDecl), value);
- 
-     return(ret);
- }
-@@ -4688,7 +4688,7 @@ xmlNodePtr elem, const xmlChar *prefix,
-       return(0);
-     }
- 
--    val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
-+    val = xmlValidateAttributeValueInternal(doc, 
XML_ATTR_GET_ATYPE(attrDecl), value);
-     if (val == 0) {
-       if (ns->prefix != NULL) {
-           xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
-@@ -4738,7 +4738,7 @@ xmlNodePtr elem, const xmlChar *prefix,
- #endif
- 
-     /* Validity Constraint: Notation Attributes */
--    if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
-+    if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_NOTATION) {
-         xmlEnumerationPtr tree = attrDecl->tree;
-         xmlNotationPtr nota;
- 
-@@ -4780,7 +4780,7 @@ xmlNodePtr elem, const xmlChar *prefix,
-     }
- 
-     /* Validity Constraint: Enumeration */
--    if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
-+    if (XML_ATTR_GET_ATYPE(attrDecl) == XML_ATTRIBUTE_ENUMERATION) {
-         xmlEnumerationPtr tree = attrDecl->tree;
-       while (tree != NULL) {
-           if (xmlStrEqual(tree->name, value)) break;
-@@ -4818,10 +4818,10 @@ xmlNodePtr elem, const xmlChar *prefix,
-     /* Extra check for the attribute value */
-     if (ns->prefix != NULL) {
-       ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
--                                        attrDecl->atype, value);
-+                                        XML_ATTR_GET_ATYPE(attrDecl), value);
-     } else {
-       ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
--                                        attrDecl->atype, value);
-+                                        XML_ATTR_GET_ATYPE(attrDecl), value);
-     }
- 
-     return(ret);
-@@ -6574,7 +6574,7 @@ xmlValidateRef(xmlRefPtr ref, xmlValidCt
+@@ -6574,7 +6574,7 @@ xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
            while (IS_BLANK_CH(*cur)) cur++;
        }
        xmlFree(dup);
@@ -536,7 +438,7 @@
        id = xmlGetID(ctxt->doc, name);
        if (id == NULL) {
            xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
-@@ -6582,7 +6582,7 @@ xmlValidateRef(xmlRefPtr ref, xmlValidCt
+@@ -6582,7 +6582,7 @@ xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
                   attr->name, name, NULL);
            ctxt->valid = 0;
        }
@@ -545,46 +447,11 @@
        xmlChar *dup, *str = NULL, *cur, save;
  
        dup = xmlStrdup(name);
-@@ -6782,7 +6782,7 @@ xmlValidateAttributeCallback(void *paylo
- 
-     if (cur == NULL)
-       return;
--    switch (cur->atype) {
-+    switch (XML_ATTR_GET_ATYPE(cur)) {
-       case XML_ATTRIBUTE_CDATA:
-       case XML_ATTRIBUTE_ID:
-       case XML_ATTRIBUTE_IDREF        :
-@@ -6797,7 +6797,7 @@ xmlValidateAttributeCallback(void *paylo
-           if (cur->defaultValue != NULL) {
- 
-               ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
--                                               cur->atype, cur->defaultValue);
-+                                               XML_ATTR_GET_ATYPE(cur), 
cur->defaultValue);
-               if ((ret == 0) && (ctxt->valid == 1))
-                   ctxt->valid = 0;
-           }
-@@ -6805,14 +6805,14 @@ xmlValidateAttributeCallback(void *paylo
-               xmlEnumerationPtr tree = cur->tree;
-               while (tree != NULL) {
-                   ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
--                                  cur->name, cur->atype, tree->name);
-+                                  cur->name, XML_ATTR_GET_ATYPE(cur), 
tree->name);
-                   if ((ret == 0) && (ctxt->valid == 1))
-                       ctxt->valid = 0;
-                   tree = tree->next;
-               }
-           }
-     }
--    if (cur->atype == XML_ATTRIBUTE_NOTATION) {
-+    if (XML_ATTR_GET_ATYPE(cur) == XML_ATTRIBUTE_NOTATION) {
-       doc = cur->doc;
-       if (cur->elem == NULL) {
-           xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
-Index: libxml2-2.9.14+dfsg/xmlreader.c
-===================================================================
---- libxml2-2.9.14+dfsg.orig/xmlreader.c
-+++ libxml2-2.9.14+dfsg/xmlreader.c
-@@ -753,7 +753,7 @@ xmlTextReaderStartElement(void *ctx, con
+diff --git a/xmlreader.c b/xmlreader.c
+index 67ff2cd..2a1a66a 100644
+--- a/xmlreader.c
++++ b/xmlreader.c
+@@ -753,7 +753,7 @@ xmlTextReaderStartElement(void *ctx, const xmlChar 
*fullname,
        if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
            (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
            (ctxt->input->cur[1] == '>'))
@@ -674,7 +541,7 @@
        xmlNodePtr tmp = reader->node->last;
        xmlUnlinkNode(tmp);
        xmlTextReaderFreeNode(reader, tmp);
-@@ -1741,7 +1741,7 @@ xmlTextReaderNext(xmlTextReaderPtr reade
+@@ -1741,7 +1741,7 @@ xmlTextReaderNext(xmlTextReaderPtr reader) {
          return(xmlTextReaderRead(reader));
      if (reader->state == XML_TEXTREADER_END || reader->state == 
XML_TEXTREADER_BACKTRACK)
          return(xmlTextReaderRead(reader));
@@ -683,7 +550,7 @@
          return(xmlTextReaderRead(reader));
      do {
          ret = xmlTextReaderRead(reader);
-@@ -3167,7 +3167,7 @@ xmlTextReaderIsEmptyElement(xmlTextReade
+@@ -3167,7 +3167,7 @@ xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
      if (reader->in_xinclude > 0)
          return(1);
  #endif
@@ -692,7 +559,7 @@
  }
  
  /**
-@@ -4035,15 +4035,15 @@ xmlTextReaderPreserve(xmlTextReaderPtr r
+@@ -4035,15 +4035,15 @@ xmlTextReaderPreserve(xmlTextReaderPtr reader) {
          return(NULL);
  
      if ((cur->type != XML_DOCUMENT_NODE) && (cur->type != XML_DTD_NODE)) {
@@ -711,11 +578,11 @@
        parent = parent->parent;
      }
      return(cur);
-Index: libxml2-2.9.14+dfsg/xmlschemas.c
-===================================================================
---- libxml2-2.9.14+dfsg.orig/xmlschemas.c
-+++ libxml2-2.9.14+dfsg/xmlschemas.c
-@@ -6024,7 +6024,7 @@ xmlSchemaPValAttrNodeID(xmlSchemaParserC
+diff --git a/xmlschemas.c b/xmlschemas.c
+index f309572..1ae078b 100644
+--- a/xmlschemas.c
++++ b/xmlschemas.c
+@@ -6024,7 +6024,7 @@ xmlSchemaPValAttrNodeID(xmlSchemaParserCtxtPtr ctxt, 
xmlAttrPtr attr)
        /*
        * NOTE: the IDness might have already be declared in the DTD
        */
@@ -724,7 +591,7 @@
            xmlIDPtr res;
            xmlChar *strip;
  
-@@ -6047,7 +6047,7 @@ xmlSchemaPValAttrNodeID(xmlSchemaParserC
+@@ -6047,7 +6047,7 @@ xmlSchemaPValAttrNodeID(xmlSchemaParserCtxtPtr ctxt, 
xmlAttrPtr attr)
                    NULL, NULL, "Duplicate value '%s' of simple "
                    "type 'xs:ID'", value, NULL);
            } else
@@ -733,11 +600,11 @@
        }
      } else if (ret > 0) {
        ret = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE;
-Index: libxml2-2.9.14+dfsg/xmlschemastypes.c
-===================================================================
---- libxml2-2.9.14+dfsg.orig/xmlschemastypes.c
-+++ libxml2-2.9.14+dfsg/xmlschemastypes.c
-@@ -2867,7 +2867,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr
+diff --git a/xmlschemastypes.c b/xmlschemastypes.c
+index af31be5..d40da49 100644
+--- a/xmlschemastypes.c
++++ b/xmlschemastypes.c
+@@ -2867,7 +2867,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const 
xmlChar * value,
                  /*
                   * NOTE: the IDness might have already be declared in the DTD
                   */
@@ -746,7 +613,7 @@
                      xmlIDPtr res;
                      xmlChar *strip;
  
-@@ -2880,7 +2880,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr
+@@ -2880,7 +2880,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const 
xmlChar * value,
                      if (res == NULL) {
                          ret = 2;
                      } else {
@@ -755,7 +622,7 @@
                      }
                  }
              }
-@@ -2905,7 +2905,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr
+@@ -2905,7 +2905,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const 
xmlChar * value,
                      xmlFree(strip);
                  } else
                      xmlAddRef(NULL, node->doc, value, attr);
@@ -764,7 +631,7 @@
              }
              goto done;
          case XML_SCHEMAS_IDREFS:
-@@ -2919,7 +2919,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr
+@@ -2919,7 +2919,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const 
xmlChar * value,
                  (node->type == XML_ATTRIBUTE_NODE)) {
                  xmlAttrPtr attr = (xmlAttrPtr) node;
  
@@ -773,7 +640,7 @@
              }
              goto done;
          case XML_SCHEMAS_ENTITY:{
-@@ -2950,7 +2950,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr
+@@ -2950,7 +2950,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const 
xmlChar * value,
                      (node->type == XML_ATTRIBUTE_NODE)) {
                      xmlAttrPtr attr = (xmlAttrPtr) node;
  
@@ -782,7 +649,7 @@
                  }
                  goto done;
              }
-@@ -2967,7 +2967,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr
+@@ -2967,7 +2967,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const 
xmlChar * value,
                  (node->type == XML_ATTRIBUTE_NODE)) {
                  xmlAttrPtr attr = (xmlAttrPtr) node;
  
diff -Nru libxml2-2.9.14+dfsg/debian/patches/CVE-2025-9714.patch 
libxml2-2.9.14+dfsg/debian/patches/CVE-2025-9714.patch
--- libxml2-2.9.14+dfsg/debian/patches/CVE-2025-9714.patch      1970-01-01 
01:00:00.000000000 +0100
+++ libxml2-2.9.14+dfsg/debian/patches/CVE-2025-9714.patch      2025-10-11 
14:41:17.000000000 +0200
@@ -0,0 +1,113 @@
+From: Nick Wellnhofer <[email protected]>
+Date: Thu, 28 Jul 2022 20:21:24 +0200
+Subject: Make XPath depth check work with recursive invocations
+
+EXSLT functions like dyn:map or dyn:evaluate invoke xmlXPathRunEval
+recursively. Don't set depth to zero but keep and restore the original
+value to avoid stack overflows when abusing these functions.
+
+Origin: 
https://gitlab.gnome.org/GNOME/libxml2/-/commit/677a42645ef22b5a50741bad5facf9d8a8bc6d21
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=2392605
+Bug: https://gitlab.gnome.org/GNOME/libxslt/-/issues/148
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-9714
+---
+ xpath.c | 23 +++++++++++++++++------
+ 1 file changed, 17 insertions(+), 6 deletions(-)
+
+diff --git a/xpath.c b/xpath.c
+index c2d8458..028471d 100644
+--- a/xpath.c
++++ b/xpath.c
+@@ -13883,12 +13883,11 @@ static int
+ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
+ {
+     xmlXPathCompExprPtr comp;
++    int oldDepth;
+ 
+     if ((ctxt == NULL) || (ctxt->comp == NULL))
+       return(-1);
+ 
+-    ctxt->context->depth = 0;
+-
+     if (ctxt->valueTab == NULL) {
+       /* Allocate the value stack */
+       ctxt->valueTab = (xmlXPathObjectPtr *)
+@@ -13942,11 +13941,13 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int 
toBool)
+           "xmlXPathRunEval: last is less than zero\n");
+       return(-1);
+     }
++    oldDepth = ctxt->context->depth;
+     if (toBool)
+       return(xmlXPathCompOpEvalToBoolean(ctxt,
+           &comp->steps[comp->last], 0));
+     else
+       xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
++    ctxt->context->depth = oldDepth;
+ 
+     return(0);
+ }
+@@ -14217,6 +14218,7 @@ xmlXPathCompExprPtr
+ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
+     xmlXPathParserContextPtr pctxt;
+     xmlXPathCompExprPtr comp;
++    int oldDepth = 0;
+ 
+ #ifdef XPATH_STREAMING
+     comp = xmlXPathTryStreamCompile(ctxt, str);
+@@ -14230,8 +14232,10 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const 
xmlChar *str) {
+     if (pctxt == NULL)
+         return NULL;
+     if (ctxt != NULL)
+-        ctxt->depth = 0;
++        oldDepth = ctxt->depth;
+     xmlXPathCompileExpr(pctxt, 1);
++    if (ctxt != NULL)
++        ctxt->depth = oldDepth;
+ 
+     if( pctxt->error != XPATH_EXPRESSION_OK )
+     {
+@@ -14252,8 +14256,10 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const 
xmlChar *str) {
+       comp = pctxt->comp;
+       if ((comp->nbStep > 1) && (comp->last >= 0)) {
+             if (ctxt != NULL)
+-                ctxt->depth = 0;
++                oldDepth = ctxt->depth;
+           xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
++            if (ctxt != NULL)
++                ctxt->depth = oldDepth;
+       }
+       pctxt->comp = NULL;
+     }
+@@ -14409,6 +14415,7 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
+ #ifdef XPATH_STREAMING
+     xmlXPathCompExprPtr comp;
+ #endif
++    int oldDepth = 0;
+ 
+     if (ctxt == NULL) return;
+ 
+@@ -14422,8 +14429,10 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
+ #endif
+     {
+         if (ctxt->context != NULL)
+-            ctxt->context->depth = 0;
++            oldDepth = ctxt->context->depth;
+       xmlXPathCompileExpr(ctxt, 1);
++        if (ctxt->context != NULL)
++            ctxt->context->depth = oldDepth;
+         CHECK_ERROR;
+ 
+         /* Check for trailing characters. */
+@@ -14432,9 +14441,11 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
+ 
+       if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
+             if (ctxt->context != NULL)
+-                ctxt->context->depth = 0;
++                oldDepth = ctxt->context->depth;
+           xmlXPathOptimizeExpression(ctxt,
+               &ctxt->comp->steps[ctxt->comp->last]);
++            if (ctxt->context != NULL)
++                ctxt->context->depth = oldDepth;
+         }
+     }
+ 
diff -Nru libxml2-2.9.14+dfsg/debian/patches/series 
libxml2-2.9.14+dfsg/debian/patches/series
--- libxml2-2.9.14+dfsg/debian/patches/series   2025-08-25 13:25:27.000000000 
+0200
+++ libxml2-2.9.14+dfsg/debian/patches/series   2025-10-11 14:41:17.000000000 
+0200
@@ -24,3 +24,4 @@
 CVE-2025-6170.patch
 CVE-2025-49794_CVE-2025-49796.patch
 CVE-2025-7425.patch
+CVE-2025-9714.patch

Attachment: signature.asc
Description: PGP signature

Reply via email to