From d71cb6a3a88c9a829951585b85acd6af31a0cfa4 Mon Sep 17 00:00:00 2001 From: MSVSphere Packaging Team Date: Wed, 24 Jul 2024 03:35:37 +0300 Subject: [PATCH] import httpd-2.4.57-11.el9_4 --- SOURCES/httpd-2.4.57-CVE-2023-31122.patch | 11 + SOURCES/httpd-2.4.57-CVE-2024-38473.patch | 172 ++++++++ SOURCES/httpd-2.4.57-CVE-2024-38474+.patch | 439 +++++++++++++++++++++ SOURCES/httpd-2.4.57-CVE-2024-38477.patch | 43 ++ SOURCES/httpd-2.4.57-CVE-2024-39573.patch | 72 ++++ SOURCES/httpd-2.4.57-r1884505+.patch | 39 ++ SOURCES/httpd-2.4.57-r1912081.patch | 91 +++++ SOURCES/httpd-2.4.57-r1912477+.patch | 381 ++++++++++++++++++ SPECS/httpd.spec | 59 ++- 9 files changed, 1304 insertions(+), 3 deletions(-) create mode 100644 SOURCES/httpd-2.4.57-CVE-2023-31122.patch create mode 100644 SOURCES/httpd-2.4.57-CVE-2024-38473.patch create mode 100644 SOURCES/httpd-2.4.57-CVE-2024-38474+.patch create mode 100644 SOURCES/httpd-2.4.57-CVE-2024-38477.patch create mode 100644 SOURCES/httpd-2.4.57-CVE-2024-39573.patch create mode 100644 SOURCES/httpd-2.4.57-r1884505+.patch create mode 100644 SOURCES/httpd-2.4.57-r1912081.patch create mode 100644 SOURCES/httpd-2.4.57-r1912477+.patch diff --git a/SOURCES/httpd-2.4.57-CVE-2023-31122.patch b/SOURCES/httpd-2.4.57-CVE-2023-31122.patch new file mode 100644 index 0000000..c2aa207 --- /dev/null +++ b/SOURCES/httpd-2.4.57-CVE-2023-31122.patch @@ -0,0 +1,11 @@ +--- a/modules/core/mod_macro.c 2023/10/16 06:19:16 1912992 ++++ b/modules/core/mod_macro.c 2023/10/16 06:38:32 1912993 +@@ -483,7 +483,7 @@ + for (i = 0; i < contents->nelts; i++) { + const char *errmsg; + /* copy the line and substitute macro parameters */ +- strncpy(line, ((char **) contents->elts)[i], MAX_STRING_LEN - 1); ++ apr_cpystrn(line, ((char **) contents->elts)[i], MAX_STRING_LEN); + errmsg = substitute_macro_args(line, MAX_STRING_LEN, + macro, replacements, used); + if (errmsg) { diff --git a/SOURCES/httpd-2.4.57-CVE-2024-38473.patch b/SOURCES/httpd-2.4.57-CVE-2024-38473.patch new file mode 100644 index 0000000..2031039 --- /dev/null +++ b/SOURCES/httpd-2.4.57-CVE-2024-38473.patch @@ -0,0 +1,172 @@ +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index 596320d..046fc40 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -1227,6 +1227,7 @@ static int proxy_fixup(request_rec *r) + + return OK; /* otherwise; we've done the best we can */ + } ++ + /* Send a redirection if the request contains a hostname which is not */ + /* fully qualified, i.e. doesn't have a domain name appended. Some proxy */ + /* servers like Netscape's allow this and access hosts from the local */ +@@ -1280,7 +1281,7 @@ static int proxy_handler(request_rec *r) + ap_get_module_config(sconf, &proxy_module); + apr_array_header_t *proxies = conf->proxies; + struct proxy_remote *ents = (struct proxy_remote *) proxies->elts; +- int i, rc, access_status; ++ int rc = DECLINED, access_status, i; + int direct_connect = 0; + const char *str; + apr_int64_t maxfwd; +@@ -1295,19 +1296,28 @@ static int proxy_handler(request_rec *r) + return DECLINED; + } + +- if (!r->proxyreq) { +- /* We may have forced the proxy handler via config or .htaccess */ +- if (r->handler && +- strncmp(r->handler, "proxy:", 6) == 0 && +- strncmp(r->filename, "proxy:", 6) != 0) { +- r->proxyreq = PROXYREQ_REVERSE; +- r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL); ++ /* We may have forced the proxy handler via config or .htaccess */ ++ if (!r->proxyreq && r->handler && strncmp(r->handler, "proxy:", 6) == 0) { ++ char *old_filename = r->filename; ++ ++ r->proxyreq = PROXYREQ_REVERSE; ++ r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL); ++ ++ /* Still need to fixup/canonicalize r->filename */ ++ rc = ap_proxy_fixup_uds_filename(r); ++ if (rc <= OK) { ++ rc = proxy_fixup(r); + } +- else { +- return DECLINED; ++ if (rc != OK) { ++ r->filename = old_filename; ++ r->proxyreq = 0; + } +- } else if (strncmp(r->filename, "proxy:", 6) != 0) { +- return DECLINED; ++ } ++ else if (r->proxyreq && strncmp(r->filename, "proxy:", 6) == 0) { ++ rc = OK; ++ } ++ if (rc != OK) { ++ return rc; + } + + /* handle max-forwards / OPTIONS / TRACE */ +diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h +index eaf431d..523304d 100644 +--- a/modules/proxy/mod_proxy.h ++++ b/modules/proxy/mod_proxy.h +@@ -994,6 +994,14 @@ PROXY_DECLARE(proxy_balancer_shared *) ap_proxy_find_balancershm(ap_slotmem_prov + proxy_balancer *balancer, + unsigned int *index); + ++/* ++ * Strip the UDS part of r->filename if any, and put the UDS path in ++ * r->notes ("uds_path") ++ * @param r current request ++ * @return OK if fixed up, DECLINED if not UDS, or an HTTP_XXX error ++ */ ++PROXY_DECLARE(int) ap_proxy_fixup_uds_filename(request_rec *r); ++ + /** + * Get the most suitable worker and/or balancer for the request + * @param worker worker used for processing request +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index fce4f1b..eba541b 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -2315,7 +2315,7 @@ static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worke + * were passed a UDS url (eg: from mod_proxy) and adjust uds_path + * as required. + */ +-static int fix_uds_filename(request_rec *r, char **url) ++PROXY_DECLARE(int) ap_proxy_fixup_uds_filename(request_rec *r) + { + char *uds_url = r->filename + 6, *origin_url; + +@@ -2323,7 +2323,6 @@ static int fix_uds_filename(request_rec *r, char **url) + !ap_cstr_casecmpn(uds_url, "unix:", 5) && + (origin_url = ap_strchr(uds_url + 5, '|'))) { + char *uds_path = NULL; +- apr_size_t url_len; + apr_uri_t urisock; + apr_status_t rv; + +@@ -2338,20 +2337,20 @@ static int fix_uds_filename(request_rec *r, char **url) + if (!uds_path) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10292) + "Invalid proxy UDS filename (%s)", r->filename); +- return 0; ++ return HTTP_BAD_REQUEST; + } + apr_table_setn(r->notes, "uds_path", uds_path); + +- /* Remove the UDS path from *url and r->filename */ +- url_len = strlen(origin_url); +- *url = apr_pstrmemdup(r->pool, origin_url, url_len); +- memcpy(uds_url, *url, url_len + 1); +- + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, +- "*: rewrite of url due to UDS(%s): %s (%s)", +- uds_path, *url, r->filename); ++ "*: fixup UDS from %s: %s (%s)", ++ r->filename, origin_url, uds_path); ++ ++ /* Overwrite the UDS part in place */ ++ memmove(uds_url, origin_url, strlen(origin_url) + 1); ++ return OK; + } +- return 1; ++ ++ return DECLINED; + } + + PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, +@@ -2370,9 +2369,6 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "%s: found worker %s for %s", + (*worker)->s->scheme, (*worker)->s->name_ex, *url); +- if (!forward && !fix_uds_filename(r, url)) { +- return HTTP_INTERNAL_SERVER_ERROR; +- } + access_status = OK; + } + else if (forward) { +@@ -2402,9 +2398,6 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, + * regarding the Connection header in the request. + */ + apr_table_setn(r->subprocess_env, "proxy-nokeepalive", "1"); +- if (!fix_uds_filename(r, url)) { +- return HTTP_INTERNAL_SERVER_ERROR; +- } + } + } + } +@@ -2414,6 +2407,20 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, + "all workers are busy. Unable to serve %s", *url); + access_status = HTTP_SERVICE_UNAVAILABLE; + } ++ ++ if (access_status == OK && r->proxyreq == PROXYREQ_REVERSE) { ++ int rc = ap_proxy_fixup_uds_filename(r); ++ if (ap_is_HTTP_ERROR(rc)) { ++ return rc; ++ } ++ /* If the URL has changed in r->filename, take everything after ++ * the "proxy:" prefix. ++ */ ++ if (rc == OK) { ++ *url = apr_pstrdup(r->pool, r->filename + 6); ++ } ++ } ++ + return access_status; + } + diff --git a/SOURCES/httpd-2.4.57-CVE-2024-38474+.patch b/SOURCES/httpd-2.4.57-CVE-2024-38474+.patch new file mode 100644 index 0000000..d8c3dbc --- /dev/null +++ b/SOURCES/httpd-2.4.57-CVE-2024-38474+.patch @@ -0,0 +1,439 @@ +diff --git a/docs/manual/mod/mod_rewrite.html.en b/docs/manual/mod/mod_rewrite.html.en +index 30d7434..c4be044 100644 +--- a/docs/manual/mod/mod_rewrite.html.en ++++ b/docs/manual/mod/mod_rewrite.html.en +@@ -1446,6 +1446,16 @@ cannot use $N in the substitution string! + Force the MIME-type of the target file + to be the specified type. details ... + ++ ++ UnsafeAllow3F ++ Allows substitutions from URL's that may be unsafe. ++ details ... ++ ++ ++ UnsafePrefixStat ++ Allows potentially unsafe substitutions from a leading variable or backreference to a filesystem path. ++ details ... ++ + + +

