From 57bf6d2e909e45c95b2d06e9b31a1535d4936aee Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Tue, 14 Apr 2026 20:35:36 +0200 Subject: [PATCH 1/4] Restore rules_set include required by XML processor build --- headers/modsecurity/audit_log.h | 1 + headers/modsecurity/rules_set_phases.h | 3 +- headers/modsecurity/rules_set_properties.h | 1 + src/actions/ctl/rule_remove_by_id.h | 2 + src/anchored_set_variable.cc | 1 + src/anchored_variable.cc | 1 + src/audit_log/audit_log.cc | 1 + src/operators/pm_from_file.cc | 1 + src/operators/validate_byte_range.cc | 1 + src/request_body_processor/json.cc | 21 ++- src/request_body_processor/json.h | 27 +-- .../json_backend_jsoncons.cc | 13 +- .../json_backend_simdjson.cc | 7 +- .../json_instrumentation.cc | 2 + src/request_body_processor/multipart.cc | 1 + src/request_body_processor/multipart.h | 3 + src/request_body_processor/xml.cc | 166 +++++++----------- src/request_body_processor/xml.h | 38 ++-- src/rule_with_actions.cc | 1 + src/rule_with_operator.cc | 2 + src/rules_exceptions.cc | 3 + src/rules_set_phases.cc | 1 + src/run_time_string.cc | 1 + src/transaction.cc | 4 + src/utils/json_writer.cc | 1 + src/utils/json_writer.h | 1 + src/utils/sha1.h | 2 + src/utils/string.h | 1 + src/variables/variable.cc | 1 + 29 files changed, 157 insertions(+), 151 deletions(-) diff --git a/headers/modsecurity/audit_log.h b/headers/modsecurity/audit_log.h index ab1e798dd7..dce0175873 100644 --- a/headers/modsecurity/audit_log.h +++ b/headers/modsecurity/audit_log.h @@ -17,6 +17,7 @@ #include #include #include +#include #endif #ifndef HEADERS_MODSECURITY_AUDIT_LOG_H_ diff --git a/headers/modsecurity/rules_set_phases.h b/headers/modsecurity/rules_set_phases.h index 849d8ec1bf..473d939f8e 100644 --- a/headers/modsecurity/rules_set_phases.h +++ b/headers/modsecurity/rules_set_phases.h @@ -20,6 +20,7 @@ #ifdef __cplusplus #include #include +#include #include #include #include @@ -60,4 +61,4 @@ class RulesSetPhases { } // namespace modsecurity #endif -#endif // HEADERS_MODSECURITY_RULES_SET_PHASES_H_ \ No newline at end of file +#endif // HEADERS_MODSECURITY_RULES_SET_PHASES_H_ diff --git a/headers/modsecurity/rules_set_properties.h b/headers/modsecurity/rules_set_properties.h index e16db04665..19a310fbe7 100644 --- a/headers/modsecurity/rules_set_properties.h +++ b/headers/modsecurity/rules_set_properties.h @@ -25,6 +25,7 @@ #ifdef __cplusplus #include #include +#include #include #include #include diff --git a/src/actions/ctl/rule_remove_by_id.h b/src/actions/ctl/rule_remove_by_id.h index f731db31cc..53cd379e76 100644 --- a/src/actions/ctl/rule_remove_by_id.h +++ b/src/actions/ctl/rule_remove_by_id.h @@ -13,7 +13,9 @@ * */ +#include #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/transaction.h" diff --git a/src/anchored_set_variable.cc b/src/anchored_set_variable.cc index 4c81dab412..eb04adf410 100644 --- a/src/anchored_set_variable.cc +++ b/src/anchored_set_variable.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/src/anchored_variable.cc b/src/anchored_variable.cc index 51860d1fe6..83f4209a3e 100644 --- a/src/anchored_variable.cc +++ b/src/anchored_variable.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/src/audit_log/audit_log.cc b/src/audit_log/audit_log.cc index 4115d5f34a..3068cbdd63 100644 --- a/src/audit_log/audit_log.cc +++ b/src/audit_log/audit_log.cc @@ -20,6 +20,7 @@ #include #include +#include #include "modsecurity/transaction.h" #include "modsecurity/rule_message.h" diff --git a/src/operators/pm_from_file.cc b/src/operators/pm_from_file.cc index 52651e95cc..7bd778dc62 100644 --- a/src/operators/pm_from_file.cc +++ b/src/operators/pm_from_file.cc @@ -15,6 +15,7 @@ #include "src/operators/pm_from_file.h" +#include #include #include "src/operators/operator.h" diff --git a/src/operators/validate_byte_range.cc b/src/operators/validate_byte_range.cc index 9ad4d2921c..2ee7725c70 100644 --- a/src/operators/validate_byte_range.cc +++ b/src/operators/validate_byte_range.cc @@ -15,6 +15,7 @@ #include "src/operators/validate_byte_range.h" +#include #include #include #include diff --git a/src/request_body_processor/json.cc b/src/request_body_processor/json.cc index 502f8ec369..800377cd54 100644 --- a/src/request_body_processor/json.cc +++ b/src/request_body_processor/json.cc @@ -20,10 +20,12 @@ #include "src/request_body_processor/json.h" #include +#include #include #include #include +#include "modsecurity/transaction.h" #include "src/request_body_processor/json_adapter.h" #include "src/request_body_processor/json_instrumentation.h" @@ -31,7 +33,8 @@ namespace modsecurity::RequestBodyProcessor { static const double json_depth_limit_default = 10000.0; -static const char* json_depth_limit_exceeded_msg = ". Parsing depth limit exceeded"; +static const char *const json_depth_limit_exceeded_msg = + ". Parsing depth limit exceeded"; namespace { @@ -119,11 +122,7 @@ JsonSinkStatus addStringViewAsSinkStatus(JSON *json, std::string_view value) { } // namespace JSON::JSON(Transaction *transaction) : m_transaction(transaction), - m_current_key(""), - m_data(""), - m_max_depth(json_depth_limit_default), - m_current_depth(0), - m_depth_limit_exceeded(false) { + m_max_depth(json_depth_limit_default) { } @@ -185,11 +184,11 @@ bool JSON::complete(std::string *err) { int JSON::addArgument(const std::string& value) { - std::string data(""); + std::string data; std::string path; - for (size_t i = 0; i < m_containers.size(); i++) { - const JSONContainerArray *a = dynamic_cast( + for (size_t i = 0; i < m_containers.size(); i++) { + const auto *a = dynamic_cast( m_containers[i].get()); path = path + m_containers[i]->m_name; if (a != nullptr) { @@ -199,8 +198,8 @@ int JSON::addArgument(const std::string& value) { } } - if (m_containers.size() > 0) { - JSONContainerArray *a = dynamic_cast( + if (!m_containers.empty()) { + auto *a = dynamic_cast( m_containers.back().get()); if (a) { a->m_elementCounter++; diff --git a/src/request_body_processor/json.h b/src/request_body_processor/json.h index 9c70c2ebcf..79c0da958a 100644 --- a/src/request_body_processor/json.h +++ b/src/request_body_processor/json.h @@ -16,15 +16,19 @@ #ifndef SRC_REQUEST_BODY_PROCESSOR_JSON_H_ #define SRC_REQUEST_BODY_PROCESSOR_JSON_H_ +#include #include #include #include #include +#include -#include "modsecurity/transaction.h" -#include "modsecurity/rules_set.h" #include "src/request_body_processor/json_backend.h" +namespace modsecurity { +class Transaction; +} + namespace modsecurity::RequestBodyProcessor { @@ -32,22 +36,21 @@ namespace modsecurity::RequestBodyProcessor { class JSONContainer { public: explicit JSONContainer(const std::string &name) : m_name(name) { } - virtual ~JSONContainer() { } + virtual ~JSONContainer() = default; std::string m_name; }; class JSONContainerArray : public JSONContainer { public: - explicit JSONContainerArray(const std::string &name) : JSONContainer(name), - m_elementCounter(0) { } - size_t m_elementCounter; + using JSONContainer::JSONContainer; + size_t m_elementCounter = 0; }; class JSONContainerMap : public JSONContainer { public: - explicit JSONContainerMap(const std::string &name) : JSONContainer(name) { } + using JSONContainer::JSONContainer; }; @@ -88,7 +91,7 @@ class JSON : public JsonEventSink { std::string getCurrentKey(bool emptyIsNull = false) { std::string ret(m_current_key); - if (m_containers.size() == 0) { + if (m_containers.empty()) { return "json"; } if (m_current_key.empty()) { @@ -109,12 +112,12 @@ class JSON : public JsonEventSink { void clearContainers(); std::deque> m_containers; - Transaction *m_transaction; + Transaction *m_transaction = nullptr; std::string m_current_key; std::string m_data; - double m_max_depth; - int64_t m_current_depth; - bool m_depth_limit_exceeded; + double m_max_depth = 0.0; + int64_t m_current_depth = 0; + bool m_depth_limit_exceeded = false; }; diff --git a/src/request_body_processor/json_backend_jsoncons.cc b/src/request_body_processor/json_backend_jsoncons.cc index 5c64d96929..32fc0b3989 100644 --- a/src/request_body_processor/json_backend_jsoncons.cc +++ b/src/request_body_processor/json_backend_jsoncons.cc @@ -22,11 +22,11 @@ #include #include +#include #include #include #include #include -#include #include "src/request_body_processor/json_instrumentation.h" #include @@ -704,7 +704,7 @@ JsonParseResult parseDocumentWithJsoncons(const std::string &input, std::chrono::steady_clock::now() - event_loop_start).count())); }; const auto finish_with_event_loop = [&record_event_loop]( - JsonParseResult result) { + const JsonParseResult &result) { record_event_loop(); return result; }; @@ -717,8 +717,9 @@ JsonParseResult parseDocumentWithJsoncons(const std::string &input, cursor.current(), cursor.context()); !result.ok()) { #ifdef MSC_JSON_AUDIT_INSTRUMENTATION return finish_with_event_loop(result); -#endif +#else return result; +#endif } cursor.next(error); @@ -726,8 +727,9 @@ JsonParseResult parseDocumentWithJsoncons(const std::string &input, #ifdef MSC_JSON_AUDIT_INSTRUMENTATION return finish_with_event_loop( fromJsonconsError(error, cursor.context())); -#endif +#else return fromJsonconsError(error, cursor.context()); +#endif } } @@ -736,8 +738,9 @@ JsonParseResult parseDocumentWithJsoncons(const std::string &input, #ifdef MSC_JSON_AUDIT_INSTRUMENTATION return finish_with_event_loop(fromJsonconsError(error, cursor.context())); -#endif +#else return fromJsonconsError(error, cursor.context()); +#endif } #ifdef MSC_JSON_AUDIT_INSTRUMENTATION diff --git a/src/request_body_processor/json_backend_simdjson.cc b/src/request_body_processor/json_backend_simdjson.cc index ac7108b5e2..525c1560b3 100644 --- a/src/request_body_processor/json_backend_simdjson.cc +++ b/src/request_body_processor/json_backend_simdjson.cc @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -107,12 +108,12 @@ simdjson::ondemand::parser &getReusableSimdjsonParser() { if (parser == nullptr) { #ifdef MSC_JSON_AUDIT_INSTRUMENTATION const auto parser_start = std::chrono::steady_clock::now(); - parser.reset(new simdjson::ondemand::parser()); + parser = std::make_unique(); recordSimdjsonParserConstruction(static_cast( std::chrono::duration_cast( std::chrono::steady_clock::now() - parser_start).count())); #else - parser.reset(new simdjson::ondemand::parser()); + parser = std::make_unique(); #endif } return *parser; @@ -398,7 +399,7 @@ class JsonBackendWalker { "handling a boolean"); } - JsonParseResult enforceTechnicalDepth(simdjson::ondemand::value value) { + JsonParseResult enforceTechnicalDepth(simdjson::ondemand::value value) const { const int32_t current_depth = value.current_depth(); if (current_depth <= 0) { return makeResult(JsonParseStatus::InternalError, diff --git a/src/request_body_processor/json_instrumentation.cc b/src/request_body_processor/json_instrumentation.cc index b5fae287e6..1d241e84d5 100644 --- a/src/request_body_processor/json_instrumentation.cc +++ b/src/request_body_processor/json_instrumentation.cc @@ -5,6 +5,8 @@ #include "src/request_body_processor/json_instrumentation.h" #include +#include +#include namespace modsecurity::RequestBodyProcessor { namespace { diff --git a/src/request_body_processor/multipart.cc b/src/request_body_processor/multipart.cc index 3ae591671e..02d7f5daf5 100644 --- a/src/request_body_processor/multipart.cc +++ b/src/request_body_processor/multipart.cc @@ -15,6 +15,7 @@ #include "src/request_body_processor/multipart.h" +#include #include #include #include diff --git a/src/request_body_processor/multipart.h b/src/request_body_processor/multipart.h index 08d4ffe920..48c1de304e 100644 --- a/src/request_body_processor/multipart.h +++ b/src/request_body_processor/multipart.h @@ -13,11 +13,14 @@ * */ +#include +#include #include #include #include #include #include +#include #ifndef SRC_REQUEST_BODY_PROCESSOR_MULTIPART_H_ #define SRC_REQUEST_BODY_PROCESSOR_MULTIPART_H_ diff --git a/src/request_body_processor/xml.cc b/src/request_body_processor/xml.cc index cbb7894c9b..48ebd6dae2 100644 --- a/src/request_body_processor/xml.cc +++ b/src/request_body_processor/xml.cc @@ -15,38 +15,33 @@ #include "src/request_body_processor/xml.h" -#include -#include +#include #include +#include "modsecurity/rules_set.h" +#include "modsecurity/rules_set_properties.h" +#include "modsecurity/transaction.h" -namespace modsecurity { -namespace RequestBodyProcessor { + +namespace modsecurity::RequestBodyProcessor { #ifdef WITH_LIBXML2 /* * NodeData for parsing XML into args */ -NodeData::NodeData() { - has_child = false; -} +NodeData::NodeData() = default; -NodeData::~NodeData() {}; +NodeData::~NodeData() = default; /* * XMLNodes for parsing XML into args */ XMLNodes::XMLNodes(Transaction *transaction) - : nodes{}, - node_depth(0), - currpath(""), - currval(""), - currval_is_set(false), - m_transaction(transaction) + : m_transaction(transaction) {} -XMLNodes::~XMLNodes() {}; +XMLNodes::~XMLNodes() = default; /* * SAX handler for parsing XML into args @@ -57,59 +52,56 @@ class MSCSAXHandler { std::string name = reinterpret_cast(localname); - XMLNodes* xml_data = static_cast(ctx); + auto *xml_data = static_cast(ctx); xml_data->nodes.push_back(std::make_shared()); xml_data->node_depth++; - // FIXME - later if we want to check the depth of XML tree - /* if (max_depth > 0 && max_depth > xml_data->node_depth) { - std::cout << "Depth of XML tree reached the given maximum value " << xml_data->node_depth << std::endl; - exit(1); - } */ // if it's not the first (root) item, then append a '.' // note, the condition should always be true because there is always a pseudo root element: 'xml' if (xml_data->nodes.size() > 1) { xml_data->currpath.append("."); - xml_data->nodes[xml_data->nodes.size()-2]->has_child = true; + const std::size_t parent_index = xml_data->nodes.size() - 2; + xml_data->nodes[parent_index]->has_child = true; } xml_data->currpath.append(name); // set the current value empty // this is necessary because if there is any text between the tags (new line, etc) // it will be added to the current value - xml_data->currval = ""; + xml_data->currval.clear(); xml_data->currval_is_set = false; } void onEndElement(void * ctx, const xmlChar *localname) { std::string name = reinterpret_cast(localname); - XMLNodes* xml_data = static_cast(ctx); - const std::shared_ptr& nd = xml_data->nodes[xml_data->nodes.size()-1]; - if (nd->has_child == false) { + auto *xml_data = static_cast(ctx); + if (const auto &nd = + xml_data->nodes.back(); + !nd->has_child && !xml_data->m_transaction->addArgument( + "XML", xml_data->currpath, xml_data->currval, 0)) { // check the return value // if false, then stop parsing // this means the number of arguments reached the limit - if (xml_data->m_transaction->addArgument("XML", xml_data->currpath, xml_data->currval, 0) == false) { - xmlStopParser(xml_data->parsing_ctx_arg); - } + xmlStopParser(xml_data->parsing_ctx_arg); } - if (xml_data->currpath.length() > 0) { + if (!xml_data->currpath.empty()) { // set an offset to store whether this is the first item, in order to know whether to remove the '.' - int offset = (xml_data->nodes.size() > 1) ? 1 : 0; - xml_data->currpath.erase(xml_data->currpath.length() - (name.length()+offset)); + const std::size_t offset = (xml_data->nodes.size() > 1) ? 1 : 0; + xml_data->currpath.erase( + xml_data->currpath.size() - (name.size() + offset)); } xml_data->nodes.pop_back(); xml_data->node_depth--; - xml_data->currval = ""; + xml_data->currval.clear(); xml_data->currval_is_set = false; } void onCharacters(void *ctx, const xmlChar *ch, int len) { - XMLNodes* xml_data = static_cast(ctx); + auto *xml_data = static_cast(ctx); std::string content(reinterpret_cast(ch), len); // libxml2 SAX parser will call this function multiple times // during the parsing of a single node, if the value has multibyte // characters, so we need to concatenate the values - if (xml_data->currval_is_set == false) { + if (!xml_data->currval_is_set) { xml_data->currval = content; xml_data->currval_is_set = true; } else { @@ -121,64 +113,56 @@ class MSCSAXHandler { extern "C" { void MSC_startElement(void *userData, const xmlChar *name, - const xmlChar *prefix, - const xmlChar *URI, - int nb_namespaces, - const xmlChar **namespaces, - int nb_attributes, - int nb_defaulted, - const xmlChar **attributes) { - - MSCSAXHandler* handler = static_cast(userData); + const xmlChar *, + const xmlChar *, + int, + const xmlChar **, + int, + int, + const xmlChar **) { + + auto *handler = static_cast(userData); handler->onStartElement(userData, name); } void MSC_endElement( void *userData, const xmlChar *name, - const xmlChar* prefix, - const xmlChar* URI) { + const xmlChar*, + const xmlChar*) { - MSCSAXHandler* handler = static_cast(userData); + auto *handler = static_cast(userData); handler->onEndElement(userData, name); } void MSC_xmlcharacters(void *userData, const xmlChar *ch, int len) { - MSCSAXHandler* handler = static_cast(userData); + auto *handler = static_cast(userData); handler->onCharacters(userData, ch, len); } } XML::XML(Transaction *transaction) - : m_transaction(transaction) { - m_data.doc = NULL; - m_data.parsing_ctx = NULL; - m_data.sax_handler = NULL; - m_data.xml_error = ""; - m_data.parsing_ctx_arg = NULL; - m_data.xml_parser_state = NULL; -} + : m_transaction(transaction) { } XML::~XML() { - if (m_data.parsing_ctx != NULL) { + if (m_data.parsing_ctx != nullptr) { xmlFreeParserCtxt(m_data.parsing_ctx); - m_data.parsing_ctx = NULL; + m_data.parsing_ctx = nullptr; } - if (m_data.doc != NULL) { + if (m_data.doc != nullptr) { xmlFreeDoc(m_data.doc); - m_data.doc = NULL; + m_data.doc = nullptr; } } bool XML::init() { - //xmlParserInputBufferCreateFilenameFunc entity; if (m_transaction->m_rules->m_secXMLExternalEntity == RulesSetProperties::TrueConfigBoolean) { - /*entity = */xmlParserInputBufferCreateFilenameDefault( + xmlParserInputBufferCreateFilenameDefault( __xmlParserInputBufferCreateFilename); } else { - /*entity = */xmlParserInputBufferCreateFilenameDefault( + xmlParserInputBufferCreateFilenameDefault( this->unloadExternalEntity); } if (m_transaction->m_secXMLParseXmlIntoArgs @@ -198,8 +182,6 @@ bool XML::init() { // set the parser state struct m_data.xml_parser_state = std::make_unique(m_transaction); - m_data.xml_parser_state->node_depth = 0; - m_data.xml_parser_state->currval = ""; // the XML will contain at least one node, which is the pseudo root node 'xml' m_data.xml_parser_state->currpath = "xml."; } @@ -208,9 +190,9 @@ bool XML::init() { } -xmlParserInputBufferPtr XML::unloadExternalEntity(const char *URI, - xmlCharEncoding enc) { - return NULL; +xmlParserInputBufferPtr XML::unloadExternalEntity(const char *, + xmlCharEncoding) { + return nullptr; } @@ -220,30 +202,17 @@ bool XML::processChunk(const char *buf, unsigned int size, * enable us to pass it the first chunk of data so that * it can attempt to auto-detect the encoding. */ - if (m_data.parsing_ctx == NULL && m_data.parsing_ctx_arg == NULL) { + if (m_data.parsing_ctx == nullptr && m_data.parsing_ctx_arg == nullptr) { /* First invocation. */ ms_dbg_a(m_transaction, 4, "XML: Initialising parser."); - /* NOTE When Sax interface is used libxml will not - * create the document object, but we need it. - - msr->xml->sax_handler = (xmlSAXHandler *)apr_pcalloc(msr->mp, - sizeof(xmlSAXHandler)); - if (msr->xml->sax_handler == NULL) return -1; - msr->xml->sax_handler->error = xml_receive_sax_error; - msr->xml->sax_handler->warning = xml_receive_sax_error; - msr->xml->parsing_ctx = xmlCreatePushParserCtxt(msr->xml->sax_handler, - msr, buf, size, "body.xml"); - - */ - if (m_transaction->m_secXMLParseXmlIntoArgs != RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs) { - m_data.parsing_ctx = xmlCreatePushParserCtxt(NULL, NULL, + m_data.parsing_ctx = xmlCreatePushParserCtxt(nullptr, nullptr, buf, size, "body.xml"); - if (m_data.parsing_ctx == NULL) { + if (m_data.parsing_ctx == nullptr) { ms_dbg_a(m_transaction, 4, "XML: Failed to create parsing context."); error->assign("XML: Failed to create parsing context."); @@ -262,8 +231,8 @@ bool XML::processChunk(const char *buf, unsigned int size, m_data.xml_parser_state.get(), buf, size, - NULL); - if (m_data.parsing_ctx_arg == NULL) { + nullptr); + if (m_data.parsing_ctx_arg == nullptr) { error->assign("XML: Failed to create parsing context for ARGS."); return false; } @@ -275,7 +244,7 @@ bool XML::processChunk(const char *buf, unsigned int size, } /* Not a first invocation. */ - if (m_data.parsing_ctx != NULL && + if (m_data.parsing_ctx != nullptr && m_transaction->m_secXMLParseXmlIntoArgs != RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs) { xmlParseChunk(m_data.parsing_ctx, buf, size, 0); @@ -287,7 +256,7 @@ bool XML::processChunk(const char *buf, unsigned int size, } } - if (m_data.parsing_ctx_arg != NULL && + if (m_data.parsing_ctx_arg != nullptr && ( m_transaction->m_secXMLParseXmlIntoArgs == RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs @@ -309,12 +278,12 @@ bool XML::processChunk(const char *buf, unsigned int size, bool XML::complete(std::string *error) { /* Only if we have a context, meaning we've done some work. */ - if (m_data.parsing_ctx != NULL || m_data.parsing_ctx_arg != NULL) { - if (m_data.parsing_ctx != NULL && + if (m_data.parsing_ctx != nullptr || m_data.parsing_ctx_arg != nullptr) { + if (m_data.parsing_ctx != nullptr && m_transaction->m_secXMLParseXmlIntoArgs != RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs) { /* This is how we signal the end of parsing to libxml. */ - xmlParseChunk(m_data.parsing_ctx, NULL, 0, 1); + xmlParseChunk(m_data.parsing_ctx, nullptr, 0, 1); /* Preserve the results for our reference. */ m_data.well_formed = m_data.parsing_ctx->wellFormed; @@ -322,7 +291,7 @@ bool XML::complete(std::string *error) { /* Clean up everything else. */ xmlFreeParserCtxt(m_data.parsing_ctx); - m_data.parsing_ctx = NULL; + m_data.parsing_ctx = nullptr; ms_dbg_a(m_transaction, 4, "XML: Parsing complete (well_formed " \ + std::to_string(m_data.well_formed) + ")."); @@ -332,7 +301,7 @@ bool XML::complete(std::string *error) { return false; } } - if (m_data.parsing_ctx_arg != NULL && + if (m_data.parsing_ctx_arg != nullptr && ( m_transaction->m_secXMLParseXmlIntoArgs == RulesSetProperties::OnlyArgsConfigXMLParseXmlIntoArgs @@ -341,19 +310,19 @@ bool XML::complete(std::string *error) { == RulesSetProperties::TrueConfigXMLParseXmlIntoArgs) ) { /* This is how we signale the end of parsing to libxml. */ - if (xmlParseChunk(m_data.parsing_ctx_arg, NULL, 0, 1) != 0) { - if (m_data.xml_error != "") { + if (xmlParseChunk(m_data.parsing_ctx_arg, nullptr, 0, 1) != 0) { + if (!m_data.xml_error.empty()) { error->assign(m_data.xml_error); } else { error->assign("XML: Failed to parse document for ARGS."); } xmlFreeParserCtxt(m_data.parsing_ctx_arg); - m_data.parsing_ctx_arg = NULL; + m_data.parsing_ctx_arg = nullptr; return false; } xmlFreeParserCtxt(m_data.parsing_ctx_arg); - m_data.parsing_ctx_arg = NULL; + m_data.parsing_ctx_arg = nullptr; } } @@ -362,5 +331,4 @@ bool XML::complete(std::string *error) { #endif -} // namespace RequestBodyProcessor -} // namespace modsecurity +} // namespace modsecurity::RequestBodyProcessor diff --git a/src/request_body_processor/xml.h b/src/request_body_processor/xml.h index df766d03b7..87f614fee2 100644 --- a/src/request_body_processor/xml.h +++ b/src/request_body_processor/xml.h @@ -19,18 +19,19 @@ #include #endif +#include #include -#include - -#include "modsecurity/transaction.h" -#include "modsecurity/rules_set.h" +#include #ifndef SRC_REQUEST_BODY_PROCESSOR_XML_H_ #define SRC_REQUEST_BODY_PROCESSOR_XML_H_ - namespace modsecurity { -namespace RequestBodyProcessor { +class Transaction; +} + + +namespace modsecurity::RequestBodyProcessor { #ifdef WITH_LIBXML2 @@ -42,7 +43,7 @@ class NodeData { explicit NodeData(); ~NodeData(); - bool has_child; + bool has_child = false; }; /* @@ -51,14 +52,14 @@ class NodeData { class XMLNodes { public: std::vector> nodes; - unsigned long int node_depth; + unsigned long int node_depth = 0; std::string currpath; std::string currval; - bool currval_is_set; - Transaction *m_transaction; + bool currval_is_set = false; + Transaction *m_transaction = nullptr; // need to store context - this is the same as in xml_data // need to stop parsing if the number of arguments reached the limit - xmlParserCtxtPtr parsing_ctx_arg; + xmlParserCtxtPtr parsing_ctx_arg = nullptr; explicit XMLNodes (Transaction *); ~XMLNodes(); @@ -66,23 +67,21 @@ class XMLNodes { struct xml_data { std::unique_ptr sax_handler; - xmlParserCtxtPtr parsing_ctx; - xmlDocPtr doc; + xmlParserCtxtPtr parsing_ctx = nullptr; + xmlDocPtr doc = nullptr; - unsigned int well_formed; + unsigned int well_formed = 0; /* error reporting and XML array flag */ std::string xml_error; /* additional parser context for arguments */ - xmlParserCtxtPtr parsing_ctx_arg; + xmlParserCtxtPtr parsing_ctx_arg = nullptr; /* parser state for SAX parser */ std::unique_ptr xml_parser_state; }; -typedef struct xml_data xml_data; - class XML { public: explicit XML(Transaction *transaction); @@ -96,13 +95,12 @@ class XML { xml_data m_data; private: - Transaction *m_transaction; + Transaction *m_transaction = nullptr; std::string m_header; }; #endif -} // namespace RequestBodyProcessor -} // namespace modsecurity +} // namespace modsecurity::RequestBodyProcessor #endif // SRC_REQUEST_BODY_PROCESSOR_XML_H_ diff --git a/src/rule_with_actions.cc b/src/rule_with_actions.cc index f6642b67e6..7469be8fe9 100644 --- a/src/rule_with_actions.cc +++ b/src/rule_with_actions.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include "modsecurity/rules_set.h" #include "src/operators/operator.h" diff --git a/src/rule_with_operator.cc b/src/rule_with_operator.cc index 9c356b8fb0..0f8b14c4bb 100644 --- a/src/rule_with_operator.cc +++ b/src/rule_with_operator.cc @@ -18,12 +18,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include "modsecurity/rules_set.h" #include "src/operators/operator.h" diff --git a/src/rules_exceptions.cc b/src/rules_exceptions.cc index 2fb0cf857f..352d3cab83 100644 --- a/src/rules_exceptions.cc +++ b/src/rules_exceptions.cc @@ -15,7 +15,10 @@ #include "modsecurity/rules_exceptions.h" +#include #include +#include +#include #include "src/utils/string.h" #include "src/variables/variable.h" diff --git a/src/rules_set_phases.cc b/src/rules_set_phases.cc index a781930498..88731edda9 100644 --- a/src/rules_set_phases.cc +++ b/src/rules_set_phases.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/src/run_time_string.cc b/src/run_time_string.cc index 45f298bc3d..48feeef38b 100644 --- a/src/run_time_string.cc +++ b/src/run_time_string.cc @@ -15,6 +15,7 @@ #include +#include #include "src/run_time_string.h" diff --git a/src/transaction.cc b/src/transaction.cc index 935da02462..c9e1401b7a 100644 --- a/src/transaction.cc +++ b/src/transaction.cc @@ -23,12 +23,16 @@ #include #include +#include #include #include #include #include +#include #include +#include #include +#include #include #include "modsecurity/actions/action.h" diff --git a/src/utils/json_writer.cc b/src/utils/json_writer.cc index 4cd7b1ba5d..1be155f123 100644 --- a/src/utils/json_writer.cc +++ b/src/utils/json_writer.cc @@ -15,6 +15,7 @@ #include "src/utils/json_writer.h" +#include #include #include diff --git a/src/utils/json_writer.h b/src/utils/json_writer.h index ac549d592b..130ec022ea 100644 --- a/src/utils/json_writer.h +++ b/src/utils/json_writer.h @@ -16,6 +16,7 @@ #ifndef SRC_UTILS_JSON_WRITER_H_ #define SRC_UTILS_JSON_WRITER_H_ +#include #include #include #include diff --git a/src/utils/sha1.h b/src/utils/sha1.h index a40d7fa1c8..aa9132c652 100644 --- a/src/utils/sha1.h +++ b/src/utils/sha1.h @@ -16,7 +16,9 @@ #ifndef SRC_UTILS_SHA1_H_ #define SRC_UTILS_SHA1_H_ +#include #include +#include #include #include "src/utils/string.h" diff --git a/src/utils/string.h b/src/utils/string.h index ca2967aa5f..8933a5f884 100644 --- a/src/utils/string.h +++ b/src/utils/string.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include diff --git a/src/variables/variable.cc b/src/variables/variable.cc index caf8f6fd88..ca1eacfe56 100644 --- a/src/variables/variable.cc +++ b/src/variables/variable.cc @@ -16,6 +16,7 @@ #include "src/variables/variable.h" #include +#include #include #include #include From aeddb2b8d58cba167c736c107fe6950fa8a8024f Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Tue, 14 Apr 2026 20:56:01 +0200 Subject: [PATCH 2/4] docs: add thorough libxml2 and JSON integration review --- docs/libxml2-json-review-2026-04-14.md | 197 +++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 docs/libxml2-json-review-2026-04-14.md diff --git a/docs/libxml2-json-review-2026-04-14.md b/docs/libxml2-json-review-2026-04-14.md new file mode 100644 index 0000000000..7a44bb2f91 --- /dev/null +++ b/docs/libxml2-json-review-2026-04-14.md @@ -0,0 +1,197 @@ +# libxml2- und JSON-Review (Stand: 2026-04-14) + +Dieses Dokument fasst den technischen Befund im Repository und den Abgleich mit aktuellen öffentlichen Quellen zusammen. + +## 1) Executive Summary + +- **Repo-Befund:** libxml2 ist in ModSecurity funktional relevant für XML-Request-Body-Parsing, XPath-Variablenzugriff sowie DTD/XSD-Validierungsoperatoren. Build-seitig ist die Abhängigkeit optional, aber breit integriert (Autotools, Windows-CMake/Conan, Tests/Fuzzer). +- **Version-Lage im Repo:** + - Autotools-Mindestversion ist historisch niedrig (**2.6.29**). + - Windows/Conan pinnt **2.12.6**. +- **Externer Stand (öffentlich):** Aktuelle Release-Linie ist **2.15.x**, mit **2.15.2** als neuestem Stand (März 2026), inkl. mehrerer Security-Fixes. +- **Kernlücke:** Keine harte, moderne Mindestversion im Haupt-Build; die Security-Härtung erfolgt nicht über `XML_PARSE_NO_XXE`, sondern über einen global registrierten I/O-Callback (`xmlParserInputBufferCreateFilenameDefault`), der upstream als deprecated dokumentiert ist. +- **JSON-Integration:** JSON ist bereits über eine eigene Backend-Abstraktion (simdjson/jsoncons) von XML getrennt. libxml2 ist **nicht** der primäre Engpass für die Integration einer weiteren JSON-Bibliothek. + +## 2) Befunde im Repo + +### 2.1 Belegt im Repo + +#### Nutzungspunkte von libxml2 + +- Initialisierung/Shutdown zentral in `ModSecurity`: + - `xmlInitParser()` im Konstruktor, `xmlCleanupParser()` im Destruktor. +- XML-Request-Body-Parsing via Push-Parser (`xmlCreatePushParserCtxt`, `xmlParseChunk`) in `src/request_body_processor/xml.cc`. +- XPath-Auswertung für `XML`-Variablenzugriffe in `src/variables/xml.cc`. +- DTD-Validierung (`xmlParseDTD`, `xmlValidateDtd`) in `src/operators/validate_dtd.cc`. +- XSD-Validierung (`xmlSchema*`) in `src/operators/validate_schema.cc`. + +#### Build-/Dependency-Einbindung + +- Autotools-Makro `CHECK_LIBXML2` mit Mindestversion `2.6.29`. +- Windows-Conan pinnt `libxml2/2.12.6`. +- Windows-Doku nennt ebenfalls `libxml2 2.12.6`. + +#### Security-relevantes Parser-Verhalten + +- Externe Entity-Ladung wird in `XML::init()` über globale Callback-Registrierung gesteuert: + - bei `SecXMLExternalEntity On`: Default-Lader aktiv, + - sonst Callback, der immer `nullptr` liefert (blockiert externe Entitäten). +- Parseroptionen setzen aktuell primär `XML_PARSE_NOWARNING | XML_PARSE_NOERROR`. +- Es wird **nicht** sichtbar `XML_PARSE_NO_XXE` gesetzt. + +#### Tests/Fuzzing + +- Regression-Tests referenzieren `libxml2` explizit als benötigte Resource. +- Ein dedizierter XXE-Testfall (`config-xml_external_entity.json`) existiert. +- Fuzzer-Build linkt `$(LIBXML2_LDADD)`. + +#### JSON-Befund im Repo + +- JSON-Backend ist wählbar (`simdjson` oder `jsoncons`) via `--with-json-backend`. +- `JSONAdapter` kapselt Backendwahl über Compile-Defines. +- JSON-Verarbeitung läuft in eigener RequestBodyProcessor-Klasse (`JSON`), getrennt vom XML-Prozessor (`XML`). + +### 2.2 Schlussfolgerung aus Repo-Befund + +- libxml2 ist für XML-Features **kritisch**, aber **modular optional** (Compile-Flag `WITH_LIBXML2`). +- JSON-Pfad ist technisch bereits entkoppelt; XML und JSON teilen sich primär nur den Dispatcher in `Transaction::processRequestBody`. +- Der heikelste Punkt in der aktuellen XML-Härtung ist die Nutzung einer **globalen** (und upstream deprecated) Loader-Umschaltung. + +### 2.3 Offen / unklar / nicht verifizierbar + +- Welche libxml2-Version produktiv auf Linux tatsächlich zur Laufzeit genutzt wird, ist aus dem Repo allein nicht feststellbar. +- Ob Distributionen lokale Backports einspielen, ist ohne konkrete Zielplattform nicht verifizierbar. + +## 3) Aktueller externer Stand zu libxml2 + +### 3.1 Belegt durch aktuelle externe Quellen + +- GNOME-Release-Archiv listet für libxml2 die Reihe **2.15** mit `LATEST-IS-2.15.2` (Datum 2026-03-04). +- 2.15.0 nennt u. a.: + - Entfernen des eingebauten HTTP-Clients, + - Entfernen von LZMA-Support, + - geänderte Build-Anforderungen (Docs/Doxygen), + - geplante weitere Entfernungen. +- 2.14.0 nennt API/ABI-relevante Änderungen: + - Binärkompatibilität nur für 2.14+, + - SONAME-Bump von `libxml2.so.2` auf `libxml2.so.16` (ELF). +- 2.15.2 nennt mehrere Security-Fixes, inklusive CVE-IDs (z. B. CVE-2026-1757, CVE-2026-0990, CVE-2026-0992, CVE-2026-0989) laut offiziellen Release Notes. +- 2.12.10 (Feb 2025) adressiert laut Release Notes u. a. CVE-2025-24928 und CVE-2024-56171. +- NVD bestätigt für CVE-2025-24928: betroffen sind Versionen vor 2.12.10 bzw. 2.13.x vor 2.13.6. +- Aktuelle libxml2-API-Doku (`parser.h`) empfiehlt bei untrusted Daten `XML_PARSE_NO_XXE`; außerdem ist dokumentiert, dass `XML_PARSE_NONET` seit Wegfall der eingebauten Netz-Clients in 2.15 praktisch keine Wirkung mehr hat (außer Weitergabe an Custom Loader). +- `xmlParserInputBufferCreateFilenameDefault()` ist in aktueller API-Doku als deprecated markiert; empfohlen werden kontextbezogene Loader-APIs (`xmlCtxtSetResourceLoader` o. ä.). + +### 3.2 Schlussfolgerung aus externem Stand + +- Das libxml2-Ökosystem bewegt sich schnell (2.14/2.15 mit relevanten API/Build-/Security-Änderungen). +- Alte Mindestversionsgrenzen (2.6.x) sind nicht mehr zeitgemäß als Security-Basis. + +### 3.3 Offen / unklar / nicht verifizierbar + +- Ob alle in 2.15.2 genannten CVE-Einträge bereits vollständig in allen öffentlichen Datenbanken normalisiert/enriched sind, ist nicht vollständig verifizierbar. + +## 4) Gap-Analyse: Repo vs. aktueller Stand + +## Belegt im Repo +- Mindestversion 2.6.29 (Autotools), Windows-Pin 2.12.6. +- XML-Schutz gegen externe Entitäten über globalen Callback-Schalter, nicht über `XML_PARSE_NO_XXE`. + +## Belegt extern +- Aktueller Stand 2.15.2 mit Security-Fixes und API/Build-Änderungen. +- Deprecation des im Repo verwendeten globalen Callback-Mechanismus. + +## Schlussfolgerung / Empfehlung +- Es gibt eine reale Modernisierungslücke, v. a. bei: + 1) Versionspolicy, + 2) Security-Optionierung, + 3) Nutzung deprecated globaler Loader-Hooks. + +## 5) Einfluss auf die Integration einer neuen JSON-Bibliothek + +### Belegt im Repo +- JSON ist bereits über `JSONAdapter` von XML entkoppelt. +- Backend-Auswahl für JSON existiert (`simdjson`/`jsoncons`). + +### Schlussfolgerung / Empfehlung +- Ein libxml2-Upgrade ist **nicht Voraussetzung**, um eine neue JSON-Bibliothek technisch zu integrieren. +- Für saubere Gesamtarchitektur ist eher eine gemeinsame Parsing-Abstraktion (einheitliche Fehler-/Limits-/Telemetry-Schnittstelle) relevant als ein Austausch von libxml2. + +## 6) Klare Entscheidungsantwort + +**Teilweise: libxml2 kann bleiben, aber die Einbindung sollte modernisiert werden.** + +Begründung: +- **Ja zur Modernisierung** wegen Security-/Wartbarkeitsaspekten (deprecated Loader-Hook, veraltete Mindestversion, fehlende explizite NO_XXE-Optionierung). +- **Nein zur These „nur wegen JSON muss libxml2 raus“**: JSON-Pfade sind bereits gekapselt; der Integrationsengpass liegt nicht primär in libxml2. + +## 7) Priorisierte Maßnahmen + +### Kurzfristig (niedriger bis mittlerer Eingriff) + +1. **Versions-Policy anheben** + - Mindestversion für libxml2 im Build auf einen sicher gepflegten Bereich anheben (z. B. 2.12.10+ oder 2.14+ je Plattformstrategie). + - Warum: reduziert Risiko bekannter Schwachstellen auf Altversionen. + +2. **Explizite XXE-Härtung ergänzen** + - Zusätzlich zu bestehender Logik `XML_PARSE_NO_XXE` (wo verfügbar) setzen. + - Warum: dokumentierter Best-Practice-Mechanismus für untrusted XML. + +3. **Tests erweitern** + - Regressionen für XXE/DTD/XInclude/Entity-Edgecases in Matrix über mehrere libxml2-Versionen. + +### Mittelfristig (mittlerer Eingriff) + +4. **Globalen Loader-Hook ablösen** + - Migration von `xmlParserInputBufferCreateFilenameDefault` zu kontextbezogenen Loader-APIs. + - Warum: deprecated API, globaler Schalter ist fehleranfällig in Multi-Thread-/Multi-Request-Szenarien. + +5. **Build-Matrix harmonisieren** + - Linux/Windows auf konsistentere libxml2-Zielversionen bringen; Policy dokumentieren. + +### Langfristig (mittlerer bis höherer Eingriff) + +6. **Parser-Abstraktion vereinheitlichen (XML/JSON)** + - Gemeinsame Schicht für Limits, Fehlernormalisierung, Telemetrie, Cancellation. + - Nutzen: Neue JSON-Bibliotheken und XML-Änderungen lassen sich mit geringerem Risiko integrieren. + +## 8) Offene Unsicherheiten / nicht verifizierbare Punkte + +- Reale Produktionsversionen pro Zielplattform: **Nicht verifizierbar.** +- Exakte Laufzeit-ABI-Risiken in allen Downstream-Packages ohne Zielumgebungen: **Nicht verifizierbar.** + +## 9) Quellen + +### Repository-Quellen +- `build/libxml.m4` +- `build/win32/conanfile.txt` +- `build/win32/README.md` +- `src/modsecurity.cc` +- `src/transaction.cc` +- `src/request_body_processor/xml.cc` +- `src/variables/xml.cc` +- `src/operators/validate_dtd.cc` +- `src/operators/validate_schema.cc` +- `src/request_body_processor/json_adapter.cc` +- `configure.ac` +- `test/test-cases/regression/config-xml_external_entity.json` +- `test/regression/regression.cc` +- `test/fuzzer/Makefile.am` + +### Externe Primärquellen +- GNOME libxml2 Release-Archiv (Index): + - https://download.gnome.org/sources/libxml2/ + - https://download.gnome.org/sources/libxml2/2.15/ + - https://download.gnome.org/sources/libxml2/2.14/ + - https://download.gnome.org/sources/libxml2/2.12/ +- Release Notes: + - https://download.gnome.org/sources/libxml2/2.15/libxml2-2.15.2.news + - https://download.gnome.org/sources/libxml2/2.15/libxml2-2.15.0.news + - https://download.gnome.org/sources/libxml2/2.14/libxml2-2.14.0.news + - https://download.gnome.org/sources/libxml2/2.14/libxml2-2.14.5.news + - https://download.gnome.org/sources/libxml2/2.14/libxml2-2.14.6.news + - https://download.gnome.org/sources/libxml2/2.12/libxml2-2.12.10.news +- Offizielle API-Doku: + - https://gnome.pages.gitlab.gnome.org/libxml2/html/parser_8h.html + - https://gnome.pages.gitlab.gnome.org/libxml2/html/xmlIO_8h.html +- NVD (CVE-Referenz): + - https://nvd.nist.gov/vuln/detail/CVE-2025-24928 From 5628ffe0b696c8ef3c4aa4f63183e6d3902d62b5 Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Tue, 14 Apr 2026 21:11:50 +0200 Subject: [PATCH 3/4] docs: expand libxml2 review with modularization assessment --- docs/libxml2-json-review-2026-04-14.md | 334 ++++++++++++++++--------- 1 file changed, 215 insertions(+), 119 deletions(-) diff --git a/docs/libxml2-json-review-2026-04-14.md b/docs/libxml2-json-review-2026-04-14.md index 7a44bb2f91..ef051a39f3 100644 --- a/docs/libxml2-json-review-2026-04-14.md +++ b/docs/libxml2-json-review-2026-04-14.md @@ -1,184 +1,282 @@ -# libxml2- und JSON-Review (Stand: 2026-04-14) +# libxml2 / JSON Architektur- und Dependency-Review (Stand: 2026-04-14) -Dieses Dokument fasst den technischen Befund im Repository und den Abgleich mit aktuellen öffentlichen Quellen zusammen. +Ziel dieses Dokuments ist eine belastbare Bewertung von Nutzung, Sicherheitslage, Wartbarkeit und Integrationsfähigkeit von **libxml2** im Projekt – inklusive Vergleich mit dem aktuellen öffentlichen Stand sowie expliziter Bewertung einer **Modularisierung von libxml2 analog zur JSON-Architektur**. + +--- ## 1) Executive Summary -- **Repo-Befund:** libxml2 ist in ModSecurity funktional relevant für XML-Request-Body-Parsing, XPath-Variablenzugriff sowie DTD/XSD-Validierungsoperatoren. Build-seitig ist die Abhängigkeit optional, aber breit integriert (Autotools, Windows-CMake/Conan, Tests/Fuzzer). -- **Version-Lage im Repo:** - - Autotools-Mindestversion ist historisch niedrig (**2.6.29**). - - Windows/Conan pinnt **2.12.6**. -- **Externer Stand (öffentlich):** Aktuelle Release-Linie ist **2.15.x**, mit **2.15.2** als neuestem Stand (März 2026), inkl. mehrerer Security-Fixes. -- **Kernlücke:** Keine harte, moderne Mindestversion im Haupt-Build; die Security-Härtung erfolgt nicht über `XML_PARSE_NO_XXE`, sondern über einen global registrierten I/O-Callback (`xmlParserInputBufferCreateFilenameDefault`), der upstream als deprecated dokumentiert ist. -- **JSON-Integration:** JSON ist bereits über eine eigene Backend-Abstraktion (simdjson/jsoncons) von XML getrennt. libxml2 ist **nicht** der primäre Engpass für die Integration einer weiteren JSON-Bibliothek. +### Belegt im Repo +- libxml2 wird für XML-Request-Body-Parsing, XPath-basierte Variablen, DTD-Validierung und XSD-Validierung genutzt. +- Die Einbindung ist optional (`WITH_LIBXML2`), aber funktional tief in XML-Features integriert. +- Autotools fordert nur `libxml2 >= 2.6.29`; Windows-Conan pinnt `2.12.6`. +- XML-Sicherheitssteuerung erfolgt aktuell über globalen Loader-Callback (`xmlParserInputBufferCreateFilenameDefault`), während JSON über eine klarere Backend-Abstraktion (`JSONAdapter` + `JsonEventSink`) geführt wird. -## 2) Befunde im Repo +### Belegt durch externe Quellen +- Upstream-Stand ist 2.15.x (aktueller Index: 2.15.2 in März 2026). +- 2.14/2.15 enthalten API/ABI- und Sicherheitsrelevanz (u. a. SONAME-Änderung in 2.14.0, Security-Fixes in neueren Releases). +- Offizielle API-Doku markiert `xmlParserInputBufferCreateFilenameDefault` als deprecated und empfiehlt kontextbezogene Loader-Mechanismen. -### 2.1 Belegt im Repo +### Schlussfolgerung +- **Update/Modernisierung von libxml2-Einbindung ist sinnvoll** (Security + Wartbarkeit + Zukunftsfähigkeit). +- **libxml2 ist nicht der primäre Blocker für neue JSON-Bibliothek**. +- **Modularisierung von libxml2 ist teilweise sinnvoll bis empfohlen**: nicht zwingend für Funktionalität heute, aber klar vorteilhaft für Konsistenz, Testbarkeit und künftige Parser-Vereinheitlichung. -#### Nutzungspunkte von libxml2 +### Unsicherheit / nicht verifizierbar +- Reale Produktionsversionen je Zielumgebung sind aus dem Repo allein nicht bestimmbar. **Nicht verifizierbar.** -- Initialisierung/Shutdown zentral in `ModSecurity`: - - `xmlInitParser()` im Konstruktor, `xmlCleanupParser()` im Destruktor. -- XML-Request-Body-Parsing via Push-Parser (`xmlCreatePushParserCtxt`, `xmlParseChunk`) in `src/request_body_processor/xml.cc`. -- XPath-Auswertung für `XML`-Variablenzugriffe in `src/variables/xml.cc`. -- DTD-Validierung (`xmlParseDTD`, `xmlValidateDtd`) in `src/operators/validate_dtd.cc`. -- XSD-Validierung (`xmlSchema*`) in `src/operators/validate_schema.cc`. +--- -#### Build-/Dependency-Einbindung +## 2) Repo-Befunde -- Autotools-Makro `CHECK_LIBXML2` mit Mindestversion `2.6.29`. -- Windows-Conan pinnt `libxml2/2.12.6`. -- Windows-Doku nennt ebenfalls `libxml2 2.12.6`. +## 2.1 Includes, Build, Versionen -#### Security-relevantes Parser-Verhalten +### Belegt im Repo +- Build-Minimum in Autotools: `MSC_CHECK_LIB(... MIN_VERSION [2.6.29] ...)`. +- Windows-Build (Conan): `libxml2/2.12.6`. +- Windows-Readme bestätigt ebenfalls libxml2 2.12.6. +- CMake Windows koppelt `WITH_LIBXML2` an `LibXml2::LibXml2`. -- Externe Entity-Ladung wird in `XML::init()` über globale Callback-Registrierung gesteuert: - - bei `SecXMLExternalEntity On`: Default-Lader aktiv, - - sonst Callback, der immer `nullptr` liefert (blockiert externe Entitäten). -- Parseroptionen setzen aktuell primär `XML_PARSE_NOWARNING | XML_PARSE_NOERROR`. -- Es wird **nicht** sichtbar `XML_PARSE_NO_XXE` gesetzt. +### Schlussfolgerung +- Versionspolitik ist uneinheitlich (sehr altes Mindestlevel vs. fester mittlerer Pin auf Windows). -#### Tests/Fuzzing +### Unsicherheit / nicht verifizierbar +- Linux-Distributionen können Backports liefern; ohne Ziel-Distroliste **nicht verifizierbar**. -- Regression-Tests referenzieren `libxml2` explizit als benötigte Resource. -- Ein dedizierter XXE-Testfall (`config-xml_external_entity.json`) existiert. -- Fuzzer-Build linkt `$(LIBXML2_LDADD)`. +## 2.2 Code-Kopplung und Nutzungsarten -#### JSON-Befund im Repo +### Belegt im Repo +- Initialisierung global in `ModSecurity` via `xmlInitParser()` / `xmlCleanupParser()`. +- XML-Request-Parsing in `src/request_body_processor/xml.cc` per Push-Parser (`xmlCreatePushParserCtxt`, `xmlParseChunk`) plus SAX-Callbacks für `SecParseXmlIntoArgs`. +- XPath-Nutzung in `src/variables/xml.cc` (`xmlXPathEvalExpression`, Namespace-Registrierung). +- DTD-Validierung (`xmlParseDTD`, `xmlValidateDtd`) in `validate_dtd.cc`. +- XSD-Validierung (`xmlSchema*`) in `validate_schema.cc`. +- XML-Verarbeitung wird in `Transaction::processRequestBody` neben JSON-Verarbeitung geschaltet. -- JSON-Backend ist wählbar (`simdjson` oder `jsoncons`) via `--with-json-backend`. -- `JSONAdapter` kapselt Backendwahl über Compile-Defines. -- JSON-Verarbeitung läuft in eigener RequestBodyProcessor-Klasse (`JSON`), getrennt vom XML-Prozessor (`XML`). +### Schlussfolgerung +- libxml2-Aufrufe sind nicht überall verstreut, aber auch nicht durch ein zentrales XML-Backend-Interface isoliert (anders als JSON). -### 2.2 Schlussfolgerung aus Repo-Befund +## 2.3 Fehlerbehandlung und Security-relevante Optionen -- libxml2 ist für XML-Features **kritisch**, aber **modular optional** (Compile-Flag `WITH_LIBXML2`). -- JSON-Pfad ist technisch bereits entkoppelt; XML und JSON teilen sich primär nur den Dispatcher in `Transaction::processRequestBody`. -- Der heikelste Punkt in der aktuellen XML-Härtung ist die Nutzung einer **globalen** (und upstream deprecated) Loader-Umschaltung. +### Belegt im Repo +- Parseroptionen setzen `XML_PARSE_NOWARNING | XML_PARSE_NOERROR`. +- Externe Entitäten werden über `SecXMLExternalEntity` gesteuert: + - ON: Default-Loader, + - sonst: Callback liefert `nullptr`. +- Regressionsfälle für XXE-Szenarien sind vorhanden (`config-xml_external_entity.json`). -### 2.3 Offen / unklar / nicht verifizierbar +### Schlussfolgerung +- Es existiert Schutzlogik, aber in Form eines globalen Mechanismus statt kontextbezogener Härtung. -- Welche libxml2-Version produktiv auf Linux tatsächlich zur Laufzeit genutzt wird, ist aus dem Repo allein nicht feststellbar. -- Ob Distributionen lokale Backports einspielen, ist ohne konkrete Zielplattform nicht verifizierbar. +### Unsicherheit / nicht verifizierbar +- Ob alle denkbaren Entity/Resource-Edgecases (z. B. bei parallel laufenden Konfigurationen) vollständig abgedeckt sind, aus vorhandenen Tests allein **nicht verifizierbar**. -## 3) Aktueller externer Stand zu libxml2 +## 2.4 JSON-Architektur im Repo (Vergleichsmuster) -### 3.1 Belegt durch aktuelle externe Quellen +### Belegt im Repo +- Konfigurierbare Backends: `--with-json-backend=simdjson|jsoncons`. +- Gemeinsames Backend-Interface (`JsonEventSink`, `JsonParseResult`, `JsonBackendParseOptions`). +- Adapter-Schicht (`JSONAdapter`) wählt Backend über Compile-Time-Defines. +- Separate Backend-Implementierungen (`json_backend_simdjson.cc`, `json_backend_jsoncons.cc`) + dedizierte Tests (`json_backend_depth_tests`, Backend-Matrix-Script). + +### Schlussfolgerung +- JSON ist strukturell modularer/abstrakter als XML. +- Dieses Muster ist als Referenz für libxml2-Kapselung geeignet. + +--- + +## 3) Externer Stand zu libxml2 (Internet-Abgleich) + +### Belegt durch externe Quellen +- Release-Index listet aktuell 2.15.x mit `LATEST-IS-2.15.2` (2026-03-04). +- 2.14.0 Release Notes: SONAME-Sprung (`libxml2.so.2` -> `libxml2.so.16`) und Binärkompatibilität nur innerhalb 2.14+. +- 2.15.0 Release Notes: Wegfall built-in HTTP/LZMA-Komponenten u. a. technische Änderungen. +- 2.15.2 Release Notes: mehrere Security-Fixes/CVE-Referenzen. +- 2.12.10 Release Notes: Fixes inkl. CVE-2025-24928 / CVE-2024-56171. +- NVD bestätigt CVE-2025-24928 als relevant für ältere Versionen (<2.12.10 bzw. 2.13.6). +- Offizielle API-Doku: + - `XML_PARSE_NO_XXE` als relevante Sicherheitsoption, + - `xmlParserInputBufferCreateFilenameDefault` deprecated, + - `XML_PARSE_NONET` seit 2.15 nur noch begrenzt relevant (kein built-in network client). -- GNOME-Release-Archiv listet für libxml2 die Reihe **2.15** mit `LATEST-IS-2.15.2` (Datum 2026-03-04). -- 2.15.0 nennt u. a.: - - Entfernen des eingebauten HTTP-Clients, - - Entfernen von LZMA-Support, - - geänderte Build-Anforderungen (Docs/Doxygen), - - geplante weitere Entfernungen. -- 2.14.0 nennt API/ABI-relevante Änderungen: - - Binärkompatibilität nur für 2.14+, - - SONAME-Bump von `libxml2.so.2` auf `libxml2.so.16` (ELF). -- 2.15.2 nennt mehrere Security-Fixes, inklusive CVE-IDs (z. B. CVE-2026-1757, CVE-2026-0990, CVE-2026-0992, CVE-2026-0989) laut offiziellen Release Notes. -- 2.12.10 (Feb 2025) adressiert laut Release Notes u. a. CVE-2025-24928 und CVE-2024-56171. -- NVD bestätigt für CVE-2025-24928: betroffen sind Versionen vor 2.12.10 bzw. 2.13.x vor 2.13.6. -- Aktuelle libxml2-API-Doku (`parser.h`) empfiehlt bei untrusted Daten `XML_PARSE_NO_XXE`; außerdem ist dokumentiert, dass `XML_PARSE_NONET` seit Wegfall der eingebauten Netz-Clients in 2.15 praktisch keine Wirkung mehr hat (außer Weitergabe an Custom Loader). -- `xmlParserInputBufferCreateFilenameDefault()` ist in aktueller API-Doku als deprecated markiert; empfohlen werden kontextbezogene Loader-APIs (`xmlCtxtSetResourceLoader` o. ä.). +### Schlussfolgerung +- Der Upstream-Stand liegt deutlich über der in Teilen des Repos sichtbaren Versionierungspolitik. +- Security- und API-Entwicklung nahelegt: Modernisierung statt „as-is“ beibehalten. -### 3.2 Schlussfolgerung aus externem Stand +### Unsicherheit / nicht verifizierbar +- Vollständige CVE-Mapping-Konsistenz über alle Datenbanken am Tag der Analyse: **Nicht verifizierbar**. -- Das libxml2-Ökosystem bewegt sich schnell (2.14/2.15 mit relevanten API/Build-/Security-Änderungen). -- Alte Mindestversionsgrenzen (2.6.x) sind nicht mehr zeitgemäß als Security-Basis. +--- -### 3.3 Offen / unklar / nicht verifizierbar +## 4) Architekturvergleich XML vs JSON -- Ob alle in 2.15.2 genannten CVE-Einträge bereits vollständig in allen öffentlichen Datenbanken normalisiert/enriched sind, ist nicht vollständig verifizierbar. +## 4.1 XML-Seite -## 4) Gap-Analyse: Repo vs. aktueller Stand +### Belegt im Repo +- XML-Logik ist funktional in mehrere konkrete Stellen verteilt (Request-Processor, Variable-Evaluation, Operatoren). +- Es gibt **kein** XML-Äquivalent zu `JSONAdapter`/`JsonEventSink`, also kein austauschbares XML-Backend-Contract. -## Belegt im Repo -- Mindestversion 2.6.29 (Autotools), Windows-Pin 2.12.6. -- XML-Schutz gegen externe Entitäten über globalen Callback-Schalter, nicht über `XML_PARSE_NO_XXE`. +### Schlussfolgerung +- XML ist integriert, aber weniger entkoppelt als JSON. -## Belegt extern -- Aktueller Stand 2.15.2 mit Security-Fixes und API/Build-Änderungen. -- Deprecation des im Repo verwendeten globalen Callback-Mechanismus. +## 4.2 JSON-Seite -## Schlussfolgerung / Empfehlung -- Es gibt eine reale Modernisierungslücke, v. a. bei: - 1) Versionspolicy, - 2) Security-Optionierung, - 3) Nutzung deprecated globaler Loader-Hooks. +### Belegt im Repo +- JSON folgt einem klaren Modul-/Interface-Muster mit getrennten Backends und normalisiertem Ergebnis-/Fehlerkonzept. -## 5) Einfluss auf die Integration einer neuen JSON-Bibliothek +### Schlussfolgerung +- JSON zeigt ein praktikables Architekturpattern, das für XML übertragbar ist (zumindest teilweise). + +## 4.3 Datenfluss XML/JSON ### Belegt im Repo -- JSON ist bereits über `JSONAdapter` von XML entkoppelt. -- Backend-Auswahl für JSON existiert (`simdjson`/`jsoncons`). +- Gemeinsamer Dispatcher in `Transaction::processRequestBody` (Auswahl über Processor-Typ). +- Getrennte Processor-Objekte (`m_xml`, `m_json`) mit ähnlichem Lifecycle (`init/processChunk/complete`). + +### Schlussfolgerung +- Es gibt bereits ein gemeinsames Lebenszyklusmuster, aber keine gemeinsame Backend-Abstraktionsebene. + +--- + +## 5) Bewertung: Soll libxml2 als eigenes Modul gekapselt werden? + +## 5.1 Technische Kriterien + +### Kopplungsgrad +- **Belegt im Repo:** libxml2-Aufrufe sitzen in mehreren Fachstellen ohne zentrales XML-Backend-Interface. +- **Schlussfolgerung:** Kapselung reduziert direkte API-Abhängigkeit im Restcode. + +### Austauschbarkeit +- **Belegt im Repo:** JSON ist per Adapter austauschbarer als XML. +- **Schlussfolgerung:** XML-Kapselung würde Austauschbarkeit erhöhen (auch wenn ein kompletter Parserwechsel nicht kurzfristig geplant ist). + +### Testbarkeit +- **Belegt im Repo:** JSON-Backends haben dedizierte Tiefen-/Backend-Tests; XML hat Funktions-/Regressionstests, aber keine analoge Backend-Schicht. +- **Schlussfolgerung:** Modulgrenze würde gezieltere XML-Unit-Tests erleichtern. -### Schlussfolgerung / Empfehlung -- Ein libxml2-Upgrade ist **nicht Voraussetzung**, um eine neue JSON-Bibliothek technisch zu integrieren. -- Für saubere Gesamtarchitektur ist eher eine gemeinsame Parsing-Abstraktion (einheitliche Fehler-/Limits-/Telemetry-Schnittstelle) relevant als ein Austausch von libxml2. +### Wartbarkeit / Build / Plattform +- **Belegt im Repo:** Uneinheitliche Versionierung + deprecated API-Nutzung + Plattformunterschiede. +- **Schlussfolgerung:** Kapselung vereinfacht zukünftige Migrationsschritte. -## 6) Klare Entscheidungsantwort +## 5.2 Architektur-Fazit (Pflichtentscheidung) -**Teilweise: libxml2 kann bleiben, aber die Einbindung sollte modernisiert werden.** +**Ergebnis: Teilweise sinnvoll (mit klarer Tendenz zu „Ja, modularisieren“).** -Begründung: -- **Ja zur Modernisierung** wegen Security-/Wartbarkeitsaspekten (deprecated Loader-Hook, veraltete Mindestversion, fehlende explizite NO_XXE-Optionierung). -- **Nein zur These „nur wegen JSON muss libxml2 raus“**: JSON-Pfade sind bereits gekapselt; der Integrationsengpass liegt nicht primär in libxml2. +Warum nicht „sofort voll Ja“? +- Weil der aktuelle Code funktional arbeitet und Refactoring-Aufwand/Regressionen real sind. -## 7) Priorisierte Maßnahmen +Warum nicht „Nein“? +- Weil JSON bereits beweist, dass ein Adapter-Modell in diesem Projekt funktioniert und Mehrwert bringt. -### Kurzfristig (niedriger bis mittlerer Eingriff) +### Risiken +- Performance-Overhead: bei dünner Wrapper-Schicht i. d. R. gering; muss gemessen werden. +- Refactoring-Aufwand: mittel bis hoch je Scope. +- ABI/API-Risiken: beherrschbar, wenn öffentliche API unverändert bleibt und nur interne Schicht eingezogen wird. +- Versteckte Abhängigkeiten: möglich; über schrittweise Migration + Regression/Fuzzing abfedern. -1. **Versions-Policy anheben** - - Mindestversion für libxml2 im Build auf einen sicher gepflegten Bereich anheben (z. B. 2.12.10+ oder 2.14+ je Plattformstrategie). - - Warum: reduziert Risiko bekannter Schwachstellen auf Altversionen. +### Unsicherheit / nicht verifizierbar +- Exakter Runtime-Impact ohne Benchmarks: **Nicht verifizierbar**. -2. **Explizite XXE-Härtung ergänzen** - - Zusätzlich zu bestehender Logik `XML_PARSE_NO_XXE` (wo verfügbar) setzen. - - Warum: dokumentierter Best-Practice-Mechanismus für untrusted XML. +--- -3. **Tests erweitern** - - Regressionen für XXE/DTD/XInclude/Entity-Edgecases in Matrix über mehrere libxml2-Versionen. +## 6) Gesamtentscheidung (kombiniert) -### Mittelfristig (mittlerer Eingriff) +1. **Soll libxml2 aktualisiert/erneuert werden?** + - **Ja, Aktualisierung/Modernisierung empfohlen.** + - Begründung: Versionsabstand, Security-/API-Entwicklung upstream, deprecated API im aktuellen Codepfad. -4. **Globalen Loader-Hook ablösen** - - Migration von `xmlParserInputBufferCreateFilenameDefault` zu kontextbezogenen Loader-APIs. - - Warum: deprecated API, globaler Schalter ist fehleranfällig in Multi-Thread-/Multi-Request-Szenarien. +2. **Soll libxml2 modularisiert werden (wie JSON)?** + - **Teilweise sinnvoll (empfohlen als schrittweise interne Modularisierung).** + - Begründung: verbessert Entkopplung, Testbarkeit, Konsistenz mit JSON-Architektur. -5. **Build-Matrix harmonisieren** - - Linux/Windows auf konsistentere libxml2-Zielversionen bringen; Policy dokumentieren. +3. **Ist libxml2 ein Hindernis für JSON-Integration?** + - **Nein, nicht der primäre Engpass.** + - Begründung: JSON besitzt bereits eigene Backend-Abstraktion; Engpass liegt eher in fehlender formatübergreifender Vereinheitlichung. -### Langfristig (mittlerer bis höherer Eingriff) +--- -6. **Parser-Abstraktion vereinheitlichen (XML/JSON)** - - Gemeinsame Schicht für Limits, Fehlernormalisierung, Telemetrie, Cancellation. - - Nutzen: Neue JSON-Bibliotheken und XML-Änderungen lassen sich mit geringerem Risiko integrieren. +## 7) Maßnahmenplan -## 8) Offene Unsicherheiten / nicht verifizierbare Punkte +## Kurzfristig (1–3 Sprints) -- Reale Produktionsversionen pro Zielplattform: **Nicht verifizierbar.** -- Exakte Laufzeit-ABI-Risiken in allen Downstream-Packages ohne Zielumgebungen: **Nicht verifizierbar.** +1. **Version-Policy festziehen** +- Änderung: Mindestversion im Build und CI-Matrix anheben; Windows-Pin überprüfen. +- Warum: reduziert bekannte Risiken alter Stände. +- Risiko bei Nicht-Umsetzung: höheres Security-/Maintenance-Risiko. +- Aufwand: niedrig-mittel. +- Nutzen: hoch. + +2. **Security-Defaults modernisieren** +- Änderung: nach verfügbarer libxml2-Version explizite sichere Optionen/API nutzen (z. B. `XML_PARSE_NO_XXE`, kontextbezogene Loader wo möglich). +- Risiko bei Nicht-Umsetzung: Abhängigkeit von legacy/deprecated Verhalten. +- Aufwand: mittel. +- Nutzen: hoch. + +3. **Sicherheits-Testmatrix erweitern** +- Änderung: zusätzliche XXE/Entity/XInclude/DTD-Edgecases + Parallelitätsfälle. +- Aufwand: mittel. +- Nutzen: hoch. + +## Mittelfristig (3–6 Sprints) + +4. **XML-Backend-Fassade einführen (intern, ohne API-Bruch)** +- Änderung: Interface ähnlich JSON-Contract (z. B. `XmlParseResult`, `XmlParseOptions`, `XmlEventSink` oder schlankere Variante) und zentraler Adapter für libxml2. +- Aufwand: mittel-hoch. +- Nutzen: hoch (Entkopplung/Testbarkeit). + +5. **Direkte libxml2-Aufrufe bündeln** +- Änderung: schrittweise Migration aus `variables/xml.cc`, `operators/*`, `request_body_processor/xml.cc` in Modulgrenze. +- Aufwand: mittel-hoch. +- Risiko: Regressionen ohne ausreichende Tests. + +## Langfristig (6+ Sprints) + +6. **Gemeinsames Parser-Framework XML/JSON** +- Änderung: vereinheitlichte Fehler-/Limit-/Telemetry-Schnittstelle für strukturierte Formate. +- Aufwand: hoch. +- Nutzen: hoch (Konsistenz, Erweiterbarkeit für weitere Formate). + +7. **Kontinuierliche Security-/Dependency-Governance** +- Änderung: feste Upgrade-Frequenz, CVE-Triage-Routine, Release-Checklisten. +- Aufwand: mittel. +- Nutzen: hoch. + +--- + +## 8) Unsicherheiten / nicht verifizierbare Punkte + +- Konkrete produktive libxml2-Versionen und Backports pro Zielplattform: **Nicht verifizierbar.** +- Exakte Performance-Auswirkung einer XML-Fassade ohne Benchmark-Läufe: **Nicht verifizierbar.** +- Vollständiger CVE-Abdeckungsgrad je Distribution/Packager: **Nicht verifizierbar.** + +--- ## 9) Quellen -### Repository-Quellen +## Repository-Quellen - `build/libxml.m4` - `build/win32/conanfile.txt` - `build/win32/README.md` +- `build/win32/CMakeLists.txt` +- `configure.ac` - `src/modsecurity.cc` - `src/transaction.cc` - `src/request_body_processor/xml.cc` +- `src/request_body_processor/json.h` +- `src/request_body_processor/json_backend.h` +- `src/request_body_processor/json_adapter.cc` +- `src/request_body_processor/json_backend_simdjson.cc` +- `src/request_body_processor/json_backend_jsoncons.cc` - `src/variables/xml.cc` - `src/operators/validate_dtd.cc` - `src/operators/validate_schema.cc` -- `src/request_body_processor/json_adapter.cc` -- `configure.ac` - `test/test-cases/regression/config-xml_external_entity.json` -- `test/regression/regression.cc` +- `test/unit/json_backend_depth_tests.cc` +- `test/run-json-backend-matrix.sh` - `test/fuzzer/Makefile.am` -### Externe Primärquellen -- GNOME libxml2 Release-Archiv (Index): +## Externe Primärquellen +- GNOME release index: - https://download.gnome.org/sources/libxml2/ - https://download.gnome.org/sources/libxml2/2.15/ - https://download.gnome.org/sources/libxml2/2.14/ @@ -187,11 +285,9 @@ Begründung: - https://download.gnome.org/sources/libxml2/2.15/libxml2-2.15.2.news - https://download.gnome.org/sources/libxml2/2.15/libxml2-2.15.0.news - https://download.gnome.org/sources/libxml2/2.14/libxml2-2.14.0.news - - https://download.gnome.org/sources/libxml2/2.14/libxml2-2.14.5.news - - https://download.gnome.org/sources/libxml2/2.14/libxml2-2.14.6.news - https://download.gnome.org/sources/libxml2/2.12/libxml2-2.12.10.news - Offizielle API-Doku: - https://gnome.pages.gitlab.gnome.org/libxml2/html/parser_8h.html - https://gnome.pages.gitlab.gnome.org/libxml2/html/xmlIO_8h.html -- NVD (CVE-Referenz): +- CVE/NVD: - https://nvd.nist.gov/vuln/detail/CVE-2025-24928 From bb4b5a77aa47c83a2bf41966d8f8b6da286f0760 Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Tue, 14 Apr 2026 21:34:25 +0200 Subject: [PATCH 4/4] docs: deliver strict libxml2/json audit with packaging and monitoring --- docs/libxml2-json-review-2026-04-14.md | 446 +++++++++++++++---------- 1 file changed, 265 insertions(+), 181 deletions(-) diff --git a/docs/libxml2-json-review-2026-04-14.md b/docs/libxml2-json-review-2026-04-14.md index ef051a39f3..c2fb80b4cf 100644 --- a/docs/libxml2-json-review-2026-04-14.md +++ b/docs/libxml2-json-review-2026-04-14.md @@ -1,293 +1,377 @@ -# libxml2 / JSON Architektur- und Dependency-Review (Stand: 2026-04-14) +# libxml2 Security-/Architektur-/Dependency-Audit (Stand: 2026-04-14) -Ziel dieses Dokuments ist eine belastbare Bewertung von Nutzung, Sicherheitslage, Wartbarkeit und Integrationsfähigkeit von **libxml2** im Projekt – inklusive Vergleich mit dem aktuellen öffentlichen Stand sowie expliziter Bewertung einer **Modularisierung von libxml2 analog zur JSON-Architektur**. +## 1. Executive Summary + +### Im Repo belegt +- libxml2 wird aktiv für XML-Request-Body-Parsing, XPath-Variablen und DTD/XSD-Validierung verwendet. +- Die Integration ist buildseitig optional (`WITH_LIBXML2`), funktional aber kritisch für XML-Regeln. +- JSON ist bereits über eine klarere Backend-Abstraktion (simdjson/jsoncons + `JSONAdapter`/`JsonEventSink`) modularisiert. +- YAJL ist im C/C++-Codepfad nicht mehr nachweisbar, aber in README/CI weiterhin als Dependency referenziert. + +### Extern belegt +- Upstream libxml2 steht bei 2.15.2 (März 2026). +- Offizielle API-Doku markiert die im Repo genutzte globale Loader-Umschaltung als deprecated. +- Debian/Ubuntu zeigen, dass numerisch ältere Paketstände weiterhin Security-Backports erhalten; Fedora und Homebrew liegen näher an aktuellen Upstream-Ständen. + +### Schlussfolgerung +- **libxml2 sollte modernisiert werden** (Version-/Security-/API-Härtung). +- **libxml2 ist aktuell nicht der Primär-Blocker für JSON-Migration**. +- **Modularisierung von libxml2 ist sinnvoll, aber gestaffelt** (nicht als Big-Bang parallel zur JSON-Ablösung). +- **Release-/Advisory-Monitoring-Workflow ist empfehlenswert**, aber als „monitor + report + manuelle Freigabe“, nicht als blindes Auto-Upgrade. + +### Unsicherheit / nicht verifizierbar +- Produktiv tatsächlich eingesetzte libxml2-Versionen außerhalb CI/Windows-Conan: **Nicht verifizierbar.** --- -## 1) Executive Summary +## 2. Repo-Befunde zu libxml2 + +### Im Repo belegt -### Belegt im Repo -- libxml2 wird für XML-Request-Body-Parsing, XPath-basierte Variablen, DTD-Validierung und XSD-Validierung genutzt. -- Die Einbindung ist optional (`WITH_LIBXML2`), aber funktional tief in XML-Features integriert. -- Autotools fordert nur `libxml2 >= 2.6.29`; Windows-Conan pinnt `2.12.6`. -- XML-Sicherheitssteuerung erfolgt aktuell über globalen Loader-Callback (`xmlParserInputBufferCreateFilenameDefault`), während JSON über eine klarere Backend-Abstraktion (`JSONAdapter` + `JsonEventSink`) geführt wird. +#### Code-Nutzung +- Globale Initialisierung/Shutdown: `xmlInitParser()`/`xmlCleanupParser()` in `src/modsecurity.cc`. +- Request-Body-XML-Parsing: Push-Parser + SAX in `src/request_body_processor/xml.cc`. +- XPath-Auswertung: `src/variables/xml.cc`. +- DTD-Validierung: `src/operators/validate_dtd.cc`. +- XSD-Validierung: `src/operators/validate_schema.cc`. +- Dispatcher XML/JSON: `src/transaction.cc`. -### Belegt durch externe Quellen -- Upstream-Stand ist 2.15.x (aktueller Index: 2.15.2 in März 2026). -- 2.14/2.15 enthalten API/ABI- und Sicherheitsrelevanz (u. a. SONAME-Änderung in 2.14.0, Security-Fixes in neueren Releases). -- Offizielle API-Doku markiert `xmlParserInputBufferCreateFilenameDefault` als deprecated und empfiehlt kontextbezogene Loader-Mechanismen. +#### Sicherheitsrelevante Befunde +- Externe Entitäten werden über `SecXMLExternalEntity` via globalen Loader-Callback gesteuert (`xmlParserInputBufferCreateFilenameDefault`). +- Parseroptionen setzen sichtbar `XML_PARSE_NOWARNING | XML_PARSE_NOERROR`. +- Sichtbarer Einsatz von `XML_PARSE_NO_XXE` im XML-Body-Parserpfad: nicht belegt. + +#### Build/Dependency +- Autotools-Mindestversion für libxml2: `2.6.29`. +- Windows-Conan pinnt `libxml2/2.12.6`. +- CI testet mit und ohne `--without-libxml`. + +#### Tests/Fuzzing +- Mehrere Regressionsfälle mit Resource-Gate `libxml2`. +- Expliziter XXE-Regressionsfall (`config-xml_external_entity.json`). +- Fuzzer-Linking enthält `$(LIBXML2_LDADD)`. + +### Extern belegt +- Keine externen Quellen für diese Repo-internen Fakten erforderlich. ### Schlussfolgerung -- **Update/Modernisierung von libxml2-Einbindung ist sinnvoll** (Security + Wartbarkeit + Zukunftsfähigkeit). -- **libxml2 ist nicht der primäre Blocker für neue JSON-Bibliothek**. -- **Modularisierung von libxml2 ist teilweise sinnvoll bis empfohlen**: nicht zwingend für Funktionalität heute, aber klar vorteilhaft für Konsistenz, Testbarkeit und künftige Parser-Vereinheitlichung. +- libxml2 ist für XML-Features technisch zentral. +- Sicherheitskontrolle ist vorhanden, aber über global/deprecated Mechanismus statt moderner, kontextbezogener API. +- Versionierungsstrategie wirkt inkonsistent (sehr alte Mindestgrenze vs. neuerer Windows-Pin). ### Unsicherheit / nicht verifizierbar -- Reale Produktionsversionen je Zielumgebung sind aus dem Repo allein nicht bestimmbar. **Nicht verifizierbar.** +- Thread-Safety-Auswirkungen des globalen Loader-Umschaltens unter realer Parallelität sind aus dem Repo allein **nicht vollständig verifizierbar**. --- -## 2) Repo-Befunde +## 3. Repo-Befunde zur JSON-Migration (YAJL → neue Bibliothek) -## 2.1 Includes, Build, Versionen +### Im Repo belegt +- `configure.ac` unterstützt `--with-json-backend=simdjson|jsoncons`. +- JSON-Backends sind separat implementiert (`json_backend_simdjson.cc`, `json_backend_jsoncons.cc`) und über `JSONAdapter` abstrahiert. +- `JsonEventSink`/`JsonParseResult` bilden ein konsistentes Contract-Modell. +- Es existieren dedizierte Backend-Tests (`json_backend_depth_tests`) und eine Matrix-Ausführung (`test/run-json-backend-matrix.sh`). +- YAJL-Nutzung im C/C++-Codepfad: durch Suche nach `yajl`/YAJL-Includes nicht belegt. +- YAJL-Referenzen verbleiben in README und CI-Paketinstallation. -### Belegt im Repo -- Build-Minimum in Autotools: `MSC_CHECK_LIB(... MIN_VERSION [2.6.29] ...)`. -- Windows-Build (Conan): `libxml2/2.12.6`. -- Windows-Readme bestätigt ebenfalls libxml2 2.12.6. -- CMake Windows koppelt `WITH_LIBXML2` an `LibXml2::LibXml2`. +### Extern belegt +- Nicht erforderlich für Repo-Befund. ### Schlussfolgerung -- Versionspolitik ist uneinheitlich (sehr altes Mindestlevel vs. fester mittlerer Pin auf Windows). +- Die neue JSON-Schicht ist klar modularer als XML. +- Der Zustand ist konsistent mit einer laufenden/weit fortgeschrittenen Ablösung von YAJL im Kerncode, bei verbleibenden Dokumentations-/CI-Resten. ### Unsicherheit / nicht verifizierbar -- Linux-Distributionen können Backports liefern; ohne Ziel-Distroliste **nicht verifizierbar**. - -## 2.2 Code-Kopplung und Nutzungsarten +- Exakter Migrationsstatus in nicht sichtbaren Branches/Downstreams: **Nicht verifizierbar.** -### Belegt im Repo -- Initialisierung global in `ModSecurity` via `xmlInitParser()` / `xmlCleanupParser()`. -- XML-Request-Parsing in `src/request_body_processor/xml.cc` per Push-Parser (`xmlCreatePushParserCtxt`, `xmlParseChunk`) plus SAX-Callbacks für `SecParseXmlIntoArgs`. -- XPath-Nutzung in `src/variables/xml.cc` (`xmlXPathEvalExpression`, Namespace-Registrierung). -- DTD-Validierung (`xmlParseDTD`, `xmlValidateDtd`) in `validate_dtd.cc`. -- XSD-Validierung (`xmlSchema*`) in `validate_schema.cc`. -- XML-Verarbeitung wird in `Transaction::processRequestBody` neben JSON-Verarbeitung geschaltet. +--- -### Schlussfolgerung -- libxml2-Aufrufe sind nicht überall verstreut, aber auch nicht durch ein zentrales XML-Backend-Interface isoliert (anders als JSON). +## 4. Aktueller externer Stand zu libxml2 -## 2.3 Fehlerbehandlung und Security-relevante Optionen +### Extern belegt +- GNOME Release-Index führt libxml2 2.15.x, inklusive `LATEST-IS-2.15.2`. +- 2.14.0 Release Notes: SONAME-Änderung (`libxml2.so.2` → `libxml2.so.16`) und ABI-Hinweise. +- 2.15.0 Release Notes: u. a. Wegfall built-in HTTP/LZMA-Komponenten. +- 2.15.2 Release Notes: mehrere Security-Fixes/CVE-Referenzen. +- 2.12.10 Release Notes enthalten u. a. CVE-2025-24928 / CVE-2024-56171. +- NVD führt CVE-2025-24928 mit betroffenen älteren Versionen. +- Offizielle API-Doku: + - `xmlParserInputBufferCreateFilenameDefault` deprecated (`xmlIO_8h`). + - `XML_PARSE_NO_XXE` als relevante Sicherheitsoption (`parser_8h`). -### Belegt im Repo -- Parseroptionen setzen `XML_PARSE_NOWARNING | XML_PARSE_NOERROR`. -- Externe Entitäten werden über `SecXMLExternalEntity` gesteuert: - - ON: Default-Loader, - - sonst: Callback liefert `nullptr`. -- Regressionsfälle für XXE-Szenarien sind vorhanden (`config-xml_external_entity.json`). +### Im Repo belegt +- Nicht anwendbar. ### Schlussfolgerung -- Es existiert Schutzlogik, aber in Form eines globalen Mechanismus statt kontextbezogener Härtung. +- Upstream entwickelt sich sicherheits- und API-seitig aktiv; mittelfristiges „stehen bleiben“ erhöht Wartungs- und Security-Risiko. ### Unsicherheit / nicht verifizierbar -- Ob alle denkbaren Entity/Resource-Edgecases (z. B. bei parallel laufenden Konfigurationen) vollständig abgedeckt sind, aus vorhandenen Tests allein **nicht verifizierbar**. +- Vollständige CVE-Enrichment-Konsistenz über alle Datenbanken am selben Tag: **Nicht verifizierbar.** -## 2.4 JSON-Architektur im Repo (Vergleichsmuster) +--- -### Belegt im Repo -- Konfigurierbare Backends: `--with-json-backend=simdjson|jsoncons`. -- Gemeinsames Backend-Interface (`JsonEventSink`, `JsonParseResult`, `JsonBackendParseOptions`). -- Adapter-Schicht (`JSONAdapter`) wählt Backend über Compile-Time-Defines. -- Separate Backend-Implementierungen (`json_backend_simdjson.cc`, `json_backend_jsoncons.cc`) + dedizierte Tests (`json_backend_depth_tests`, Backend-Matrix-Script). +## 5. Linux- und macOS-Versions-/Packaging-Vergleich -### Schlussfolgerung -- JSON ist strukturell modularer/abstrakter als XML. -- Dieses Muster ist als Referenz für libxml2-Kapselung geeignet. +### Extern belegt ---- +#### Linux +- Debian Security Tracker zeigt für stabile Releases numerisch ältere Versionsstände mit separaten Security-Updates/DSA/DLA (Backport-Modell). +- Ubuntu Paket-/USN-Seiten zeigen ebenfalls ältere Versionsnummern mit Security-Notices/Updates. +- Fedora-Paketseite listet deutlich neuere Stände (z. B. 2.12.10 in Fedora-Releases laut gelisteter Übersicht). -## 3) Externer Stand zu libxml2 (Internet-Abgleich) +#### macOS +- Homebrew `libxml2`-API zeigt `stable: 2.15.2`, `keg_only` mit Grund `provided_by_macos`. +- Das belegt zugleich die Trennung zwischen systembereitgestellter libxml2 und explizit installierter Homebrew-Variante. -### Belegt durch externe Quellen -- Release-Index listet aktuell 2.15.x mit `LATEST-IS-2.15.2` (2026-03-04). -- 2.14.0 Release Notes: SONAME-Sprung (`libxml2.so.2` -> `libxml2.so.16`) und Binärkompatibilität nur innerhalb 2.14+. -- 2.15.0 Release Notes: Wegfall built-in HTTP/LZMA-Komponenten u. a. technische Änderungen. -- 2.15.2 Release Notes: mehrere Security-Fixes/CVE-Referenzen. -- 2.12.10 Release Notes: Fixes inkl. CVE-2025-24928 / CVE-2024-56171. -- NVD bestätigt CVE-2025-24928 als relevant für ältere Versionen (<2.12.10 bzw. 2.13.6). -- Offizielle API-Doku: - - `XML_PARSE_NO_XXE` als relevante Sicherheitsoption, - - `xmlParserInputBufferCreateFilenameDefault` deprecated, - - `XML_PARSE_NONET` seit 2.15 nur noch begrenzt relevant (kein built-in network client). +### Im Repo belegt +- CI installiert auf Linux `libxml2-dev` (APT) und auf macOS `brew install libxml2`. ### Schlussfolgerung -- Der Upstream-Stand liegt deutlich über der in Teilen des Repos sichtbaren Versionierungspolitik. -- Security- und API-Entwicklung nahelegt: Modernisierung statt „as-is“ beibehalten. +- Reiner Versionsnummernvergleich reicht nicht: Debian/Ubuntu können numerisch ältere, aber security-gepflegte Pakete liefern. +- Für reproduzierbare Sicherheitsbewertung muss das Projekt klarer festlegen, ob Systempakete, Homebrew/Conan oder pin-basierte Vendor-Strategie maßgeblich sind. ### Unsicherheit / nicht verifizierbar -- Vollständige CVE-Mapping-Konsistenz über alle Datenbanken am Tag der Analyse: **Nicht verifizierbar**. +- Exakte Backport-Abdeckung aller relevanten CVEs je Distribution/Release ohne vollständige Advisory-Matrix: **Nicht verifizierbar.** --- -## 4) Architekturvergleich XML vs JSON +## 6. Sicherheitsbewertung -## 4.1 XML-Seite +### Im Repo belegt +- XML-Eingaben sind untrusted Request-Body-Daten. +- Schutz gegen externe Entitäten basiert aktuell auf globalem Loader-Override. +- `XML_PARSE_NO_XXE`-Setzung im gezeigten XML-Body-Pfad ist nicht belegt. +- XML und JSON laufen beide über denselben Request-Body-Dispatcher, aber mit separaten Prozessoren. -### Belegt im Repo -- XML-Logik ist funktional in mehrere konkrete Stellen verteilt (Request-Processor, Variable-Evaluation, Operatoren). -- Es gibt **kein** XML-Äquivalent zu `JSONAdapter`/`JsonEventSink`, also kein austauschbares XML-Backend-Contract. +### Extern belegt +- Deprecated-Status des globalen Loader-Mechanismus. +- Vorhandensein aktueller Sicherheitsfixes in neueren libxml2-Releases. ### Schlussfolgerung -- XML ist integriert, aber weniger entkoppelt als JSON. +- Sicherheit ist **teilweise abgesichert**, aber nicht auf dem robustesten verfügbaren Mechanismus. +- Zentralisierte Sicherheitsdefaults in einer XML-Fassade würden das Risiko inkonsistenter Parser-Konfiguration senken. -## 4.2 JSON-Seite +### Unsicherheit / nicht verifizierbar +- Ob alle Angriffsvektoren (insb. Race-/Global-State-Randfälle) unter Produktionslast abgedeckt sind: **Nicht verifizierbar.** -### Belegt im Repo -- JSON folgt einem klaren Modul-/Interface-Muster mit getrennten Backends und normalisiertem Ergebnis-/Fehlerkonzept. +--- -### Schlussfolgerung -- JSON zeigt ein praktikables Architekturpattern, das für XML übertragbar ist (zumindest teilweise). +## 7. Architekturvergleich: libxml2 vs. neue JSON-Schicht -## 4.3 Datenfluss XML/JSON +### Im Repo belegt +- JSON: klarer Backend-Contract (`JsonEventSink`, Result-Typen), Adapter (`JSONAdapter`), austauschbare Implementierungen, dedizierte Backendspezifik-Tests. +- XML: direkte libxml2-Aufrufe in mehreren Fachkomponenten ohne zentrales XML-Backend-Interface. -### Belegt im Repo -- Gemeinsamer Dispatcher in `Transaction::processRequestBody` (Auswahl über Processor-Typ). -- Getrennte Processor-Objekte (`m_xml`, `m_json`) mit ähnlichem Lifecycle (`init/processChunk/complete`). +### Extern belegt +- Nicht erforderlich. ### Schlussfolgerung -- Es gibt bereits ein gemeinsames Lebenszyklusmuster, aber keine gemeinsame Backend-Abstraktionsebene. +- JSON ist architektonisch stärker entkoppelt. +- Das JSON-Muster ist ein konkreter Referenzentwurf für ein XML-Modul (Facade/Adapter/Options/Result-Contract). + +### Unsicherheit / nicht verifizierbar +- Netto-Performanceeffekt einer XML-Adapter-Schicht ohne Benchmarks: **Nicht verifizierbar.** --- -## 5) Bewertung: Soll libxml2 als eigenes Modul gekapselt werden? +## 8. Bewertung: libxml2 als Modul integrieren oder nicht -## 5.1 Technische Kriterien +### Kategorie +**Ja, aber nur in einem gestaffelten Ansatz.** -### Kopplungsgrad -- **Belegt im Repo:** libxml2-Aufrufe sitzen in mehreren Fachstellen ohne zentrales XML-Backend-Interface. -- **Schlussfolgerung:** Kapselung reduziert direkte API-Abhängigkeit im Restcode. +### Im Repo belegt +- XML ist aktuell weniger modular als JSON. +- Direkte libxml2-Nutzung existiert an mehreren Stellen. -### Austauschbarkeit -- **Belegt im Repo:** JSON ist per Adapter austauschbarer als XML. -- **Schlussfolgerung:** XML-Kapselung würde Austauschbarkeit erhöhen (auch wenn ein kompletter Parserwechsel nicht kurzfristig geplant ist). +### Extern belegt +- Upstream/API-Situation (deprecated global loader + laufende Security-Fixes) stützt die Notwendigkeit zentraler Kontrolle. -### Testbarkeit -- **Belegt im Repo:** JSON-Backends haben dedizierte Tiefen-/Backend-Tests; XML hat Funktions-/Regressionstests, aber keine analoge Backend-Schicht. -- **Schlussfolgerung:** Modulgrenze würde gezieltere XML-Unit-Tests erleichtern. +### Schlussfolgerung +- Modulgrenze bringt Vorteile bei Wartbarkeit, Testbarkeit, Sicherheitsstandardisierung und späteren Upgrades. +- Parallel als Big-Bang zur JSON-Migration wäre unnötig riskant; sinnvoll ist eine sequenzierte Einführung. -### Wartbarkeit / Build / Plattform -- **Belegt im Repo:** Uneinheitliche Versionierung + deprecated API-Nutzung + Plattformunterschiede. -- **Schlussfolgerung:** Kapselung vereinfacht zukünftige Migrationsschritte. +### Unsicherheit / nicht verifizierbar +- Konkreter Refactoring-Aufwand bis auf Funktions-/Dateiebene ohne Spike-Implementierung: **Nicht verifizierbar.** -## 5.2 Architektur-Fazit (Pflichtentscheidung) +--- -**Ergebnis: Teilweise sinnvoll (mit klarer Tendenz zu „Ja, modularisieren“).** +## 9. Bewertung: Ist direkte Modulbildung sicher -Warum nicht „sofort voll Ja“? -- Weil der aktuelle Code funktional arbeitet und Refactoring-Aufwand/Regressionen real sind. +### Im Repo belegt +- Es gibt aktuell globale libxml2-Steuerungspunkte und direkte API-Aufrufe in Fachcode. -Warum nicht „Nein“? -- Weil JSON bereits beweist, dass ein Adapter-Modell in diesem Projekt funktioniert und Mehrwert bringt. +### Extern belegt +- Deprecated API-Hinweise unterstützen eine Umstellung auf zentral kontrollierte, kontextbezogene Ressourcen-/Parserkonfiguration. -### Risiken -- Performance-Overhead: bei dünner Wrapper-Schicht i. d. R. gering; muss gemessen werden. -- Refactoring-Aufwand: mittel bis hoch je Scope. -- ABI/API-Risiken: beherrschbar, wenn öffentliche API unverändert bleibt und nur interne Schicht eingezogen wird. -- Versteckte Abhängigkeiten: möglich; über schrittweise Migration + Regression/Fuzzing abfedern. +### Schlussfolgerung +- **Direkte Modulbildung ist nicht automatisch „sicher“, aber kann sicherer werden**, wenn Guardrails verpflichtend sind: + 1. Zentrale Parser-Defaults (inkl. XXE-/Resource-Policy) im Modul. + 2. Harte Limits (Depth/Size/Entity-Policy) im Modul-Contract. + 3. Einheitliche Fehlerklassifikation und Auditierbarkeit. + 4. Explizite Trennung trusted/untrusted Inputs. + 5. Verbot neuer direkter libxml2-Aufrufe außerhalb des Moduls (CI-Lint/Codeowners). ### Unsicherheit / nicht verifizierbar -- Exakter Runtime-Impact ohne Benchmarks: **Nicht verifizierbar**. +- Ohne diese Guardrails ist die Aussage „Modulbildung ist sicher genug“ **nicht verifizierbar**. --- -## 6) Gesamtentscheidung (kombiniert) +## 10. Bewertung: Release-/Security-Monitoring-Workflow -1. **Soll libxml2 aktualisiert/erneuert werden?** - - **Ja, Aktualisierung/Modernisierung empfohlen.** - - Begründung: Versionsabstand, Security-/API-Entwicklung upstream, deprecated API im aktuellen Codepfad. +### Im Repo belegt +- CI testet Build-Varianten, aber ein dediziertes Release-/Advisory-Monitoring für libxml2 + JSON-Backend ist nicht als eigener Workflow ersichtlich. -2. **Soll libxml2 modularisiert werden (wie JSON)?** - - **Teilweise sinnvoll (empfohlen als schrittweise interne Modularisierung).** - - Begründung: verbessert Entkopplung, Testbarkeit, Konsistenz mit JSON-Architektur. +### Extern belegt +- Upstream-Releases (libxml2, simdjson/jsoncons) ändern sich regelmäßig. +- Distributionen liefern teils Backports, daher reicht „nur Upstream-Version vergleichen“ nicht. -3. **Ist libxml2 ein Hindernis für JSON-Integration?** - - **Nein, nicht der primäre Engpass.** - - Begründung: JSON besitzt bereits eigene Backend-Abstraktion; Engpass liegt eher in fehlender formatübergreifender Vereinheitlichung. +### Schlussfolgerung +**Empfehlung: beobachten + reporten + manuell freigegebene Updates.** ---- +- **Release Monitoring:** Ja (Upstream libxml2 + verwendetes JSON-Backend). +- **Security Advisory Monitoring:** Ja (CVE/NVD + distro advisories). +- **Automatisches Upgrade:** Nein, nicht blind. +- **Manuell freigegebener Update-Prozess:** Ja. -## 7) Maßnahmenplan +Pragmatisches Modell: +1. Geplanter Workflow (z. B. wöchentlich) sammelt Versionen/Advisories. +2. Erzeugt Report + optional GitHub Issue/PR-Kommentar. +3. Menschen entscheiden über Upgrade/Patchbackport nach Testmatrix. -## Kurzfristig (1–3 Sprints) +### Unsicherheit / nicht verifizierbar +- Konkretes Signal-zu-Rauschen-Verhältnis ohne Pilotlauf: **Nicht verifizierbar.** -1. **Version-Policy festziehen** -- Änderung: Mindestversion im Build und CI-Matrix anheben; Windows-Pin überprüfen. -- Warum: reduziert bekannte Risiken alter Stände. -- Risiko bei Nicht-Umsetzung: höheres Security-/Maintenance-Risiko. -- Aufwand: niedrig-mittel. -- Nutzen: hoch. +--- -2. **Security-Defaults modernisieren** -- Änderung: nach verfügbarer libxml2-Version explizite sichere Optionen/API nutzen (z. B. `XML_PARSE_NO_XXE`, kontextbezogene Loader wo möglich). -- Risiko bei Nicht-Umsetzung: Abhängigkeit von legacy/deprecated Verhalten. -- Aufwand: mittel. -- Nutzen: hoch. +## 11. Klare Gesamtentscheidungen -3. **Sicherheits-Testmatrix erweitern** -- Änderung: zusätzliche XXE/Entity/XInclude/DTD-Edgecases + Parallelitätsfälle. -- Aufwand: mittel. -- Nutzen: hoch. +1. **Soll libxml2 aktualisiert oder erneuert werden?** + - **Ja, Aktualisierung/Modernisierung empfohlen.** + - Belege: Upstream 2.15.2, Security-Fixes, deprecated API-Hinweise, Repo nutzt alte Mindestgrenze + globalen Mechanismus. + - Hauptrisiko: Migrations-/Kompatibilitätsaufwand. + - Unsicherheit: konkrete Upgrade-Auswirkungen je Zielplattform **nicht vollständig verifizierbar**. -## Mittelfristig (3–6 Sprints) +2. **Soll libxml2 als eigenes Modul integriert werden?** + - **Ja, aber nur in gestaffeltem Ansatz.** + - Belege: JSON-Adaptermuster vorhanden; XML aktuell weniger entkoppelt. + - Hauptrisiko: Refactoring-Komplexität. -4. **XML-Backend-Fassade einführen (intern, ohne API-Bruch)** -- Änderung: Interface ähnlich JSON-Contract (z. B. `XmlParseResult`, `XmlParseOptions`, `XmlEventSink` oder schlankere Variante) und zentraler Adapter für libxml2. -- Aufwand: mittel-hoch. -- Nutzen: hoch (Entkopplung/Testbarkeit). +3. **Ist jetzt wegen YAJL-Ablösung ein guter Zeitpunkt dafür?** + - **Teilweise ja: vorbereiten jetzt, harte Umstellung gestaffelt.** + - Belege: JSON-Migrationsarchitektur liefert Muster; gleichzeitiger Big-Bang erhöht Risiko. -5. **Direkte libxml2-Aufrufe bündeln** -- Änderung: schrittweise Migration aus `variables/xml.cc`, `operators/*`, `request_body_processor/xml.cc` in Modulgrenze. -- Aufwand: mittel-hoch. -- Risiko: Regressionen ohne ausreichende Tests. +4. **Ist direkte Modulbildung sicher genug?** + - **Nur mit Guardrails.** + - Ohne zentrale Sicherheitsdefaults/Limits/Policy-Enforcement: **nicht sicher genug belastbar belegt**. -## Langfristig (6+ Sprints) +5. **Soll ein Workflow zur Abfrage aktueller Releases/Sicherheitsstände eingeführt werden?** + - **Ja: Monitoring + Reporting + manuelle Freigabe.** + - Kein blindes Auto-Upgrade. -6. **Gemeinsames Parser-Framework XML/JSON** -- Änderung: vereinheitlichte Fehler-/Limit-/Telemetry-Schnittstelle für strukturierte Formate. -- Aufwand: hoch. -- Nutzen: hoch (Konsistenz, Erweiterbarkeit für weitere Formate). +--- -7. **Kontinuierliche Security-/Dependency-Governance** -- Änderung: feste Upgrade-Frequenz, CVE-Triage-Routine, Release-Checklisten. -- Aufwand: mittel. -- Nutzen: hoch. +## 12. Priorisierte Maßnahmen + +## Kurzfristig +1. **Repo-Hygiene YAJL-Reste bereinigen** +- Änderung: README/CI-Dependency-Liste gegen tatsächliche JSON-Backends konsolidieren. +- Ziel: Architektur- und Security-Transparenz. +- Risiko bei Nicht-Umsetzung: falsche Annahmen in Betrieb/Audit. +- Eingriffsgrad: niedrig. +- Plattformauswirkung: gering. +- Testbedarf: CI-Konfig-Tests. +- Sicherheitsauswirkung: indirekt positiv (weniger Drift). + +2. **XML-Sicherheits-Baseline dokumentieren und härten** +- Änderung: explizite Policy für XXE/DTD/externes Laden, Limits, Fehlermeldungsstrategie. +- Eingriffsgrad: niedrig-mittel. +- Sicherheitsauswirkung: hoch. + +3. **Monitoring-Workflow als Report-only einführen** +- Änderung: geplanter Job sammelt libxml2 + JSON-Backend Releases, CVE/NVD, Debian/Ubuntu/Fedora, Homebrew-Stände. +- Ausgabe: maschinenlesbarer Report + optional Issue. +- Sicherheitsauswirkung: hoch. + +## Mittelfristig +4. **XML-Fassade (intern) einführen** +- Änderung: `XmlParseOptions`, `XmlParseResult`, zentrale `XmlProcessor`-Schnittstelle. +- Ziel: Entkopplung/Standardisierung. +- Risiko: Regressionen. +- Eingriffsgrad: mittel-hoch. +- Testbedarf: neue Unit-/Integrationstests + bestehende Regressionen. + +5. **Direkte libxml2-Aufrufe schrittweise konsolidieren** +- Kandidaten: `request_body_processor/xml.cc`, `variables/xml.cc`, `operators/validate_*`. +- Ziel: keine direkten libxml2-Calls außerhalb XML-Modul. +- Sicherheitsauswirkung: mittel-hoch. + +## Langfristig +6. **Formatübergreifendes Parsing-Contract (JSON/XML) harmonisieren** +- Änderung: gemeinsame Prinzipien für Optionen, Limits, Errors, Telemetrie. +- Ziel: konsistente Security- und Wartbarkeitseigenschaften. + +7. **Governance-Prozess für Abhängigkeiten** +- Änderung: feste Review-Kadenz, Security-Triage, manuelle Freigabegates. +- Sicherheitsauswirkung: hoch. --- -## 8) Unsicherheiten / nicht verifizierbare Punkte +## 13. Offene Unsicherheiten / nicht verifizierbare Punkte -- Konkrete produktive libxml2-Versionen und Backports pro Zielplattform: **Nicht verifizierbar.** -- Exakte Performance-Auswirkung einer XML-Fassade ohne Benchmark-Läufe: **Nicht verifizierbar.** -- Vollständiger CVE-Abdeckungsgrad je Distribution/Packager: **Nicht verifizierbar.** +- Produktiv verwendete libxml2-Version je Deployment: **Nicht verifizierbar.** +- Vollständige Backport-Abdeckung aller relevanten CVEs je Linux-Distribution/Release: **Nicht verifizierbar.** +- Genaue Upgrade-Kompatibilität (ABI/API) für alle Downstreams: **Nicht verifizierbar.** +- Exakter Performance-Impact einer XML-Fassade ohne Benchmarks: **Nicht verifizierbar.** +- Eindeutiger Abschlussstatus der YAJL-Migration außerhalb sichtbarer Repo-Artefakte: **Nicht verifizierbar.** --- -## 9) Quellen +## 14. Quellenliste -## Repository-Quellen -- `build/libxml.m4` -- `build/win32/conanfile.txt` -- `build/win32/README.md` -- `build/win32/CMakeLists.txt` -- `configure.ac` +## Repository - `src/modsecurity.cc` - `src/transaction.cc` - `src/request_body_processor/xml.cc` -- `src/request_body_processor/json.h` +- `src/variables/xml.cc` +- `src/operators/validate_dtd.cc` +- `src/operators/validate_schema.cc` - `src/request_body_processor/json_backend.h` - `src/request_body_processor/json_adapter.cc` - `src/request_body_processor/json_backend_simdjson.cc` - `src/request_body_processor/json_backend_jsoncons.cc` -- `src/variables/xml.cc` -- `src/operators/validate_dtd.cc` -- `src/operators/validate_schema.cc` -- `test/test-cases/regression/config-xml_external_entity.json` -- `test/unit/json_backend_depth_tests.cc` +- `configure.ac` +- `build/libxml.m4` +- `build/win32/conanfile.txt` +- `build/win32/README.md` +- `.github/workflows/ci.yml` +- `.github/workflows/ci_new.yml` +- `README.md` - `test/run-json-backend-matrix.sh` +- `test/unit/json_backend_depth_tests.cc` +- `test/test-cases/regression/config-xml_external_entity.json` - `test/fuzzer/Makefile.am` ## Externe Primärquellen -- GNOME release index: +- libxml2 Upstream Releases/Archive: - https://download.gnome.org/sources/libxml2/ - https://download.gnome.org/sources/libxml2/2.15/ - - https://download.gnome.org/sources/libxml2/2.14/ - - https://download.gnome.org/sources/libxml2/2.12/ -- Release Notes: - https://download.gnome.org/sources/libxml2/2.15/libxml2-2.15.2.news - https://download.gnome.org/sources/libxml2/2.15/libxml2-2.15.0.news - https://download.gnome.org/sources/libxml2/2.14/libxml2-2.14.0.news - https://download.gnome.org/sources/libxml2/2.12/libxml2-2.12.10.news -- Offizielle API-Doku: +- Offizielle API-Dokumentation: - https://gnome.pages.gitlab.gnome.org/libxml2/html/parser_8h.html - https://gnome.pages.gitlab.gnome.org/libxml2/html/xmlIO_8h.html -- CVE/NVD: +- CVE-Datenbank: - https://nvd.nist.gov/vuln/detail/CVE-2025-24928 +- Linux-Paketquellen: + - Debian Security Tracker: https://security-tracker.debian.org/tracker/source-package/libxml2 + - Ubuntu Packages (noble): https://packages.ubuntu.com/noble/libxml2-dev + - Ubuntu Security Notice (USN-7743-1): https://ubuntu.com/security/notices/USN-7743-1 + - Fedora Packages: https://packages.fedoraproject.org/pkgs/libxml2/libxml2/ +- macOS/Packaging: + - Homebrew libxml2 API: https://formulae.brew.sh/api/formula/libxml2.json + - Homebrew simdjson API: https://formulae.brew.sh/api/formula/simdjson.json +- JSON-Backend Upstream-Releases: + - simdjson Releases: https://github.com/simdjson/simdjson/releases + - jsoncons Releases: https://github.com/danielaparker/jsoncons/releases