From 7ea902ca624460bc79d1d05211c3059703fcb3f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Uhliarik?= Date: Tue, 14 Jul 2026 19:48:51 +0200 Subject: [PATCH] Resolves: RHEL-186198 - httpd: Apache HTTP Server: Heap-based Buffer Overflow via untrusted content in mod_xml2enc (CVE-2026-42536) Resolves: RHEL-186166 - httpd: Apache HTTP Server: Buffer Over-read via outbound OCSP requests to attacker-controlled server (CVE-2026-44185) Resolves: RHEL-175620 - httpd:2.4/httpd: NULL pointer dereference via specially crafted request (CVE-2026-29169) Resolves: RHEL-186176 - httpd: Apache HTTP Server: Buffer overflow in mod_proxy_html allows security bypass (CVE-2026-34355) Resolves: RHEL-192751 - mod_proxy_html regression in CVE-2026-34355 fix Resolves: RHEL-193114 - httpd: Apache HTTP Server: Denial of Service in mod_proxy_ftp via attacker-controlled FTP server (CVE-2026-44186) Resolves: RHEL-186219 - httpd: Apache HTTP Server: Heap-based Buffer Overflow via malicious backend servers (CVE-2026-34356) Resolves: RHEL-191243 - httpd: Apache HTTP Server: Out-of-bounds Read in mod_headers and mod_mime (CVE-2026-43951) Resolves: RHEL-184307 - httpd: Apache HTTP Server: Denial of Service via crafted regular expressions (CVE-2026-44631) Resolves: RHEL-182577 - httpd: incomplete fix for CVE-2023-38709 (CVE-2024-42516) --- httpd-2.4.37-CVE-2024-42516.patch | 326 +++++++++++++++++ httpd-2.4.37-CVE-2026-29169.patch | 39 ++ httpd-2.4.37-CVE-2026-34355.patch | 571 ++++++++++++++++++++++++++++++ httpd-2.4.37-CVE-2026-34356.patch | 30 ++ httpd-2.4.37-CVE-2026-42536.patch | 25 ++ httpd-2.4.37-CVE-2026-43951.patch | 16 + httpd-2.4.37-CVE-2026-44185.patch | 30 ++ httpd-2.4.37-CVE-2026-44186.patch | 18 + httpd-2.4.37-CVE-2026-44631.patch | 87 +++++ httpd.spec | 50 ++- 10 files changed, 1191 insertions(+), 1 deletion(-) create mode 100644 httpd-2.4.37-CVE-2024-42516.patch create mode 100644 httpd-2.4.37-CVE-2026-29169.patch create mode 100644 httpd-2.4.37-CVE-2026-34355.patch create mode 100644 httpd-2.4.37-CVE-2026-34356.patch create mode 100644 httpd-2.4.37-CVE-2026-42536.patch create mode 100644 httpd-2.4.37-CVE-2026-43951.patch create mode 100644 httpd-2.4.37-CVE-2026-44185.patch create mode 100644 httpd-2.4.37-CVE-2026-44186.patch create mode 100644 httpd-2.4.37-CVE-2026-44631.patch diff --git a/httpd-2.4.37-CVE-2024-42516.patch b/httpd-2.4.37-CVE-2024-42516.patch new file mode 100644 index 0000000..69b6dd1 --- /dev/null +++ b/httpd-2.4.37-CVE-2024-42516.patch @@ -0,0 +1,326 @@ +diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c +index 8ac2cb4..790351d 100644 +--- a/modules/http/http_filters.c ++++ b/modules/http/http_filters.c +@@ -1284,107 +1284,10 @@ typedef struct header_filter_ctx { + int headers_sent; + } header_filter_ctx; + +-AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, +- apr_bucket_brigade *b) ++static void merge_response_headers(request_rec *r, const char **protocol) + { +- request_rec *r = f->r; +- conn_rec *c = r->connection; +- const char *clheader; +- int header_only = (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status)); +- const char *protocol = NULL; +- apr_bucket *e; +- apr_bucket_brigade *b2; +- header_struct h; +- header_filter_ctx *ctx = f->ctx; +- const char *ctype; +- ap_bucket_error *eb = NULL; +- apr_status_t rv = APR_SUCCESS; +- int recursive_error = 0; +- +- AP_DEBUG_ASSERT(!r->main); +- +- if (!ctx) { +- ctx = f->ctx = apr_pcalloc(r->pool, sizeof(header_filter_ctx)); +- } +- else if (ctx->headers_sent) { +- /* Eat body if response must not have one. */ +- if (header_only) { +- /* Still next filters may be waiting for EOS, so pass it (alone) +- * when encountered and be done with this filter. +- */ +- e = APR_BRIGADE_LAST(b); +- if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) { +- APR_BUCKET_REMOVE(e); +- apr_brigade_cleanup(b); +- APR_BRIGADE_INSERT_HEAD(b, e); +- ap_remove_output_filter(f); +- rv = ap_pass_brigade(f->next, b); +- } +- apr_brigade_cleanup(b); +- return rv; +- } +- } +- +- for (e = APR_BRIGADE_FIRST(b); +- e != APR_BRIGADE_SENTINEL(b); +- e = APR_BUCKET_NEXT(e)) +- { +- if (AP_BUCKET_IS_ERROR(e) && !eb) { +- eb = e->data; +- continue; +- } +- /* +- * If we see an EOC bucket it is a signal that we should get out +- * of the way doing nothing. +- */ +- if (AP_BUCKET_IS_EOC(e)) { +- ap_remove_output_filter(f); +- return ap_pass_brigade(f->next, b); +- } +- } +- +- if (!ctx->headers_sent && !check_headers(r)) { +- /* We may come back here from ap_die() below, +- * so clear anything from this response. +- */ +- apr_table_clear(r->headers_out); +- apr_table_clear(r->err_headers_out); +- r->content_type = r->content_encoding = NULL; +- r->content_languages = NULL; +- r->clength = r->chunked = 0; +- apr_brigade_cleanup(b); +- +- /* Don't recall ap_die() if we come back here (from its own internal +- * redirect or error response), otherwise we can end up in infinite +- * recursion; better fall through with 500, minimal headers and an +- * empty body (EOS only). +- */ +- if (!check_headers_recursion(r)) { +- ap_die(HTTP_INTERNAL_SERVER_ERROR, r); +- return AP_FILTER_ERROR; +- } +- r->status = HTTP_INTERNAL_SERVER_ERROR; +- e = ap_bucket_eoc_create(c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(b, e); +- e = apr_bucket_eos_create(c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(b, e); +- ap_set_content_length(r, 0); +- recursive_error = 1; +- } +- else if (eb) { +- int status; +- status = eb->status; +- apr_brigade_cleanup(b); +- ap_die(status, r); +- return AP_FILTER_ERROR; +- } +- +- if (r->assbackwards) { +- r->sent_bodyct = 1; +- ap_remove_output_filter(f); +- rv = ap_pass_brigade(f->next, b); +- goto out; +- } ++ const char *ctype = NULL; ++ const char *clheader = NULL; + + /* + * Now that we are ready to send a response, we need to combine the two +@@ -1414,6 +1317,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, + fixup_vary(r); + } + ++ /* determine the protocol and whether we should use keepalives. */ ++ basic_http_header_check(r, protocol); ++ ap_set_keepalive(r); + + /* + * Control cachability for non-cacheable responses if not already set by +@@ -1433,10 +1339,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, + apr_table_unset(r->headers_out, "ETag"); + } + +- /* determine the protocol and whether we should use keepalives. */ +- basic_http_header_check(r, &protocol); +- ap_set_keepalive(r); +- + /* 204/304 responses don't have content related headers */ + if (AP_STATUS_IS_HEADER_ONLY(r->status)) { + apr_table_unset(r->headers_out, "Transfer-Encoding"); +@@ -1497,49 +1399,156 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, + && !strcmp(clheader, "0")) { + apr_table_unset(r->headers_out, "Content-Length"); + } ++} + +- b2 = apr_brigade_create(r->pool, c->bucket_alloc); +- basic_http_header(r, b2, protocol); ++AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, ++ apr_bucket_brigade *b) ++{ ++ request_rec *r = f->r; ++ conn_rec *c = r->connection; ++ int header_only = (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status)); ++ apr_bucket *e; ++ apr_bucket_brigade *b2; ++ header_struct h; ++ header_filter_ctx *ctx = f->ctx; ++ ap_bucket_error *eb = NULL; ++ apr_status_t rv = APR_SUCCESS; ++ int recursive_error = 0; ++ const char *protocol; + +- h.pool = r->pool; +- h.bb = b2; +- +- if (r->status == HTTP_NOT_MODIFIED) { +- apr_table_do((int (*)(void *, const char *, const char *)) form_header_field, +- (void *) &h, r->headers_out, +- "Connection", +- "Keep-Alive", +- "ETag", +- "Content-Location", +- "Expires", +- "Cache-Control", +- "Vary", +- "Warning", +- "WWW-Authenticate", +- "Proxy-Authenticate", +- "Set-Cookie", +- "Set-Cookie2", +- NULL); ++ AP_DEBUG_ASSERT(!r->main); ++ ++ if (!ctx) { ++ ctx = f->ctx = apr_pcalloc(r->pool, sizeof(header_filter_ctx)); + } +- else { +- send_all_header_fields(&h, r); ++ else if (ctx->headers_sent) { ++ /* Eat body if response must not have one. */ ++ if (header_only) { ++ /* Still next filters may be waiting for EOS, so pass it (alone) ++ * when encountered and be done with this filter. ++ */ ++ e = APR_BRIGADE_LAST(b); ++ if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) { ++ APR_BUCKET_REMOVE(e); ++ apr_brigade_cleanup(b); ++ APR_BRIGADE_INSERT_HEAD(b, e); ++ ap_remove_output_filter(f); ++ rv = ap_pass_brigade(f->next, b); ++ } ++ apr_brigade_cleanup(b); ++ return rv; ++ } + } + +- terminate_header(b2); + +- if (header_only) { +- e = APR_BRIGADE_LAST(b); +- if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) { +- APR_BUCKET_REMOVE(e); +- APR_BRIGADE_INSERT_TAIL(b2, e); ++ for (e = APR_BRIGADE_FIRST(b); ++ e != APR_BRIGADE_SENTINEL(b); ++ e = APR_BUCKET_NEXT(e)) ++ { ++ if (AP_BUCKET_IS_ERROR(e) && !eb) { ++ eb = e->data; ++ continue; ++ } ++ /* ++ * If we see an EOC bucket it is a signal that we should get out ++ * of the way doing nothing. ++ */ ++ if (AP_BUCKET_IS_EOC(e)) { + ap_remove_output_filter(f); ++ return ap_pass_brigade(f->next, b); ++ } ++ } ++ ++ if (!ctx->headers_sent) { ++ merge_response_headers(r, &protocol); ++ if (!check_headers(r)) { ++ /* We may come back here from ap_die() below, ++ * so clear anything from this response. ++ */ ++ apr_table_clear(r->headers_out); ++ apr_table_clear(r->err_headers_out); ++ r->content_type = r->content_encoding = NULL; ++ r->content_languages = NULL; ++ r->clength = r->chunked = 0; ++ apr_brigade_cleanup(b); ++ ++ /* Don't recall ap_die() if we come back here (from its own internal ++ * redirect or error response), otherwise we can end up in infinite ++ * recursion; better fall through with 500, minimal headers and an ++ * empty body (EOS only). ++ */ ++ if (!check_headers_recursion(r)) { ++ ap_die(HTTP_INTERNAL_SERVER_ERROR, r); ++ return AP_FILTER_ERROR; ++ } ++ r->status = HTTP_INTERNAL_SERVER_ERROR; ++ e = ap_bucket_eoc_create(c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(b, e); ++ e = apr_bucket_eos_create(c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(b, e); ++ ap_set_content_length(r, 0); ++ recursive_error = 1; ++ } ++ else if (eb) { ++ int status; ++ status = eb->status; ++ apr_brigade_cleanup(b); ++ ap_die(status, r); ++ return AP_FILTER_ERROR; + } +- apr_brigade_cleanup(b); + } + +- rv = ap_pass_brigade(f->next, b2); +- apr_brigade_cleanup(b2); +- ctx->headers_sent = 1; ++ if (r->assbackwards) { ++ r->sent_bodyct = 1; ++ ap_remove_output_filter(f); ++ rv = ap_pass_brigade(f->next, b); ++ goto out; ++ } ++ ++ if (!ctx->headers_sent) { ++ b2 = apr_brigade_create(r->pool, c->bucket_alloc); ++ basic_http_header(r, b2, protocol); ++ ++ h.pool = r->pool; ++ h.bb = b2; ++ ++ if (r->status == HTTP_NOT_MODIFIED) { ++ apr_table_do((int (*)(void *, const char *, const char *)) form_header_field, ++ (void *) &h, r->headers_out, ++ "Connection", ++ "Keep-Alive", ++ "ETag", ++ "Content-Location", ++ "Expires", ++ "Cache-Control", ++ "Vary", ++ "Warning", ++ "WWW-Authenticate", ++ "Proxy-Authenticate", ++ "Set-Cookie", ++ "Set-Cookie2", ++ NULL); ++ } ++ else { ++ send_all_header_fields(&h, r); ++ } ++ ++ terminate_header(b2); ++ ++ if (header_only) { ++ e = APR_BRIGADE_LAST(b); ++ if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) { ++ APR_BUCKET_REMOVE(e); ++ APR_BRIGADE_INSERT_TAIL(b2, e); ++ ap_remove_output_filter(f); ++ } ++ apr_brigade_cleanup(b); ++ } ++ ++ rv = ap_pass_brigade(f->next, b2); ++ apr_brigade_cleanup(b2); ++ ctx->headers_sent = 1; ++ } + + if (rv != APR_SUCCESS || header_only) { + goto out; diff --git a/httpd-2.4.37-CVE-2026-29169.patch b/httpd-2.4.37-CVE-2026-29169.patch new file mode 100644 index 0000000..5802899 --- /dev/null +++ b/httpd-2.4.37-CVE-2026-29169.patch @@ -0,0 +1,39 @@ +From 6736911b0b1dac27bae9fb36514008bc5dae8602 Mon Sep 17 00:00:00 2001 +From: Eric Covener +Date: Sun, 26 Apr 2026 16:04:35 +0000 +Subject: [PATCH] Merge r1933353 from trunk: + +mod_dav_lock: use the right dav_lock_discovery + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1933354 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/dav/lock/locks.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/modules/dav/lock/locks.c b/modules/dav/lock/locks.c +index 17b9ee6..fc354fa 100644 +--- a/modules/dav/lock/locks.c ++++ b/modules/dav/lock/locks.c +@@ -1164,13 +1164,13 @@ static dav_error * dav_generic_refresh_locks(dav_lockdb *lockdb, + } + if (dav_generic_do_refresh(dp_scan, ltl, new_time)) { + /* the lock was refreshed. return the lock. */ +- newlock = dav_generic_alloc_lock(lockdb, ip->key, dp->locktoken); ++ newlock = dav_generic_alloc_lock(lockdb, ip->key, dp_scan->locktoken); + newlock->is_locknull = !resource->exists; +- newlock->scope = dp->f.scope; +- newlock->type = dp->f.type; +- newlock->depth = dp->f.depth; +- newlock->timeout = dp->f.timeout; +- newlock->owner = dp->owner; ++ newlock->scope = dp_scan->f.scope; ++ newlock->type = dp_scan->f.type; ++ newlock->depth = dp_scan->f.depth; ++ newlock->timeout = dp_scan->f.timeout; ++ newlock->owner = dp_scan->owner; + newlock->auth_user = dp_scan->auth_user; + + newlock->next = *locks; +-- +2.44.0 + diff --git a/httpd-2.4.37-CVE-2026-34355.patch b/httpd-2.4.37-CVE-2026-34355.patch new file mode 100644 index 0000000..4e52a86 --- /dev/null +++ b/httpd-2.4.37-CVE-2026-34355.patch @@ -0,0 +1,571 @@ +From 9b1cfbb0f943577029dcad69f8f7652dc55897b2 Mon Sep 17 00:00:00 2001 +From: Joe Orton +Date: Thu, 4 Jun 2026 11:22:27 +0000 +Subject: [PATCH] Merge r1934975 from trunk: + +mod_proxy_html: Simplify to use the ap_varbuf API. + +* modules/filters/mod_proxy_html.c: Include util_varbuf.h. + (saxctxt): Replace buf/offset/avail members with struct ap_varbuf vb. + (DEFAULT_BUFSZ): New macro. + (normalise): Take struct ap_varbuf * parameter instead of char *. + (preserve, pappend): Remove functions, replaced by ap_varbuf_grow + and ap_varbuf_strmemcat respectively. + (dump_content): Use ap_varbuf for regex substitutions via + ap_varbuf_regsub, avoiding manual buffer resizing with + preserve/memmove/memcpy. Use a temporary ap_varbuf for building + regex replacement results. + (pcharacters, pcomment): Use ap_varbuf_strmemcat and ap_varbuf_strcat + in place of pappend. + (pendElement): Check vb.strlen instead of offset. + (pstartElement): Use ap_varbuf for attribute URL rewriting with the + same ap_varbuf_regsub approach. Use a temporary ap_varbuf for + regex replacements. + (proxy_html_filter): Initialize the ap_varbuf with a clamped bufsz. + (proxy_html_merge): Use DEFAULT_BUFSZ macro. + +Assisted-by: Claude Opus 4.6 (claude-opus-4-6) +Reviewed by: covener, jfclere, jorton + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1934977 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/filters/mod_proxy_html.c | 270 ++++++++++++++----------------- + 1 file changed, 121 insertions(+), 149 deletions(-) + +diff --git a/modules/filters/mod_proxy_html.c b/modules/filters/mod_proxy_html.c +index 8b619e8..8b8e505 100644 +--- a/modules/filters/mod_proxy_html.c ++++ b/modules/filters/mod_proxy_html.c +@@ -44,6 +44,7 @@ + #include "mod_xml2enc.h" + #include "http_request.h" + #include "ap_expr.h" ++#include "util_varbuf.h" + + /* globals set once at startup */ + static ap_rxplus_t *old_expr; +@@ -103,9 +104,7 @@ typedef struct { + proxy_html_conf *cfg; + htmlParserCtxtPtr parser; + apr_bucket_brigade *bb; +- char *buf; +- size_t offset; +- size_t avail; ++ struct ap_varbuf vb; + const char *encoding; + urlmap *map; + char rbuf[4]; +@@ -113,6 +112,7 @@ typedef struct { + apr_size_t rmin; + } saxctxt; + ++#define DEFAULT_BUFSZ (8192) + + #define NORM_LC 0x1 + #define NORM_MSSLASH 0x2 +@@ -136,17 +136,17 @@ static const char *const xhtml_etag = " />"; + static const char *const DEFAULT_DOCTYPE = ""; + #define DEFAULT_ETAG html_etag + +-static void normalise(unsigned int flags, char *str) ++static void normalise(unsigned int flags, struct ap_varbuf *vb) + { +- char *p; ++ apr_size_t n; + if (flags & NORM_LC) +- for (p = str; *p; ++p) +- if (isupper(*p)) +- *p = tolower(*p); ++ for (n = 0; n < vb->strlen; ++n) ++ vb->buf[n] = apr_tolower(vb->buf[n]); + + if (flags & NORM_MSSLASH) +- for (p = ap_strchr(str, '\\'); p; p = ap_strchr(p+1, '\\')) +- *p = '/'; ++ for (n = 0; n < vb->strlen; ++n) ++ if (vb->buf[n] == '\\') ++ vb->buf[n] = '/'; + + } + #define consume_buffer(ctx,inbuf,bytes,flag) \ +@@ -175,120 +175,97 @@ static void pcharacters(void *ctxt, const xmlChar *uchars, int length) + FLUSH; + } + +-static void preserve(saxctxt *ctx, const size_t len) +-{ +- char *newbuf; +- if (len <= (ctx->avail - ctx->offset)) +- return; +- else while (len > (ctx->avail - ctx->offset)) +- ctx->avail += ctx->cfg->bufsz; +- +- newbuf = realloc(ctx->buf, ctx->avail); +- if (newbuf != ctx->buf) { +- if (ctx->buf) +- apr_pool_cleanup_kill(ctx->f->r->pool, ctx->buf, +- (int(*)(void*))free); +- apr_pool_cleanup_register(ctx->f->r->pool, newbuf, +- (int(*)(void*))free, apr_pool_cleanup_null); +- ctx->buf = newbuf; +- } +-} +- +-static void pappend(saxctxt *ctx, const char *buf, const size_t len) +-{ +- preserve(ctx, len); +- memcpy(ctx->buf+ctx->offset, buf, len); +- ctx->offset += len; +-} +- + static void dump_content(saxctxt *ctx) + { + urlmap *m; + char *found; + size_t s_from, s_to; + size_t match; +- char c = 0; + int nmatch; + ap_regmatch_t pmatch[10]; +- char *subs; + size_t len, offs; + urlmap *themap = ctx->map; ++ struct ap_varbuf temp; + #ifndef GO_FASTER + int verbose = APLOGrtrace1(ctx->f->r); + #endif + +- pappend(ctx, &c, 1); /* append null byte */ +- /* parse the text for URLs */ ++ /* Ensure buffer is null-terminated and strlen is set */ ++ if (ctx->vb.strlen == AP_VARBUF_UNKNOWN) { ++ ctx->vb.strlen = strlen(ctx->vb.buf); ++ } ++ ++ ap_varbuf_init(ctx->f->r->pool, &temp, 0); ++ ++ /* parse the text for URLs */ + for (m = themap; m; m = m->next) { + if (!(m->flags & M_CDATA)) + continue; + if (m->flags & M_REGEX) { ++ temp.strlen = 0; + nmatch = 10; + offs = 0; +- while (!ap_regexec(m->from.r, ctx->buf+offs, nmatch, pmatch, 0)) { ++ while (!ap_regexec(m->from.r, ctx->vb.buf+offs, nmatch, pmatch, 0)) { + match = pmatch[0].rm_so; + s_from = pmatch[0].rm_eo - match; +- subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs, +- nmatch, pmatch); +- s_to = strlen(subs); +- len = strlen(ctx->buf); +- offs += match; + VERBOSEB( + const char *f = apr_pstrndup(ctx->f->r->pool, +- ctx->buf + offs, s_from); ++ ctx->vb.buf + offs + match, s_from); + ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, ctx->f->r, +- "C/RX: match at %s, substituting %s", f, subs); ++ "C/RX: match at %s, substituting with pattern %s", ++ f, m->to); + ) +- if (s_to > s_from) { +- preserve(ctx, s_to - s_from); +- memmove(ctx->buf+offs+s_to, ctx->buf+offs+s_from, +- len + 1 - s_from - offs); +- memcpy(ctx->buf+offs, subs, s_to); +- } +- else { +- memcpy(ctx->buf + offs, subs, s_to); +- memmove(ctx->buf+offs+s_to, ctx->buf+offs+s_from, +- len + 1 - s_from - offs); +- } +- offs += s_to; ++ /* Copy text before the match */ ++ ap_varbuf_strmemcat(&temp, ctx->vb.buf+offs, match); ++ /* Append the substitution */ ++ ap_varbuf_regsub(&temp, m->to, ctx->vb.buf+offs, nmatch, pmatch, 0); ++ /* Continue past the match */ ++ offs += pmatch[0].rm_eo; + } ++ /* Copy any remaining text */ ++ ap_varbuf_strcat(&temp, ctx->vb.buf+offs); ++ /* Replace the original buffer with the result */ ++ ctx->vb.strlen = 0; ++ ap_varbuf_strmemcat(&ctx->vb, temp.buf, temp.strlen); + } + else { + s_from = strlen(m->from.c); + s_to = strlen(m->to); +- for (found = strstr(ctx->buf, m->from.c); found; +- found = strstr(ctx->buf+match+s_to, m->from.c)) { +- match = found - ctx->buf; ++ for (found = strstr(ctx->vb.buf, m->from.c); found; ++ found = strstr(ctx->vb.buf+match+s_to, m->from.c)) { ++ match = found - ctx->vb.buf; + if ((m->flags & M_ATSTART) && (match != 0)) + break; +- len = strlen(ctx->buf); ++ len = ctx->vb.strlen; + if ((m->flags & M_ATEND) && (match < (len - s_from))) + continue; + VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, ctx->f->r, + "C: matched %s, substituting %s", + m->from.c, m->to)); + if (s_to > s_from) { +- preserve(ctx, s_to - s_from); +- memmove(ctx->buf+match+s_to, ctx->buf+match+s_from, ++ ap_varbuf_grow(&ctx->vb, len + s_to - s_from); ++ memmove(ctx->vb.buf+match+s_to, ctx->vb.buf+match+s_from, + len + 1 - s_from - match); +- memcpy(ctx->buf+match, m->to, s_to); ++ memcpy(ctx->vb.buf+match, m->to, s_to); + } + else { +- memcpy(ctx->buf+match, m->to, s_to); +- memmove(ctx->buf+match+s_to, ctx->buf+match+s_from, ++ memcpy(ctx->vb.buf+match, m->to, s_to); ++ memmove(ctx->vb.buf+match+s_to, ctx->vb.buf+match+s_from, + len + 1 - s_from - match); + } ++ ctx->vb.strlen = len - s_from + s_to; + } + } + } +- AP_fwrite(ctx, ctx->buf, strlen(ctx->buf), 1); ++ AP_fwrite(ctx, ctx->vb.buf, ctx->vb.strlen, 1); ++ ap_varbuf_free(&temp); + } + static void pcdata(void *ctxt, const xmlChar *uchars, int length) + { + const char *chars = (const char*) uchars; + saxctxt *ctx = (saxctxt*) ctxt; + if (ctx->cfg->extfix) { +- pappend(ctx, chars, length); ++ ap_varbuf_strmemcat(&ctx->vb, chars, length); + } + else { + /* not sure if this should force-flush +@@ -305,15 +282,14 @@ static void pcomment(void *ctxt, const xmlChar *uchars) + return; + + if (ctx->cfg->extfix) { +- pappend(ctx, "", 3); ++ ap_varbuf_strcat(&ctx->vb, ""); + } + else { + ap_fputs(ctx->f->next, ctx->bb, ""); +- dump_content(ctx); + } + } + static void pendElement(void *ctxt, const xmlChar *uname) +@@ -337,9 +313,9 @@ static void pendElement(void *ctxt, const xmlChar *uname) + /* TODO - implement HTML "allowed here" using the stack */ + /* nah. Keeping the stack is too much overhead */ + +- if (ctx->offset > 0) { ++ if (ctx->vb.strlen > 0) { + dump_content(ctx); +- ctx->offset = 0; /* having dumped it, we can re-use the memory */ ++ ctx->vb.strlen = 0; /* having dumped it, we can re-use the memory */ + } + if (!desc || !desc->empty) { + ap_fprintf(ctx->f->next, ctx->bb, "", name); +@@ -352,7 +328,6 @@ static void pstartElement(void *ctxt, const xmlChar *uname, + int required_attrs; + int num_match; + size_t offs, len; +- char *subs; + rewrite_t is_uri; + const char** a; + urlmap *m; +@@ -370,6 +345,7 @@ static void pstartElement(void *ctxt, const xmlChar *uname, + const char** attrs = (const char**) uattrs; + const htmlElemDesc* desc = htmlTagLookup(uname); + urlmap *themap = ctx->map; ++ struct ap_varbuf temp; + #ifdef HAVE_STACK + const void** descp; + #endif +@@ -399,6 +375,8 @@ static void pstartElement(void *ctxt, const xmlChar *uname, + /* TODO - implement HTML "allowed here" */ + #endif + ++ ap_varbuf_init(ctx->f->r->pool, &temp, 0); ++ + ap_fputc(ctx->f->next, ctx->bb, '<'); + ap_fputs(ctx->f->next, ctx->bb, name); + +@@ -429,9 +407,10 @@ static void pstartElement(void *ctxt, const xmlChar *uname, + break; + } + } +- ctx->offset = 0; ++ ctx->vb.strlen = 0; ++ ctx->vb.buf[0] = '\0'; + if (a[1]) { +- pappend(ctx, a[1], strlen(a[1])+1); ++ ap_varbuf_strcat(&ctx->vb, a[1]); + is_uri = ATTR_IGNORE; + if (linkattrs) { + tattr *attrs = (tattr*) linkattrs->elts; +@@ -460,59 +439,53 @@ static void pstartElement(void *ctxt, const xmlChar *uname, + continue; + if (m->flags & M_REGEX) { + nmatch = 10; +- if (!ap_regexec(m->from.r, ctx->buf, nmatch, ++ if (!ap_regexec(m->from.r, ctx->vb.buf, nmatch, + pmatch, 0)) { + ++num_match; +- offs = match = pmatch[0].rm_so; ++ match = pmatch[0].rm_so; + s_from = pmatch[0].rm_eo - match; +- subs = ap_pregsub(ctx->f->r->pool, m->to, +- ctx->buf, nmatch, pmatch); + VERBOSE({ + const char *f; + f = apr_pstrndup(ctx->f->r->pool, +- ctx->buf + offs, s_from); ++ ctx->vb.buf + match, s_from); + ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, + ctx->f->r, +- "H/RX: match at %s, substituting %s", +- f, subs); ++ "H/RX: match at %s, substituting with pattern %s", ++ f, m->to); + }) +- s_to = strlen(subs); +- len = strlen(ctx->buf); +- if (s_to > s_from) { +- preserve(ctx, s_to - s_from); +- memmove(ctx->buf+offs+s_to, +- ctx->buf+offs+s_from, +- len + 1 - s_from - offs); +- memcpy(ctx->buf+offs, subs, s_to); +- } +- else { +- memcpy(ctx->buf + offs, subs, s_to); +- memmove(ctx->buf+offs+s_to, +- ctx->buf+offs+s_from, +- len + 1 - s_from - offs); +- } ++ temp.strlen = 0; ++ /* Copy text before match */ ++ ap_varbuf_strmemcat(&temp, ctx->vb.buf, match); ++ /* Append substitution */ ++ ap_varbuf_regsub(&temp, m->to, ctx->vb.buf, nmatch, pmatch, 0); ++ /* Copy text after match */ ++ ap_varbuf_strcat(&temp, ctx->vb.buf + pmatch[0].rm_eo); ++ /* Replace buffer */ ++ ctx->vb.strlen = 0; ++ ap_varbuf_strmemcat(&ctx->vb, temp.buf, temp.strlen); + } + } else { + s_from = strlen(m->from.c); +- if (!strncasecmp(ctx->buf, m->from.c, s_from)) { ++ if (!strncasecmp(ctx->vb.buf, m->from.c, s_from)) { + ++num_match; + s_to = strlen(m->to); +- len = strlen(ctx->buf); ++ len = ctx->vb.strlen; + VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3, + 0, ctx->f->r, + "H: matched %s, substituting %s", + m->from.c, m->to)); + if (s_to > s_from) { +- preserve(ctx, s_to - s_from); +- memmove(ctx->buf+s_to, ctx->buf+s_from, ++ ap_varbuf_grow(&ctx->vb, len + s_to - s_from); ++ memmove(ctx->vb.buf+s_to, ctx->vb.buf+s_from, + len + 1 - s_from); +- memcpy(ctx->buf, m->to, s_to); ++ memcpy(ctx->vb.buf, m->to, s_to); + } + else { /* it fits in the existing space */ +- memcpy(ctx->buf, m->to, s_to); +- memmove(ctx->buf+s_to, ctx->buf+s_from, ++ memcpy(ctx->vb.buf, m->to, s_to); ++ memmove(ctx->vb.buf+s_to, ctx->vb.buf+s_from, + len + 1 - s_from); + } ++ ctx->vb.strlen = len - s_from + s_to; + break; + } + } +@@ -527,79 +500,73 @@ static void pstartElement(void *ctxt, const xmlChar *uname, + if (!(m->flags & M_EVENTS)) + continue; + if (m->flags & M_REGEX) { ++ temp.strlen = 0; + nmatch = 10; + offs = 0; +- while (!ap_regexec(m->from.r, ctx->buf+offs, ++ while (!ap_regexec(m->from.r, ctx->vb.buf+offs, + nmatch, pmatch, 0)) { + match = pmatch[0].rm_so; + s_from = pmatch[0].rm_eo - match; +- subs = ap_pregsub(ctx->f->r->pool, m->to, ctx->buf+offs, +- nmatch, pmatch); + VERBOSE({ + const char *f; + f = apr_pstrndup(ctx->f->r->pool, +- ctx->buf + offs, s_from); ++ ctx->vb.buf + offs + match, s_from); + ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, + ctx->f->r, +- "E/RX: match at %s, substituting %s", +- f, subs); ++ "E/RX: match at %s, substituting with pattern %s", ++ f, m->to); + }) +- s_to = strlen(subs); +- offs += match; +- len = strlen(ctx->buf); +- if (s_to > s_from) { +- preserve(ctx, s_to - s_from); +- memmove(ctx->buf+offs+s_to, +- ctx->buf+offs+s_from, +- len + 1 - s_from - offs); +- memcpy(ctx->buf+offs, subs, s_to); +- } +- else { +- memcpy(ctx->buf + offs, subs, s_to); +- memmove(ctx->buf+offs+s_to, +- ctx->buf+offs+s_from, +- len + 1 - s_from - offs); +- } +- offs += s_to; ++ /* Copy text before match */ ++ ap_varbuf_strmemcat(&temp, ctx->vb.buf+offs, match); ++ /* Append substitution */ ++ ap_varbuf_regsub(&temp, m->to, ctx->vb.buf+offs, nmatch, pmatch, 0); ++ /* Continue past the match */ ++ offs += pmatch[0].rm_eo; + ++num_match; + } ++ /* Copy any remaining text */ ++ ap_varbuf_strcat(&temp, ctx->vb.buf+offs); ++ /* Replace buffer */ ++ ctx->vb.strlen = 0; ++ ap_varbuf_strmemcat(&ctx->vb, temp.buf, temp.strlen); + } + else { +- found = strstr(ctx->buf, m->from.c); +- if ((m->flags & M_ATSTART) && (found != ctx->buf)) ++ found = strstr(ctx->vb.buf, m->from.c); ++ if ((m->flags & M_ATSTART) && (found != ctx->vb.buf)) + continue; + while (found) { + s_from = strlen(m->from.c); + s_to = strlen(m->to); +- match = found - ctx->buf; ++ match = found - ctx->vb.buf; + if ((s_from < strlen(found)) + && (m->flags & M_ATEND)) { +- found = strstr(ctx->buf+match+s_from, ++ found = strstr(ctx->vb.buf+match+s_from, + m->from.c); + continue; + } + else { +- found = strstr(ctx->buf+match+s_to, ++ found = strstr(ctx->vb.buf+match+s_to, + m->from.c); + } + VERBOSE(ap_log_rerror(APLOG_MARK, APLOG_TRACE3, + 0, ctx->f->r, + "E: matched %s, substituting %s", + m->from.c, m->to)); +- len = strlen(ctx->buf); ++ len = ctx->vb.strlen; + if (s_to > s_from) { +- preserve(ctx, s_to - s_from); +- memmove(ctx->buf+match+s_to, +- ctx->buf+match+s_from, ++ ap_varbuf_grow(&ctx->vb, len + s_to - s_from); ++ memmove(ctx->vb.buf+match+s_to, ++ ctx->vb.buf+match+s_from, + len + 1 - s_from - match); +- memcpy(ctx->buf+match, m->to, s_to); ++ memcpy(ctx->vb.buf+match, m->to, s_to); + } + else { +- memcpy(ctx->buf+match, m->to, s_to); +- memmove(ctx->buf+match+s_to, +- ctx->buf+match+s_from, ++ memcpy(ctx->vb.buf+match, m->to, s_to); ++ memmove(ctx->vb.buf+match+s_to, ++ ctx->vb.buf+match+s_from, + len + 1 - s_from - match); + } ++ ctx->vb.strlen = len - s_from + s_to; + ++num_match; + } + } +@@ -616,18 +583,18 @@ static void pstartElement(void *ctxt, const xmlChar *uname, + else { + + if (ctx->cfg->flags != 0) +- normalise(ctx->cfg->flags, ctx->buf); ++ normalise(ctx->cfg->flags, &ctx->vb); + + /* write the attribute, using pcharacters to html-escape + anything that needs it in the value. + */ + ap_fputstrs(ctx->f->next, ctx->bb, " ", a[0], "=\"", NULL); +- pcharacters(ctx, (const xmlChar*)ctx->buf, strlen(ctx->buf)); ++ pcharacters(ctx, (const xmlChar*)ctx->vb.buf, ctx->vb.strlen); + ap_fputc(ctx->f->next, ctx->bb, '"'); + } + } + } +- ctx->offset = 0; ++ ctx->vb.strlen = 0; + if (desc && desc->empty) + ap_fputs(ctx->f->next, ctx->bb, ctx->cfg->etag); + else +@@ -639,6 +606,7 @@ static void pstartElement(void *ctxt, const xmlChar *uname, + "HTML element %s is missing %d required attributes", + name, required_attrs); + } ++ ap_varbuf_free(&temp); + } + + static meta *metafix(request_rec *r, const char *buf, apr_size_t len) +@@ -807,6 +775,8 @@ static saxctxt *check_filter_init (ap_filter_t *f) + proxy_html_conf *cfg; + const char *force; + const char *errmsg = NULL; ++ apr_size_t bufsz; ++ + cfg = ap_get_module_config(f->r->per_dir_config, &proxy_html_module); + force = apr_table_get(f->r->subprocess_env, "PROXY_HTML_FORCE"); + +@@ -840,6 +810,8 @@ static saxctxt *check_filter_init (ap_filter_t *f) + fctx->bb = apr_brigade_create(f->r->pool, + f->r->connection->bucket_alloc); + fctx->cfg = cfg; ++ bufsz = (cfg->bufsz <= 0 || cfg->bufsz > (128 * 1024)) ? DEFAULT_BUFSZ : cfg->bufsz; ++ ap_varbuf_init(f->r->pool, &fctx->vb, bufsz); + apr_table_unset(f->r->headers_out, "Content-Length"); + + if (cfg->interp) +@@ -1009,7 +981,7 @@ static void *proxy_html_config(apr_pool_t *pool, char *x) + proxy_html_conf *ret = apr_pcalloc(pool, sizeof(proxy_html_conf)); + ret->doctype = DEFAULT_DOCTYPE; + ret->etag = DEFAULT_ETAG; +- ret->bufsz = 8192; ++ ret->bufsz = DEFAULT_BUFSZ; + /* ret->interp = 1; */ + /* don't initialise links and events until they get set/used */ + return ret; +-- +2.44.0 + diff --git a/httpd-2.4.37-CVE-2026-34356.patch b/httpd-2.4.37-CVE-2026-34356.patch new file mode 100644 index 0000000..2487b35 --- /dev/null +++ b/httpd-2.4.37-CVE-2026-34356.patch @@ -0,0 +1,30 @@ +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index f5c3283..012b6aa 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -982,6 +982,12 @@ PROXY_DECLARE(const char *) ap_proxy_cookie_reverse_map(request_rec *r, + poffs = pathp - tmpstr_orig; + l1 = strlen(pathp); + pathe = str + poffs + l1; ++ /* ++ * RFC 6265 § 5.3 7): Only the last path= should be meaningful ++ * so reset anything previously found. ++ */ ++ newpath = NULL; ++ pdiff = 0; + if (conf->interpolate_env == 1) { + ent = (struct proxy_alias *)rconf->cookie_paths->elts; + } +@@ -1002,6 +1008,12 @@ PROXY_DECLARE(const char *) ap_proxy_cookie_reverse_map(request_rec *r, + doffs = domainp - tmpstr_orig; + l1 = strlen(domainp); + domaine = str + doffs + l1; ++ /* ++ * RFC 6265 § 5.3 4): Only the last domain= should be meaningful ++ * so reset anything previously found. ++ */ ++ newdomain = NULL; ++ ddiff = 0; + if (conf->interpolate_env == 1) { + ent = (struct proxy_alias *)rconf->cookie_domains->elts; + } diff --git a/httpd-2.4.37-CVE-2026-42536.patch b/httpd-2.4.37-CVE-2026-42536.patch new file mode 100644 index 0000000..add1ed3 --- /dev/null +++ b/httpd-2.4.37-CVE-2026-42536.patch @@ -0,0 +1,25 @@ +From 6fb79c31629bcbcb002dabb769602c20093c9aea Mon Sep 17 00:00:00 2001 +From: Joe Orton +Date: Thu, 4 Jun 2026 08:46:03 +0000 +Subject: [PATCH] * modules/filters/mod_xml2enc.c (fix_skipto): Fix accounting. + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1934970 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/filters/mod_xml2enc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/modules/filters/mod_xml2enc.c b/modules/filters/mod_xml2enc.c +index dc4d021..5118d5b 100644 +--- a/modules/filters/mod_xml2enc.c ++++ b/modules/filters/mod_xml2enc.c +@@ -145,6 +145,7 @@ static void fix_skipto(request_rec* r, xml2ctx* ctx) + apr_bucket_delete(b); + } + ctx->bytes -= (p-ctx->buf); ++ ctx->bblen -= (p-ctx->buf); + ctx->buf = p ; + found = 1; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01428) +-- +2.44.0 + diff --git a/httpd-2.4.37-CVE-2026-43951.patch b/httpd-2.4.37-CVE-2026-43951.patch new file mode 100644 index 0000000..16ab95b --- /dev/null +++ b/httpd-2.4.37-CVE-2026-43951.patch @@ -0,0 +1,16 @@ +diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c +index bfa8952..8ac2cb4 100644 +--- a/modules/http/http_filters.c ++++ b/modules/http/http_filters.c +@@ -1463,10 +1463,10 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, + if (!apr_is_empty_array(r->content_languages)) { + int i; + char *token; +- char **languages = (char **)(r->content_languages->elts); + const char *field = apr_table_get(r->headers_out, "Content-Language"); + + while (field && (token = ap_get_list_item(r->pool, &field)) != NULL) { ++ char **languages = (char **)(r->content_languages->elts); + for (i = 0; i < r->content_languages->nelts; ++i) { + if (!strcasecmp(token, languages[i])) + break; diff --git a/httpd-2.4.37-CVE-2026-44185.patch b/httpd-2.4.37-CVE-2026-44185.patch new file mode 100644 index 0000000..3db0ece --- /dev/null +++ b/httpd-2.4.37-CVE-2026-44185.patch @@ -0,0 +1,30 @@ +From 5310922061aec62914e8ffc19bbd6fb2ac52bab6 Mon Sep 17 00:00:00 2001 +From: Joe Orton +Date: Wed, 3 Jun 2026 10:43:09 +0000 +Subject: [PATCH] * modules/ssl/ssl_util_ocsp.c (send_request): Increase wbuf + with the len read by apr_socket_send + +Submitted by: gbechis +Github: closes #603 + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1934918 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/ssl/ssl_util_ocsp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/modules/ssl/ssl_util_ocsp.c b/modules/ssl/ssl_util_ocsp.c +index b66e151..553ecde 100644 +--- a/modules/ssl/ssl_util_ocsp.c ++++ b/modules/ssl/ssl_util_ocsp.c +@@ -132,7 +132,7 @@ static apr_socket_t *send_request(BIO *request, const apr_uri_t *uri, + apr_size_t wlen = remain; + + rv = apr_socket_send(sd, wbuf, &wlen); +- wbuf += remain; ++ wbuf += wlen; + remain -= wlen; + } while (rv == APR_SUCCESS && remain > 0); + +-- +2.44.0 + diff --git a/httpd-2.4.37-CVE-2026-44186.patch b/httpd-2.4.37-CVE-2026-44186.patch new file mode 100644 index 0000000..1bba1ea --- /dev/null +++ b/httpd-2.4.37-CVE-2026-44186.patch @@ -0,0 +1,18 @@ +diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c +index 5c4d641..a81028e 100644 +--- a/modules/proxy/mod_proxy_ftp.c ++++ b/modules/proxy/mod_proxy_ftp.c +@@ -1243,10 +1243,12 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, + time_t secs; + + /* Look for a number, preceded by whitespace */ +- while (*secs_str) ++ while (*secs_str) { + if ((secs_str==ftpmessage || apr_isspace(secs_str[-1])) && + apr_isdigit(secs_str[0])) + break; ++ secs_str++; ++ } + if (*secs_str != '\0') { + secs = atol(secs_str); + apr_table_addn(r->headers_out, "Retry-After", diff --git a/httpd-2.4.37-CVE-2026-44631.patch b/httpd-2.4.37-CVE-2026-44631.patch new file mode 100644 index 0000000..77306e8 --- /dev/null +++ b/httpd-2.4.37-CVE-2026-44631.patch @@ -0,0 +1,87 @@ +diff --git a/include/ap_regex.h b/include/ap_regex.h +index 7af2f99..6ff8eaa 100644 +--- a/include/ap_regex.h ++++ b/include/ap_regex.h +@@ -187,6 +187,8 @@ AP_DECLARE(apr_size_t) ap_regerror(int errcode, const ap_regex_t *preg, + * @param preg The precompiled regex + * @param names The array to which the names will be added + * @param upper If non zero, uppercase the names ++ * @return number of regex backrefernces returned, -1 for error ++ * for successful match, AP_REG_NOMATCH otherwise + */ + AP_DECLARE(int) ap_regname(const ap_regex_t *preg, + apr_array_header_t *names, const char *prefix, +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index 16ebd98..06a6ad7 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -2597,7 +2597,9 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) + + if (r) { + conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *)); +- ap_regname(r, conf->refs, AP_REG_MATCH, 1); ++ if (ap_regname(r, conf->refs, AP_REG_MATCH, 1) < 0) { ++ return "Error processing regex captures"; ++ } + } + + ap_add_per_proxy_conf(cmd->server, new_dir_conf); +diff --git a/server/core.c b/server/core.c +index 1f99b3a..d9e366d 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -2423,7 +2423,9 @@ static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg) + + if (r) { + conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *)); +- ap_regname(r, conf->refs, AP_REG_MATCH, 1); ++ if (ap_regname(r, conf->refs, AP_REG_MATCH, 1) < 0) { ++ return "Error processing regex captures"; ++ } + } + + /* Make this explicit - the "/" root has 0 elements, that is, we +@@ -2504,7 +2506,9 @@ static const char *urlsection(cmd_parms *cmd, void *mconfig, const char *arg) + + if (r) { + conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *)); +- ap_regname(r, conf->refs, AP_REG_MATCH, 1); ++ if (ap_regname(r, conf->refs, AP_REG_MATCH, 1) < 0) { ++ return "Error processing regex captures"; ++ } + } + + ap_add_per_url_conf(cmd->server, new_url_conf); +@@ -2591,7 +2595,9 @@ static const char *filesection(cmd_parms *cmd, void *mconfig, const char *arg) + + if (r) { + conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *)); +- ap_regname(r, conf->refs, AP_REG_MATCH, 1); ++ if (ap_regname(r, conf->refs, AP_REG_MATCH, 1) < 0) { ++ return "Error processing regex captures"; ++ } + } + + ap_add_file_conf(cmd->pool, (core_dir_config *)mconfig, new_file_conf); +diff --git a/server/util_pcre.c b/server/util_pcre.c +index 2a665c8..8fa672f 100644 +--- a/server/util_pcre.c ++++ b/server/util_pcre.c +@@ -320,7 +320,16 @@ AP_DECLARE(int) ap_regname(const ap_regex_t *preg, + + for (i = 0; i < namecount; i++) { + const char *offset = nametable + i * nameentrysize; +- int capture = ((offset[0] << 8) + offset[1]); ++ int capture = (((unsigned char)offset[0] << 8) + (unsigned char)offset[1]); ++ ++ /* Sanity check: reject unreasonably large capture group numbers. ++ * PCRE allows up to 65535 groups, but such large numbers would ++ * cause excessive memory allocation. Limit to a reasonable maximum. ++ */ ++ if (capture > 1024) { ++ return -1; ++ } ++ + while (names->nelts <= capture) { + apr_array_push(names); + } diff --git a/httpd.spec b/httpd.spec index 3ad4ca7..954a97d 100644 --- a/httpd.spec +++ b/httpd.spec @@ -14,7 +14,7 @@ Summary: Apache HTTP Server Name: httpd Version: 2.4.37 -Release: 65%{?dist}.8 +Release: 65%{?dist}.9 URL: https://httpd.apache.org/ Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source2: httpd.logrotate @@ -309,6 +309,24 @@ Patch257: httpd-2.4.37-CVE-2026-33857.patch Patch258: httpd-2.4.37-CVE-2026-34032.patch # https://bugzilla.redhat.com/show_bug.cgi?id=2464940 Patch259: httpd-2.4.37-CVE-2026-34059.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2486411 +Patch260: httpd-2.4.37-CVE-2026-42536.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2486397 +Patch261: httpd-2.4.37-CVE-2026-44185.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2465296 +Patch262: httpd-2.4.37-CVE-2026-29169.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2486414 +Patch263: httpd-2.4.37-CVE-2026-34355.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2486402 +Patch264: httpd-2.4.37-CVE-2026-44186.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2486395 +Patch265: httpd-2.4.37-CVE-2026-34356.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2486415 +Patch266: httpd-2.4.37-CVE-2026-43951.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2486399 +Patch267: httpd-2.4.37-CVE-2026-44631.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2374549 +Patch268: httpd-2.4.37-CVE-2024-42516.patch License: ASL 2.0 Group: System Environment/Daemons @@ -558,6 +576,15 @@ interface for storing and accessing per-user session data. %patch257 -p1 -b .CVE-2026-33857 %patch258 -p1 -b .CVE-2026-34032 %patch259 -p1 -b .CVE-2026-34059 +%patch260 -p1 -b .CVE-2026-42536 +%patch261 -p1 -b .CVE-2026-44185 +%patch262 -p1 -b .CVE-2026-29169 +%patch263 -p1 -b .CVE-2026-34355 +%patch264 -p1 -b .CVE-2026-44186 +%patch265 -p1 -b .CVE-2026-34356 +%patch266 -p1 -b .CVE-2026-43951 +%patch267 -p1 -b .CVE-2026-44631 +%patch268 -p1 -b .CVE-2024-42516 %patch96 -p1 -b .r1922080 @@ -1069,6 +1096,27 @@ rm -rf $RPM_BUILD_ROOT %{_rpmconfigdir}/macros.d/macros.httpd %changelog +* Thu Jul 09 2026 Luboš Uhliarik - 2.4.37-65.9 +- Resolves: RHEL-186198 - httpd: Apache HTTP Server: Heap-based Buffer Overflow + via untrusted content in mod_xml2enc (CVE-2026-42536) +- Resolves: RHEL-186166 - httpd: Apache HTTP Server: Buffer Over-read via + outbound OCSP requests to attacker-controlled server (CVE-2026-44185) +- Resolves: RHEL-175620 - httpd:2.4/httpd: NULL pointer dereference via + specially crafted request (CVE-2026-29169) +- Resolves: RHEL-186176 - httpd: Apache HTTP Server: Buffer overflow in + mod_proxy_html allows security bypass (CVE-2026-34355) +- Resolves: RHEL-192751 - mod_proxy_html regression in CVE-2026-34355 fix +- Resolves: RHEL-193114 - httpd: Apache HTTP Server: Denial of Service + in mod_proxy_ftp via attacker-controlled FTP server (CVE-2026-44186) +- Resolves: RHEL-186219 - httpd: Apache HTTP Server: Heap-based Buffer Overflow + via malicious backend servers (CVE-2026-34356) +- Resolves: RHEL-191243 - httpd: Apache HTTP Server: Out-of-bounds Read in + mod_headers and mod_mime (CVE-2026-43951) +- Resolves: RHEL-184307 - httpd: Apache HTTP Server: Denial of Service via + crafted regular expressions (CVE-2026-44631) +- Resolves: RHEL-182577 - httpd: incomplete fix + for CVE-2023-38709 (CVE-2024-42516) + * Tue May 12 2026 Luboš Uhliarik - 2.4.37-65.8 - Resolves: RHEL-173558 - httpd:2.4/httpd: Apache HTTP Server mod_proxy_ajp: Arbitrary code execution via heap-based buffer overflow (CVE-2026-28780)