Home directory expansion

+diff --git a/docs/manual/rewrite/flags.html.en b/docs/manual/rewrite/flags.html.en +index 5e175f1..a43aa82 100644 +--- a/docs/manual/rewrite/flags.html.en ++++ b/docs/manual/rewrite/flags.html.en +@@ -811,6 +811,30 @@ re-processing (including subsequent rounds of mod_rewrite processing). + The L flag can be useful in this context to end the + current round of mod_rewrite processing.

+ ++
++ ++
++

UnsafeAllow3F

++ ++

++Setting this flag is required to allow a rewrite to continue If the ++HTTP request being written has an encoded question mark, '%3f', and the ++rewritten result has a '?' in the substiution. This protects from a malicious ++URL taking advantage of a capture and re-substitution of the encoded ++question mark.

++ ++
++
++

UnsafePrefixStat

++ ++

++Setting this flag is required in server-scoped substitutions ++start with a variable or backreference and resolve to a filesystem path. ++These substitutions are not prefixed with the document root. ++This protects from a malicious URL causing the expanded substitution to ++map to an unexpected filesystem location. ++

++ +
+
+

Available Languages:  en  | +diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c +index 0df25ee..e3f7510 100644 +--- a/modules/mappers/mod_rewrite.c ++++ b/modules/mappers/mod_rewrite.c +@@ -177,6 +177,8 @@ static const char* really_last_key = "rewrite_really_last"; + #define RULEFLAG_QSLAST (1<<19) + #define RULEFLAG_QSNONE (1<<20) /* programattic only */ + #define RULEFLAG_ESCAPECTLS (1<<21) ++#define RULEFLAG_UNSAFE_PREFIX_STAT (1<<22) ++#define RULEFLAG_UNSAFE_ALLOW3F (1<<23) + + /* return code of the rewrite rule + * the result may be escaped - or not +@@ -184,7 +186,7 @@ static const char* really_last_key = "rewrite_really_last"; + #define ACTION_NORMAL (1<<0) + #define ACTION_NOESCAPE (1<<1) + #define ACTION_STATUS (1<<2) +- ++#define ACTION_STATUS_SET (1<<3) + + #define MAPTYPE_TXT (1<<0) + #define MAPTYPE_DBM (1<<1) +@@ -208,6 +210,7 @@ static const char* really_last_key = "rewrite_really_last"; + #define OPTION_IGNORE_INHERIT (1<<8) + #define OPTION_IGNORE_CONTEXT_INFO (1<<9) + #define OPTION_LEGACY_PREFIX_DOCROOT (1<<10) ++#define OPTION_UNSAFE_PREFIX_STAT (1<<12) + + #ifndef RAND_MAX + #define RAND_MAX 32767 +@@ -301,6 +304,14 @@ typedef enum { + CONDPAT_AP_EXPR + } pattern_type; + ++typedef enum { ++ RULE_RC_NOMATCH = 0, /* the rule didn't match */ ++ RULE_RC_MATCH = 1, /* a matching rule w/ substitution */ ++ RULE_RC_NOSUB = 2, /* a matching rule w/ no substitution */ ++ RULE_RC_STATUS_SET = 3 /* a matching rule that has set an HTTP error ++ to be returned in r->status */ ++} rule_return_type; ++ + typedef struct { + char *input; /* Input string of RewriteCond */ + char *pattern; /* the RegExp pattern string */ +@@ -927,10 +938,15 @@ static void fully_qualify_uri(request_rec *r) + return; + } + ++static int startsWith(request_rec *r, const char *haystack, const char *needle) { ++ int rc = (ap_strstr_c(haystack, needle) == haystack); ++ rewritelog((r, 5, NULL, "prefix_stat startsWith(%s, %s) %d", haystack, needle, rc)); ++ return rc; ++} + /* +- * stat() only the first segment of a path ++ * stat() only the first segment of a path, and only if it matches the output of the last matching rule + */ +-static int prefix_stat(const char *path, apr_pool_t *pool) ++static int prefix_stat(request_rec *r, const char *path, apr_pool_t *pool, rewriterule_entry *lastsub) + { + const char *curpath = path; + const char *root; +@@ -964,10 +980,36 @@ static int prefix_stat(const char *path, apr_pool_t *pool) + apr_finfo_t sb; + + if (apr_stat(&sb, statpath, APR_FINFO_MIN, pool) == APR_SUCCESS) { +- return 1; ++ if (!lastsub) { ++ rewritelog((r, 3, NULL, "prefix_stat no lastsub subst prefix %s", statpath)); ++ return 1; ++ } ++ ++ rewritelog((r, 3, NULL, "prefix_stat compare statpath %s and lastsub output %s STATOK %d ", ++ statpath, lastsub->output, lastsub->flags & RULEFLAG_UNSAFE_PREFIX_STAT)); ++ if (lastsub->flags & RULEFLAG_UNSAFE_PREFIX_STAT) { ++ return 1; ++ } ++ else { ++ const char *docroot = ap_document_root(r); ++ const char *context_docroot = ap_context_document_root(r); ++ /* ++ * As an example, path (r->filename) is /var/foo/bar/baz.html ++ * even if the flag is not set, we can accept a rule that ++ * began with a literal /var (stapath), or if the entire path ++ * starts with the docroot or context document root ++ */ ++ if (startsWith(r, lastsub->output, statpath) || ++ startsWith(r, path, docroot) || ++ ((docroot != context_docroot) && ++ startsWith(r, path, context_docroot))) { ++ return 1; ++ } ++ } + } + } + ++ /* prefix will be added */ + return 0; + } + +@@ -3072,6 +3114,9 @@ static const char *cmd_rewriteoptions(cmd_parms *cmd, + else if (!strcasecmp(w, "legacyprefixdocroot")) { + options |= OPTION_LEGACY_PREFIX_DOCROOT; + } ++ else if (!strcasecmp(w, "UnsafePrefixStat")) { ++ options |= OPTION_UNSAFE_PREFIX_STAT; ++ } + else { + return apr_pstrcat(cmd->pool, "RewriteOptions: unknown option '", + w, "'", NULL); +@@ -3780,6 +3825,18 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg, + ++error; + } + break; ++ case 'u': ++ case 'U': ++ if (!strcasecmp(key, "nsafePrefixStat")){ ++ cfg->flags |= (RULEFLAG_UNSAFE_PREFIX_STAT); ++ } ++ else if(!strcasecmp(key, "nsafeAllow3F")) { ++ cfg->flags |= RULEFLAG_UNSAFE_ALLOW3F; ++ } ++ else { ++ ++error; ++ } ++ break; + default: + ++error; + break; +@@ -4130,7 +4187,8 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p, + /* + * Apply a single RewriteRule + */ +-static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) ++static rule_return_type apply_rewrite_rule(rewriterule_entry *p, ++ rewrite_ctx *ctx) + { + ap_regmatch_t regmatch[AP_MAX_REG_MATCH]; + apr_array_header_t *rewriteconds; +@@ -4181,7 +4239,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + rc = !ap_regexec(p->regexp, ctx->uri, AP_MAX_REG_MATCH, regmatch, 0); + if (! (( rc && !(p->flags & RULEFLAG_NOTMATCH)) || + (!rc && (p->flags & RULEFLAG_NOTMATCH)) ) ) { +- return 0; ++ return RULE_RC_NOMATCH; + } + + /* It matched, wow! Now it's time to prepare the context structure for +@@ -4232,7 +4290,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + } + } + else if (!rc) { +- return 0; ++ return RULE_RC_NOMATCH; + } + + /* If some HTTP header was involved in the condition, remember it +@@ -4252,6 +4310,15 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + newuri = do_expand(p->output, ctx, p); + rewritelog((r, 2, ctx->perdir, "rewrite '%s' -> '%s'", ctx->uri, + newuri)); ++ if (!(p->flags & RULEFLAG_UNSAFE_ALLOW3F) && ++ ap_strcasestr(r->unparsed_uri, "%3f") && ++ ap_strchr_c(newuri, '?')) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO() ++ "Unsafe URL with %%3f URL rewritten without " ++ "UnsafeAllow3F"); ++ r->status = HTTP_FORBIDDEN; ++ return RULE_RC_STATUS_SET; ++ } + } + + /* expand [E=var:val] and [CO=] */ +@@ -4269,7 +4336,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + r->status = p->forced_responsecode; + } + +- return 2; ++ return RULE_RC_NOSUB; + } + + /* Add the previously stripped per-directory location prefix, unless +@@ -4335,7 +4402,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + r->filename)); + + r->filename = apr_pstrcat(r->pool, "proxy:", r->filename, NULL); +- return 1; ++ return RULE_RC_MATCH; + } + + /* If this rule is explicitly forced for HTTP redirection +@@ -4350,7 +4417,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + r->filename)); + + r->status = p->forced_responsecode; +- return 1; ++ return RULE_RC_MATCH; + } + + /* Special Rewriting Feature: Self-Reduction +@@ -4372,7 +4439,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + "with %s", p->forced_responsecode, r->filename)); + + r->status = p->forced_responsecode; +- return 1; ++ return RULE_RC_MATCH; + } + + /* Finally remember the forced mime-type */ +@@ -4381,7 +4448,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + /* Puuhhhhhhhh... WHAT COMPLICATED STUFF ;_) + * But now we're done for this particular rule. + */ +- return 1; ++ return RULE_RC_MATCH; + } + + /* +@@ -4389,13 +4456,13 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + * i.e. a list of rewrite rules + */ + static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules, +- char *perdir) ++ char *perdir, rewriterule_entry **lastsub) + { + rewriterule_entry *entries; + rewriterule_entry *p; + int i; + int changed; +- int rc; ++ rule_return_type rc; + int s; + rewrite_ctx *ctx; + int round = 1; +@@ -4403,6 +4470,7 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules, + ctx = apr_palloc(r->pool, sizeof(*ctx)); + ctx->perdir = perdir; + ctx->r = r; ++ *lastsub = NULL; + + /* + * Iterate over all existing rules +@@ -4430,7 +4498,12 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules, + ctx->vary = NULL; + rc = apply_rewrite_rule(p, ctx); + +- if (rc) { ++ if (rc != RULE_RC_NOMATCH) { ++ ++ if (!(p->flags & RULEFLAG_NOSUB)) { ++ rewritelog((r, 2, perdir, "setting lastsub to rule with output %s", p->output)); ++ *lastsub = p; ++ } + + /* Catch looping rules with pathinfo growing unbounded */ + if ( strlen( r->filename ) > 2*r->server->limit_req_line ) { +@@ -4450,6 +4523,12 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules, + apr_table_merge(r->headers_out, "Vary", ctx->vary); + } + ++ ++ /* Error while evaluating rule, r->status set */ ++ if (RULE_RC_STATUS_SET == rc) { ++ return ACTION_STATUS_SET; ++ } ++ + /* + * The rule sets the response code (implies match-only) + */ +@@ -4460,7 +4539,7 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules, + /* + * Indicate a change if this was not a match-only rule. + */ +- if (rc != 2) { ++ if (rc != RULE_RC_NOSUB) { + changed = ((p->flags & RULEFLAG_NOESCAPE) + ? ACTION_NOESCAPE : ACTION_NORMAL); + } +@@ -4649,6 +4728,7 @@ static int hook_uri2file(request_rec *r) + int rulestatus; + void *skipdata; + const char *oargs; ++ rewriterule_entry *lastsub = NULL; + + /* + * retrieve the config structures +@@ -4760,7 +4840,7 @@ static int hook_uri2file(request_rec *r) + /* + * now apply the rules ... + */ +- rulestatus = apply_rewrite_list(r, conf->rewriterules, NULL); ++ rulestatus = apply_rewrite_list(r, conf->rewriterules, NULL, &lastsub); + apr_table_setn(r->notes, "mod_rewrite_rewritten", + apr_psprintf(r->pool,"%d",rulestatus)); + } +@@ -4798,6 +4878,9 @@ static int hook_uri2file(request_rec *r) + r->status = HTTP_OK; + return n; + } ++ else if (ACTION_STATUS_SET == rulestatus) { ++ return r->status; ++ } + + if (to_proxyreq) { + /* it should be go on as an internal proxy request */ +@@ -4917,23 +5000,29 @@ static int hook_uri2file(request_rec *r) + return HTTP_BAD_REQUEST; + } + +- /* if there is no valid prefix, we call +- * the translator from the core and +- * prefix the filename with document_root ++ /* We have r->filename as a path in a server-context rewrite without ++ * the PT flag. The historical behavior is to treat it as a verbatim ++ * filesystem path iff the first component of the path exists and is ++ * readable by httpd. Otherwise, it is interpreted as DocumentRoot ++ * relative. + * + * NOTICE: + * We cannot leave out the prefix_stat because +- * - when we always prefix with document_root +- * then no absolute path can be created, e.g. via +- * emulating a ScriptAlias directive, etc. +- * - when we always NOT prefix with document_root ++ * - If we always prefix with document_root ++ * then no absolute path can could ever be used in ++ * a substitution. e.g. emulating an Alias. ++ * - If we never prefix with document_root + * then the files under document_root have to + * be references directly and document_root + * gets never used and will be a dummy parameter - +- * this is also bad ++ * this is also bad. ++ * - Later addition: This part is questionable. ++ * If we had never prefixed, users would just ++ * need %{DOCUMENT_ROOT} in substitutions or the ++ * [PT] flag. + * + * BUT: +- * Under real Unix systems this is no problem, ++ * Under real Unix systems this is no perf problem, + * because we only do stat() on the first directory + * and this gets cached by the kernel for along time! + */ +@@ -4942,7 +5031,9 @@ static int hook_uri2file(request_rec *r) + uri_reduced = apr_table_get(r->notes, "mod_rewrite_uri_reduced"); + } + +- if (!prefix_stat(r->filename, r->pool) || uri_reduced != NULL) { ++ if (!prefix_stat(r, r->filename, r->pool, ++ conf->options & OPTION_UNSAFE_PREFIX_STAT ? NULL : lastsub) ++ || uri_reduced != NULL) { + int res; + char *tmp = r->uri; + +@@ -4987,6 +5078,7 @@ static int hook_fixup(request_rec *r) + char *ofilename, *oargs; + int is_proxyreq; + void *skipdata; ++ rewriterule_entry *lastsub; + + dconf = (rewrite_perdir_conf *)ap_get_module_config(r->per_dir_config, + &rewrite_module); +@@ -5071,7 +5163,7 @@ static int hook_fixup(request_rec *r) + /* + * now apply the rules ... + */ +- rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory); ++ rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory, &lastsub); + if (rulestatus) { + unsigned skip_absolute = is_absolute_uri(r->filename, NULL); + int to_proxyreq = 0; +@@ -5100,6 +5192,9 @@ static int hook_fixup(request_rec *r) + r->status = HTTP_OK; + return n; + } ++ else if (ACTION_STATUS_SET == rulestatus) { ++ return r->status; ++ } + + if (to_proxyreq) { + /* it should go on as an internal proxy request */ diff --git a/SOURCES/httpd-2.4.57-CVE-2024-38477.patch b/SOURCES/httpd-2.4.57-CVE-2024-38477.patch new file mode 100644 index 0000000..f9a9479 --- /dev/null +++ b/SOURCES/httpd-2.4.57-CVE-2024-38477.patch @@ -0,0 +1,43 @@ +From 1d98d4db186e708f059336fb9342d0adb6925e85 Mon Sep 17 00:00:00 2001 +From: Eric Covener +Date: Tue, 25 Jun 2024 17:29:32 +0000 +Subject: [PATCH] Merge r1918606 from trunk: + +validate hostname + + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1918607 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/proxy/proxy_util.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index ea36465..fce4f1b 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -2619,6 +2619,13 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + apr_pstrcat(p,"URI cannot be parsed: ", *url, + NULL)); + } ++ ++ if (!uri->hostname) { ++ return ap_proxyerror(r, HTTP_BAD_REQUEST, ++ apr_pstrcat(p,"URI has no hostname: ", *url, ++ NULL)); ++ } ++ + if (!uri->port) { + uri->port = ap_proxy_port_of_scheme(uri->scheme); + } +@@ -3989,6 +3996,10 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + + /* Compute Host header */ + if (dconf->preserve_host == 0) { ++ if (!uri->hostname) { ++ rc = HTTP_BAD_REQUEST; ++ goto cleanup; ++ } + if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */ + if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) { + host = apr_pstrcat(r->pool, "[", uri->hostname, "]:", diff --git a/SOURCES/httpd-2.4.57-CVE-2024-39573.patch b/SOURCES/httpd-2.4.57-CVE-2024-39573.patch new file mode 100644 index 0000000..946a12f --- /dev/null +++ b/SOURCES/httpd-2.4.57-CVE-2024-39573.patch @@ -0,0 +1,72 @@ +From 93aec0e3ca451bcc97f6d91c14d5399d13a73365 Mon Sep 17 00:00:00 2001 +From: Eric Covener +Date: Tue, 25 Jun 2024 15:28:00 +0000 +Subject: [PATCH] Merge r1918553 from trunk: + +block inadvertent subst of special filenames + ++ cosmetic merge conflicts + + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1918600 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/mappers/mod_rewrite.c | 38 ++++++++++++++++++++++++----------- + 1 file changed, 26 insertions(+), 12 deletions(-) + +diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c +index 4be51de..0df25ee 100644 +--- a/modules/mappers/mod_rewrite.c ++++ b/modules/mappers/mod_rewrite.c +@@ -4272,6 +4272,32 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + return 2; + } + ++ /* Add the previously stripped per-directory location prefix, unless ++ * (1) it's an absolute URL path and ++ * (2) it's a full qualified URL ++ */ ++ if (!is_proxyreq && *newuri != '/' && !is_absolute_uri(newuri, NULL)) { ++ if (ctx->perdir) { ++ rewritelog((r, 3, ctx->perdir, "add per-dir prefix: %s -> %s%s", ++ newuri, ctx->perdir, newuri)); ++ ++ newuri = apr_pstrcat(r->pool, ctx->perdir, newuri, NULL); ++ } ++ else if (!(p->flags & (RULEFLAG_PROXY | RULEFLAG_FORCEREDIRECT))) { ++ /* Not an absolute URI-path and the scheme (if any) is unknown, ++ * and it won't be passed to fully_qualify_uri() below either, ++ * so add an implicit '/' prefix. This avoids potentially a common ++ * rule like "RewriteRule ^/some/path(.*) $1" that is given a path ++ * like "/some/pathscheme:..." to produce the fully qualified URL ++ * "scheme:..." which could be misinterpreted later. ++ */ ++ rewritelog((r, 3, ctx->perdir, "add root prefix: %s -> /%s", ++ newuri, newuri)); ++ ++ newuri = apr_pstrcat(r->pool, "/", newuri, NULL); ++ } ++ } ++ + /* Now adjust API's knowledge about r->filename and r->args */ + r->filename = newuri; + +@@ -4281,18 +4307,6 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + + splitout_queryargs(r, p->flags); + +- /* Add the previously stripped per-directory location prefix, unless +- * (1) it's an absolute URL path and +- * (2) it's a full qualified URL +- */ +- if ( ctx->perdir && !is_proxyreq && *r->filename != '/' +- && !is_absolute_uri(r->filename, NULL)) { +- rewritelog((r, 3, ctx->perdir, "add per-dir prefix: %s -> %s%s", +- r->filename, ctx->perdir, r->filename)); +- +- r->filename = apr_pstrcat(r->pool, ctx->perdir, r->filename, NULL); +- } +- + /* If this rule is forced for proxy throughput + * (`RewriteRule ... ... [P]') then emulate mod_proxy's + * URL-to-filename handler to be sure mod_proxy is triggered diff --git a/SOURCES/httpd-2.4.57-r1884505+.patch b/SOURCES/httpd-2.4.57-r1884505+.patch new file mode 100644 index 0000000..97bc6a8 --- /dev/null +++ b/SOURCES/httpd-2.4.57-r1884505+.patch @@ -0,0 +1,39 @@ +# ./pullrev.sh 1884505 1915625 +http://svn.apache.org/viewvc?view=revision&revision=1884505 +http://svn.apache.org/viewvc?view=revision&revision=1915625 + +--- httpd-2.4.57/modules/filters/mod_xml2enc.c ++++ httpd-2.4.57/modules/filters/mod_xml2enc.c +@@ -329,7 +329,7 @@ + apr_bucket* bstart; + apr_size_t insz = 0; + int pending_meta = 0; +- char *ctype; ++ char *mtype; + char *p; + + if (!ctx || !f->r->content_type) { +@@ -338,13 +338,17 @@ + return ap_pass_brigade(f->next, bb) ; + } + +- ctype = apr_pstrdup(f->r->pool, f->r->content_type); +- for (p = ctype; *p; ++p) +- if (isupper(*p)) +- *p = tolower(*p); ++ /* Extract the media type, ignoring parameters in content-type. */ ++ mtype = apr_pstrdup(f->r->pool, f->r->content_type); ++ if ((p = ap_strchr(mtype, ';')) != NULL) *p = '\0'; ++ ap_str_tolower(mtype); + +- /* only act if starts-with "text/" or contains "xml" */ +- if (strncmp(ctype, "text/", 5) && !strstr(ctype, "xml")) { ++ /* Accept text/ types, plus any XML media type per RFC 7303. */ ++ if (!(strncmp(mtype, "text/", 5) == 0 ++ || strcmp(mtype, "application/xml") == 0 ++ || (strlen(mtype) > 7 /* minimum 'a/b+xml' length */ ++ && (p = strstr(mtype, "+xml")) != NULL ++ && strlen(p) == 4 /* ensures +xml is a suffix */))) { + ap_remove_output_filter(f); + return ap_pass_brigade(f->next, bb) ; + } diff --git a/SOURCES/httpd-2.4.57-r1912081.patch b/SOURCES/httpd-2.4.57-r1912081.patch new file mode 100644 index 0000000..111e5ac --- /dev/null +++ b/SOURCES/httpd-2.4.57-r1912081.patch @@ -0,0 +1,91 @@ +# ./pullrev.sh 1912081 +http://svn.apache.org/viewvc?view=revision&revision=1912081 + +Upstream-Status: merged in 2.4.58 + +--- httpd-2.4.57/modules/dav/main/mod_dav.c ++++ httpd-2.4.57/modules/dav/main/mod_dav.c +@@ -81,6 +81,7 @@ + const char *provider_name; + const dav_provider *provider; + const char *dir; ++ const char *base; + int locktimeout; + int allow_depthinfinity; + int allow_lockdiscovery; +@@ -196,6 +197,7 @@ + + newconf->locktimeout = DAV_INHERIT_VALUE(parent, child, locktimeout); + newconf->dir = DAV_INHERIT_VALUE(parent, child, dir); ++ newconf->base = DAV_INHERIT_VALUE(parent, child, base); + newconf->allow_depthinfinity = DAV_INHERIT_VALUE(parent, child, + allow_depthinfinity); + newconf->allow_lockdiscovery = DAV_INHERIT_VALUE(parent, child, +@@ -283,6 +285,18 @@ + } + + /* ++ * Command handler for the DAVBasePath directive, which is TAKE1 ++ */ ++static const char *dav_cmd_davbasepath(cmd_parms *cmd, void *config, const char *arg1) ++{ ++ dav_dir_conf *conf = config; ++ ++ conf->base = arg1; ++ ++ return NULL; ++} ++ ++/* + * Command handler for the DAVDepthInfinity directive, which is FLAG. + */ + static const char *dav_cmd_davdepthinfinity(cmd_parms *cmd, void *config, +@@ -748,7 +762,7 @@ + int use_checked_in, dav_resource **res_p) + { + dav_dir_conf *conf; +- const char *label = NULL; ++ const char *label = NULL, *base; + dav_error *err; + + /* if the request target can be overridden, get any target selector */ +@@ -765,11 +779,27 @@ + ap_escape_html(r->pool, r->uri))); + } + ++ /* Take the repos root from DAVBasePath if configured, else the ++ * path of the enclosing section. */ ++ base = conf->base ? conf->base : conf->dir; ++ + /* resolve the resource */ +- err = (*conf->provider->repos->get_resource)(r, conf->dir, ++ err = (*conf->provider->repos->get_resource)(r, base, + label, use_checked_in, + res_p); + if (err != NULL) { ++ /* In the error path, give a hint that DavBasePath needs to be ++ * used if the location was configured via a regex match. */ ++ if (!conf->base) { ++ core_dir_config *cdc = ap_get_core_module_config(r->per_dir_config); ++ ++ if (cdc->r) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(10484) ++ "failed to find repository for location configured " ++ "via regex match - missing DAVBasePath?"); ++ } ++ } ++ + err = dav_push_error(r->pool, err->status, 0, + "Could not fetch resource information.", err); + return err; +@@ -5164,6 +5194,10 @@ + AP_INIT_TAKE1("DAV", dav_cmd_dav, NULL, ACCESS_CONF, + "specify the DAV provider for a directory or location"), + ++ /* per directory/location */ ++ AP_INIT_TAKE1("DAVBasePath", dav_cmd_davbasepath, NULL, ACCESS_CONF, ++ "specify the DAV repository base URL"), ++ + /* per directory/location, or per server */ + AP_INIT_TAKE1("DAVMinTimeout", dav_cmd_davmintimeout, NULL, + ACCESS_CONF|RSRC_CONF, diff --git a/SOURCES/httpd-2.4.57-r1912477+.patch b/SOURCES/httpd-2.4.57-r1912477+.patch new file mode 100644 index 0000000..6458df8 --- /dev/null +++ b/SOURCES/httpd-2.4.57-r1912477+.patch @@ -0,0 +1,381 @@ +# ./pullrev.sh 1912477 1912571 1912718 1913654 1914438 +http://svn.apache.org/viewvc?view=revision&revision=1912477 +http://svn.apache.org/viewvc?view=revision&revision=1912571 +http://svn.apache.org/viewvc?view=revision&revision=1912718 +http://svn.apache.org/viewvc?view=revision&revision=1913654 +http://svn.apache.org/viewvc?view=revision&revision=1914438 + +--- httpd-2.4.58/modules/dav/fs/config6.m4.r1912477+ ++++ httpd-2.4.58/modules/dav/fs/config6.m4 +@@ -20,4 +20,10 @@ + + APACHE_MODULE(dav_fs, DAV provider for the filesystem. --enable-dav also enables mod_dav_fs., $dav_fs_objects, , $dav_fs_enable,,dav) + ++if test "x$enable_dav_fs" = "xshared"; then ++ # The only symbol which needs to be exported is the module ++ # structure, so ask libtool to hide everything else: ++ APR_ADDTO(MOD_DAV_FS_LDADD, [-export-symbols-regex dav_fs_module]) ++fi ++ + APACHE_MODPATH_FINISH +--- httpd-2.4.58/modules/dav/fs/dbm.c.r1912477+ ++++ httpd-2.4.58/modules/dav/fs/dbm.c +@@ -47,6 +47,10 @@ + #include "http_log.h" + #include "http_main.h" /* for ap_server_conf */ + ++#ifndef DEFAULT_PROPDB_DBM_TYPE ++#define DEFAULT_PROPDB_DBM_TYPE "default" ++#endif ++ + APLOG_USE_MODULE(dav_fs); + + struct dav_db { +@@ -100,7 +104,7 @@ + /* There might not be a if we had problems creating it. */ + if (db == NULL) { + errcode = 1; +- errstr = "Could not open property database."; ++ errstr = "Could not open database."; + if (APR_STATUS_IS_EDSOOPEN(status)) + ap_log_error(APLOG_MARK, APLOG_CRIT, status, ap_server_conf, APLOGNO(00576) + "The DBM driver could not be loaded"); +@@ -129,10 +133,10 @@ + /* dav_dbm_open_direct: Opens a *dbm database specified by path. + * ro = boolean read-only flag. + */ +-dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, int ro, +- dav_db **pdb) ++dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, ++ const char *dbmtype, int ro, dav_db **pdb) + { +-#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) ++#if APR_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) + const apr_dbm_driver_t *driver; + const apu_err_t *err; + #endif +@@ -141,13 +145,13 @@ + + *pdb = NULL; + +-#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) +- if ((status = apr_dbm_get_driver(&driver, NULL, &err, p)) != APR_SUCCESS) { ++#if APR_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) ++ if ((status = apr_dbm_get_driver(&driver, dbmtype, &err, p)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf, APLOGNO(10289) +- "mod_dav_fs: The DBM library '%s' could not be loaded: %s", +- err->reason, err->msg); ++ "mod_dav_fs: The DBM library '%s' for '%s' could not be loaded: %s", ++ err->reason, dbmtype, err->msg); + return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 1, status, +- "Could not load library for property database."); ++ "Could not load library for database."); + } + if ((status = apr_dbm_open2(&file, driver, pathname, + ro ? APR_DBM_READONLY : APR_DBM_RWCREATE, +@@ -156,7 +160,7 @@ + return dav_fs_dbm_error(NULL, p, status); + } + #else +- if ((status = apr_dbm_open(&file, pathname, ++ if ((status = apr_dbm_open_ex(&file, dbmtype, pathname, + ro ? APR_DBM_READONLY : APR_DBM_RWCREATE, + APR_OS_DEFAULT, p)) + != APR_SUCCESS +@@ -206,7 +210,7 @@ + + /* ### do we need to deal with the umask? */ + +- return dav_dbm_open_direct(p, pathname, ro, pdb); ++ return dav_dbm_open_direct(p, pathname, DEFAULT_PROPDB_DBM_TYPE, ro, pdb); + } + + void dav_dbm_close(dav_db *db) +--- httpd-2.4.58/modules/dav/fs/lock.c.r1912477+ ++++ httpd-2.4.58/modules/dav/fs/lock.c +@@ -181,8 +181,7 @@ + { + request_rec *r; /* for accessing the uuid state */ + apr_pool_t *pool; /* a pool to use */ +- const char *lockdb_path; /* where is the lock database? */ +- ++ const dav_fs_server_conf *conf; /* lock database config & metadata */ + int opened; /* we opened the database */ + dav_db *db; /* if non-NULL, the lock database */ + }; +@@ -292,6 +291,19 @@ + return dav_compare_locktoken(lt1, lt2); + } + ++static apr_status_t dav_fs_lockdb_cleanup(void *data) ++{ ++ dav_lockdb *lockdb = data; ++ ++ apr_global_mutex_unlock(lockdb->info->conf->lockdb_mutex); ++ ++ if (lockdb->info->db) { ++ dav_dbm_close(lockdb->info->db); ++ } ++ ++ return APR_SUCCESS; ++} ++ + /* + ** dav_fs_really_open_lockdb: + ** +@@ -300,15 +312,27 @@ + static dav_error * dav_fs_really_open_lockdb(dav_lockdb *lockdb) + { + dav_error *err; ++ apr_status_t rv; + + if (lockdb->info->opened) + return NULL; + ++ rv = apr_global_mutex_lock(lockdb->info->conf->lockdb_mutex); ++ if (rv) { ++ return dav_new_error(lockdb->info->pool, ++ HTTP_INTERNAL_SERVER_ERROR, ++ DAV_ERR_LOCK_OPENDB, rv, ++ "Could not lock mutex for lock database."); ++ } ++ + err = dav_dbm_open_direct(lockdb->info->pool, +- lockdb->info->lockdb_path, ++ lockdb->info->conf->lockdb_path, ++ lockdb->info->conf->lockdb_type, + lockdb->ro, + &lockdb->info->db); + if (err != NULL) { ++ apr_global_mutex_unlock(lockdb->info->conf->lockdb_mutex); ++ + return dav_push_error(lockdb->info->pool, + HTTP_INTERNAL_SERVER_ERROR, + DAV_ERR_LOCK_OPENDB, +@@ -316,6 +340,10 @@ + err); + } + ++ apr_pool_cleanup_register(lockdb->info->pool, lockdb, ++ dav_fs_lockdb_cleanup, ++ dav_fs_lockdb_cleanup); ++ + /* all right. it is opened now. */ + lockdb->info->opened = 1; + +@@ -341,9 +369,9 @@ + comb->pub.info = &comb->priv; + comb->priv.r = r; + comb->priv.pool = r->pool; +- +- comb->priv.lockdb_path = dav_get_lockdb_path(r); +- if (comb->priv.lockdb_path == NULL) { ++ comb->priv.conf = dav_fs_get_server_conf(r); ++ ++ if (comb->priv.conf == NULL || comb->priv.conf->lockdb_path == NULL) { + return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, + DAV_ERR_LOCK_NO_DB, 0, + "A lock database was not specified with the " +@@ -369,8 +397,8 @@ + */ + static void dav_fs_close_lockdb(dav_lockdb *lockdb) + { +- if (lockdb->info->db != NULL) +- dav_dbm_close(lockdb->info->db); ++ apr_pool_cleanup_run(lockdb->info->pool, lockdb, ++ dav_fs_lockdb_cleanup); + } + + /* +--- httpd-2.4.58/modules/dav/fs/mod_dav_fs.c.r1912477+ ++++ httpd-2.4.58/modules/dav/fs/mod_dav_fs.c +@@ -14,31 +14,35 @@ + * limitations under the License. + */ + ++#if !defined(_MSC_VER) && !defined(NETWARE) ++#include "ap_config_auto.h" ++#endif ++ + #include "httpd.h" + #include "http_config.h" ++#include "http_core.h" ++#include "http_log.h" + #include "apr_strings.h" + + #include "mod_dav.h" + #include "repos.h" + +-/* per-server configuration */ +-typedef struct { +- const char *lockdb_path; +- +-} dav_fs_server_conf; +- + extern module AP_MODULE_DECLARE_DATA dav_fs_module; + + #ifndef DEFAULT_DAV_LOCKDB + #define DEFAULT_DAV_LOCKDB "davlockdb" + #endif ++#ifndef DEFAULT_DAV_LOCKDB_TYPE ++#define DEFAULT_DAV_LOCKDB_TYPE "default" ++#endif + +-const char *dav_get_lockdb_path(const request_rec *r) +-{ +- dav_fs_server_conf *conf; ++static const char dav_fs_mutexid[] = "dav_fs-lockdb"; + +- conf = ap_get_module_config(r->server->module_config, &dav_fs_module); +- return conf->lockdb_path; ++static apr_global_mutex_t *dav_fs_lockdb_mutex; ++ ++const dav_fs_server_conf *dav_fs_get_server_conf(const request_rec *r) ++{ ++ return ap_get_module_config(r->server->module_config, &dav_fs_module); + } + + static void *dav_fs_create_server_config(apr_pool_t *p, server_rec *s) +@@ -57,15 +61,50 @@ + + newconf->lockdb_path = + child->lockdb_path ? child->lockdb_path : parent->lockdb_path; ++ newconf->lockdb_type = ++ child->lockdb_type ? child->lockdb_type : parent->lockdb_type; + + return newconf; + } + ++static int dav_fs_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) ++{ ++ if (ap_mutex_register(pconf, dav_fs_mutexid, NULL, APR_LOCK_DEFAULT, 0)) ++ return !OK; ++ return OK; ++} ++ ++static void dav_fs_child_init(apr_pool_t *p, server_rec *s) ++{ ++ apr_status_t rv; ++ ++ rv = apr_global_mutex_child_init(&dav_fs_lockdb_mutex, ++ apr_global_mutex_lockfile(dav_fs_lockdb_mutex), ++ p); ++ if (rv) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, ++ APLOGNO(10488) "child init failed for mutex"); ++ } ++} ++ + static apr_status_t dav_fs_post_config(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *base_server) + { + server_rec *s; ++ apr_status_t rv; + ++ /* Ignore first pass through the config. */ ++ if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) ++ return OK; ++ ++ rv = ap_global_mutex_create(&dav_fs_lockdb_mutex, NULL, dav_fs_mutexid, NULL, ++ base_server, p, 0); ++ if (rv) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, base_server, ++ APLOGNO(10489) "could not create lock mutex"); ++ return !OK; ++ } ++ + for (s = base_server; s; s = s->next) { + dav_fs_server_conf *conf; + +@@ -74,6 +113,13 @@ + if (!conf->lockdb_path) { + conf->lockdb_path = ap_state_dir_relative(p, DEFAULT_DAV_LOCKDB); + } ++ if (!conf->lockdb_type) { ++ conf->lockdb_type = DEFAULT_DAV_LOCKDB_TYPE; ++ } ++ ++ /* Mutex is common across all vhosts, but could have one per ++ * vhost if required. */ ++ conf->lockdb_mutex = dav_fs_lockdb_mutex; + } + + return OK; +@@ -98,19 +144,36 @@ + return NULL; + } + ++/* ++ * Command handler for the DAVLockDBType directive, which is TAKE1 ++ */ ++static const char *dav_fs_cmd_davlockdbtype(cmd_parms *cmd, void *config, ++ const char *arg1) ++{ ++ dav_fs_server_conf *conf = ap_get_module_config(cmd->server->module_config, ++ &dav_fs_module); ++ conf->lockdb_type = arg1; ++ ++ return NULL; ++} ++ + static const command_rec dav_fs_cmds[] = + { + /* per server */ + AP_INIT_TAKE1("DAVLockDB", dav_fs_cmd_davlockdb, NULL, RSRC_CONF, + "specify a lock database"), ++ AP_INIT_TAKE1("DAVLockDBType", dav_fs_cmd_davlockdbtype, NULL, RSRC_CONF, ++ "specify a lock database DBM type"), + + { NULL } + }; + + static void register_hooks(apr_pool_t *p) + { ++ ap_hook_pre_config(dav_fs_pre_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_post_config(dav_fs_post_config, NULL, NULL, APR_HOOK_MIDDLE); +- ++ ap_hook_child_init(dav_fs_child_init, NULL, NULL, APR_HOOK_MIDDLE); ++ + dav_hook_gather_propsets(dav_fs_gather_propsets, NULL, NULL, + APR_HOOK_MIDDLE); + dav_hook_find_liveprop(dav_fs_find_liveprop, NULL, NULL, APR_HOOK_MIDDLE); +--- httpd-2.4.58/modules/dav/fs/repos.h.r1912477+ ++++ httpd-2.4.58/modules/dav/fs/repos.h +@@ -25,6 +25,8 @@ + #ifndef _DAV_FS_REPOS_H_ + #define _DAV_FS_REPOS_H_ + ++#include "util_mutex.h" ++ + /* the subdirectory to hold all DAV-related information for a directory */ + #define DAV_FS_STATE_DIR ".DAV" + #define DAV_FS_STATE_FILE_FOR_DIR ".state_for_dir" +@@ -53,8 +55,8 @@ + /* DBM functions used by the repository and locking providers */ + extern const dav_hooks_db dav_hooks_db_dbm; + +-dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, int ro, +- dav_db **pdb); ++dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, ++ const char *dbmtype, int ro, dav_db **pdb); + void dav_dbm_get_statefiles(apr_pool_t *p, const char *fname, + const char **state1, const char **state2); + dav_error * dav_dbm_delete(dav_db *db, apr_datum_t key); +@@ -64,8 +66,15 @@ + int dav_dbm_exists(dav_db *db, apr_datum_t key); + void dav_dbm_close(dav_db *db); + +-/* where is the lock database located? */ +-const char *dav_get_lockdb_path(const request_rec *r); ++/* Per-server configuration. */ ++typedef struct { ++ const char *lockdb_path; ++ const char *lockdb_type; ++ apr_global_mutex_t *lockdb_mutex; ++} dav_fs_server_conf; ++ ++/* Returns server configuration for the request. */ ++const dav_fs_server_conf *dav_fs_get_server_conf(const request_rec *r); + + const dav_hooks_locks *dav_fs_get_lock_hooks(request_rec *r); + const dav_hooks_propdb *dav_fs_get_propdb_hooks(request_rec *r); diff --git a/SPECS/httpd.spec b/SPECS/httpd.spec index e36fb1f..230d599 100644 --- a/SPECS/httpd.spec +++ b/SPECS/httpd.spec @@ -13,7 +13,7 @@ Summary: Apache HTTP Server Name: httpd Version: 2.4.57 -Release: 5%{?dist} +Release: 11%{?dist} URL: https://httpd.apache.org/ Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source1: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2.asc @@ -94,6 +94,10 @@ Patch49: httpd-2.4.48-ssl-proxy-chains.patch Patch50: httpd-2.4.57-r1825120.patch # https://bugzilla.redhat.com/show_bug.cgi?id=2065677 Patch52: httpd-2.4.53-separate-systemd-fns.patch +# https://issues.redhat.com/browse/RHEL-5071 +Patch53: httpd-2.4.57-r1912477+.patch +# https://issues.redhat.com/browse/RHEL-6600 +Patch54: httpd-2.4.57-r1912081.patch # Bug fixes @@ -116,11 +120,25 @@ Patch69: httpd-2.4.57-covscan.patch Patch70: httpd-2.4.57-mod_status-duplicate-key.patch # https://bugzilla.redhat.com/show_bug.cgi?id=2217726 Patch71: httpd-2.4.57-davenoent.patch - +# https://issues.redhat.com/browse/RHEL-17686 +Patch72: httpd-2.4.57-r1884505+.patch # Security fixes # https://bugzilla.redhat.com/show_bug.cgi?id=... -# Patch200: ... +# +# https://bugzilla.redhat.com/show_bug.cgi?id=2245332 +Patch200: httpd-2.4.57-CVE-2023-31122.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2295016 +Patch201: httpd-2.4.57-CVE-2024-38477.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2295022 +Patch202: httpd-2.4.57-CVE-2024-39573.patch +# CVE-2024-38474 and CVE-2024-38475 fixed in one patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2295013 +# https://bugzilla.redhat.com/show_bug.cgi?id=2295014 +Patch204: httpd-2.4.57-CVE-2024-38474+.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2295012 +Patch206: httpd-2.4.57-CVE-2024-38473.patch + License: ASL 2.0 BuildRequires: gcc, autoconf, pkgconfig, findutils, xmlto @@ -278,6 +296,8 @@ written in the Lua programming language. %patch49 -p1 -b .ssl-proxy-chains %patch50 -p1 -b .r1825120 %patch52 -p1 -b .separatesystemd +%patch53 -p1 -b .r1912477+ +%patch54 -p1 -b .r1912081 %patch60 -p1 -b .enable-sslv3 %patch61 -p1 -b .htcacheclean-dont-break @@ -289,7 +309,13 @@ written in the Lua programming language. %patch69 -p1 -b .covstan %patch70 -p1 -b .duplicate-key %patch71 -p1 -b .davenoent +%patch72 -p1 -b .r1884505+ +%patch200 -p1 -b .CVE-2023-31122 +%patch201 -p1 -b .CVE-2024-38477 +%patch202 -p1 -b .CVE-2024-39573 +%patch204 -p1 -b .CVE-2024-38474+ +%patch206 -p1 -b .CVE-2024-38473 # Patch in the vendor string sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h @@ -850,6 +876,33 @@ exit $rv %{_rpmconfigdir}/macros.d/macros.httpd %changelog +* Thu Jul 04 2024 Luboš Uhliarik - 2.4.57-11 +- Resolves: RHEL-45792 - httpd: Encoding problem in + mod_proxy (CVE-2024-38473) + +* Wed Jul 03 2024 Luboš Uhliarik - 2.4.57-9 +- Resolves: RHEL-45766 - httpd: null pointer dereference in + mod_proxy (CVE-2024-38477) +- Resolves: RHEL-45749 - httpd: Potential SSRF in mod_rewrite (CVE-2024-39573) +- Resolves: RHEL-45818 - httpd: Substitution encoding issue in + mod_rewrite (CVE-2024-38474) +- Resolves: RHEL-45771 - httpd: Improper escaping of output in + mod_rewrite (CVE-2024-38475) + +* Wed Feb 7 2024 Joe Orton - 2.4.57-8 +- mod_xml2enc: fix media type handling + Resolves: RHEL-17686 +- mod_dav: add DavBasePath + Resolves: RHEL-6600 + +* Mon Feb 05 2024 Luboš Uhliarik - 2.4.57-7 +- Resolves: RHEL-14447 - httpd: mod_macro: out-of-bounds read + vulnerability (CVE-2023-31122) + +* Wed Oct 4 2023 Joe Orton - 2.4.57-6 +- Resolves: RHEL-5071 - mod_dav_fs: add DavLockDBType +- mod_dav_fs: add global mutex around lockdb interaction + * Thu Jul 20 2023 Tomas Korbar - 2.4.57-5 - Fix issue found by covscan - Related: #2222001