1
0
mirror of https://github.com/openbsd/src.git synced 2024-12-21 23:18:00 -08:00

Update libexpat to version 2.6.4.

Relevant for OpenBSD are security fix #915, other changes #905 #902
#904 #317 #918 #914.  Major library bump is necessary as new error
constant has been added to a public header file.  CVE-2024-50602

OK matthieu@ tb@ deraadt@
This commit is contained in:
bluhm 2024-11-12 20:33:37 +00:00
parent 69de2c91f8
commit aa071e6ed2
13 changed files with 195 additions and 81 deletions

View File

@ -30,6 +30,37 @@
!! THANK YOU! Sebastian Pipping -- Berlin, 2024-03-09 !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Release 2.6.4 Wed November 6 2024
Security fixes:
#915 CVE-2024-50602 -- Fix crash within function XML_ResumeParser
from a NULL pointer dereference by disallowing function
XML_StopParser to (stop or) suspend an unstarted parser.
A new error code XML_ERROR_NOT_STARTED was introduced to
properly communicate this situation. // CWE-476 CWE-754
Other changes:
#903 CMake: Add alias target "expat::expat"
#905 docs: Document use via CMake >=3.18 with FetchContent
and SOURCE_SUBDIR and its consequences
#902 tests: Reduce use of global parser instance
#904 tests: Resolve duplicate handler
#317 #918 tests: Improve tests on doctype closing (ex CVE-2019-15903)
#914 Fix signedness of format strings
#919 #920 Version info bumped from 10:3:9 (libexpat*.so.1.9.3)
to 11:0:10 (libexpat*.so.1.10.0); see https://verbump.de/
for what these numbers do
Infrastructure:
#907 CI: Upgrade Clang from 18 to 19
#913 CI: Drop macos-12 and add macos-15
#910 CI: Adapt to breaking changes in GitHub Actions
#898 Add missing entries to .gitignore
Special thanks to:
Hanno Böck
José Eduardo Gutiérrez Conejo
José Ricardo Cardona Quesada
Release 2.6.3 Wed September 4 2024
Security fixes:
#887 #890 CVE-2024-45490 -- Calling function XML_ParseBuffer with

View File

