diff --git a/0001-HTTP_BAD_REQUEST.patch b/0001-HTTP_BAD_REQUEST.patch new file mode 100644 index 0000000000000000000000000000000000000000..99c5a3bc954f34f88de4c55a5bb8ea385053b6fc --- /dev/null +++ b/0001-HTTP_BAD_REQUEST.patch @@ -0,0 +1,24 @@ +From 323e409a5c15de7568cd2606f728c39f0c20d678 Mon Sep 17 00:00:00 2001 +From: ut005731 +Date: Wed, 16 Oct 2024 19:39:39 +0800 +Subject: [PATCH] HTTP_BAD_REQUEST + +--- + modules/proxy/proxy_util.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 5278f67..19b0c50 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -3403,6 +3403,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + char **old_cl_val, + char **old_te_val) + { ++ int rc = OK; + conn_rec *c = r->connection; + int counter; + char *buf; +-- +2.39.3 + diff --git a/0001-cleanup.patch b/0001-cleanup.patch new file mode 100644 index 0000000000000000000000000000000000000000..64176ba170ae92247b2bccac1557688113b2068e --- /dev/null +++ b/0001-cleanup.patch @@ -0,0 +1,35 @@ +From f943c3b0ee07031838e3d0771fe2056bd11ba39c Mon Sep 17 00:00:00 2001 +From: ut005731 +Date: Thu, 17 Oct 2024 13:32:53 +0800 +Subject: [PATCH] cleanup + +--- + modules/proxy/proxy_util.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 19b0c50..72f4760 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -3407,6 +3407,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + conn_rec *c = r->connection; + int counter; + char *buf; ++ apr_table_t *saved_headers_in = r->headers_in; + const apr_array_header_t *headers_in_array; + const apr_table_entry_t *headers_in; + apr_table_t *headers_in_copy; +@@ -3645,7 +3646,9 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(header_brigade, e); + } +- return OK; ++ cleanup: ++ r->headers_in = saved_headers_in; ++ return rc; + } + + PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc, +-- +2.39.3 + diff --git a/0001-cve-CVE-2024-38474.patch b/0001-cve-CVE-2024-38474.patch new file mode 100644 index 0000000000000000000000000000000000000000..1d08676ec05b156c456a9d35a69ed1c45c0f6c43 --- /dev/null +++ b/0001-cve-CVE-2024-38474.patch @@ -0,0 +1,372 @@ +From c847eb26623f0142e06ed432ede2bfe0ce154a26 Mon Sep 17 00:00:00 2001 +From: ut005731 +Date: Wed, 16 Oct 2024 10:45:36 +0800 +Subject: [PATCH] cve: CVE-2024-38474 + +--- + docs/manual/mod/mod_rewrite.html.en | 12 ++- + docs/manual/rewrite/flags.html.en | 26 ++++++- + modules/mappers/mod_rewrite.c | 110 ++++++++++++++++++++++++---- + 3 files changed, 130 insertions(+), 18 deletions(-) + +diff --git a/docs/manual/mod/mod_rewrite.html.en b/docs/manual/mod/mod_rewrite.html.en +index dbc00bf..04da9e3 100644 +--- a/docs/manual/mod/mod_rewrite.html.en ++++ b/docs/manual/mod/mod_rewrite.html.en +@@ -1268,6 +1268,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

