From: Yann Ylavic Date: Fri, 15 Jul 2022 10:46:37 +0000 (+0000) Subject: util_pcre: Restore nmatch < ncaps behaviour with PCRE1 (only). X-Git-Tag: 2.5.0-alpha2-ci-test-only~260 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=97afea48fd328304d74fc174c742518175063ab7;p=thirdparty%2Fapache%2Fhttpd.git util_pcre: Restore nmatch < ncaps behaviour with PCRE1 (only). When the requested nmatch is below the number of captures for the regex (i.e. nmatch is zero if the user does not care about the captures), with PCRE1 we can pass a smaller ovector to pcre_exec() (or even NULL) which allows for somes optimizations (less or even no recursion) internally in pcre. This might avoid crashes due to stack usage/exhaustion with pathological patterns (see BZ 66119). git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1902732 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/server/util_pcre.c b/server/util_pcre.c index 53096ea69c2..e3ee4558375 100644 --- a/server/util_pcre.c +++ b/server/util_pcre.c @@ -484,6 +484,32 @@ AP_DECLARE(int) ap_regexec_len(const ap_regex_t *preg, const char *buff, match_vector_pt ovector = NULL; apr_uint32_t ncaps = (apr_uint32_t)preg->re_nsub + 1; +#ifndef HAVE_PCRE2 + /* This is fine if pcre_exec() gets a vector size smaller than the + * number of capturing groups (it will treat the remaining ones as + * non-capturing), but if the vector is too small to keep track of + * the potential backrefs within the pattern, it will temporarily + * malloc()ate the necessary space anyway. So let's provide a vector + * of at least PCRE_INFO_BACKREFMAX entries (likely zero, otherwise + * the vector is most likely cached already anyway). + * Note that if no captures are to be used by the caller, passing an + * nmatch of zero (thus forcing all groups to be non-capturing) may + * allow for some optimizations and/or less recursion (stack usage) + * with PCRE1, unless backrefs.. + */ + if (ncaps > nmatch) { + int backrefmax = 0; + pcre_fullinfo((const pcre *)preg->re_pcre, NULL, + PCRE_INFO_BACKREFMAX, &backrefmax); + if (backrefmax > 0 && (apr_uint32_t)backrefmax >= nmatch) { + ncaps = (apr_uint32_t)backrefmax + 1; + } + else { + ncaps = nmatch; + } + } +#endif + if (!setup_state(&state, ncaps)) { return AP_REG_ESPACE; }