From b2a28a861e9d43a23b877c3994daa28f8af69618 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 4 Jul 2025 14:28:26 +0200 Subject: [PATCH] schematron: Fix memory safety issues in xmlSchematronReportOutput Fix use-after-free (CVE-2025-49794) and type confusion (CVE-2025-49796) in xmlSchematronReportOutput. Fixes #931. Fixes #933. --- result/schematron/cve-2025-49794_0.err | 2 + result/schematron/cve-2025-49796_0.err | 2 + schematron.c | 67 ++++++++++++++------------ test/schematron/cve-2025-49794.sct | 10 ++++ test/schematron/cve-2025-49794_0.xml | 6 +++ test/schematron/cve-2025-49796.sct | 9 ++++ test/schematron/cve-2025-49796_0.xml | 3 ++ 7 files changed, 67 insertions(+), 32 deletions(-) create mode 100644 result/schematron/cve-2025-49794_0.err create mode 100644 result/schematron/cve-2025-49796_0.err create mode 100644 test/schematron/cve-2025-49794.sct create mode 100644 test/schematron/cve-2025-49794_0.xml create mode 100644 test/schematron/cve-2025-49796.sct create mode 100644 test/schematron/cve-2025-49796_0.xml diff --git a/result/schematron/cve-2025-49794_0.err b/result/schematron/cve-2025-49794_0.err new file mode 100644 index 00000000..57752310 --- /dev/null +++ b/result/schematron/cve-2025-49794_0.err @@ -0,0 +1,2 @@ +./test/schematron/cve-2025-49794_0.xml:2: element boo0: schematron error : /librar0/boo0 line 2: +./test/schematron/cve-2025-49794_0.xml fails to validate diff --git a/result/schematron/cve-2025-49796_0.err b/result/schematron/cve-2025-49796_0.err new file mode 100644 index 00000000..bf875ee0 --- /dev/null +++ b/result/schematron/cve-2025-49796_0.err @@ -0,0 +1,2 @@ +./test/schematron/cve-2025-49796_0.xml:2: element boo0: schematron error : /librar0/boo0 line 2: +./test/schematron/cve-2025-49796_0.xml fails to validate diff --git a/schematron.c b/schematron.c index ddbb069b..0c7bc84a 100644 --- a/schematron.c +++ b/schematron.c @@ -1239,27 +1239,15 @@ exit: * * ************************************************************************/ -static xmlNodePtr +static xmlXPathObjectPtr xmlSchematronGetNode(xmlSchematronValidCtxtPtr ctxt, xmlNodePtr cur, const xmlChar *xpath) { - xmlNodePtr node = NULL; - xmlXPathObjectPtr ret; - if ((ctxt == NULL) || (cur == NULL) || (xpath == NULL)) return(NULL); ctxt->xctxt->doc = cur->doc; ctxt->xctxt->node = cur; - ret = xmlXPathEval(xpath, ctxt->xctxt); - if (ret == NULL) - return(NULL); - - if ((ret->type == XPATH_NODESET) && - (ret->nodesetval != NULL) && (ret->nodesetval->nodeNr > 0)) - node = ret->nodesetval->nodeTab[0]; - - xmlXPathFreeObject(ret); - return(node); + return(xmlXPathEval(xpath, ctxt->xctxt)); } /** @@ -1301,28 +1289,43 @@ xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt, child = test->children; while (child != NULL) { if ((child->type == XML_TEXT_NODE) || - (child->type == XML_CDATA_SECTION_NODE)) - ret = xmlStrcat(ret, child->content); - else if (IS_SCHEMATRON(child, "name")) { - xmlChar *path; + (child->type == XML_CDATA_SECTION_NODE)) + ret = xmlStrcat(ret, child->content); + else if (IS_SCHEMATRON(child, "name")) { + xmlXPathObject *obj = NULL; + xmlChar *path; path = xmlGetNoNsProp(child, BAD_CAST "path"); node = cur; - if (path != NULL) { - node = xmlSchematronGetNode(ctxt, cur, path); - if (node == NULL) - node = cur; - xmlFree(path); - } - - if ((node->ns == NULL) || (node->ns->prefix == NULL)) - ret = xmlStrcat(ret, node->name); - else { - ret = xmlStrcat(ret, node->ns->prefix); - ret = xmlStrcat(ret, BAD_CAST ":"); - ret = xmlStrcat(ret, node->name); - } + if (path != NULL) { + obj = xmlSchematronGetNode(ctxt, cur, path); + if ((obj != NULL) && + (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && + (obj->nodesetval->nodeNr > 0)) + node = obj->nodesetval->nodeTab[0]; + xmlFree(path); + } + + switch (node->type) { + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + if ((node->ns == NULL) || (node->ns->prefix == NULL)) + ret = xmlStrcat(ret, node->name); + else { + ret = xmlStrcat(ret, node->ns->prefix); + ret = xmlStrcat(ret, BAD_CAST ":"); + ret = xmlStrcat(ret, node->name); + } + break; + + /* TODO: handle other node types */ + default: + break; + } + + xmlXPathFreeObject(obj); } else { child = child->next; continue; diff --git a/test/schematron/cve-2025-49794.sct b/test/schematron/cve-2025-49794.sct new file mode 100644 index 00000000..7fc9ee3d --- /dev/null +++ b/test/schematron/cve-2025-49794.sct @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/test/schematron/cve-2025-49794_0.xml b/test/schematron/cve-2025-49794_0.xml new file mode 100644 index 00000000..debc64ba --- /dev/null +++ b/test/schematron/cve-2025-49794_0.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/test/schematron/cve-2025-49796.sct b/test/schematron/cve-2025-49796.sct new file mode 100644 index 00000000..e9702d75 --- /dev/null +++ b/test/schematron/cve-2025-49796.sct @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/test/schematron/cve-2025-49796_0.xml b/test/schematron/cve-2025-49796_0.xml new file mode 100644 index 00000000..be33c4ec --- /dev/null +++ b/test/schematron/cve-2025-49796_0.xml @@ -0,0 +1,3 @@ + + + -- 2.49.0