From 226d1f5f066f02a9576ad6f8a1ac23f928e6c0e1 Mon Sep 17 00:00:00 2001 From: Arturo Bernal Date: Sat, 10 Oct 2026 16:41:36 +0200 Subject: [PATCH] core: Reject invalid values of LimitXMLRequestBody. set_limit_xml_req_body() used atol(), so "abc123" and "123abc" were accepted as 0 and 123, and overflows were silently clamped. Parse the whole argument with apr_strtoff() like LimitRequestBody, and reject values that do not fit in limit_xml_body or exceed AP_MAX_LIMIT_XML_BODY. BZ 69975. --- changes-entries/limit-xml-request-body.txt | 2 + server/core.c | 25 ++++++++--- .../core/test_010_limit_xml_request_body.py | 41 +++++++++++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 changes-entries/limit-xml-request-body.txt create mode 100644 test/modules/core/test_010_limit_xml_request_body.py diff --git a/changes-entries/limit-xml-request-body.txt b/changes-entries/limit-xml-request-body.txt new file mode 100644 index 00000000000..666e64db5ea --- /dev/null +++ b/changes-entries/limit-xml-request-body.txt @@ -0,0 +1,2 @@ + *) core: Reject invalid non-numeric values of LimitXMLRequestBody, as + LimitRequestBody does. PR 69975 diff --git a/server/core.c b/server/core.c index b060ce5f64e..e2a94a049e0 100644 --- a/server/core.c +++ b/server/core.c @@ -59,6 +59,8 @@ #include "mod_so.h" /* for ap_find_loaded_module_symbol */ +#include /* for LONG_MAX */ + #if defined(RLIMIT_CPU) || defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS) || defined (RLIMIT_NPROC) #include "unixd.h" #endif @@ -3914,16 +3916,29 @@ static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_, const char *arg) { core_dir_config *conf = conf_; + apr_uint64_t max = AP_MAX_LIMIT_XML_BODY; + apr_off_t limit; + char *errp; - conf->limit_xml_body = atol(arg); - if (conf->limit_xml_body < 0) + if (APR_SUCCESS != apr_strtoff(&limit, arg, &errp, 10)) { + return "LimitXMLRequestBody argument is not parsable."; + } + if (*errp || limit < 0) { return "LimitXMLRequestBody requires a non-negative integer."; + } - /* zero is AP_MAX_LIMIT_XML_BODY (implicitly) */ - if ((apr_size_t)conf->limit_xml_body > AP_MAX_LIMIT_XML_BODY) + /* zero is AP_MAX_LIMIT_XML_BODY (implicitly), and limit_xml_body is + * a long, which is narrower than apr_size_t on some platforms. + */ + if (max > LONG_MAX) { + max = LONG_MAX; + } + if ((apr_uint64_t)limit > max) { return apr_psprintf(cmd->pool, "LimitXMLRequestBody must not exceed " - "%" APR_SIZE_T_FMT, AP_MAX_LIMIT_XML_BODY); + "%" APR_UINT64_T_FMT, max); + } + conf->limit_xml_body = (long)limit; return NULL; } diff --git a/test/modules/core/test_010_limit_xml_request_body.py b/test/modules/core/test_010_limit_xml_request_body.py new file mode 100644 index 00000000000..c57ff612b4d --- /dev/null +++ b/test/modules/core/test_010_limit_xml_request_body.py @@ -0,0 +1,41 @@ +import os + +import pytest + +from pyhttpd.conf import HttpdConf + + +class TestLimitXMLRequestBody: + + # have httpd parse the configuration, like "httpd -t" does + def check_config(self, env, value): + conf = HttpdConf(env) + conf.add(f"LimitXMLRequestBody {value}") + conf.add_vhost_test1() + conf.install() + return env.run([os.path.join(env.bin_dir, 'httpd'), + "-t", "-d", env.server_dir, + "-f", os.path.join(env.server_dir, 'conf', 'httpd.conf')]) + + @pytest.mark.parametrize("value", ["0", "1", "123", "1000000"]) + def test_core_010_001(self, env, value): + r = self.check_config(env, value) + assert r.exit_code == 0, f"{r.stderr}" + + # only a whole non-negative decimal number is a valid limit + @pytest.mark.parametrize("value", [ + "abc123", "123abc", "123foo456", "-1", "1.5", "0x10", "+", "-", + ]) + def test_core_010_002(self, env, value): + r = self.check_config(env, value) + assert r.exit_code != 0, f"{value} was accepted" + assert "LimitXMLRequestBody requires a non-negative integer" in r.stderr + + # more than can be stored or than the directive permits + @pytest.mark.parametrize("value", [ + "9223372036854775807", "9223372036854775808", "9" * 40, + ]) + def test_core_010_003(self, env, value): + r = self.check_config(env, value) + assert r.exit_code != 0, f"{value} was accepted" + assert "LimitXMLRequestBody" in r.stderr