git: f30300703245 - stable/12 - MFV: expat 2.5.0
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 02 Dec 2022 06:08:51 UTC
The branch stable/12 has been updated by delphij: URL: https://cgit.FreeBSD.org/src/commit/?id=f303007032456993a2e9d199ac86beb31dab7560 commit f303007032456993a2e9d199ac86beb31dab7560 Author: Xin LI <delphij@FreeBSD.org> AuthorDate: 2022-11-18 06:10:01 +0000 Commit: Xin LI <delphij@FreeBSD.org> CommitDate: 2022-12-02 06:08:41 +0000 MFV: expat 2.5.0 (cherry picked from commit dc58b3fca5e7a7bb1e9aa640667944d0fe0601cd) --- contrib/expat/Changes | 34 ++++++++ contrib/expat/README.md | 2 +- contrib/expat/configure.ac | 9 +- contrib/expat/doc/reference.html | 2 +- contrib/expat/doc/xmlwf.1 | 2 +- contrib/expat/doc/xmlwf.xml | 2 +- contrib/expat/examples/elements.c | 47 +++++++--- contrib/expat/examples/outline.c | 77 +++++++++-------- contrib/expat/expat_config.h.in | 5 ++ contrib/expat/lib/expat.h | 4 +- contrib/expat/lib/xmlparse.c | 47 ++++++---- contrib/expat/lib/xmltok_impl.h | 2 +- contrib/expat/tests/runtests.c | 177 +++++++++++++++++++++++++++++++++++++- lib/libexpat/expat_config.h | 11 ++- lib/libexpat/libbsdxml.3 | 4 +- 15 files changed, 340 insertions(+), 85 deletions(-) diff --git a/contrib/expat/Changes b/contrib/expat/Changes index cfc83a09dae3..e67171056950 100644 --- a/contrib/expat/Changes +++ b/contrib/expat/Changes @@ -2,6 +2,40 @@ NOTE: We are looking for help with a few things: https://github.com/libexpat/libexpat/labels/help%20wanted If you can help, please get in touch. Thanks! +Release 2.5.0 Tue October 25 2022 + Security fixes: + #616 #649 #650 CVE-2022-43680 -- Fix heap use-after-free after overeager + destruction of a shared DTD in function + XML_ExternalEntityParserCreate in out-of-memory situations. + Expected impact is denial of service or potentially + arbitrary code execution. + + Bug fixes: + #612 #645 Fix curruption from undefined entities + #613 #654 Fix case when parsing was suspended while processing nested + entities + #616 #652 #653 Stop leaking opening tag bindings after a closing tag + mismatch error where a parser is reset through + XML_ParserReset and then reused to parse + #656 CMake: Fix generation of pkg-config file + #658 MinGW|CMake: Fix static library name + + Other changes: + #663 Protect header expat_config.h from multiple inclusion + #666 examples: Make use of XML_GetBuffer and be more + consistent across examples + #648 Address compiler warnings + #667 #668 Version info bumped from 9:9:8 to 9:10:8; + see https://verbump.de/ for what these numbers do + + Special thanks to: + Jann Horn + Mark Brand + Osyotr + Rhodri James + and + Google Project Zero + Release 2.4.9 Tue September 20 2022 Security fixes: #629 #640 CVE-2022-40674 -- Heap use-after-free vulnerability in diff --git a/contrib/expat/README.md b/contrib/expat/README.md index c0ac8b0fb23a..e5e237fc9496 100644 --- a/contrib/expat/README.md +++ b/contrib/expat/README.md @@ -5,7 +5,7 @@ [![Downloads GitHub](https://img.shields.io/github/downloads/libexpat/libexpat/total?label=Downloads%20GitHub)](https://github.com/libexpat/libexpat/releases) -# Expat, Release 2.4.9 +# Expat, Release 2.5.0 This is Expat, a C library for parsing XML, started by [James Clark](https://en.wikipedia.org/wiki/James_Clark_%28programmer%29) in 1997. diff --git a/contrib/expat/configure.ac b/contrib/expat/configure.ac index 47216941658b..d3642dea5864 100644 --- a/contrib/expat/configure.ac +++ b/contrib/expat/configure.ac @@ -81,11 +81,14 @@ dnl dnl If the API changes incompatibly set LIBAGE back to 0 dnl -LIBCURRENT=9 # sync -LIBREVISION=9 # with -LIBAGE=8 # CMakeLists.txt! +LIBCURRENT=9 # sync +LIBREVISION=10 # with +LIBAGE=8 # CMakeLists.txt! AC_CONFIG_HEADERS([expat_config.h]) +AH_TOP([#ifndef EXPAT_CONFIG_H +#define EXPAT_CONFIG_H 1]) +AH_BOTTOM([#endif // ndef EXPAT_CONFIG_H]) AM_PROG_AR AC_PROG_INSTALL diff --git a/contrib/expat/doc/reference.html b/contrib/expat/doc/reference.html index 4ab8d5a76b2c..8b0d47d6dd7b 100644 --- a/contrib/expat/doc/reference.html +++ b/contrib/expat/doc/reference.html @@ -50,7 +50,7 @@ <div> <h1> The Expat XML Parser - <small>Release 2.4.9</small> + <small>Release 2.5.0</small> </h1> </div> <div class="content"> diff --git a/contrib/expat/doc/xmlwf.1 b/contrib/expat/doc/xmlwf.1 index 1c810df7d0c4..6d88adc823f9 100644 --- a/contrib/expat/doc/xmlwf.1 +++ b/contrib/expat/doc/xmlwf.1 @@ -5,7 +5,7 @@ \\$2 \(la\\$1\(ra\\$3 .. .if \n(.g .mso www.tmac -.TH XMLWF 1 "September 20, 2022" "" "" +.TH XMLWF 1 "October 25, 2022" "" "" .SH NAME xmlwf \- Determines if an XML document is well-formed .SH SYNOPSIS diff --git a/contrib/expat/doc/xmlwf.xml b/contrib/expat/doc/xmlwf.xml index 09d8dc8940a7..9603abf1cca4 100644 --- a/contrib/expat/doc/xmlwf.xml +++ b/contrib/expat/doc/xmlwf.xml @@ -21,7 +21,7 @@ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [ <!ENTITY dhfirstname "<firstname>Scott</firstname>"> <!ENTITY dhsurname "<surname>Bronson</surname>"> - <!ENTITY dhdate "<date>September 20, 2022</date>"> + <!ENTITY dhdate "<date>October 25, 2022</date>"> <!-- Please adjust this^^ date whenever cutting a new release. --> <!ENTITY dhsection "<manvolnum>1</manvolnum>"> <!ENTITY dhemail "<email>bronson@rinspin.com</email>"> diff --git a/contrib/expat/examples/elements.c b/contrib/expat/examples/elements.c index 481d44472686..e5fb850d501b 100644 --- a/contrib/expat/examples/elements.c +++ b/contrib/expat/examples/elements.c @@ -14,7 +14,7 @@ Copyright (c) 2001-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net> Copyright (c) 2004-2006 Karl Waclawek <karl@waclawek.net> Copyright (c) 2005-2007 Steven Solie <steven@solie.ca> - Copyright (c) 2016-2019 Sebastian Pipping <sebastian@pipping.org> + Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org> Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk> Copyright (c) 2019 Zhongyuan Zhou <zhouzhongyuan@huawei.com> Licensed under the MIT license: @@ -49,7 +49,6 @@ #endif #ifdef XML_UNICODE_WCHAR_T -# include <wchar.h> # define XML_FMT_STR "ls" #else # define XML_FMT_STR "s" @@ -58,7 +57,7 @@ static void XMLCALL startElement(void *userData, const XML_Char *name, const XML_Char **atts) { int i; - int *depthPtr = (int *)userData; + int *const depthPtr = (int *)userData; (void)atts; for (i = 0; i < *depthPtr; i++) @@ -69,34 +68,54 @@ startElement(void *userData, const XML_Char *name, const XML_Char **atts) { static void XMLCALL endElement(void *userData, const XML_Char *name) { - int *depthPtr = (int *)userData; + int *const depthPtr = (int *)userData; (void)name; *depthPtr -= 1; } int -main(int argc, char *argv[]) { - char buf[BUFSIZ]; +main(void) { XML_Parser parser = XML_ParserCreate(NULL); int done; int depth = 0; - (void)argc; - (void)argv; + + if (! parser) { + fprintf(stderr, "Couldn't allocate memory for parser\n"); + return 1; + } XML_SetUserData(parser, &depth); XML_SetElementHandler(parser, startElement, endElement); + do { - size_t len = fread(buf, 1, sizeof(buf), stdin); - done = len < sizeof(buf); - if (XML_Parse(parser, buf, (int)len, done) == XML_STATUS_ERROR) { - fprintf(stderr, "%" XML_FMT_STR " at line %" XML_FMT_INT_MOD "u\n", - XML_ErrorString(XML_GetErrorCode(parser)), - XML_GetCurrentLineNumber(parser)); + void *const buf = XML_GetBuffer(parser, BUFSIZ); + if (! buf) { + fprintf(stderr, "Couldn't allocate memory for buffer\n"); + XML_ParserFree(parser); + return 1; + } + + const size_t len = fread(buf, 1, BUFSIZ, stdin); + + if (ferror(stdin)) { + fprintf(stderr, "Read error\n"); + XML_ParserFree(parser); + return 1; + } + + done = feof(stdin); + + if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) { + fprintf(stderr, + "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n", + XML_GetCurrentLineNumber(parser), + XML_ErrorString(XML_GetErrorCode(parser))); XML_ParserFree(parser); return 1; } } while (! done); + XML_ParserFree(parser); return 0; } diff --git a/contrib/expat/examples/outline.c b/contrib/expat/examples/outline.c index 936f0e09053f..d2df914fedb8 100644 --- a/contrib/expat/examples/outline.c +++ b/contrib/expat/examples/outline.c @@ -12,7 +12,7 @@ Copyright (c) 2001-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net> Copyright (c) 2005-2007 Steven Solie <steven@solie.ca> Copyright (c) 2005-2006 Karl Waclawek <karl@waclawek.net> - Copyright (c) 2016-2019 Sebastian Pipping <sebastian@pipping.org> + Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org> Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk> Licensed under the MIT license: @@ -51,73 +51,74 @@ # define XML_FMT_STR "s" #endif -#define BUFFSIZE 8192 - -char Buff[BUFFSIZE]; - -int Depth; - static void XMLCALL -start(void *data, const XML_Char *el, const XML_Char **attr) { +startElement(void *userData, const XML_Char *name, const XML_Char **atts) { int i; - (void)data; + int *const depthPtr = (int *)userData; - for (i = 0; i < Depth; i++) + for (i = 0; i < *depthPtr; i++) printf(" "); - printf("%" XML_FMT_STR, el); + printf("%" XML_FMT_STR, name); - for (i = 0; attr[i]; i += 2) { - printf(" %" XML_FMT_STR "='%" XML_FMT_STR "'", attr[i], attr[i + 1]); + for (i = 0; atts[i]; i += 2) { + printf(" %" XML_FMT_STR "='%" XML_FMT_STR "'", atts[i], atts[i + 1]); } printf("\n"); - Depth++; + *depthPtr += 1; } static void XMLCALL -end(void *data, const XML_Char *el) { - (void)data; - (void)el; +endElement(void *userData, const XML_Char *name) { + int *const depthPtr = (int *)userData; + (void)name; - Depth--; + *depthPtr -= 1; } int -main(int argc, char *argv[]) { - XML_Parser p = XML_ParserCreate(NULL); - (void)argc; - (void)argv; +main(void) { + XML_Parser parser = XML_ParserCreate(NULL); + int done; + int depth = 0; - if (! p) { + if (! parser) { fprintf(stderr, "Couldn't allocate memory for parser\n"); - exit(-1); + return 1; } - XML_SetElementHandler(p, start, end); + XML_SetUserData(parser, &depth); + XML_SetElementHandler(parser, startElement, endElement); - for (;;) { - int done; - int len; + do { + void *const buf = XML_GetBuffer(parser, BUFSIZ); + if (! buf) { + fprintf(stderr, "Couldn't allocate memory for buffer\n"); + XML_ParserFree(parser); + return 1; + } + + const size_t len = fread(buf, 1, BUFSIZ, stdin); - len = (int)fread(Buff, 1, BUFFSIZE, stdin); if (ferror(stdin)) { fprintf(stderr, "Read error\n"); - exit(-1); + XML_ParserFree(parser); + return 1; } + done = feof(stdin); - if (XML_Parse(p, Buff, len, done) == XML_STATUS_ERROR) { + if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) { fprintf(stderr, "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n", - XML_GetCurrentLineNumber(p), - XML_ErrorString(XML_GetErrorCode(p))); - exit(-1); + XML_GetCurrentLineNumber(parser), + XML_ErrorString(XML_GetErrorCode(parser))); + XML_ParserFree(parser); + return 1; } + } while (! done); - if (done) - break; - } - XML_ParserFree(p); + XML_ParserFree(parser); return 0; } diff --git a/contrib/expat/expat_config.h.in b/contrib/expat/expat_config.h.in index ec068caab89c..077569cb56d4 100644 --- a/contrib/expat/expat_config.h.in +++ b/contrib/expat/expat_config.h.in @@ -1,5 +1,8 @@ /* expat_config.h.in. Generated from configure.ac by autoheader. */ +#ifndef EXPAT_CONFIG_H +#define EXPAT_CONFIG_H 1 + /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD @@ -132,3 +135,5 @@ /* Define to `unsigned int' if <sys/types.h> does not define. */ #undef size_t + +#endif // ndef EXPAT_CONFIG_H diff --git a/contrib/expat/lib/expat.h b/contrib/expat/lib/expat.h index 2b47ce2a8d3a..1c83563cbf68 100644 --- a/contrib/expat/lib/expat.h +++ b/contrib/expat/lib/expat.h @@ -1054,8 +1054,8 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold( See http://semver.org. */ #define XML_MAJOR_VERSION 2 -#define XML_MINOR_VERSION 4 -#define XML_MICRO_VERSION 9 +#define XML_MINOR_VERSION 5 +#define XML_MICRO_VERSION 0 #ifdef __cplusplus } diff --git a/contrib/expat/lib/xmlparse.c b/contrib/expat/lib/xmlparse.c index c0bece51d700..b6c2eca97567 100644 --- a/contrib/expat/lib/xmlparse.c +++ b/contrib/expat/lib/xmlparse.c @@ -1,4 +1,4 @@ -/* 90815a2b2c80c03b2b889fe1d427bb2b9e3282aa065e42784e001db4f23de324 (2.4.9+) +/* 5ab094ffadd6edfc94c3eee53af44a86951f9f1f0933ada3114bbce2bfb02c99 (2.5.0+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -35,6 +35,7 @@ Copyright (c) 2021 Dong-hee Na <donghee.na@python.org> Copyright (c) 2022 Samanta Navarro <ferivoz@riseup.net> Copyright (c) 2022 Jeffrey Walton <noloader@gmail.com> + Copyright (c) 2022 Jann Horn <jannh@google.com> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -1068,6 +1069,14 @@ parserCreate(const XML_Char *encodingName, parserInit(parser, encodingName); if (encodingName && ! parser->m_protocolEncodingName) { + if (dtd) { + // We need to stop the upcoming call to XML_ParserFree from happily + // destroying parser->m_dtd because the DTD is shared with the parent + // parser and the only guard that keeps XML_ParserFree from destroying + // parser->m_dtd is parser->m_isParamEntity but it will be set to + // XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all). + parser->m_dtd = NULL; + } XML_ParserFree(parser); return NULL; } @@ -3011,9 +3020,6 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, int len; const char *rawName; TAG *tag = parser->m_tagStack; - parser->m_tagStack = tag->parent; - tag->parent = parser->m_freeTagList; - parser->m_freeTagList = tag; rawName = s + enc->minBytesPerChar * 2; len = XmlNameLength(enc, rawName); if (len != tag->rawNameLength @@ -3021,6 +3027,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, *eventPP = rawName; return XML_ERROR_TAG_MISMATCH; } + parser->m_tagStack = tag->parent; + tag->parent = parser->m_freeTagList; + parser->m_freeTagList = tag; --parser->m_tagLevel; if (parser->m_endElementHandler) { const XML_Char *localPart; @@ -4975,10 +4984,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, parser->m_handlerArg, parser->m_declElementType->name, parser->m_declAttributeId->name, parser->m_declAttributeType, 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); - poolClear(&parser->m_tempPool); handleDefault = XML_FALSE; } } + poolClear(&parser->m_tempPool); break; case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: case XML_ROLE_FIXED_ATTRIBUTE_VALUE: @@ -5386,7 +5395,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, * * If 'standalone' is false, the DTD must have no * parameter entities or we wouldn't have passed the outer - * 'if' statement. That measn the only entity in the hash + * 'if' statement. That means the only entity in the hash * table is the external subset name "#" which cannot be * given as a parameter entity name in XML syntax, so the * lookup must have returned NULL and we don't even reach @@ -5798,19 +5807,27 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end, if (result != XML_ERROR_NONE) return result; - else if (textEnd != next - && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + + if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) { entity->processed = (int)(next - (const char *)entity->textPtr); return result; - } else { + } + #ifdef XML_DTD - entityTrackingOnClose(parser, entity, __LINE__); + entityTrackingOnClose(parser, entity, __LINE__); #endif - entity->open = XML_FALSE; - parser->m_openInternalEntities = openEntity->next; - /* put openEntity back in list of free instances */ - openEntity->next = parser->m_freeInternalEntities; - parser->m_freeInternalEntities = openEntity; + entity->open = XML_FALSE; + parser->m_openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = parser->m_freeInternalEntities; + parser->m_freeInternalEntities = openEntity; + + // If there are more open entities we want to stop right here and have the + // upcoming call to XML_ResumeParser continue with entity content, or it would + // be ignored altogether. + if (parser->m_openInternalEntities != NULL + && parser->m_parsingStatus.parsing == XML_SUSPENDED) { + return XML_ERROR_NONE; } #ifdef XML_DTD diff --git a/contrib/expat/lib/xmltok_impl.h b/contrib/expat/lib/xmltok_impl.h index c518aada013d..3469c4ae138c 100644 --- a/contrib/expat/lib/xmltok_impl.h +++ b/contrib/expat/lib/xmltok_impl.h @@ -45,7 +45,7 @@ enum { BT_LF, /* line feed = "\n" */ BT_GT, /* greater than = ">" */ BT_QUOT, /* quotation character = "\"" */ - BT_APOS, /* aposthrophe = "'" */ + BT_APOS, /* apostrophe = "'" */ BT_EQUALS, /* equal sign = "=" */ BT_QUEST, /* question mark = "?" */ BT_EXCL, /* exclamation mark = "!" */ diff --git a/contrib/expat/tests/runtests.c b/contrib/expat/tests/runtests.c index 530f1844b5e1..915fa5206adc 100644 --- a/contrib/expat/tests/runtests.c +++ b/contrib/expat/tests/runtests.c @@ -11,7 +11,7 @@ Copyright (c) 2005-2007 Steven Solie <steven@solie.ca> Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net> Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org> - Copyright (c) 2017-2018 Rhodri James <rhodri@wildebeest.org.uk> + Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk> Copyright (c) 2017 Joe Orton <jorton@redhat.com> Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com> Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it> @@ -4990,7 +4990,7 @@ START_TEST(test_suspend_resume_internal_entity) { } END_TEST -void +static void XMLCALL suspending_comment_handler(void *userData, const XML_Char *data) { UNUSED_P(data); XML_Parser parser = (XML_Parser)userData; @@ -6734,6 +6734,102 @@ START_TEST(test_empty_element_abort) { } END_TEST +/* Regression test for GH issue #612: unfinished m_declAttributeType + * allocation in ->m_tempPool can corrupt following allocation. + */ +static int XMLCALL +external_entity_unfinished_attlist(XML_Parser parser, const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) { + const char *text = "<!ELEMENT barf ANY>\n" + "<!ATTLIST barf my_attr (blah|%blah;a|foo) #REQUIRED>\n" + "<!--COMMENT-->\n"; + XML_Parser ext_parser; + + UNUSED_P(base); + UNUSED_P(publicId); + if (systemId == NULL) + return XML_STATUS_OK; + + ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); + if (ext_parser == NULL) + fail("Could not create external entity parser"); + + if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) + == XML_STATUS_ERROR) + xml_failure(ext_parser); + + XML_ParserFree(ext_parser); + return XML_STATUS_OK; +} + +START_TEST(test_pool_integrity_with_unfinished_attr) { + const char *text = "<?xml version='1.0' encoding='UTF-8'?>\n" + "<!DOCTYPE foo [\n" + "<!ELEMENT foo ANY>\n" + "<!ENTITY % entp SYSTEM \"external.dtd\">\n" + "%entp;\n" + "]>\n" + "<a></a>\n"; + const XML_Char *expected = XCS("COMMENT"); + CharData storage; + + CharData_Init(&storage); + XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetExternalEntityRefHandler(g_parser, external_entity_unfinished_attlist); + XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler); + XML_SetCommentHandler(g_parser, accumulate_comment); + XML_SetUserData(g_parser, &storage); + if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) + == XML_STATUS_ERROR) + xml_failure(g_parser); + CharData_CheckXMLChars(&storage, expected); +} +END_TEST + +typedef struct { + XML_Parser parser; + CharData *storage; +} ParserPlusStorage; + +static void XMLCALL +accumulate_and_suspend_comment_handler(void *userData, const XML_Char *data) { + ParserPlusStorage *const parserPlusStorage = (ParserPlusStorage *)userData; + accumulate_comment(parserPlusStorage->storage, data); + XML_StopParser(parserPlusStorage->parser, XML_TRUE); +} + +START_TEST(test_nested_entity_suspend) { + const char *const text = "<!DOCTYPE a [\n" + " <!ENTITY e1 '<!--e1-->'>\n" + " <!ENTITY e2 '<!--e2 head-->&e1;<!--e2 tail-->'>\n" + " <!ENTITY e3 '<!--e3 head-->&e2;<!--e3 tail-->'>\n" + "]>\n" + "<a><!--start-->&e3;<!--end--></a>"; + const XML_Char *const expected = XCS("start") XCS("e3 head") XCS("e2 head") + XCS("e1") XCS("e2 tail") XCS("e3 tail") XCS("end"); + CharData storage; + XML_Parser parser = XML_ParserCreate(NULL); + ParserPlusStorage parserPlusStorage = {parser, &storage}; + + CharData_Init(&storage); + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetCommentHandler(parser, accumulate_and_suspend_comment_handler); + XML_SetUserData(parser, &parserPlusStorage); + + enum XML_Status status = XML_Parse(parser, text, (int)strlen(text), XML_TRUE); + while (status == XML_STATUS_SUSPENDED) { + status = XML_ResumeParser(parser); + } + if (status != XML_STATUS_OK) + xml_failure(parser); + + CharData_CheckXMLChars(&storage, expected); + XML_ParserFree(parser); +} +END_TEST + /* * Namespaces tests. */ @@ -7661,7 +7757,7 @@ START_TEST(test_misc_version) { fail("Version mismatch"); #if ! defined(XML_UNICODE) || defined(XML_UNICODE_WCHAR_T) - if (xcstrcmp(version_text, XCS("expat_2.4.9"))) /* needs bump on releases */ + if (xcstrcmp(version_text, XCS("expat_2.5.0"))) /* needs bump on releases */ fail("XML_*_VERSION in expat.h out of sync?\n"); #else /* If we have XML_UNICODE defined but not XML_UNICODE_WCHAR_T @@ -7873,6 +7969,28 @@ START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) { } END_TEST +START_TEST(test_misc_tag_mismatch_reset_leak) { +#ifdef XML_NS + const char *const text = "<open xmlns='https://namespace1.test'></close>"; + XML_Parser parser = XML_ParserCreateNS(NULL, XCS('\n')); + + if (XML_Parse(parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_ERROR) + fail("Call to parse was expected to fail"); + if (XML_GetErrorCode(parser) != XML_ERROR_TAG_MISMATCH) + fail("Call to parse was expected to fail from a closing tag mismatch"); + + XML_ParserReset(parser, NULL); + + if (XML_Parse(parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_ERROR) + fail("Call to parse was expected to fail"); + if (XML_GetErrorCode(parser) != XML_ERROR_TAG_MISMATCH) + fail("Call to parse was expected to fail from a closing tag mismatch"); + + XML_ParserFree(parser); +#endif +} +END_TEST + static void alloc_setup(void) { XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free}; @@ -10090,6 +10208,53 @@ START_TEST(test_alloc_long_notation) { } END_TEST +static int XMLCALL +external_entity_parser_create_alloc_fail_handler(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) { + UNUSED_P(base); + UNUSED_P(systemId); + UNUSED_P(publicId); + + if (context != NULL) + fail("Unexpected non-NULL context"); + + // The following number intends to fail the upcoming allocation in line + // "parser->m_protocolEncodingName = copyString(encodingName, + // &(parser->m_mem));" in function parserInit. + allocation_count = 3; + + const XML_Char *const encodingName = XCS("UTF-8"); // needs something non-NULL + const XML_Parser ext_parser + = XML_ExternalEntityParserCreate(parser, context, encodingName); + if (ext_parser != NULL) + fail( + "Call to XML_ExternalEntityParserCreate was expected to fail out-of-memory"); + + allocation_count = ALLOC_ALWAYS_SUCCEED; + return XML_STATUS_ERROR; +} + +START_TEST(test_alloc_reset_after_external_entity_parser_create_fail) { + const char *const text = "<!DOCTYPE doc SYSTEM 'foo'><doc/>"; + + XML_SetExternalEntityRefHandler( + g_parser, external_entity_parser_create_alloc_fail_handler); + XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + + if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) + != XML_STATUS_ERROR) + fail("Call to parse was expected to fail"); + + if (XML_GetErrorCode(g_parser) != XML_ERROR_EXTERNAL_ENTITY_HANDLING) + fail("Call to parse was expected to fail from the external entity handler"); + + XML_ParserReset(g_parser, NULL); +} +END_TEST + static void nsalloc_setup(void) { XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free}; @@ -12169,6 +12334,9 @@ make_suite(void) { tcase_add_test(tc_basic, test_bad_notation); tcase_add_test(tc_basic, test_default_doctype_handler); tcase_add_test(tc_basic, test_empty_element_abort); + tcase_add_test__ifdef_xml_dtd(tc_basic, + test_pool_integrity_with_unfinished_attr); + tcase_add_test(tc_basic, test_nested_entity_suspend); suite_add_tcase(s, tc_namespace); tcase_add_checked_fixture(tc_namespace, namespace_setup, namespace_teardown); @@ -12221,6 +12389,7 @@ make_suite(void) { tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_2); tcase_add_test__ifdef_xml_dtd( tc_misc, test_misc_deny_internal_entity_closing_doctype_issue_317); + tcase_add_test(tc_misc, test_misc_tag_mismatch_reset_leak); suite_add_tcase(s, tc_alloc); tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown); @@ -12279,6 +12448,8 @@ make_suite(void) { tcase_add_test(tc_alloc, test_alloc_long_public_id); tcase_add_test(tc_alloc, test_alloc_long_entity_value); tcase_add_test(tc_alloc, test_alloc_long_notation); + tcase_add_test__ifdef_xml_dtd( + tc_alloc, test_alloc_reset_after_external_entity_parser_create_fail); suite_add_tcase(s, tc_nsalloc); tcase_add_checked_fixture(tc_nsalloc, nsalloc_setup, nsalloc_teardown); diff --git a/lib/libexpat/expat_config.h b/lib/libexpat/expat_config.h index bebee0d28d62..369cebcbe451 100644 --- a/lib/libexpat/expat_config.h +++ b/lib/libexpat/expat_config.h @@ -1,6 +1,9 @@ /* expat_config.h. Generated from expat_config.h.in by configure. */ /* expat_config.h.in. Generated from configure.ac by autoheader. */ +#ifndef EXPAT_CONFIG_H +#define EXPAT_CONFIG_H 1 + #include <machine/endian.h> /* Define if building universal (internal helper macro) */ @@ -83,7 +86,7 @@ #define PACKAGE_NAME "expat" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "expat 2.4.9" +#define PACKAGE_STRING "expat 2.5.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "expat" @@ -92,7 +95,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "2.4.9" +#define PACKAGE_VERSION "2.5.0" /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for @@ -100,7 +103,7 @@ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "2.4.9" +#define VERSION "2.5.0" /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ @@ -139,3 +142,5 @@ /* Define to `unsigned int' if <sys/types.h> does not define. */ /* #undef size_t */ + +#endif // ndef EXPAT_CONFIG_H diff --git a/lib/libexpat/libbsdxml.3 b/lib/libexpat/libbsdxml.3 index d50d552e3edb..f162ddadfd2b 100644 --- a/lib/libexpat/libbsdxml.3 +++ b/lib/libexpat/libbsdxml.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\"/ -.Dd September 20, 2022 +.Dd November 18, 2022 .Dt LIBBSDXML 3 .Os .Sh NAME @@ -36,7 +36,7 @@ .Sh DESCRIPTION The .Nm -library is a verbatim copy of the eXpat XML library version 2.4.9. +library is a verbatim copy of the eXpat XML library version 2.5.0. .Pp The .Nm