From 554554b0ebb14d6578adb70a389c57a0d5f18a3b Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Mon, 24 Jun 2024 17:54:34 +0000 Subject: [PATCH] Merge r1918551 from trunk: add ap_set_content_type_ex to differentiate trusted sources git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1918560 13f79535-47bb-0310-9956-ffa450edef68 --- include/http_protocol.h | 11 +++++++++++ include/httpd.h | 7 +++++++ modules/http/http_protocol.c | 6 ++++++ modules/http/mod_mime.c | 20 ++++++++++---------- modules/mappers/mod_actions.c | 6 ++++-- modules/mappers/mod_negotiation.c | 8 ++++---- modules/mappers/mod_rewrite.c | 2 +- modules/metadata/mod_headers.c | 6 +++--- modules/metadata/mod_mime_magic.c | 4 ++-- server/config.c | 2 +- server/core.c | 2 +- 11 files changed, 50 insertions(+), 24 deletions(-) diff --git a/include/http_protocol.h b/include/http_protocol.h index 94c481e5f43..f2c99c9e86e 100644 --- a/include/http_protocol.h +++ b/include/http_protocol.h @@ -438,6 +438,17 @@ 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 826c46ef591..766df2bde00 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -667,6 +667,7 @@ typedef apr_uint64_t ap_request_bnotes_t; * */ #define AP_REQUEST_STRONG_ETAG 1 >> 0 +#define AP_REQUEST_TRUSTED_CT 1 << 1 /** * This is a convenience macro to ease with getting specific request @@ -689,6 +690,12 @@ typedef apr_uint64_t ap_request_bnotes_t; AP_REQUEST_GET_BNOTE((r), AP_REQUEST_STRONG_ETAG) /** @} */ +/** + * 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)) +/** @} */ /** * @defgroup module_magic Module Magic mime types diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c index d031f245188..c31e8737337 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -1097,8 +1097,14 @@ 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) { diff --git a/modules/http/mod_mime.c b/modules/http/mod_mime.c index 700f824f32a..51095a0e74c 100644 --- a/modules/http/mod_mime.c +++ b/modules/http/mod_mime.c @@ -759,7 +759,7 @@ 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); + ap_set_content_type_ex(r, DIR_MAGIC_TYPE, 1); return OK; } @@ -850,7 +850,7 @@ 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); + ap_set_content_type_ex(r, (char*) type, 1); found = 1; } } @@ -859,7 +859,7 @@ 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); + ap_set_content_type_ex(r, exinfo->forced_type, 1); found = 1; } @@ -964,33 +964,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); + 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 ac9c3b7428f..5e398b53d9e 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))) { int virtual = (*t++ == '0' ? 0 : 1); diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c index c056b284550..a528f814397 100644 --- a/modules/mappers/mod_negotiation.c +++ b/modules/mappers/mod_negotiation.c @@ -1167,7 +1167,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); } /* @@ -3003,14 +3003,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 bbcc11b3c52..df6f16b83f0 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -5333,7 +5333,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 ef812cd3edc..4838bd6cd0d 100644 --- a/modules/metadata/mod_headers.c +++ b/modules/metadata/mod_headers.c @@ -783,14 +783,14 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers, break; case hdr_set: if (!ap_cstr_casecmp(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; case hdr_setifempty: if (NULL == apr_table_get(headers, hdr->header)) { if (!ap_cstr_casecmp(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)); } @@ -809,7 +809,7 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers, const char *repl = process_regexp(hdr, r->content_type, r); 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 7dac4fdbd3d..1c96db4cd7a 100644 --- a/modules/metadata/mod_mime_magic.c +++ b/modules/metadata/mod_mime_magic.c @@ -788,7 +788,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 3d11ff58a44..635b65def1d 100644 --- a/server/config.c +++ b/server/config.c @@ -418,7 +418,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 f511bba4897..843b97320f8 100644 --- a/server/core.c +++ b/server/core.c @@ -4835,7 +4835,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->expr_handler) { const char *err;