From dc1284f0d0a18ac63dc7ac1bcf1a0993a36353ba Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Mon, 10 Mar 2025 13:18:51 +0100 Subject: [PATCH 1/2] meson: Fix libxml2 header test --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index ce465577..e0c10865 100644 --- a/meson.build +++ b/meson.build @@ -382,7 +382,7 @@ endif if get_option('enable-xkbregistry') dep_libxml = dependency('libxml-2.0') if cc.has_header_symbol( - 'libxml/xmlerror.h', + 'libxml/parser.h', 'xmlCtxtSetErrorHandler', prefix: system_ext_define ) From fe7f56bb1db9918c28417670ec0935aee93d026e Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Mon, 10 Mar 2025 13:19:37 +0100 Subject: [PATCH 2/2] registry: Use safer contextual libxml2 functions Avoid using functions depreacted in 2.13 and 2.14 libxml releases. Follow-up of: 5f1b06b7497dc0e69ecfef8a934bce01f4f7fe8e. --- meson.build | 11 +++++++- src/registry.c | 71 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 58 insertions(+), 24 deletions(-) diff --git a/meson.build b/meson.build index e0c10865..24c18767 100644 --- a/meson.build +++ b/meson.build @@ -381,13 +381,22 @@ endif # libxkbregistry if get_option('enable-xkbregistry') dep_libxml = dependency('libxml-2.0') + # Since libxml-2.13 if cc.has_header_symbol( 'libxml/parser.h', 'xmlCtxtSetErrorHandler', - prefix: system_ext_define + prefix: system_ext_define, ) configh_data.set10('HAVE_XML_CTXT_SET_ERRORHANDLER', true) endif + # Since libxml-2.14 + if cc.has_header_symbol( + 'libxml/parser.h', + 'xmlCtxtParseDtd', + prefix: system_ext_define, + ) + configh_data.set10('HAVE_XML_CTXT_PARSE_DTD', true) + endif deps_libxkbregistry = [dep_libxml] libxkbregistry_sources = [ 'src/registry.c', diff --git a/src/registry.c b/src/registry.c index df18304e..148c7a6e 100644 --- a/src/registry.c +++ b/src/registry.c @@ -1142,13 +1142,16 @@ xml_structured_error_func(void *userData, const xmlError * error) } #endif +#ifdef XML_PARSE_NO_XXE +#define _XML_OPTIONS (XML_PARSE_NONET | XML_PARSE_NOENT | XML_PARSE_NO_XXE) +#else +#define _XML_OPTIONS (XML_PARSE_NONET) +#endif + static bool validate(struct rxkb_context *ctx, xmlDoc *doc) { bool success = false; - xmlValidCtxt *dtdvalid = NULL; - xmlDtd *dtd = NULL; - xmlParserInputBufferPtr buf = NULL; /* This is a modified version of the xkeyboard-config xkb.dtd: * • xkeyboard-config requires modelList, layoutList and optionList, * but we allow for any of those to be missing. @@ -1183,34 +1186,53 @@ validate(struct rxkb_context *ctx, xmlDoc *doc) "\n" "\n"; +#ifdef HAVE_XML_CTXT_PARSE_DTD + /* Use safer function with context if available, and set + * the contextual error handler. */ + xmlParserCtxtPtr xmlCtxt = xmlNewParserCtxt(); + if (!xmlCtxt) + return false; + xmlCtxtSetErrorHandler(xmlCtxt, xml_structured_error_func, ctx); + xmlCtxtSetOptions(xmlCtxt, _XML_OPTIONS | XML_PARSE_DTDLOAD); + + xmlParserInputPtr pinput = + xmlNewInputFromMemory(NULL, dtdstr, sizeof(dtdstr), + XML_INPUT_BUF_STATIC); + if (!pinput) + goto dtd_error; + + xmlDtd *dtd = xmlCtxtParseDtd(xmlCtxt, pinput, NULL, NULL); +#else /* Note: do not use xmlParserInputBufferCreateStatic, it generates random * DTD validity errors for unknown reasons */ - buf = xmlParserInputBufferCreateMem(dtdstr, sizeof(dtdstr), - XML_CHAR_ENCODING_NONE); + xmlParserInputBufferPtr buf = + xmlParserInputBufferCreateMem(dtdstr, sizeof(dtdstr), + XML_CHAR_ENCODING_NONE); if (!buf) - return false; + goto dtd_error; + xmlDtd *dtd = dtd = xmlIOParseDTD(NULL, buf, XML_CHAR_ENCODING_UTF8); +#endif - /* TODO: use safer function with context, once published, and set - * the contextual error handler. - * See: https://gitlab.gnome.org/GNOME/libxml2/-/issues/808 */ - dtd = xmlIOParseDTD(NULL, buf, XML_CHAR_ENCODING_UTF8); if (!dtd) { log_err(ctx, XKB_LOG_MESSAGE_NO_ID, "Failed to load DTD\n"); - return false; + goto dtd_error; } - dtdvalid = xmlNewValidCtxt(); - /* TODO: use safer function with context, once published, then set - * the contextual error handler. - * See: https://gitlab.gnome.org/GNOME/libxml2/-/issues/808 */ - if (xmlValidateDtd(dtdvalid, doc, dtd)) - success = true; - - if (dtd) - xmlFreeDtd(dtd); +#ifdef HAVE_XML_CTXT_PARSE_DTD + success = xmlCtxtValidateDtd(xmlCtxt, doc, dtd); +#else + xmlValidCtxt *dtdvalid = xmlNewValidCtxt(); + success = xmlValidateDtd(dtdvalid, doc, dtd); if (dtdvalid) xmlFreeValidCtxt(dtdvalid); +#endif + xmlFreeDtd(dtd); + +dtd_error: +#ifdef HAVE_XML_CTXT_PARSE_DTD + xmlFreeParserCtxt(xmlCtxt); +#endif return success; } @@ -1243,8 +1265,10 @@ parse(struct rxkb_context *ctx, const char *path, * the global generic handler. */ xmlCtxtSetErrorHandler(xmlCtxt, xml_structured_error_func, ctx); #endif - /* This is still unconditionnally needed for the DTD validation (for now) */ +#ifndef HAVE_XML_CTXT_PARSE_DTD + /* This is needed for the DTD validation */ xmlSetGenericErrorFunc(ctx, xml_error_func); +#endif doc = xmlCtxtReadFile(xmlCtxt, path, NULL, 0); if (!doc) @@ -1263,6 +1287,8 @@ parse(struct rxkb_context *ctx, const char *path, validate_error: xmlFreeDoc(doc); parse_error: + +#ifndef HAVE_XML_CTXT_PARSE_DTD /* * Reset the default libxml2 error handler to default, because this handler * is global and may be used on an invalid rxkb_context, e.g. *after* the @@ -1272,9 +1298,8 @@ parse(struct rxkb_context *ctx, const char *path, * rxkb_context_parse(); * rxkb_context_unref(); */ - /* TODO: remove once safer variants of xmlIOParseDTD and xmlValidateDtd are - * published. See: https://gitlab.gnome.org/GNOME/libxml2/-/issues/808 */ xmlSetGenericErrorFunc(NULL, NULL); +#endif #ifdef HAVE_XML_CTXT_SET_ERRORHANDLER xmlCtxtSetErrorHandler(xmlCtxt, NULL, NULL); #endif