import UBI httpd-2.4.37-65.module+el8.10.0+22196+d82931da.2

This commit is contained in:
eabdullin 2024-08-12 01:12:34 +00:00
parent 5be0469cd1
commit 65a81b172d
4 changed files with 802 additions and 1 deletions

View File

@ -0,0 +1,301 @@
-- backported bnotes needed by this CVE fix from https://svn.apache.org/viewvc?view=revision&revision=1887384
-- modified it a little bit so it actually doesn't store bnotes into req structure to not brake compatibility
-- but it stores AP_REQUEST_TRUSTED_CT info into r->notes
diff --git a/include/http_protocol.h b/include/http_protocol.h
index 8ed77ac..81949ca 100644
--- a/include/http_protocol.h
+++ b/include/http_protocol.h
@@ -402,6 +402,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 99f7f04..d8746c1 100644
--- a/include/httpd.h
+++ b/include/httpd.h
@@ -645,6 +645,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
@@ -715,6 +716,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 df862e0..d003aea 100644
--- a/modules/http/http_protocol.c
+++ b/modules/http/http_protocol.c
@@ -1077,8 +1077,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 28c53be..4cd1c48 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;
}
@@ -837,7 +837,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;
}
}
@@ -846,7 +846,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;
}
@@ -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);
+ 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 ac9c3b7..5e398b5 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 da68353..e91ba5f 100644
--- a/modules/mappers/mod_negotiation.c
+++ b/modules/mappers/mod_negotiation.c
@@ -1169,7 +1169,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);
}
/*
@@ -3008,14 +3008,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 a25c7ae..2b70d66 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -5477,7 +5477,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 1ea970d..55ab281 100644
--- a/modules/metadata/mod_headers.c
+++ b/modules/metadata/mod_headers.c
@@ -792,14 +792,14 @@ 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;
case hdr_setifempty:
if (NULL == apr_table_get(headers, hdr->header)) {
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));
}
@@ -818,7 +818,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 c12529a..fe30f27 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 f815b22..fc4d76b 100644
--- a/server/config.c
+++ b/server/config.c
@@ -419,7 +419,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 8575aae..82706cf 100644
--- a/server/core.c
+++ b/server/core.c
@@ -4722,7 +4722,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;

View File

@ -0,0 +1,266 @@
diff --git a/modules/cluster/mod_heartmonitor.c b/modules/cluster/mod_heartmonitor.c
index 965fef5..6df3bf4 100644
--- a/modules/cluster/mod_heartmonitor.c
+++ b/modules/cluster/mod_heartmonitor.c
@@ -782,7 +782,7 @@ static int hm_handler(request_rec *r)
hmserver.seen = apr_time_now();
hm_update_stat(ctx, &hmserver, r->pool);
- ap_set_content_type(r, "text/plain");
+ ap_set_content_type_ex(r, "text/plain", 1);
ap_set_content_length(r, 2);
ap_rputs("OK", r);
ap_rflush(r);
diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c
index 792b514..28479b9 100644
--- a/modules/dav/main/mod_dav.c
+++ b/modules/dav/main/mod_dav.c
@@ -323,7 +323,7 @@ static int dav_error_response(request_rec *r, int status, const char *body)
r->status = status;
r->status_line = ap_get_status_line(status);
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
/* begin the response now... */
ap_rvputs(r,
@@ -354,7 +354,7 @@ static int dav_error_response_tag(request_rec *r,
{
r->status = err->status;
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
+ ap_set_content_type_ex(r, DAV_XML_CONTENT_TYPE, 1);
ap_rputs(DAV_XML_HEADER DEBUG_CR
"<D:error xmlns:D=\"DAV:\"", r);
@@ -512,7 +512,7 @@ DAV_DECLARE(void) dav_begin_multistatus(apr_bucket_brigade *bb,
{
/* Set the correct status and Content-Type */
r->status = status;
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
+ ap_set_content_type_ex(r, DAV_XML_CONTENT_TYPE, 1);
/* Send the headers and actual multistatus response now... */
ap_fputs(r->output_filters, bb, DAV_XML_HEADER DEBUG_CR
@@ -1923,7 +1923,7 @@ static int dav_method_options(request_rec *r)
/* send the options response */
r->status = HTTP_OK;
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
+ ap_set_content_type_ex(r, DAV_XML_CONTENT_TYPE, 1);
/* send the headers and response body */
ap_rputs(DAV_XML_HEADER DEBUG_CR
@@ -3191,7 +3191,7 @@ static int dav_method_lock(request_rec *r)
(*locks_hooks->close_lockdb)(lockdb);
r->status = HTTP_OK;
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
+ ap_set_content_type_ex(r, DAV_XML_CONTENT_TYPE, 1);
ap_rputs(DAV_XML_HEADER DEBUG_CR "<D:prop xmlns:D=\"DAV:\">" DEBUG_CR, r);
if (lock == NULL)
diff --git a/modules/examples/mod_example_hooks.c b/modules/examples/mod_example_hooks.c
index d818dc1..4d79b86 100644
--- a/modules/examples/mod_example_hooks.c
+++ b/modules/examples/mod_example_hooks.c
@@ -993,7 +993,7 @@ static int x_handler(request_rec *r)
* Set the Content-type header. Note that we do not actually have to send
* the headers: this is done by the http core.
*/
- ap_set_content_type(r, "text/html");
+ ap_set_content_type_ex(r, "text/html", 1);
/*
* If we're only supposed to send header information (HEAD request), we're
* already there.
diff --git a/modules/filters/mod_data.c b/modules/filters/mod_data.c
index d083d32..489e76c 100644
--- a/modules/filters/mod_data.c
+++ b/modules/filters/mod_data.c
@@ -117,7 +117,7 @@ static apr_status_t data_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
}
}
- ap_set_content_type(r, "text/plain");
+ ap_set_content_type_ex(r, "text/plain", 1);
}
diff --git a/modules/filters/mod_include.c b/modules/filters/mod_include.c
index a46a944..05f994c 100644
--- a/modules/filters/mod_include.c
+++ b/modules/filters/mod_include.c
@@ -3971,7 +3971,7 @@ static int include_fixup(request_rec *r)
if (r->handler && (strcmp(r->handler, "server-parsed") == 0))
{
if (!r->content_type || !*r->content_type) {
- ap_set_content_type(r, "text/html");
+ ap_set_content_type_ex(r, "text/html", 1);
}
r->handler = "default-handler";
}
diff --git a/modules/filters/mod_proxy_html.c b/modules/filters/mod_proxy_html.c
index ea6bf03..8b619e8 100644
--- a/modules/filters/mod_proxy_html.c
+++ b/modules/filters/mod_proxy_html.c
@@ -933,7 +933,7 @@ static apr_status_t proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(01422)
"No i18n support found. Install mod_xml2enc if required");
enc = XML_CHAR_ENCODING_NONE;
- ap_set_content_type(f->r, "text/html;charset=utf-8");
+ ap_set_content_type_ex(f->r, "text/html;charset=utf-8", 1);
}
else {
/* if we wanted a non-default charset_out, insert the
@@ -949,7 +949,7 @@ static apr_status_t proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
cenc, NULL));
}
else /* Normal case, everything worked, utf-8 output */
- ap_set_content_type(f->r, "text/html;charset=utf-8");
+ ap_set_content_type_ex(f->r, "text/html;charset=utf-8", 1);
}
ap_fputs(f->next, ctxt->bb, ctxt->cfg->doctype);
diff --git a/modules/generators/mod_cgi.c b/modules/generators/mod_cgi.c
index 66cd31c..4650d18 100644
--- a/modules/generators/mod_cgi.c
+++ b/modules/generators/mod_cgi.c
@@ -795,7 +795,7 @@ static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f,
/* Force sub_req to be treated as a CGI request, even if ordinary
* typing rules would have called it something else.
*/
- ap_set_content_type(rr, CGI_MAGIC_TYPE);
+ ap_set_content_type_ex(rr, CGI_MAGIC_TYPE, 1);
/* Run it. */
rr_status = ap_run_sub_req(rr);
diff --git a/modules/generators/mod_cgid.c b/modules/generators/mod_cgid.c
index 102d2b3..57e119f 100644
--- a/modules/generators/mod_cgid.c
+++ b/modules/generators/mod_cgid.c
@@ -1801,7 +1801,7 @@ static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f,
/* Force sub_req to be treated as a CGI request, even if ordinary
* typing rules would have called it something else.
*/
- ap_set_content_type(rr, CGI_MAGIC_TYPE);
+ ap_set_content_type_ex(rr, CGI_MAGIC_TYPE, 1);
/* Run it. */
rr_status = ap_run_sub_req(rr);
diff --git a/modules/generators/mod_info.c b/modules/generators/mod_info.c
index e5e63de..67df675 100644
--- a/modules/generators/mod_info.c
+++ b/modules/generators/mod_info.c
@@ -777,7 +777,7 @@ static int display_info(request_rec * r)
return DECLINED;
}
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
ap_rputs(DOCTYPE_XHTML_1_0T
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
diff --git a/modules/generators/mod_status.c b/modules/generators/mod_status.c
index 5bada07..2cb38c7 100644
--- a/modules/generators/mod_status.c
+++ b/modules/generators/mod_status.c
@@ -273,7 +273,7 @@ static int status_handler(request_rec *r)
if (r->method_number != M_GET)
return DECLINED;
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
/*
* Simple table-driven form data set parser that lets you alter the header
@@ -301,7 +301,7 @@ static int status_handler(request_rec *r)
no_table_report = 1;
break;
case STAT_OPT_AUTO:
- ap_set_content_type(r, "text/plain; charset=ISO-8859-1");
+ ap_set_content_type_ex(r, "text/plain; charset=ISO-8859-1", 1);
short_report = 1;
break;
}
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
index 16cb23c..27c44b2 100644
--- a/modules/http/http_filters.c
+++ b/modules/http/http_filters.c
@@ -1245,7 +1245,7 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r)
}
}
- ap_set_content_type(r, "message/http");
+ ap_set_content_type_ex(r, "message/http", 1);
/* Now we recreate the request, and echo it back */
diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c
index 417fee6..d003aea 100644
--- a/modules/http/http_protocol.c
+++ b/modules/http/http_protocol.c
@@ -1423,10 +1423,10 @@ AP_DECLARE(void) ap_send_error_response(request_rec *r, int recursive_error)
request_conf->suppress_charset = 1; /* avoid adding default
* charset later
*/
- ap_set_content_type(r, "text/html");
+ ap_set_content_type_ex(r, "text/html", 1);
}
else {
- ap_set_content_type(r, "text/html; charset=iso-8859-1");
+ ap_set_content_type_ex(r, "text/html; charset=iso-8859-1", 1);
}
if ((status == HTTP_METHOD_NOT_ALLOWED)
diff --git a/modules/http/http_request.c b/modules/http/http_request.c
index e873aab..3521cfb 100644
--- a/modules/http/http_request.c
+++ b/modules/http/http_request.c
@@ -709,7 +709,7 @@ AP_DECLARE(void) ap_internal_fast_redirect(request_rec *rr, request_rec *r)
r->args = rr->args;
r->finfo = rr->finfo;
r->handler = rr->handler;
- ap_set_content_type(r, rr->content_type);
+ ap_set_content_type_ex(r, rr->content_type, AP_REQUEST_IS_TRUSTED_CT(rr));
r->content_encoding = rr->content_encoding;
r->content_languages = rr->content_languages;
r->per_dir_config = rr->per_dir_config;
diff --git a/modules/ldap/util_ldap.c b/modules/ldap/util_ldap.c
index eecb3f7..b71dc98 100644
--- a/modules/ldap/util_ldap.c
+++ b/modules/ldap/util_ldap.c
@@ -125,7 +125,7 @@ static int util_ldap_handler(request_rec *r)
st = (util_ldap_state_t *) ap_get_module_config(r->server->module_config,
&ldap_module);
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
if (r->header_only)
return OK;
diff --git a/modules/mappers/mod_imagemap.c b/modules/mappers/mod_imagemap.c
index 187a500..3e14933 100644
--- a/modules/mappers/mod_imagemap.c
+++ b/modules/mappers/mod_imagemap.c
@@ -475,7 +475,7 @@ static int imap_reply(request_rec *r, const char *redirect)
static void menu_header(request_rec *r, char *menu)
{
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
ap_rvputs(r, DOCTYPE_HTML_3_2, "<html><head>\n<title>Menu for ",
ap_escape_html(r->pool, r->uri),
diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
index c599e1a..d5c20af 100644
--- a/modules/proxy/mod_proxy_balancer.c
+++ b/modules/proxy/mod_proxy_balancer.c
@@ -1480,7 +1480,7 @@ static int balancer_handler(request_rec *r)
if (apr_table_get(params, "xml")) {
char date[APR_RFC822_DATE_LEN];
- ap_set_content_type(r, "text/xml");
+ ap_set_content_type_ex(r, "text/xml", 1);
ap_rputs("<?xml version='1.0' encoding='UTF-8' ?>\n", r);
ap_rputs("<httpd:manager xmlns:httpd='http://httpd.apache.org'>\n", r);
ap_rputs(" <httpd:balancers>\n", r);

View File

@ -0,0 +1,217 @@
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
index 114b126..a25c7ae 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -2343,9 +2343,16 @@ static APR_INLINE char *find_char_in_curlies(char *s, int c)
* of an earlier expansion to include expansion specifiers that
* are interpreted by a later expansion, producing results that
* were not intended by the administrator.
+ *
+ * unsafe_qmark if not NULL will be set to 1 or 0 if a question mark
+ * is found respectively in a literal or in a lookup/expansion (whether
+ * it's the first or last qmark depends on [QSL]). Should be initialized
+ * to -1 and remains so if no qmark is found.
*/
-static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
+static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry,
+ int *unsafe_qmark)
{
+#define EXPAND_SPECIALS "\\$%"
result_list *result, *current;
result_list sresult[SMALL_EXPANSION];
unsigned spc = 0;
@@ -2353,8 +2360,29 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
char *p, *c;
apr_pool_t *pool = ctx->r->pool;
- span = strcspn(input, "\\$%");
inputlen = strlen(input);
+ if (!unsafe_qmark) {
+ span = strcspn(input, EXPAND_SPECIALS);
+ }
+ else {
+ span = strcspn(input, EXPAND_SPECIALS "?");
+ if (input[span] == '?') {
+ /* this qmark is not from an expansion thus safe */
+ *unsafe_qmark = 0;
+
+ /* keep tracking only if interested in the last qmark */
+ if (entry && (entry->flags & RULEFLAG_QSLAST)) {
+ do {
+ span++;
+ span += strcspn(input + span, EXPAND_SPECIALS "?");
+ } while (input[span] == '?');
+ }
+ else {
+ unsafe_qmark = NULL;
+ span += strcspn(input + span, EXPAND_SPECIALS);
+ }
+ }
+ }
/* fast exit */
if (inputlen == span) {
@@ -2372,6 +2400,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
/* loop for specials */
do {
+ int expanded = 0;
+
/* prepare next entry */
if (current->len) {
current->next = (spc < SMALL_EXPANSION)
@@ -2417,6 +2447,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
current->len = span;
current->string = p;
outlen += span;
+
+ expanded = 1;
p = endp + 1;
}
@@ -2456,19 +2488,18 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
}
/* reuse of key variable as result */
- key = lookup_map(ctx->r, map, do_expand(key, ctx, entry));
-
+ key = lookup_map(ctx->r, map, do_expand(key, ctx, entry, NULL));
if (!key && dflt && *dflt) {
- key = do_expand(dflt, ctx, entry);
+ key = do_expand(dflt, ctx, entry, NULL);
}
-
- if (key) {
+ if (key && *key) {
span = strlen(key);
current->len = span;
current->string = key;
outlen += span;
}
+ expanded = 1;
p = endp + 1;
}
}
@@ -2498,8 +2529,9 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
current->len = span;
current->string = bri->source + bri->regmatch[n].rm_so;
}
-
outlen += span;
+
+ expanded = 1;
}
p += 2;
@@ -2512,8 +2544,41 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
++outlen;
}
+ if (unsafe_qmark && expanded && current->len
+ && memchr(current->string, '?', current->len)) {
+ /* this qmark is from an expansion thus unsafe */
+ *unsafe_qmark = 1;
+
+ /* keep tracking only if interested in the last qmark */
+ if (!entry || !(entry->flags & RULEFLAG_QSLAST)) {
+ unsafe_qmark = NULL;
+ }
+ }
+
/* check the remainder */
- if (*p && (span = strcspn(p, "\\$%")) > 0) {
+ if (!unsafe_qmark) {
+ span = strcspn(p, EXPAND_SPECIALS);
+ }
+ else {
+ span = strcspn(p, EXPAND_SPECIALS "?");
+ if (p[span] == '?') {
+ /* this qmark is not from an expansion thus safe */
+ *unsafe_qmark = 0;
+
+ /* keep tracking only if interested in the last qmark */
+ if (entry && (entry->flags & RULEFLAG_QSLAST)) {
+ do {
+ span++;
+ span += strcspn(p + span, EXPAND_SPECIALS "?");
+ } while (p[span] == '?');
+ }
+ else {
+ unsafe_qmark = NULL;
+ span += strcspn(p + span, EXPAND_SPECIALS);
+ }
+ }
+ }
+ if (span > 0) {
if (current->len) {
current->next = (spc < SMALL_EXPANSION)
? &(sresult[spc++])
@@ -2558,7 +2623,7 @@ static void do_expand_env(data_item *env, rewrite_ctx *ctx)
char *name, *val;
while (env) {
- name = do_expand(env->data, ctx, NULL);
+ name = do_expand(env->data, ctx, NULL, NULL);
if (*name == '!') {
name++;
apr_table_unset(ctx->r->subprocess_env, name);
@@ -2685,7 +2750,7 @@ static void add_cookie(request_rec *r, char *s)
static void do_expand_cookie(data_item *cookie, rewrite_ctx *ctx)
{
while (cookie) {
- add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL));
+ add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL, NULL));
cookie = cookie->next;
}
@@ -3964,7 +4029,7 @@ static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx)
int basis;
if (p->ptype != CONDPAT_AP_EXPR)
- input = do_expand(p->input, ctx, NULL);
+ input = do_expand(p->input, ctx, NULL, NULL);
switch (p->ptype) {
case CONDPAT_FILE_EXISTS:
@@ -4128,7 +4193,7 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p,
char *expanded;
if (p->forced_mimetype) {
- expanded = do_expand(p->forced_mimetype, ctx, p);
+ expanded = do_expand(p->forced_mimetype, ctx, p, NULL);
if (*expanded) {
ap_str_tolower(expanded);
@@ -4142,7 +4207,7 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p,
}
if (p->forced_handler) {
- expanded = do_expand(p->forced_handler, ctx, p);
+ expanded = do_expand(p->forced_handler, ctx, p, NULL);
if (*expanded) {
ap_str_tolower(expanded);
@@ -4279,12 +4344,18 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p,
/* expand the result */
if (!(p->flags & RULEFLAG_NOSUB)) {
- newuri = do_expand(p->output, ctx, p);
+ int unsafe_qmark = -1;
+
+ if (p->flags & RULEFLAG_UNSAFE_ALLOW3F) {
+ newuri = do_expand(p->output, ctx, p, NULL);
+ }
+ else {
+ newuri = do_expand(p->output, ctx, p, &unsafe_qmark);
+ }
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, '?')) {
+
+ if (unsafe_qmark > 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO()
"Unsafe URL with %%3f URL rewritten without "
"UnsafeAllow3F");

View File

@ -13,7 +13,7 @@
Summary: Apache HTTP Server
Name: httpd
Version: 2.4.37
Release: 65%{?dist}.1
Release: 65%{?dist}.2
URL: https://httpd.apache.org/
Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2
Source2: httpd.logrotate
@ -171,6 +171,8 @@ Patch92: httpd-2.4.37-mod_status-duplicate-key.patch
Patch93: httpd-2.4.37-r1885607.patch
# https://issues.redhat.com/browse/RHEL-14321
Patch94: httpd-2.4.57-r1884505+.patch
# https://bz.apache.org/bugzilla/show_bug.cgi?id=69197
Patch95: httpd-2.4.37-r1919325.patch
# Security fixes
Patch200: httpd-2.4.37-r1851471.patch
@ -270,6 +272,11 @@ Patch243: httpd-2.4.37-CVE-2024-38473.patch
Patch244: httpd-2.4.37-CVE-2024-38477.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2295022
Patch245: httpd-2.4.37-CVE-2024-39573.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2295015
Patch246: httpd-2.4.37-CVE-2024-38476.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2297362
# https://bugzilla.redhat.com/show_bug.cgi?id=2295761
Patch247: httpd-2.4.37-CVE-2024-39884+.patch
License: ASL 2.0
Group: System Environment/Daemons
@ -502,6 +509,11 @@ interface for storing and accessing per-user session data.
%patch244 -p1 -b .CVE-2024-38477
%patch245 -p1 -b .CVE-2024-39573
# CVE-2024-38474 regression fix
%patch95 -p1 -b .r1919325
%patch246 -p1 -b .CVE-2024-38476
%patch247 -p1 -b .CVE-2024-39884+
# Patch in the vendor string
sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h
sed -i 's/@RELEASE@/%{release}/' server/core.c
@ -1006,6 +1018,11 @@ rm -rf $RPM_BUILD_ROOT
%{_rpmconfigdir}/macros.d/macros.httpd
%changelog
* Tue Aug 06 2024 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-65.2
- Resolves: RHEL-46040 - httpd:2.4/httpd: Security issues via backend
applications whose response headers are malicious or exploitable (CVE-2024-38476)
- Resolves: RHEL-53022 - Regression introduced by CVE-2024-38474 fix
* Thu Jul 11 2024 Luboš Uhliarik <luhliari@redhat.com> - 2.4.37-65.1
- Resolves: RHEL-45812 - httpd:2.4/httpd: Substitution encoding issue
in mod_rewrite (CVE-2024-38474)