--- a/testparser.c +++ b/testparser.c @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -777,6 +778,63 @@ } #endif /* WIN32 */ +#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_SCHEMAS_ENABLED) +/* + * Regression test for CVE-2026-6732: a type confusion in xmlParseReference + * crashed a schema-validating xmlTextReader whenever the document expanded + * an internal entity. Without the fix this triggers SIGSEGV on the first + * read; with the fix the entity expansion is read and the schema correctly + * reports the substituted content as invalid against xs:integer. + * + * Backport of upstream commit 7cea3fd1 adapted for the libxml2 2.13 + * testparser.c layout (which predates the testReaderSchemaResourceLoader + * helper that upstream uses as an anchor on master). + */ +static int +testReaderSchemaEntityExpansion(void) { + static const char xsd[] = + "\n" + "\n" + " \n" + "\n"; + static const char xml[] = + "]>\n" + "&n;"; + xmlSchemaParserCtxtPtr spc; + xmlSchemaPtr schema; + xmlTextReaderPtr reader; + int err = 0; + int ret; + + spc = xmlSchemaNewMemParserCtxt(xsd, (int) sizeof(xsd) - 1); + schema = xmlSchemaParse(spc); + xmlSchemaFreeParserCtxt(spc); + if (schema == NULL) { + fprintf(stderr, "xmlSchemaParse failed\n"); + return 1; + } + + reader = xmlReaderForMemory(xml, (int) sizeof(xml) - 1, "doc.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_DTDLOAD); + xmlTextReaderSetSchema(reader, schema); + + while ((ret = xmlTextReaderRead(reader)) == 1) + ; + if (ret != 0) { + fprintf(stderr, "reader failed on entity-expanded document\n"); + err = 1; + } + if (xmlTextReaderIsValid(reader) != 0) { + fprintf(stderr, "schema missed invalid entity-expanded text\n"); + err = 1; + } + + xmlFreeTextReader(reader); + xmlSchemaFree(schema); + return err; +} +#endif + int main(void) { int err = 0; @@ -807,6 +865,9 @@ #ifdef LIBXML_XINCLUDE_ENABLED err |= testReaderXIncludeError(); #endif +#ifdef LIBXML_SCHEMAS_ENABLED + err |= testReaderSchemaEntityExpansion(); +#endif #endif #ifdef LIBXML_WRITER_ENABLED err |= testWriterClose();