@ -11,7 +11,7 @@
> at the top of the `Changes` file.
# Expat, Release 2.6.3
# Expat, Release 2.6.4
This is Expat, a C99 library for parsing
[XML 1.0 Fourth Edition](https://www.w3.org/TR/2006/REC-xml-20060816/), started by
@ -43,9 +43,9 @@ This license is the same as the MIT/X Consortium license.
## Using libexpat in your CMake-Based Project
There are two ways of using libexpat with CMake:
There are three documented ways of using libexpat with CMake:
### a) Module Mode
### a) `find_package` with Module Mode
This approach leverages CMake's own [module `FindEXPAT`](https://cmake.org/cmake/help/latest/module/FindEXPAT.html).
@ -70,7 +70,7 @@ target_include_directories(hello PRIVATE ${EXPAT_INCLUDE_DIRS})
target_link_libraries(hello PUBLIC ${EXPAT_LIBRARIES})
```
### b) Config Mode
### b) `find_package` with Config Mode
This approach requires files from…
@ -98,6 +98,45 @@ add_executable(hello
target_link_libraries(hello PUBLIC expat::expat)
```
### c) The `FetchContent` module
This approach — as demonstrated below — requires CMake >=3.18 for both the
[`FetchContent` module](https://cmake.org/cmake/help/latest/module/FetchContent.html)
and its support for the `SOURCE_SUBDIR` option to be available.
Please note that:
- Use of the `FetchContent` module with *non-release* SHA1s or `master`
of libexpat is neither advised nor considered officially supported.
- Pinning to a specific commit is great for robust CI.
- Pinning to a specific commit needs updating every time there is a new
release of libexpat — either manually or through automation —,
to not miss out on libexpat security updates.
For an example that pulls in libexpat via Git:
```cmake
cmake_minimum_required(VERSION 3.18)
include(FetchContent)
project(hello VERSION 1.0.0)
FetchContent_Declare(
expat
GIT_REPOSITORY https://github.com/libexpat/libexpat/
GIT_TAG 000000000_GIT_COMMIT_SHA1_HERE_000000000 # i.e. Git tag R_0_Y_Z
SOURCE_SUBDIR expat/
)
FetchContent_MakeAvailable(expat)
add_executable(hello
hello.c
)
target_link_libraries(hello PUBLIC expat)
```
## Building from a Git Clone

View File

@ -52,7 +52,7 @@
<div>
<h1>
The Expat XML Parser
<small>Release 2.6.3</small>
<small>Release 2.6.4</small>
</h1>
</div>
<div class="content">

View File

@ -15,6 +15,7 @@
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Copyright (c) 2019 Zhongyuan Zhou <zhouzhongyuan@huawei.com>
Copyright (c) 2024 Hanno Böck <hanno@gentoo.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@ -127,15 +128,15 @@ dumpContentModelElement(const XML_Content *model, unsigned level,
}
// Node
printf("[%u] type=%s(%d), quant=%s(%d)", (unsigned)(model - root),
contentTypeName(model->type), model->type,
contentQuantName(model->quant), model->quant);
printf("[%u] type=%s(%u), quant=%s(%u)", (unsigned)(model - root),
contentTypeName(model->type), (unsigned int)model->type,
contentQuantName(model->quant), (unsigned int)model->quant);
if (model->name) {
printf(", name=\"%" XML_FMT_STR "\"", model->name);
} else {
printf(", name=NULL");
}
printf(", numchildren=%d", model->numchildren);
printf(", numchildren=%u", model->numchildren);
printf("\n");
}

View File

@ -130,7 +130,9 @@ enum XML_Error {
/* Added in 2.3.0. */
XML_ERROR_NO_BUFFER,
/* Added in 2.4.0. */
XML_ERROR_AMPLIFICATION_LIMIT_BREACH
XML_ERROR_AMPLIFICATION_LIMIT_BREACH,
/* Added in 2.6.4. */
XML_ERROR_NOT_STARTED,
};
enum XML_Content_Type {
@ -1066,7 +1068,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
*/
#define XML_MAJOR_VERSION 2
#define XML_MINOR_VERSION 6
#define XML_MICRO_VERSION 3
#define XML_MICRO_VERSION 4
#ifdef __cplusplus
}

View File

@ -1,4 +1,4 @@
/* ba4cdf9bdb534f355a9def4c9e25d20ee8e72f95b0a4d930be52e563f5080196 (2.6.3+)
/* c5625880f4bf417c1463deee4eb92d86ff413f802048621c57e25fe483eb59e4 (2.6.4+)
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@ -40,6 +40,7 @@
Copyright (c) 2023 Owain Davies <owaind@bath.edu>
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
Copyright (c) 2024 Berkay Eren Ürün <berkay.ueruen@siemens.com>
Copyright (c) 2024 Hanno Böck <hanno@gentoo.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@ -2234,6 +2235,9 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable) {
if (parser == NULL)
return XML_STATUS_ERROR;
switch (parser->m_parsingStatus.parsing) {
case XML_INITIALIZED:
parser->m_errorCode = XML_ERROR_NOT_STARTED;
return XML_STATUS_ERROR;
case XML_SUSPENDED:
if (resumable) {
parser->m_errorCode = XML_ERROR_SUSPENDED;
@ -2244,7 +2248,7 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable) {
case XML_FINISHED:
parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
default:
case XML_PARSING:
if (resumable) {
#ifdef XML_DTD
if (parser->m_isParamEntity) {
@ -2255,6 +2259,9 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable) {
parser->m_parsingStatus.parsing = XML_SUSPENDED;
} else
parser->m_parsingStatus.parsing = XML_FINISHED;
break;
default:
assert(0);
}
return XML_STATUS_OK;
}
@ -2519,6 +2526,9 @@ XML_ErrorString(enum XML_Error code) {
case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
return XML_L(
"limit on input amplification factor (from DTD and entities) breached");
/* Added in 2.6.4. */
case XML_ERROR_NOT_STARTED:
return XML_L("parser not started");
}
return NULL;
}
@ -7856,7 +7866,7 @@ accountingReportDiff(XML_Parser rootParser,
assert(! rootParser->m_parentParser);
fprintf(stderr,
" (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d, xmlparse.c:%d) %*s\"",
" (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%u, xmlparse.c:%d) %*s\"",
bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP",
levelsAwayFromRootParser, source_line, 10, "");
@ -7969,7 +7979,7 @@ entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
fprintf(
stderr,
"expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s length %d (xmlparse.c:%d)\n",
"expat: Entities(%p): Count %9u, depth %2u/%2u %*s%s%s; %s length %d (xmlparse.c:%d)\n",
(void *)rootParser, rootParser->m_entity_stats.countEverOpened,
rootParser->m_entity_stats.currentDepth,
rootParser->m_entity_stats.maximumDepthSeen,

View File

@ -1,2 +1,2 @@
major=14
minor=1
major=15
minor=0

View File

@ -2357,11 +2357,20 @@ START_TEST(test_attributes) {
info[0].attributes = doc_info;
info[1].attributes = tag_info;
XML_SetStartElementHandler(g_parser, counting_start_element_handler);
XML_SetUserData(g_parser, info);
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
XML_Parser parser = XML_ParserCreate(NULL);
assert_true(parser != NULL);
ParserAndElementInfo parserAndElementInfos = {
parser,
info,
};
XML_SetStartElementHandler(parser, counting_start_element_handler);
XML_SetUserData(parser, &parserAndElementInfos);
if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(g_parser);
xml_failure(parser);
XML_ParserFree(parser);
}
END_TEST

View File

@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
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>
@ -51,6 +51,7 @@
#include "chardata.h"
#include "minicheck.h"
#include "common.h"
#include "handlers.h"
/* Common test data */
@ -221,30 +222,6 @@ _expect_failure(const char *text, enum XML_Error errorCode,
_xml_failure(g_parser, file, lineno);
}
/* Character data support for handlers, built on top of the code in
* chardata.c
*/
void XMLCALL
accumulate_characters(void *userData, const XML_Char *s, int len) {
CharData_AppendXMLChars((CharData *)userData, s, len);
}
void XMLCALL
accumulate_attribute(void *userData, const XML_Char *name,
const XML_Char **atts) {
CharData *storage = (CharData *)userData;
UNUSED_P(name);
/* Check there are attributes to deal with */
if (atts == NULL)
return;
while (storage->count < 0 && atts[0] != NULL) {
/* "accumulate" the value of the first attribute we see */
CharData_AppendXMLChars(storage, atts[1], -1);
atts += 2;
}
}
void
_run_character_check(const char *text, const XML_Char *expected,
const char *file, int line) {
@ -273,12 +250,6 @@ _run_attribute_check(const char *text, const XML_Char *expected,
CharData_CheckXMLChars(&storage, expected);
}
void XMLCALL
ext_accumulate_characters(void *userData, const XML_Char *s, int len) {
ExtTest *test_data = (ExtTest *)userData;
accumulate_characters(test_data->storage, s, len);
}
void
_run_ext_character_check(const char *text, ExtTest *test_data,
const XML_Char *expected, const char *file, int line) {

View File

@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
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>
@ -111,12 +111,6 @@ extern void _expect_failure(const char *text, enum XML_Error errorCode,
/* Support functions for handlers to collect up character and attribute data.
*/
extern void XMLCALL accumulate_characters(void *userData, const XML_Char *s,
int len);
extern void XMLCALL accumulate_attribute(void *userData, const XML_Char *name,
const XML_Char **atts);
extern void _run_character_check(const char *text, const XML_Char *expected,
const char *file, int line);
@ -135,9 +129,6 @@ typedef struct ExtTest {
CharData *storage;
} ExtTest;
extern void XMLCALL ext_accumulate_characters(void *userData, const XML_Char *s,
int len);
extern void _run_ext_character_check(const char *text, ExtTest *test_data,
const XML_Char *expected, const char *file,
int line);

View File

@ -103,7 +103,9 @@ end_element_event_handler2(void *userData, const XML_Char *name) {
void XMLCALL
counting_start_element_handler(void *userData, const XML_Char *name,
const XML_Char **atts) {
ElementInfo *info = (ElementInfo *)userData;
ParserAndElementInfo *const parserAndElementInfos
= (ParserAndElementInfo *)userData;
ElementInfo *info = parserAndElementInfos->info;
AttrInfo *attr;
int count, id, i;
@ -120,12 +122,12 @@ counting_start_element_handler(void *userData, const XML_Char *name,
* is possibly a little unexpected, but it is what the
* documentation in expat.h tells us to expect.
*/
count = XML_GetSpecifiedAttributeCount(g_parser);
count = XML_GetSpecifiedAttributeCount(parserAndElementInfos->parser);
if (info->attr_count * 2 != count) {
fail("Not got expected attribute count");
return;
}
id = XML_GetIdAttributeIndex(g_parser);
id = XML_GetIdAttributeIndex(parserAndElementInfos->parser);
if (id == -1 && info->id_name != NULL) {
fail("ID not present");
return;
@ -1880,12 +1882,6 @@ accumulate_entity_decl(void *userData, const XML_Char *entityName,
CharData_AppendXMLChars(storage, XCS("\n"), 1);
}
void XMLCALL
accumulate_char_data(void *userData, const XML_Char *s, int len) {
CharData *const storage = (CharData *)userData;
CharData_AppendXMLChars(storage, s, len);
}
void XMLCALL
accumulate_start_element(void *userData, const XML_Char *name,
const XML_Char **atts) {
@ -1910,6 +1906,34 @@ accumulate_start_element(void *userData, const XML_Char *name,
CharData_AppendXMLChars(storage, XCS(")\n"), 2);
}
void XMLCALL
accumulate_characters(void *userData, const XML_Char *s, int len) {
CharData *const storage = (CharData *)userData;
CharData_AppendXMLChars(storage, s, len);
}
void XMLCALL
accumulate_attribute(void *userData, const XML_Char *name,
const XML_Char **atts) {
CharData *const storage = (CharData *)userData;
UNUSED_P(name);
/* Check there are attributes to deal with */
if (atts == NULL)
return;
while (storage->count < 0 && atts[0] != NULL) {
/* "accumulate" the value of the first attribute we see */
CharData_AppendXMLChars(storage, atts[1], -1);
atts += 2;
}
}
void XMLCALL
ext_accumulate_characters(void *userData, const XML_Char *s, int len) {
ExtTest *const test_data = (ExtTest *)userData;
accumulate_characters(test_data->storage, s, len);
}
void XMLCALL
checking_default_handler(void *userData, const XML_Char *s, int len) {
DefaultCheck *data = (DefaultCheck *)userData;

View File

@ -92,6 +92,11 @@ typedef struct elementInfo {
AttrInfo *attributes;
} ElementInfo;
typedef struct StructParserAndElementInfo {
XML_Parser parser;
ElementInfo *info;
} ParserAndElementInfo;
extern void XMLCALL counting_start_element_handler(void *userData,
const XML_Char *name,
const XML_Char **atts);
@ -564,13 +569,19 @@ extern void XMLCALL accumulate_entity_decl(
const XML_Char *systemId, const XML_Char *publicId,
const XML_Char *notationName);
extern void XMLCALL accumulate_char_data(void *userData, const XML_Char *s,
int len);
extern void XMLCALL accumulate_start_element(void *userData,
const XML_Char *name,
const XML_Char **atts);
extern void XMLCALL accumulate_characters(void *userData, const XML_Char *s,
int len);
extern void XMLCALL accumulate_attribute(void *userData, const XML_Char *name,
const XML_Char **atts);
extern void XMLCALL ext_accumulate_characters(void *userData, const XML_Char *s,
int len);
typedef struct default_check {
const XML_Char *expected;
const int expectedLen;

View File

@ -208,7 +208,7 @@ START_TEST(test_misc_version) {
if (! versions_equal(&read_version, &parsed_version))
fail("Version mismatch");
if (xcstrcmp(version_text, XCS("expat_2.6.3"))) /* needs bump on releases */
if (xcstrcmp(version_text, XCS("expat_2.6.4"))) /* needs bump on releases */
fail("XML_*_VERSION in expat.h out of sync?\n");
}
END_TEST
@ -332,14 +332,15 @@ START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) {
"<!ENTITY % e ']><d/>'>\n"
"\n"
"%e;";
const char *const inputTwo = "<!DOCTYPE d [\n"
"<!ENTITY % e1 ']><d/>'><!ENTITY % e2 '&e1;'>\n"
"\n"
"%e2;";
const char *const inputTwo
= "<!DOCTYPE d [\n"
"<!ENTITY % e1 ']><d/>'><!ENTITY % e2 '&#37;e1;'>\n"
"\n"
"%e2;";
const char *const inputThree = "<!DOCTYPE d [\n"
"<!ENTITY % e ']><d'>\n"
"\n"
"%e;";
"%e;/>";
const char *const inputIssue317 = "<!DOCTYPE doc [\n"
"<!ENTITY % foo ']>\n"
"<doc>Hell<oc (#PCDATA)*>'>\n"
@ -447,7 +448,7 @@ START_TEST(test_misc_general_entities_support) {
XML_SetExternalEntityRefHandler(parser,
external_entity_failer__if_not_xml_ge);
XML_SetEntityDeclHandler(parser, accumulate_entity_decl);
XML_SetCharacterDataHandler(parser, accumulate_char_data);
XML_SetCharacterDataHandler(parser, accumulate_characters);
if (_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), XML_TRUE)
!= XML_STATUS_OK) {
@ -496,6 +497,28 @@ START_TEST(test_misc_char_handler_stop_without_leak) {
}
END_TEST
START_TEST(test_misc_resumeparser_not_crashing) {
XML_Parser parser = XML_ParserCreate(NULL);
XML_GetBuffer(parser, 1);
XML_StopParser(parser, /*resumable=*/XML_TRUE);
XML_ResumeParser(parser); // could crash here, previously
XML_ParserFree(parser);
}
END_TEST
START_TEST(test_misc_stopparser_rejects_unstarted_parser) {
const XML_Bool cases[] = {XML_TRUE, XML_FALSE};
for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
const XML_Bool resumable = cases[i];
XML_Parser parser = XML_ParserCreate(NULL);
assert_true(XML_GetErrorCode(parser) == XML_ERROR_NONE);
assert_true(XML_StopParser(parser, resumable) == XML_STATUS_ERROR);
assert_true(XML_GetErrorCode(parser) == XML_ERROR_NOT_STARTED);
XML_ParserFree(parser);
}
}
END_TEST
void
make_miscellaneous_test_case(Suite *s) {
TCase *tc_misc = tcase_create("miscellaneous tests");
@ -520,4 +543,6 @@ make_miscellaneous_test_case(Suite *s) {
test_misc_create_external_entity_parser_with_null_context);
tcase_add_test(tc_misc, test_misc_general_entities_support);
tcase_add_test(tc_misc, test_misc_char_handler_stop_without_leak);
tcase_add_test(tc_misc, test_misc_resumeparser_not_crashing);
tcase_add_test(tc_misc, test_misc_stopparser_rejects_unstarted_parser);
}