LibXML: Add element-nesting depth limit for XML-parsed documents

This change adds a limit of 5000 on the count for how deeply elements
can be nested in documents parsed with our XML parser. Blink and WebKit
both have such a limit, and both set it at 5000.

This prevents bad actors from performing attacks by giving us XML docs
with pathological levels of nesting, and causing stack exhaustion.
This commit is contained in:
sideshowbarker 2026-01-08 15:00:50 +09:00 committed by Jelle Raaijmakers
parent 5cc3e136e4
commit cfe5ef32e1

View file

@ -14,6 +14,8 @@
namespace XML {
static constexpr int MAX_XML_TREE_DEPTH = 5000;
struct ParserContext {
Listener* listener { nullptr };
Optional<ParseError> error;
@ -26,6 +28,8 @@ struct ParserContext {
Version version { Version::Version11 };
Vector<ParseError> parse_errors;
int depth { 0 };
};
static ByteString xml_char_to_byte_string(xmlChar const* str)
@ -91,6 +95,24 @@ static void start_element_ns_handler(void* ctx, xmlChar const* localname, xmlCha
if (!context)
return;
if (++context->depth > MAX_XML_TREE_DEPTH) {
size_t offset = 0;
if (parser_ctx->input && parser_ctx->input->cur && parser_ctx->input->base)
offset = static_cast<size_t>(parser_ctx->input->cur - parser_ctx->input->base);
ParseError parse_error {
.position = LineTrackingLexer::Position { .offset = offset },
.error = ByteString("Excessive node nesting."sv),
};
context->parse_errors.append(parse_error);
if (context->listener)
context->listener->error(parse_error);
xmlStopParser(parser_ctx);
return;
}
StringBuilder name_builder;
if (prefix) {
name_builder.append(xml_char_to_string_view(prefix));
@ -162,6 +184,8 @@ static void end_element_ns_handler(void* ctx, xmlChar const* localname, xmlChar
if (!context)
return;
--context->depth;
StringBuilder name_builder;
if (prefix) {
name_builder.append(xml_char_to_string_view(prefix));