+@@ -1466,4 +1476,4 @@ if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); + } + //--> +- +\ No newline at end of file ++ +diff --git a/docs/manual/rewrite/flags.html.en b/docs/manual/rewrite/flags.html.en +index 1153c2e..e58233f 100644 +--- a/docs/manual/rewrite/flags.html.en ++++ b/docs/manual/rewrite/flags.html.en +@@ -724,6 +724,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  | +@@ -752,4 +776,4 @@ if (typeof(prettyPrint) !== 'undefined') { + prettyPrint(); + } + //--> +- +\ No newline at end of file ++ +diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c +index 0103d37..6d1e5f9 100644 +--- a/modules/mappers/mod_rewrite.c ++++ b/modules/mappers/mod_rewrite.c +@@ -167,6 +167,9 @@ static const char* really_last_key = "rewrite_really_last"; + #define RULEFLAG_QSDISCARD 1<<16 + #define RULEFLAG_END 1<<17 + #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 +@@ -174,6 +177,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 +@@ -283,6 +287,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 */ +@@ -873,10 +885,16 @@ 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; +@@ -910,7 +928,32 @@ 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; ++ } ++ } + } + } + +@@ -3635,6 +3678,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; +@@ -3985,7 +4040,7 @@ 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; +@@ -4036,7 +4091,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 +@@ -4087,7 +4142,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 +@@ -4107,6 +4162,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=] */ +@@ -4124,7 +4188,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + r->status = p->forced_responsecode; + } + +- return 2; ++ return RULE_RC_NOSUB; + } + + /* Now adjust API's knowledge about r->filename and r->args */ +@@ -4177,7 +4241,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + + r->filename = apr_pstrcat(r->pool, "proxy:", r->filename, NULL); + apr_table_setn(r->notes, "rewrite-proxy", "1"); +- return 1; ++ return RULE_RC_MATCH; + } + + /* If this rule is explicitly forced for HTTP redirection +@@ -4192,7 +4256,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 +@@ -4214,7 +4278,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 */ +@@ -4223,7 +4287,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; + } + + /* +@@ -4231,19 +4295,20 @@ 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; + + ctx = apr_palloc(r->pool, sizeof(*ctx)); + ctx->perdir = perdir; + ctx->r = r; ++ *lastsub = NULL; + + /* + * Iterate over all existing rules +@@ -4280,6 +4345,11 @@ 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) + */ +@@ -4290,7 +4360,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); + } +@@ -4469,6 +4539,8 @@ static int hook_uri2file(request_rec *r) + unsigned int port; + int rulestatus; + void *skipdata; ++ const char *oargs; ++ rewriterule_entry *lastsub = NULL; + + /* + * retrieve the config structures +@@ -4574,7 +4646,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)); + } +@@ -4606,6 +4678,9 @@ static int hook_uri2file(request_rec *r) + r->status = HTTP_OK; + return n; + } ++ else if (ACTION_STATUS_SET == rulestatus) { ++ return r->status; ++ } + + flen = r->filename ? strlen(r->filename) : 0; + if (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0) { +@@ -4735,7 +4810,9 @@ static int hook_uri2file(request_rec *r) + * because we only do stat() on the first directory + * and this gets cached by the kernel for along time! + */ +- if (!prefix_stat(r->filename, r->pool)) { ++ 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; + +@@ -4780,6 +4857,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); +-- +2.39.3 + diff --git a/0001-cve-CVE-2024-38477.patch b/0001-cve-CVE-2024-38477.patch new file mode 100644 index 0000000000000000000000000000000000000000..438da4c0dd20aaf314235797f61bb58ff4ec233d --- /dev/null +++ b/0001-cve-CVE-2024-38477.patch @@ -0,0 +1,72 @@ +From 308f183a72983014250e60c07cebe37b5c708490 Mon Sep 17 00:00:00 2001 +From: ut005731 +Date: Wed, 16 Oct 2024 18:31:04 +0800 +Subject: [PATCH] cve: CVE-2024-38477 + +--- + modules/mappers/mod_rewrite.c | 5 +++-- + modules/proxy/proxy_util.c | 11 ++++++++++- + 2 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c +index 6d1e5f9..f8154ae 100644 +--- a/modules/mappers/mod_rewrite.c ++++ b/modules/mappers/mod_rewrite.c +@@ -197,6 +197,7 @@ static const char* really_last_key = "rewrite_really_last"; + #define OPTION_NOSLASH 1<<3 + #define OPTION_ANYURI 1<<4 + #define OPTION_MERGEBASE 1<<5 ++#define OPTION_UNSAFE_PREFIX_STAT (1<<12) + + #ifndef RAND_MAX + #define RAND_MAX 32767 +@@ -4775,7 +4776,7 @@ static int hook_uri2file(request_rec *r) + } + else { + /* it was finally rewritten to a local path */ +- ++ const char *uri_reduced = NULL; + /* expand "/~user" prefix */ + #if APR_HAS_USER + r->filename = expand_tildepaths(r, r->filename); +@@ -4942,7 +4943,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; + +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 47d3eaf..5278f67 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -2266,6 +2266,11 @@ 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); + } +@@ -3440,7 +3445,11 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(header_brigade, e); + if (dconf->preserve_host == 0) { +- if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */ ++ 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) { + buf = apr_pstrcat(p, "Host: [", uri->hostname, "]:", + uri->port_str, CRLF, NULL); +-- +2.39.3 + diff --git a/0001-cve-fix-CVE-2024-38476.patch b/0001-cve-fix-CVE-2024-38476.patch new file mode 100644 index 0000000000000000000000000000000000000000..fa03064b0aa1605aeeb93496ef1cb01aa7055d1b --- /dev/null +++ b/0001-cve-fix-CVE-2024-38476.patch @@ -0,0 +1,318 @@ +From bac436d5605720414691c24e1a30005ff9843eaa Mon Sep 17 00:00:00 2001 +From: ut005731 +Date: Thu, 24 Oct 2024 21:11:08 +0800 +Subject: [PATCH] cve:fix CVE-2024-38476 + +--- + include/http_protocol.h | 10 ++++++++++ + include/httpd.h | 26 ++++++++++++++++++++++++++ + modules/http/http_protocol.c | 7 +++++++ + modules/http/mod_mime.c | 28 ++++++++++++++-------------- + modules/mappers/mod_actions.c | 6 ++++-- + modules/mappers/mod_negotiation.c | 8 ++++---- + modules/mappers/mod_rewrite.c | 2 +- + modules/metadata/mod_headers.c | 4 ++-- + modules/metadata/mod_mime_magic.c | 4 ++-- + server/config.c | 2 +- + server/core.c | 2 +- + 11 files changed, 72 insertions(+), 27 deletions(-) + +diff --git a/include/http_protocol.h b/include/http_protocol.h +index f3a5137..c2b4f00 100644 +--- a/include/http_protocol.h ++++ b/include/http_protocol.h +@@ -374,6 +374,16 @@ AP_DECLARE(void) ap_clear_method_list(ap_method_list_t *l); + */ + AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct); + ++/** ++ * Set the content type for this request (r->content_type). ++ * @param r The current request ++ * @param ct The new content type ++ * @param trusted If non-zero, The content-type should come from a ++ * trusted source such as server configuration rather ++ * than application output. ++ * for the AddOutputFilterByType directive to work correctly. ++ */ ++AP_DECLARE(void) ap_set_content_type_ex(request_rec *r, const char *ct, int trusted); + /** + * Set the Accept-Ranges header for this response + * @param r The current request +diff --git a/include/httpd.h b/include/httpd.h +index d2a060e..f0f97fd 100644 +--- a/include/httpd.h ++++ b/include/httpd.h +@@ -640,6 +640,7 @@ struct ap_method_list_t { + /** the array used for extension methods */ + apr_array_header_t *method_list; + }; ++/** @} */ + + /** + * @defgroup module_magic Module Magic mime types +@@ -707,6 +708,31 @@ struct ap_method_list_t { + + /** @} // values_request_rec_used_path_info */ + ++#define AP_REQUEST_TRUSTED_CT "rh-bnotes-trusted-ct" ++ ++/** ++ * This is a convenience macro to ease with getting specific request ++ * binary notes. ++ */ ++#define AP_REQUEST_GET_BNOTE(r, mask) (apr_table_get(r->notes, mask) ? 1 : 0) ++ ++/** ++ * This is a convenience macro to ease with setting specific request ++ * binary notes. ++ */ ++#define AP_REQUEST_SET_BNOTE(r, mask, val) do { \ ++ if (val) \ ++ apr_table_setn(r->notes, mask, "1"); \ ++ else \ ++ apr_table_unset(r->notes, mask); \ ++} while (0) ++ ++/** ++ * Returns true if the content-type field is from a trusted source ++ */ ++#define AP_REQUEST_IS_TRUSTED_CT(r) \ ++ (!!AP_REQUEST_GET_BNOTE((r), AP_REQUEST_TRUSTED_CT)) ++/** @} */ + + /* + * Things which may vary per file-lookup WITHIN a request --- +diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c +index 20e8a97..0590f09 100644 +--- a/modules/http/http_protocol.c ++++ b/modules/http/http_protocol.c +@@ -1082,9 +1082,16 @@ AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct) + } + else if (!r->content_type || strcmp(r->content_type, ct)) { + r->content_type = ct; ++ AP_REQUEST_SET_BNOTE(r, AP_REQUEST_TRUSTED_CT, 0); + } + } + ++AP_DECLARE(void) ap_set_content_type_ex(request_rec *r, const char *ct, int trusted) ++{ ++ ap_set_content_type(r, ct); ++ AP_REQUEST_SET_BNOTE(r, AP_REQUEST_TRUSTED_CT, trusted ? AP_REQUEST_TRUSTED_CT : 0); ++} ++ + AP_DECLARE(void) ap_set_accept_ranges(request_rec *r) + { + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); +diff --git a/modules/http/mod_mime.c b/modules/http/mod_mime.c +index 28c53be..02fc4ad 100644 +--- a/modules/http/mod_mime.c ++++ b/modules/http/mod_mime.c +@@ -759,8 +759,8 @@ static int find_ct(request_rec *r) + int found_metadata = 0; + + if (r->finfo.filetype == APR_DIR) { +- ap_set_content_type(r, DIR_MAGIC_TYPE); +- return OK; ++ ap_set_content_type_ex(r, DIR_MAGIC_TYPE, 1); ++ return OK; + } + + if (!r->filename) { +@@ -837,8 +837,8 @@ static int find_ct(request_rec *r) + if (exinfo == NULL || !exinfo->forced_type) { + if ((type = apr_hash_get(mime_type_extensions, ext, + APR_HASH_KEY_STRING)) != NULL) { +- ap_set_content_type(r, (char*) type); +- found = 1; ++ ap_set_content_type_ex(r, (char*) type, 1); ++ found = 1; + } + } + +@@ -846,8 +846,8 @@ static int find_ct(request_rec *r) + + /* empty string is treated as special case for RemoveType */ + if (exinfo->forced_type && *exinfo->forced_type) { +- ap_set_content_type(r, exinfo->forced_type); +- found = 1; ++ ap_set_content_type_ex(r, exinfo->forced_type, 1); ++ found = 1; + } + + if (exinfo->charset_type) { +@@ -951,33 +951,33 @@ static int find_ct(request_rec *r) + memcpy(tmp, ctp->subtype, ctp->subtype_len); + tmp += ctp->subtype_len; + *tmp = 0; +- ap_set_content_type(r, base_content_type); +- while (pp != NULL) { ++ ap_set_content_type_ex(r, base_content_type, AP_REQUEST_IS_TRUSTED_CT(r)); ++ while (pp != NULL) { + if (charset && !strcmp(pp->attr, "charset")) { + if (!override) { +- ap_set_content_type(r, ++ ap_set_content_type_ex(r, + apr_pstrcat(r->pool, + r->content_type, + "; charset=", + charset, +- NULL)); ++ NULL), AP_REQUEST_IS_TRUSTED_CT(r)); + override = 1; + } + } + else { +- ap_set_content_type(r, ++ ap_set_content_type_ex(r, + apr_pstrcat(r->pool, + r->content_type, + "; ", pp->attr, + "=", pp->val, +- NULL)); ++ NULL), AP_REQUEST_IS_TRUSTED_CT(r)); + } + pp = pp->next; + } + if (charset && !override) { +- ap_set_content_type(r, apr_pstrcat(r->pool, r->content_type, ++ ap_set_content_type_ex(r, apr_pstrcat(r->pool, r->content_type, + "; charset=", charset, +- NULL)); ++ NULL), AP_REQUEST_IS_TRUSTED_CT(r)); + } + } + } +diff --git a/modules/mappers/mod_actions.c b/modules/mappers/mod_actions.c +index c311a3b..db4bda4 100644 +--- a/modules/mappers/mod_actions.c ++++ b/modules/mappers/mod_actions.c +@@ -182,8 +182,10 @@ static int action_handler(request_rec *r) + return DECLINED; + + /* Second, check for actions (which override the method scripts) */ +- action = r->handler ? r->handler : +- ap_field_noparam(r->pool, r->content_type); ++ action = r->handler; ++ if (!action && AP_REQUEST_IS_TRUSTED_CT(r)) { ++ action = ap_field_noparam(r->pool, r->content_type); ++ } + + if (action && (t = apr_table_get(conf->action_types, action))) { + if (*t++ == '0' && r->finfo.filetype == APR_NOFILE) { +diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c +index 5ec0d4d..43a1a49 100644 +--- a/modules/mappers/mod_negotiation.c ++++ b/modules/mappers/mod_negotiation.c +@@ -1175,7 +1175,7 @@ static int read_types_multi(negotiation_state *neg) + * might be doing. + */ + if (sub_req->handler && !sub_req->content_type) { +- ap_set_content_type(sub_req, CGI_MAGIC_TYPE); ++ ap_set_content_type_ex(sub_req, CGI_MAGIC_TYPE, 1); + } + + /* +@@ -3013,14 +3013,14 @@ static int handle_map_file(request_rec *r) + /* set MIME type and charset as negotiated */ + if (best->mime_type && *best->mime_type) { + if (best->content_charset && *best->content_charset) { +- ap_set_content_type(r, apr_pstrcat(r->pool, ++ ap_set_content_type_ex(r, apr_pstrcat(r->pool, + best->mime_type, + "; charset=", + best->content_charset, +- NULL)); ++ NULL), 1); + } + else { +- ap_set_content_type(r, apr_pstrdup(r->pool, best->mime_type)); ++ ap_set_content_type_ex(r, apr_pstrdup(r->pool, best->mime_type), 1); + } + } + +diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c +index f8154ae..8dae215 100644 +--- a/modules/mappers/mod_rewrite.c ++++ b/modules/mappers/mod_rewrite.c +@@ -5178,7 +5178,7 @@ static int hook_mimetype(request_rec *r) + rewritelog((r, 1, NULL, "force filename %s to have MIME-type '%s'", + r->filename, t)); + +- ap_set_content_type(r, t); ++ ap_set_content_type_ex(r, t, 1); + } + + /* handler */ +diff --git a/modules/metadata/mod_headers.c b/modules/metadata/mod_headers.c +index 9ce2fde..3be69f6 100644 +--- a/modules/metadata/mod_headers.c ++++ b/modules/metadata/mod_headers.c +@@ -751,7 +751,7 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers, + break; + case hdr_set: + if (!strcasecmp(hdr->header, "Content-Type")) { +- ap_set_content_type(r, process_tags(hdr, r)); ++ ap_set_content_type_ex(r, process_tags(hdr, r), 1); + } + apr_table_setn(headers, hdr->header, process_tags(hdr, r)); + break; +@@ -770,7 +770,7 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers, + const char *repl = process_regexp(hdr, r->content_type, r->pool); + if (repl == NULL) + return 0; +- ap_set_content_type(r, repl); ++ ap_set_content_type_ex(r, repl, 1); + } + if (apr_table_get(headers, hdr->header)) { + edit_do ed; +diff --git a/modules/metadata/mod_mime_magic.c b/modules/metadata/mod_mime_magic.c +index 80c585d..2937c25 100644 +--- a/modules/metadata/mod_mime_magic.c ++++ b/modules/metadata/mod_mime_magic.c +@@ -789,7 +789,7 @@ static int magic_rsl_to_request(request_rec *r) + /* XXX: this could be done at config time I'm sure... but I'm + * confused by all this magic_rsl stuff. -djg */ + ap_content_type_tolower(tmp); +- ap_set_content_type(r, tmp); ++ ap_set_content_type_ex(r, tmp, 1); + + if (state == rsl_encoding) { + tmp = rsl_strdup(r, encoding_frag, +@@ -2326,7 +2326,7 @@ static int revision_suffix(request_rec *r) + + /* extract content type/encoding/language from sub-request */ + if (sub->content_type) { +- ap_set_content_type(r, apr_pstrdup(r->pool, sub->content_type)); ++ ap_set_content_type_ex(r, apr_pstrdup(r->pool, sub->content_type), 1); + #if MIME_MAGIC_DEBUG + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01557) + MODNAME ": subrequest %s got %s", +diff --git a/server/config.c b/server/config.c +index 265744e..effad73 100644 +--- a/server/config.c ++++ b/server/config.c +@@ -414,7 +414,7 @@ AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r) + } + + if (!r->handler) { +- if (r->content_type) { ++ if (r->content_type && AP_REQUEST_IS_TRUSTED_CT(r)) { + handler = r->content_type; + if ((p=ap_strchr_c(handler, ';')) != NULL) { + char *new_handler = (char *)apr_pmemdup(r->pool, handler, +diff --git a/server/core.c b/server/core.c +index 9b26075..03cc68a 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -4376,7 +4376,7 @@ static int core_override_type(request_rec *r) + /* Check for overrides with ForceType / SetHandler + */ + if (conf->mime_type && strcmp(conf->mime_type, "none")) +- ap_set_content_type(r, (char*) conf->mime_type); ++ ap_set_content_type_ex(r, (char*) conf->mime_type, 1); + + if (conf->handler && strcmp(conf->handler, "none")) + r->handler = conf->handler; +-- +2.39.3 + diff --git a/httpd.spec b/httpd.spec index f95830db9b26396322907cf7b76f85b640242f84..f1bb4d05915ecde59ef4c0f4de9168b74272b400 100644 --- a/httpd.spec +++ b/httpd.spec @@ -15,7 +15,7 @@ Summary: Apache HTTP Server Name: httpd Version: 2.4.6 -Release: 99%{?dist}.1 +Release: 99%{?dist}.3 URL: http://httpd.apache.org/ Source0: http://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source1: index.html @@ -250,6 +250,13 @@ Patch244: httpd-2.4.6-CVE-2021-39275.patch Patch245: httpd-2.4.6-CVE-2021-26691.patch Patch246: httpd-2.4.6-CVE-2022-22720.patch Patch247: httpd-2.4.6-CVE-2023-25690.patch +#add by uos +Patch248: 0001-cve-CVE-2024-38474.patch +Patch249: 0001-cve-CVE-2024-38477.patch +Patch250: 0001-HTTP_BAD_REQUEST.patch +Patch251: 0001-cleanup.patch +Patch252: 0001-cve-fix-CVE-2024-38476.patch +#end License: ASL 2.0 Group: System Environment/Daemons @@ -520,6 +527,11 @@ rm modules/ssl/ssl_engine_dh.c %patch245 -p1 -b .cve26691 %patch246 -p1 -b .cve22720 %patch247 -p1 -b .cve25690 +%patch248 -p1 -b .cve-CVE-2024-38474 +%patch249 -p1 -b .cve-CVE-2024-38477 +%patch250 -p1 -b .HTTP_BAD_REQUEST +%patch251 -p1 -b .cleanup +%patch252 -p1 -b .cve-fix-CVE-2024-38476 # need to be applied in the end since security patches # are changing the code that present in this patch @@ -953,6 +965,13 @@ rm -rf $RPM_BUILD_ROOT %{_sysconfdir}/rpm/macros.httpd %changelog +* Mon Oct 14 2024 zhuhongbo - 2.4.6-99.3 +- update to httpd-2.4.6-99.el7_9.3 +- cve:fix CVE-2024-38476 + +* Mon Oct 14 2024 zhuhongbo - 2.4.6-99.2 +- cve: CVE-2024-38474 CVE-2024-38475 CVE-2024-38477 + * Thu Apr 27 2023 Luboš Uhliarik - 2.4.6-99.1 - Resolves: #2190143 - mod_rewrite regression with CVE-2023-25690