new file mode 100644
@@ -0,0 +1,238 @@
+From 68ce19940f8e08c85f9c8ce65180cdb90bf4b0d2 Mon Sep 17 00:00:00 2001
+From: Michael Mann <mmann78@netscape.net>
+Date: Sat, 21 Jun 2025 12:11:30 -0400
+Subject: [PATCH] Schematron: Fix null pointer dereference leading to DoS
+
+(CVE-2025-49795)
+
+Fixes #932
+
+Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libxml2/-/commit/c24909ba2601848825b49a60f988222da3019667]
+CVE: CVE-2025-49795
+
+(cherry picked from commit c24909ba2601848825b49a60f988222da3019667)
+Signed-off-by: Roland Kovacs <roland.kovacs@est.tech>
+---
+ result/schematron/zvon16_0.err | 3 +
+ runtest.c | 139 +++++++++++++++++++++++++++++++++
+ schematron.c | 5 ++
+ test/schematron/zvon16.sct | 7 ++
+ test/schematron/zvon16_0.xml | 5 ++
+ 5 files changed, 159 insertions(+)
+ create mode 100644 result/schematron/zvon16_0.err
+ create mode 100644 test/schematron/zvon16.sct
+ create mode 100644 test/schematron/zvon16_0.xml
+
+diff --git a/result/schematron/zvon16_0.err b/result/schematron/zvon16_0.err
+new file mode 100644
+index 00000000..3d052409
+--- /dev/null
++++ b/result/schematron/zvon16_0.err
+@@ -0,0 +1,3 @@
++XPath error : Unregistered function
++./test/schematron/zvon16_0.xml:2: element book: schematron error : /library/book line 2: Book
++./test/schematron/zvon16_0.xml fails to validate
+diff --git a/runtest.c b/runtest.c
+index c78eec81..736cae5e 100644
+--- a/runtest.c
++++ b/runtest.c
+@@ -52,6 +52,10 @@
+ #include <libxml/xmlschemastypes.h>
+ #endif
+
++#ifdef LIBXML_SCHEMATRON_ENABLED
++#include <libxml/schematron.h>
++#endif
++
+ #ifdef LIBXML_PATTERN_ENABLED
+ #include <libxml/pattern.h>
+ #endif
+@@ -3881,6 +3885,136 @@ rngStreamTest(const char *filename,
+
+ #endif
+
++/************************************************************************
++ * *
++ * Schematron tests *
++ * *
++ ************************************************************************/
++
++#ifdef LIBXML_SCHEMATRON_ENABLED
++static int
++schematronOneTest(const char *sch, const char *filename, int options,
++ xmlSchematronPtr schematron) {
++ xmlDocPtr doc;
++ xmlSchematronValidCtxtPtr ctxt;
++ int ret;
++
++ doc = xmlReadFile(filename, NULL, options);
++ if (doc == NULL) {
++ fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
++ return(-1);
++ }
++
++ ctxt = xmlSchematronNewValidCtxt(schematron, XML_SCHEMATRON_OUT_ERROR);
++ xmlSchematronSetValidStructuredErrors(ctxt, testStructuredErrorHandler,
++ NULL);
++ ret = xmlSchematronValidateDoc(ctxt, doc);
++ if (ret == 0) {
++ testErrorHandler(NULL, "%s validates\n", filename);
++ } else if (ret > 0) {
++ testErrorHandler(NULL, "%s fails to validate\n", filename);
++ } else {
++ testErrorHandler(NULL, "%s validation generated an internal error\n",
++ filename);
++ }
++
++ xmlSchematronFreeValidCtxt(ctxt);
++ xmlFreeDoc(doc);
++ return(0);
++}
++
++/**
++ * schematronTest:
++ * @filename: the schemas file
++ * @result: the file with expected result
++ * @err: the file with error messages
++ *
++ * Returns 0 in case of success, an error code otherwise
++ */
++static int
++schematronTest(const char *filename,
++ const char *resul ATTRIBUTE_UNUSED,
++ const char *errr ATTRIBUTE_UNUSED,
++ int options) {
++ const char *base = baseFilename(filename);
++ const char *base2;
++ const char *instance;
++ xmlSchematronParserCtxtPtr pctxt;
++ xmlSchematronPtr schematron;
++ int res = 0, len, ret = 0;
++ int parseErrorsSize;
++ char pattern[500];
++ char prefix[500];
++ char err[500];
++ glob_t globbuf;
++ size_t i;
++ char count = 0;
++
++ /* Redirect XPath errors */
++ xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
++
++ pctxt = xmlSchematronNewParserCtxt(filename);
++ schematron = xmlSchematronParse(pctxt);
++ xmlSchematronFreeParserCtxt(pctxt);
++ if (schematron == NULL)
++ testErrorHandler(NULL, "Schematron schema %s failed to compile\n",
++ filename);
++ parseErrorsSize = testErrorsSize;
++
++ /*
++ * most of the mess is about the output filenames generated by the Makefile
++ */
++ len = strlen(base);
++ if ((len > 499) || (len < 5)) {
++ ret = -1;
++ goto done;
++ }
++ len -= 4; /* remove trailing .sct */
++ memcpy(prefix, base, len);
++ prefix[len] = 0;
++
++ if (snprintf(pattern, 499, "./test/schematron/%s_?.xml", prefix) >= 499)
++ pattern[499] = 0;
++
++ globbuf.gl_offs = 0;
++ glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
++ for (i = 0;i < globbuf.gl_pathc;i++) {
++ testErrorsSize = parseErrorsSize;
++ testErrors[parseErrorsSize] = 0;
++ instance = globbuf.gl_pathv[i];
++ base2 = baseFilename(instance);
++ len = strlen(base2);
++ if ((len > 6) && (base2[len - 6] == '_')) {
++ count = base2[len - 5];
++ res = snprintf(err, 499, "result/schematron/%s_%c.err",
++ prefix, count);
++ if (res >= 499)
++ err[499] = 0;
++ } else {
++ fprintf(stderr, "don't know how to process %s\n", instance);
++ continue;
++ }
++ if (schematron != NULL) {
++ nb_tests++;
++ res = schematronOneTest(filename, instance, options, schematron);
++ if (res != 0)
++ ret = res;
++ }
++ if (compareFileMem(err, testErrors, testErrorsSize)) {
++ fprintf(stderr, "Error for %s on %s failed\n", instance,
++ filename);
++ ret = 1;
++ }
++ }
++ globfree(&globbuf);
++
++done:
++ xmlSchematronFree(schematron);
++ xmlSetStructuredErrorFunc(NULL, NULL);
++ return(ret);
++}
++#endif /* LIBXML_SCHEMATRON_ENABLED */
++
+ #ifdef LIBXML_PATTERN_ENABLED
+ #ifdef LIBXML_READER_ENABLED
+ /************************************************************************
+@@ -5117,6 +5251,11 @@ testDesc testDescriptions[] = {
+ rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
+ XML_PARSE_DTDATTR | XML_PARSE_NOENT },
+ #endif
++#if defined(LIBXML_SCHEMATRON_ENABLED)
++ { "Schematron regression tests" ,
++ schematronTest, "./test/schematron/*.sct", NULL, NULL, NULL,
++ 0 },
++#endif
+ #endif
+ #ifdef LIBXML_PATTERN_ENABLED
+ #ifdef LIBXML_READER_ENABLED
+diff --git a/schematron.c b/schematron.c
+index 411a515c..c970d31f 100644
+--- a/schematron.c
++++ b/schematron.c
+@@ -1484,6 +1484,11 @@ xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt,
+ select = xmlGetNoNsProp(child, BAD_CAST "select");
+ comp = xmlXPathCtxtCompile(ctxt->xctxt, select);
+ eval = xmlXPathCompiledEval(comp, ctxt->xctxt);
++ if (eval == NULL) {
++ xmlXPathFreeCompExpr(comp);
++ xmlFree(select);
++ return ret;
++ }
+
+ switch (eval->type) {
+ case XPATH_NODESET: {
+diff --git a/test/schematron/zvon16.sct b/test/schematron/zvon16.sct
+new file mode 100644
+index 00000000..f03848aa
+--- /dev/null
++++ b/test/schematron/zvon16.sct
+@@ -0,0 +1,7 @@
++<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron">
++ <sch:pattern id="TestPattern">
++ <sch:rule context="book">
++ <sch:report test="not(@available)">Book <sch:value-of select="falae()"/> test</sch:report>
++ </sch:rule>
++ </sch:pattern>
++</sch:schema>
+diff --git a/test/schematron/zvon16_0.xml b/test/schematron/zvon16_0.xml
+new file mode 100644
+index 00000000..551e2d65
+--- /dev/null
++++ b/test/schematron/zvon16_0.xml
+@@ -0,0 +1,5 @@
++<library>
++ <book title="Test Book" id="bk101">
++ <author>Test Author</author>
++ </book>
++</library>
@@ -20,6 +20,7 @@ SRC_URI += "http://www.w3.org/XML/Test/xmlts20130923.tar;subdir=${BP};name=testt
file://install-tests.patch \
file://CVE-2025-32414.patch \
file://CVE-2025-32415.patch \
+ file://CVE-2025-49795.patch \
"
SRC_URI[archive.sha256sum] = "c3d8c0c34aa39098f66576fe51969db12a5100b956233dc56506f7a8679be995"