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 8f9d89d8926278ba751dd7fa95eff711d85a25b0..30dde218ad6868d793203df475c42f9c7caf14c6 100644 --- a/httpd.spec +++ b/httpd.spec @@ -15,7 +15,7 @@ Summary: Apache HTTP Server Name: httpd Version: 2.4.6 -Release: 99%{?dist}.2 +Release: 99%{?dist}.3 URL: http://httpd.apache.org/ Source0: http://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source1: index.html @@ -255,6 +255,7 @@ 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 @@ -530,6 +531,7 @@ rm modules/ssl/ssl_engine_dh.c %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 @@ -963,6 +965,10 @@ 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.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