Compare commits

4 Commits
1.1 ... main

44 changed files with 5644 additions and 2031 deletions

303
CVE-2024-42516.patch Normal file
View File

@@ -0,0 +1,303 @@
From a7a9d814c7c23e990283277230ddd5a9efec27c7 Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Mon, 7 Jul 2025 11:59:38 +0000
Subject: [PATCH] fix header merging
Reviewed By: rpluem, jorton, ylavic
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1927039 13f79535-47bb-0310-9956-ffa450edef68
---
modules/http/http_filters.c | 248 +++++++++++++++++++-----------------
1 file changed, 128 insertions(+), 120 deletions(-)
Index: httpd-2.4.58/modules/http/http_filters.c
===================================================================
--- httpd-2.4.58.orig/modules/http/http_filters.c
+++ httpd-2.4.58/modules/http/http_filters.c
@@ -1300,107 +1300,10 @@ typedef struct header_filter_ctx {
int headers_sent;
} header_filter_ctx;
-AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
- apr_bucket_brigade *b)
+static void merge_response_headers(request_rec *r, const char **protocol)
{
- request_rec *r = f->r;
- conn_rec *c = r->connection;
- const char *clheader;
- int header_only = (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status));
- const char *protocol = NULL;
- apr_bucket *e;
- apr_bucket_brigade *b2;
- header_struct h;
- header_filter_ctx *ctx = f->ctx;
- const char *ctype;
- ap_bucket_error *eb = NULL;
- apr_status_t rv = APR_SUCCESS;
- int recursive_error = 0;
-
- AP_DEBUG_ASSERT(!r->main);
-
- if (!ctx) {
- ctx = f->ctx = apr_pcalloc(r->pool, sizeof(header_filter_ctx));
- }
- else if (ctx->headers_sent) {
- /* Eat body if response must not have one. */
- if (header_only) {
- /* Still next filters may be waiting for EOS, so pass it (alone)
- * when encountered and be done with this filter.
- */
- e = APR_BRIGADE_LAST(b);
- if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) {
- APR_BUCKET_REMOVE(e);
- apr_brigade_cleanup(b);
- APR_BRIGADE_INSERT_HEAD(b, e);
- ap_remove_output_filter(f);
- rv = ap_pass_brigade(f->next, b);
- }
- apr_brigade_cleanup(b);
- return rv;
- }
- }
-
- for (e = APR_BRIGADE_FIRST(b);
- e != APR_BRIGADE_SENTINEL(b);
- e = APR_BUCKET_NEXT(e))
- {
- if (AP_BUCKET_IS_ERROR(e) && !eb) {
- eb = e->data;
- continue;
- }
- /*
- * If we see an EOC bucket it is a signal that we should get out
- * of the way doing nothing.
- */
- if (AP_BUCKET_IS_EOC(e)) {
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, b);
- }
- }
-
- if (!ctx->headers_sent && !check_headers(r)) {
- /* We may come back here from ap_die() below,
- * so clear anything from this response.
- */
- apr_table_clear(r->headers_out);
- apr_table_clear(r->err_headers_out);
- r->content_type = r->content_encoding = NULL;
- r->content_languages = NULL;
- r->clength = r->chunked = 0;
- apr_brigade_cleanup(b);
-
- /* Don't recall ap_die() if we come back here (from its own internal
- * redirect or error response), otherwise we can end up in infinite
- * recursion; better fall through with 500, minimal headers and an
- * empty body (EOS only).
- */
- if (!check_headers_recursion(r)) {
- ap_die(HTTP_INTERNAL_SERVER_ERROR, r);
- return AP_FILTER_ERROR;
- }
- r->status = HTTP_INTERNAL_SERVER_ERROR;
- e = ap_bucket_eoc_create(c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(b, e);
- e = apr_bucket_eos_create(c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(b, e);
- ap_set_content_length(r, 0);
- recursive_error = 1;
- }
- else if (eb) {
- int status;
- status = eb->status;
- apr_brigade_cleanup(b);
- ap_die(status, r);
- return AP_FILTER_ERROR;
- }
-
- if (r->assbackwards) {
- r->sent_bodyct = 1;
- ap_remove_output_filter(f);
- rv = ap_pass_brigade(f->next, b);
- goto out;
- }
+ const char *ctype = NULL;
+ const char *clheader = NULL;
/*
* Now that we are ready to send a response, we need to combine the two
@@ -1430,6 +1333,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_
fixup_vary(r);
}
+ /* determine the protocol and whether we should use keepalives. */
+ basic_http_header_check(r, protocol);
+ ap_set_keepalive(r);
/*
* Control cachability for non-cacheable responses if not already set by
@@ -1449,10 +1355,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_
apr_table_unset(r->headers_out, "ETag");
}
- /* determine the protocol and whether we should use keepalives. */
- basic_http_header_check(r, &protocol);
- ap_set_keepalive(r);
-
/* 204/304 responses don't have content related headers */
if (AP_STATUS_IS_HEADER_ONLY(r->status)) {
apr_table_unset(r->headers_out, "Transfer-Encoding");
@@ -1520,30 +1422,136 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_
&& conf->http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_ENABLE) {
apr_table_unset(r->headers_out, "Content-Length");
}
+}
- b2 = apr_brigade_create(r->pool, c->bucket_alloc);
- basic_http_header(r, b2, protocol);
-
- h.pool = r->pool;
- h.bb = b2;
+AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
+ apr_bucket_brigade *b)
+{
+ request_rec *r = f->r;
+ conn_rec *c = r->connection;
+ int header_only = (r->header_only || AP_STATUS_IS_HEADER_ONLY(r->status));
+ apr_bucket *e;
+ apr_bucket_brigade *b2;
+ header_struct h;
+ header_filter_ctx *ctx = f->ctx;
+ ap_bucket_error *eb = NULL;
+ apr_status_t rv = APR_SUCCESS;
+ int recursive_error = 0;
+ const char *protocol;
- send_all_header_fields(&h, r);
+ AP_DEBUG_ASSERT(!r->main);
- terminate_header(b2);
+ if (!ctx) {
+ ctx = f->ctx = apr_pcalloc(r->pool, sizeof(header_filter_ctx));
+ }
+ else if (ctx->headers_sent) {
+ /* Eat body if response must not have one. */
+ if (header_only) {
+ /* Still next filters may be waiting for EOS, so pass it (alone)
+ * when encountered and be done with this filter.
+ */
+ e = APR_BRIGADE_LAST(b);
+ if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) {
+ APR_BUCKET_REMOVE(e);
+ apr_brigade_cleanup(b);
+ APR_BRIGADE_INSERT_HEAD(b, e);
+ ap_remove_output_filter(f);
+ rv = ap_pass_brigade(f->next, b);
+ }
+ apr_brigade_cleanup(b);
+ return rv;
+ }
+ }
- if (header_only) {
- e = APR_BRIGADE_LAST(b);
- if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) {
- APR_BUCKET_REMOVE(e);
- APR_BRIGADE_INSERT_TAIL(b2, e);
+ for (e = APR_BRIGADE_FIRST(b);
+ e != APR_BRIGADE_SENTINEL(b);
+ e = APR_BUCKET_NEXT(e))
+ {
+ if (AP_BUCKET_IS_ERROR(e) && !eb) {
+ eb = e->data;
+ continue;
+ }
+ /*
+ * If we see an EOC bucket it is a signal that we should get out
+ * of the way doing nothing.
+ */
+ if (AP_BUCKET_IS_EOC(e)) {
ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, b);
+ }
+ }
+
+ if (!ctx->headers_sent) {
+ merge_response_headers(r, &protocol);
+ if (!check_headers(r)) {
+ /* We may come back here from ap_die() below,
+ * so clear anything from this response.
+ */
+ apr_table_clear(r->headers_out);
+ apr_table_clear(r->err_headers_out);
+ r->content_type = r->content_encoding = NULL;
+ r->content_languages = NULL;
+ r->clength = r->chunked = 0;
+ apr_brigade_cleanup(b);
+
+ /* Don't recall ap_die() if we come back here (from its own internal
+ * redirect or error response), otherwise we can end up in infinite
+ * recursion; better fall through with 500, minimal headers and an
+ * empty body (EOS only).
+ */
+ if (!check_headers_recursion(r)) {
+ ap_die(HTTP_INTERNAL_SERVER_ERROR, r);
+ return AP_FILTER_ERROR;
+ }
+ r->status = HTTP_INTERNAL_SERVER_ERROR;
+ e = ap_bucket_eoc_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(b, e);
+ e = apr_bucket_eos_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(b, e);
+ ap_set_content_length(r, 0);
+ recursive_error = 1;
+ }
+ else if (eb) {
+ int status;
+ status = eb->status;
+ apr_brigade_cleanup(b);
+ ap_die(status, r);
+ return AP_FILTER_ERROR;
}
- apr_brigade_cleanup(b);
}
- rv = ap_pass_brigade(f->next, b2);
- apr_brigade_cleanup(b2);
- ctx->headers_sent = 1;
+ if (r->assbackwards) {
+ r->sent_bodyct = 1;
+ ap_remove_output_filter(f);
+ rv = ap_pass_brigade(f->next, b);
+ goto out;
+ }
+
+ if (!ctx->headers_sent) {
+ b2 = apr_brigade_create(r->pool, c->bucket_alloc);
+ basic_http_header(r, b2, protocol);
+
+ h.pool = r->pool;
+ h.bb = b2;
+
+ send_all_header_fields(&h, r);
+
+ terminate_header(b2);
+
+ if (header_only) {
+ e = APR_BRIGADE_LAST(b);
+ if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) {
+ APR_BUCKET_REMOVE(e);
+ APR_BRIGADE_INSERT_TAIL(b2, e);
+ ap_remove_output_filter(f);
+ }
+ apr_brigade_cleanup(b);
+ }
+
+ rv = ap_pass_brigade(f->next, b2);
+ apr_brigade_cleanup(b2);
+ ctx->headers_sent = 1;
+ }
if (rv != APR_SUCCESS || header_only) {
goto out;

37
CVE-2024-43204.patch Normal file
View File

@@ -0,0 +1,37 @@
From b3d3ded288815bea063c3bf77dd80b26446f76ce Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Mon, 7 Jul 2025 12:01:02 +0000
Subject: [PATCH] backport 1927032 from trunk
header only
Reviewed By: rpluem, jorton, ylavic
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1927040 13f79535-47bb-0310-9956-ffa450edef68
---
modules/metadata/mod_headers.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
Index: httpd-2.4.51/modules/metadata/mod_headers.c
===================================================================
--- httpd-2.4.51.orig/modules/metadata/mod_headers.c
+++ httpd-2.4.51/modules/metadata/mod_headers.c
@@ -783,14 +783,14 @@ static int do_headers_fixup(request_rec
break;
case hdr_set:
if (!ap_cstr_casecmp(hdr->header, "Content-Type")) {
- ap_set_content_type_ex(r, process_tags(hdr, r), 1);
+ ap_set_content_type(r, process_tags(hdr, r));
}
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_ex(r, process_tags(hdr, r), 1);
+ ap_set_content_type(r, process_tags(hdr, r));
}
apr_table_setn(headers, hdr->header, process_tags(hdr, r));
}

44
CVE-2024-47252.patch Normal file
View File

@@ -0,0 +1,44 @@
From c01e60707048be14a510f0a92128a5227923215c Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Mon, 7 Jul 2025 12:03:42 +0000
Subject: [PATCH] backport 1927034 from trunk
escape ssl vars
Reviewed By: rpluem, jorton, covener, ylavic
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1927042 13f79535-47bb-0310-9956-ffa450edef68
---
modules/ssl/ssl_engine_vars.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c
index 418d849e00e..4060c0f6a63 100644
--- a/modules/ssl/ssl_engine_vars.c
+++ b/modules/ssl/ssl_engine_vars.c
@@ -1208,8 +1208,9 @@ static const char *ssl_var_log_handler_c(request_rec *r, char *a)
result = "-";
else if (strEQ(a, "errstr"))
result = (char *)sslconn->verify_error;
- if (result != NULL && result[0] == NUL)
- result = NULL;
+ if (result) {
+ result = *result ? ap_escape_logitem(r->pool, result) : NULL;
+ }
return result;
}
@@ -1222,8 +1223,9 @@ static const char *ssl_var_log_handler_x(request_rec *r, char *a)
char *result;
result = ssl_var_lookup(r->pool, r->server, r->connection, r, a);
- if (result != NULL && result[0] == NUL)
- result = NULL;
+ if (result) {
+ result = *result ? ap_escape_logitem(r->pool, result) : NULL;
+ }
return result;
}

62
CVE-2025-23048.patch Normal file
View File

@@ -0,0 +1,62 @@
From c4cfa50c9068e8b8134c530ab21674e77d1278a2 Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Mon, 7 Jul 2025 12:04:49 +0000
Subject: [PATCH] backport 1927035 from trunk
update SNI validation
Reviewed By: rpluem, jorton, covener, ylavic
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1927043 13f79535-47bb-0310-9956-ffa450edef68
---
modules/ssl/ssl_engine_kernel.c | 28 +++++++++++++++-------------
1 file changed, 15 insertions(+), 13 deletions(-)
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
index 9c510218441..d912a874dd9 100644
--- a/modules/ssl/ssl_engine_kernel.c
+++ b/modules/ssl/ssl_engine_kernel.c
@@ -371,19 +371,6 @@ int ssl_hook_ReadReq(request_rec *r)
" provided in HTTP request", servername);
return HTTP_BAD_REQUEST;
}
- if (r->server != handshakeserver
- && !ssl_server_compatible(sslconn->server, r->server)) {
- /*
- * The request does not select the virtual host that was
- * selected by the SNI and its SSL parameters are different
- */
-
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02032)
- "Hostname %s provided via SNI and hostname %s provided"
- " via HTTP have no compatible SSL setup",
- servername, r->hostname);
- return HTTP_MISDIRECTED_REQUEST;
- }
}
else if (((sc->strict_sni_vhost_check == SSL_ENABLED_TRUE)
|| hssc->strict_sni_vhost_check == SSL_ENABLED_TRUE)
@@ -404,6 +391,21 @@ int ssl_hook_ReadReq(request_rec *r)
"which is required to access this server.<br />\n");
return HTTP_FORBIDDEN;
}
+ if (r->server != handshakeserver
+ && !ssl_server_compatible(sslconn->server, r->server)) {
+ /*
+ * The request does not select the virtual host that was
+ * selected for handshaking and its SSL parameters are different
+ */
+
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02032)
+ "Hostname %s %s and hostname %s provided"
+ " via HTTP have no compatible SSL setup",
+ servername ? servername : handshakeserver->server_hostname,
+ servername ? "provided via SNI" : "(default host as no SNI was provided)",
+ r->hostname);
+ return HTTP_MISDIRECTED_REQUEST;
+ }
}
#endif
modssl_set_app_data2(ssl, r);

39
CVE-2025-49630.patch Normal file
View File

@@ -0,0 +1,39 @@
From 88304321841a2fe8bd5eacc70e69418b0b545ca5 Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Mon, 7 Jul 2025 12:05:49 +0000
Subject: [PATCH] backport 1927036 from trunk
tolerate missing host header in h2 proxy
Reviewed By: jorton, icing, rpluem
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1927044 13f79535-47bb-0310-9956-ffa450edef68
---
modules/http2/h2_proxy_session.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/modules/http2/h2_proxy_session.c b/modules/http2/h2_proxy_session.c
index d5d0f9bc6bc..2cfbb5f5d4b 100644
--- a/modules/http2/h2_proxy_session.c
+++ b/modules/http2/h2_proxy_session.c
@@ -850,6 +850,18 @@ static apr_status_t open_stream(h2_proxy_session *session, const char *url,
dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
if (dconf->preserve_host) {
authority = orig_host;
+ if (!authority) {
+ /* Duplicate mod_proxy behaviour if ProxyPreserveHost is
+ * used but an "HTTP/0.9" request is received without a
+ * Host: header */
+ authority = r->server->server_hostname;
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10511)
+ "HTTP/0.9 request (with no host line) "
+ "on incoming request and preserve host set "
+ "forcing hostname to be %s for uri %s",
+ authority, r->uri);
+ apr_table_setn(r->headers_in, "Host", authority);
+ }
}
else {
authority = puri.hostname;

198
CVE-2025-49812.patch Normal file
View File

@@ -0,0 +1,198 @@
From 87a7351c755c9ef8ab386e3090e44838c2a06d48 Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Mon, 7 Jul 2025 12:09:30 +0000
Subject: [PATCH] backport 1927037 from trunk
remove antiquated 'SSLEngine optional' TLS upgrade
Reviewed By: rpluem, jorton, covener
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1927045 13f79535-47bb-0310-9956-ffa450edef68
---
modules/ssl/ssl_engine_config.c | 6 ++-
modules/ssl/ssl_engine_init.c | 6 +--
modules/ssl/ssl_engine_kernel.c | 86 ---------------------------------
modules/ssl/ssl_private.h | 1 -
4 files changed, 7 insertions(+), 92 deletions(-)
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
index 9af6f70fd03..d1f4fad8e23 100644
--- a/modules/ssl/ssl_engine_config.c
+++ b/modules/ssl/ssl_engine_config.c
@@ -741,11 +741,13 @@ const char *ssl_cmd_SSLEngine(cmd_parms *cmd, void *dcfg, const char *arg)
return NULL;
}
else if (!strcasecmp(arg, "Optional")) {
- sc->enabled = SSL_ENABLED_OPTIONAL;
+ sc->enabled = SSL_ENABLED_FALSE;
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, cmd->server, APLOGNO(10510)
+ "'SSLEngine optional' is no longer supported");
return NULL;
}
- return "Argument must be On, Off, or Optional";
+ return "Argument must be On or Off";
}
const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag)
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index f9eca79e462..94cc2772e01 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -427,7 +427,7 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
&ssl_module);
sc = mySrvConfig(s);
- if (sc->enabled == SSL_ENABLED_TRUE || sc->enabled == SSL_ENABLED_OPTIONAL) {
+ if (sc->enabled == SSL_ENABLED_TRUE) {
if ((rv = ssl_run_init_server(s, p, 0, sc->server->ssl_ctx)) != APR_SUCCESS) {
return rv;
}
@@ -2126,9 +2126,9 @@ apr_status_t ssl_init_ConfigureServer(server_rec *s,
&ssl_module);
apr_status_t rv;
- /* Initialize the server if SSL is enabled or optional.
+ /* Initialize the server if SSL is enabled.
*/
- if ((sc->enabled == SSL_ENABLED_TRUE) || (sc->enabled == SSL_ENABLED_OPTIONAL)) {
+ if (sc->enabled == SSL_ENABLED_TRUE) {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01914)
"Configuring server %s for SSL protocol", sc->vhost_id);
if ((rv = ssl_init_server_ctx(s, p, ptemp, sc, pphrases))
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
index d912a874dd9..33aa1f71dc7 100644
--- a/modules/ssl/ssl_engine_kernel.c
+++ b/modules/ssl/ssl_engine_kernel.c
@@ -38,59 +38,6 @@ static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn);
static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s);
#endif
-#define SWITCH_STATUS_LINE "HTTP/1.1 101 Switching Protocols"
-#define UPGRADE_HEADER "Upgrade: TLS/1.0, HTTP/1.1"
-#define CONNECTION_HEADER "Connection: Upgrade"
-
-/* Perform an upgrade-to-TLS for the given request, per RFC 2817. */
-static apr_status_t upgrade_connection(request_rec *r)
-{
- struct conn_rec *conn = r->connection;
- apr_bucket_brigade *bb;
- SSLConnRec *sslconn;
- apr_status_t rv;
- SSL *ssl;
-
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02028)
- "upgrading connection to TLS");
-
- bb = apr_brigade_create(r->pool, conn->bucket_alloc);
-
- rv = ap_fputs(conn->output_filters, bb, SWITCH_STATUS_LINE CRLF
- UPGRADE_HEADER CRLF CONNECTION_HEADER CRLF CRLF);
- if (rv == APR_SUCCESS) {
- APR_BRIGADE_INSERT_TAIL(bb,
- apr_bucket_flush_create(conn->bucket_alloc));
- rv = ap_pass_brigade(conn->output_filters, bb);
- }
-
- if (rv) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02029)
- "failed to send 101 interim response for connection "
- "upgrade");
- return rv;
- }
-
- ssl_init_ssl_connection(conn, r);
-
- sslconn = myConnConfig(conn);
- ssl = sslconn->ssl;
-
- /* Perform initial SSL handshake. */
- SSL_set_accept_state(ssl);
- SSL_do_handshake(ssl);
-
- if (!SSL_is_init_finished(ssl)) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02030)
- "TLS upgrade handshake failed");
- ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, r->server);
-
- return APR_ECONNABORTED;
- }
-
- return APR_SUCCESS;
-}
-
/* Perform a speculative (and non-blocking) read from the connection
* filters for the given request, to determine whether there is any
* pending data to read. Return non-zero if there is, else zero. */
@@ -270,40 +217,17 @@ int ssl_hook_ReadReq(request_rec *r)
{
SSLSrvConfigRec *sc = mySrvConfig(r->server);
SSLConnRec *sslconn;
- const char *upgrade;
#ifdef HAVE_TLSEXT
const char *servername;
#endif
SSL *ssl;
- /* Perform TLS upgrade here if "SSLEngine optional" is configured,
- * SSL is not already set up for this connection, and the client
- * has sent a suitable Upgrade header. */
- if (sc->enabled == SSL_ENABLED_OPTIONAL && !myConnConfig(r->connection)
- && (upgrade = apr_table_get(r->headers_in, "Upgrade")) != NULL
- && ap_find_token(r->pool, upgrade, "TLS/1.0")) {
- if (upgrade_connection(r)) {
- return AP_FILTER_ERROR;
- }
- }
-
/* If we are on a slave connection, we do not expect to have an SSLConnRec,
* but our master connection might. */
sslconn = myConnConfig(r->connection);
if (!(sslconn && sslconn->ssl) && r->connection->master) {
sslconn = myConnConfig(r->connection->master);
}
-
- /* If "SSLEngine optional" is configured, this is not an SSL
- * connection, and this isn't a subrequest, send an Upgrade
- * response header. Note this must happen before map_to_storage
- * and OPTIONS * request processing is completed.
- */
- if (sc->enabled == SSL_ENABLED_OPTIONAL && !(sslconn && sslconn->ssl)
- && !r->main) {
- apr_table_setn(r->headers_out, "Upgrade", "TLS/1.0, HTTP/1.1");
- apr_table_mergen(r->headers_out, "Connection", "upgrade");
- }
if (!sslconn) {
return DECLINED;
@@ -1238,16 +1162,6 @@ int ssl_hook_Access(request_rec *r)
* Support for SSLRequireSSL directive
*/
if (dc->bSSLRequired && !ssl) {
- if ((sc->enabled == SSL_ENABLED_OPTIONAL) && !r->connection->master) {
- /* This vhost was configured for optional SSL, just tell the
- * client that we need to upgrade.
- */
- apr_table_setn(r->err_headers_out, "Upgrade", "TLS/1.0, HTTP/1.1");
- apr_table_setn(r->err_headers_out, "Connection", "Upgrade");
-
- return HTTP_UPGRADE_REQUIRED;
- }
-
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02219)
"access to %s failed, reason: %s",
r->filename, "SSL connection required");
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index fb9edaa5eeb..794e51aa937 100644
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -526,7 +526,6 @@ typedef enum {
SSL_ENABLED_UNSET = UNSET,
SSL_ENABLED_FALSE = 0,
SSL_ENABLED_TRUE = 1,
- SSL_ENABLED_OPTIONAL = 3
} ssl_enabled_t;
/**

496
CVE-2025-53020.patch Normal file
View File

@@ -0,0 +1,496 @@
From ef98f4f494ff2f99d736a3716cd31219688b46f5 Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Mon, 7 Jul 2025 12:12:49 +0000
Subject: [PATCH] backport 1927038 from trunk
improve h2 header error handling
Rewviewed By: icing, covener, rpluem
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1927046 13f79535-47bb-0310-9956-ffa450edef68
---
modules/http2/h2_request.c | 12 ++--
modules/http2/h2_request.h | 8 ++-
modules/http2/h2_session.c | 31 ++++++++-
modules/http2/h2_session.h | 3 +
modules/http2/h2_stream.c | 69 ++++++++++++-------
modules/http2/h2_util.c | 51 ++++++++------
modules/http2/h2_util.h | 11 ++-
test/modules/http2/test_200_header_invalid.py | 4 +-
8 files changed, 130 insertions(+), 59 deletions(-)
diff --git a/modules/http2/h2_request.c b/modules/http2/h2_request.c
index 2713947c377..6373e0a244d 100644
--- a/modules/http2/h2_request.c
+++ b/modules/http2/h2_request.c
@@ -64,18 +64,20 @@ typedef struct {
apr_table_t *headers;
apr_pool_t *pool;
apr_status_t status;
+ h2_hd_scratch *scratch;
} h1_ctx;
static int set_h1_header(void *ctx, const char *key, const char *value)
{
h1_ctx *x = ctx;
int was_added;
- h2_req_add_header(x->headers, x->pool, key, strlen(key), value, strlen(value), 0, &was_added);
+ h2_req_add_header(x->headers, x->pool, key, strlen(key),
+ value, strlen(value), x->scratch, &was_added);
return 1;
}
apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool,
- request_rec *r)
+ request_rec *r, h2_hd_scratch *scratch)
{
h2_request *req;
const char *scheme, *authority, *path;
@@ -125,6 +127,7 @@ apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool,
x.pool = pool;
x.headers = req->headers;
x.status = APR_SUCCESS;
+ x.scratch = scratch;
apr_table_do(set_h1_header, &x, r->headers_in, NULL);
*preq = req;
@@ -134,7 +137,8 @@ apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool,
apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool,
const char *name, size_t nlen,
const char *value, size_t vlen,
- size_t max_field_len, int *pwas_added)
+ struct h2_hd_scratch *scratch,
+ int *pwas_added)
{
apr_status_t status = APR_SUCCESS;
@@ -185,7 +189,7 @@ apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool,
else {
/* non-pseudo header, add to table */
status = h2_req_add_header(req->headers, pool, name, nlen, value, vlen,
- max_field_len, pwas_added);
+ scratch, pwas_added);
}
return status;
diff --git a/modules/http2/h2_request.h b/modules/http2/h2_request.h
index 7e20b697246..ae6b6a2510c 100644
--- a/modules/http2/h2_request.h
+++ b/modules/http2/h2_request.h
@@ -19,17 +19,21 @@
#include "h2.h"
+struct h2_hd_scratch;
+
h2_request *h2_request_create(int id, apr_pool_t *pool, const char *method,
const char *scheme, const char *authority,
const char *path, apr_table_t *header);
apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool,
- request_rec *r);
+ request_rec *r,
+ struct h2_hd_scratch *scratch);
apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool,
const char *name, size_t nlen,
const char *value, size_t vlen,
- size_t max_field_len, int *pwas_added);
+ struct h2_hd_scratch *scratch,
+ int *pwas_added);
apr_status_t h2_request_add_trailer(h2_request *req, apr_pool_t *pool,
const char *name, size_t nlen,
diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c
index fc8b6119ae8..a5f1872bc20 100644
--- a/modules/http2/h2_session.c
+++ b/modules/http2/h2_session.c
@@ -109,13 +109,29 @@ static void cleanup_unprocessed_streams(h2_session *session)
h2_mplx_c1_streams_do(session->mplx, rst_unprocessed_stream, session);
}
+/* APR callback invoked if allocation fails. */
+static int abort_on_oom(int retcode)
+{
+ ap_abort_on_oom();
+ return retcode; /* unreachable, hopefully. */
+}
+
static h2_stream *h2_session_open_stream(h2_session *session, int stream_id,
int initiated_on)
{
h2_stream * stream;
+ apr_allocator_t *allocator;
apr_pool_t *stream_pool;
+ apr_status_t rv;
- apr_pool_create(&stream_pool, session->pool);
+ rv = apr_allocator_create(&allocator);
+ if (rv != APR_SUCCESS)
+ return NULL;
+
+ apr_allocator_max_free_set(allocator, ap_max_mem_free);
+ apr_pool_create_ex(&stream_pool, session->pool, NULL, allocator);
+ apr_allocator_owner_set(allocator, stream_pool);
+ apr_pool_abort_set(abort_on_oom, stream_pool);
apr_pool_tag(stream_pool, "h2_stream");
stream = h2_stream_create(stream_id, stream_pool, session,
@@ -972,6 +988,14 @@ apr_status_t h2_session_create(h2_session **psession, conn_rec *c, request_rec *
}
h2_c1_io_init(&session->io, session);
+ /* setup request header scratch buffers */
+ session->hd_scratch.max_len = session->s->limit_req_fieldsize?
+ session->s->limit_req_fieldsize : 8190;
+ session->hd_scratch.name =
+ apr_pcalloc(session->pool, session->hd_scratch.max_len + 1);
+ session->hd_scratch.value =
+ apr_pcalloc(session->pool, session->hd_scratch.max_len + 1);
+
session->padding_max = h2_config_sgeti(s, H2_CONF_PADDING_BITS);
if (session->padding_max) {
session->padding_max = (0x01 << session->padding_max) - 1;
@@ -1032,7 +1056,7 @@ apr_status_t h2_session_create(h2_session **psession, conn_rec *c, request_rec *
n = h2_config_sgeti(s, H2_CONF_PUSH_DIARY_SIZE);
session->push_diary = h2_push_diary_create(session->pool, n);
-
+
if (APLOGcdebug(c)) {
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
H2_SSSN_LOG(APLOGNO(03200), session,
@@ -1699,9 +1723,10 @@ static void on_stream_state_enter(void *ctx, h2_stream *stream)
break;
case H2_SS_CLEANUP:
nghttp2_session_set_stream_user_data(session->ngh2, stream->id, NULL);
+ update_child_status(session, SERVER_BUSY_WRITE, "done", stream);
h2_mplx_c1_stream_cleanup(session->mplx, stream, &session->open_streams);
+ stream = NULL;
++session->streams_done;
- update_child_status(session, SERVER_BUSY_WRITE, "done", stream);
break;
default:
break;
diff --git a/modules/http2/h2_session.h b/modules/http2/h2_session.h
index 2c8f334cce0..7932a9e2ccf 100644
--- a/modules/http2/h2_session.h
+++ b/modules/http2/h2_session.h
@@ -29,6 +29,7 @@
*/
#include "h2.h"
+#include "h2_util.h"
struct apr_thread_mutext_t;
struct apr_thread_cond_t;
@@ -118,6 +119,8 @@ typedef struct h2_session {
struct h2_iqueue *out_c1_blocked; /* all streams with output blocked on c1 buffer full */
struct h2_iqueue *ready_to_process; /* all streams ready for processing */
+ h2_hd_scratch hd_scratch;
+
} h2_session;
const char *h2_session_state_str(h2_session_state state);
diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c
index 35b53860c03..f8214019404 100644
--- a/modules/http2/h2_stream.c
+++ b/modules/http2/h2_stream.c
@@ -659,7 +659,8 @@ apr_status_t h2_stream_set_request_rec(h2_stream *stream,
if (stream->rst_error) {
return APR_ECONNRESET;
}
- status = h2_request_rcreate(&req, stream->pool, r);
+ status = h2_request_rcreate(&req, stream->pool, r,
+ &stream->session->hd_scratch);
if (status == APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r,
H2_STRM_LOG(APLOGNO(03058), stream,
@@ -691,13 +692,11 @@ static void set_error_response(h2_stream *stream, int http_status)
static apr_status_t add_trailer(h2_stream *stream,
const char *name, size_t nlen,
const char *value, size_t vlen,
- size_t max_field_len, int *pwas_added)
+ h2_hd_scratch *scratch)
{
conn_rec *c = stream->session->c1;
- char *hname, *hvalue;
const char *existing;
- *pwas_added = 0;
if (nlen == 0 || name[0] == ':') {
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_EINVAL, c,
H2_STRM_LOG(APLOGNO(03060), stream,
@@ -710,20 +709,35 @@ static apr_status_t add_trailer(h2_stream *stream,
if (!stream->trailers_in) {
stream->trailers_in = apr_table_make(stream->pool, 5);
}
- hname = apr_pstrndup(stream->pool, name, nlen);
- h2_util_camel_case_header(hname, nlen);
- existing = apr_table_get(stream->trailers_in, hname);
- if (max_field_len
- && ((existing? strlen(existing)+2 : 0) + vlen + nlen + 2 > max_field_len)) {
- /* "key: (oldval, )?nval" is too long */
+
+ if (((nlen + vlen + 2) > scratch->max_len))
return APR_EINVAL;
+
+ /* We need 0-terminated strings to operate on apr_table */
+ AP_DEBUG_ASSERT(nlen < scratch->max_len);
+ memcpy(scratch->name, name, nlen);
+ scratch->name[nlen] = 0;
+ AP_DEBUG_ASSERT(vlen < scratch->max_len);
+ memcpy(scratch->value, value, vlen);
+ scratch->value[vlen] = 0;
+
+ existing = apr_table_get(stream->trailers_in, scratch->name);
+ if(existing) {
+ if (!vlen) /* not adding a 0-length value to existing */
+ return APR_SUCCESS;
+ if ((strlen(existing) + 2 + vlen + nlen + 2 > scratch->max_len)) {
+ /* "name: existing, value" is too long */
+ return APR_EINVAL;
+ }
+ apr_table_merge(stream->trailers_in, scratch->name, scratch->value);
}
- if (!existing) *pwas_added = 1;
- hvalue = apr_pstrndup(stream->pool, value, vlen);
- apr_table_mergen(stream->trailers_in, hname, hvalue);
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
- H2_STRM_MSG(stream, "added trailer '%s: %s'"), hname, hvalue);
-
+ else {
+ h2_util_camel_case_header(scratch->name, nlen);
+ apr_table_set(stream->trailers_in, scratch->name, scratch->value);
+ }
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
+ H2_STRM_MSG(stream, "added trailer '%s: %s'"),
+ scratch->name, scratch->value);
return APR_SUCCESS;
}
@@ -732,7 +746,7 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
const char *value, size_t vlen)
{
h2_session *session = stream->session;
- int error = 0, was_added = 0;
+ int error = 0;
apr_status_t status = APR_SUCCESS;
H2_STRM_ASSERT_MAGIC(stream, H2_STRM_MAGIC_OK);
@@ -760,6 +774,7 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
++stream->request_headers_added;
}
else if (H2_SS_IDLE == stream->state) {
+ int was_added;
if (!stream->rtmp) {
if (H2_STREAM_CLIENT_INITIATED(stream->id)) {
++stream->session->remote.emitted_count;
@@ -771,7 +786,7 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
}
status = h2_request_add_header(stream->rtmp, stream->pool,
name, nlen, value, vlen,
- session->s->limit_req_fieldsize, &was_added);
+ &session->hd_scratch, &was_added);
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, session->c1,
H2_STRM_MSG(stream, "add_header: '%.*s: %.*s"),
(int)nlen, name, (int)vlen, value);
@@ -779,8 +794,8 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
}
else if (H2_SS_OPEN == stream->state) {
status = add_trailer(stream, name, nlen, value, vlen,
- session->s->limit_req_fieldsize, &was_added);
- if (was_added) ++stream->request_headers_added;
+ &session->hd_scratch);
+ if (!status) ++stream->request_headers_added;
}
else {
status = APR_EINVAL;
@@ -789,16 +804,17 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
if (APR_EINVAL == status) {
/* header too long */
- if (!h2_stream_is_ready(stream)) {
+ if (!h2_stream_is_ready(stream) && !stream->request_headers_failed) {
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, session->c1,
- H2_STRM_LOG(APLOGNO(10180), stream,"Request header exceeds "
- "LimitRequestFieldSize: %.*s"),
+ H2_STRM_LOG(APLOGNO(10180), stream,
+ "Request header exceeds LimitRequestFieldSize(%d): %.*s"),
+ (int)session->hd_scratch.max_len,
(int)H2MIN(nlen, 80), name);
}
error = HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
goto cleanup;
}
-
+
if (session->s->limit_req_fields > 0
&& stream->request_headers_added > session->s->limit_req_fields) {
/* too many header lines */
@@ -810,12 +826,13 @@ apr_status_t h2_stream_add_header(h2_stream *stream,
if (!h2_stream_is_ready(stream)) {
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, session->c1,
H2_STRM_LOG(APLOGNO(10181), stream, "Number of request headers "
- "exceeds LimitRequestFields"));
+ "exceeds LimitRequestFields(%d)"),
+ (int)session->s->limit_req_fields);
}
error = HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
goto cleanup;
}
-
+
cleanup:
if (error) {
++stream->request_headers_failed;
diff --git a/modules/http2/h2_util.c b/modules/http2/h2_util.c
index 8e53cebdf92..605c348ca12 100644
--- a/modules/http2/h2_util.c
+++ b/modules/http2/h2_util.c
@@ -1693,10 +1693,9 @@ int h2_ignore_resp_trailer(const char *name, size_t len)
}
static apr_status_t req_add_header(apr_table_t *headers, apr_pool_t *pool,
- nghttp2_nv *nv, size_t max_field_len,
+ nghttp2_nv *nv, h2_hd_scratch *scratch,
int *pwas_added)
{
- char *hname, *hvalue;
const char *existing;
*pwas_added = 0;
@@ -1712,15 +1711,14 @@ static apr_status_t req_add_header(apr_table_t *headers, apr_pool_t *pool,
/* Cookie header come separately in HTTP/2, but need
* to be merged by "; " (instead of default ", ")
*/
- if (max_field_len
- && strlen(existing) + nv->valuelen + nv->namelen + 4
- > max_field_len) {
+ if ((strlen(existing) + nv->valuelen + nv->namelen + 4)
+ > scratch->max_len) {
/* "key: oldval, nval" is too long */
return APR_EINVAL;
}
- hvalue = apr_pstrndup(pool, (const char*)nv->value, nv->valuelen);
apr_table_setn(headers, "Cookie",
- apr_psprintf(pool, "%s; %s", existing, hvalue));
+ apr_psprintf(pool, "%s; %.*s", existing,
+ (int)nv->valuelen, nv->value));
return APR_SUCCESS;
}
}
@@ -1731,27 +1729,40 @@ static apr_status_t req_add_header(apr_table_t *headers, apr_pool_t *pool,
}
}
- hname = apr_pstrndup(pool, (const char*)nv->name, nv->namelen);
- h2_util_camel_case_header(hname, nv->namelen);
- existing = apr_table_get(headers, hname);
- if (max_field_len) {
- if ((existing? strlen(existing)+2 : 0) + nv->valuelen + nv->namelen + 2
- > max_field_len) {
- /* "key: (oldval, )?nval" is too long */
+ if (((nv->namelen + nv->valuelen + 2) > scratch->max_len))
+ return APR_EINVAL;
+
+ /* We need 0-terminated strings to operate on apr_table */
+ AP_DEBUG_ASSERT(nv->namelen < scratch->max_len);
+ memcpy(scratch->name, nv->name, nv->namelen);
+ scratch->name[nv->namelen] = 0;
+ AP_DEBUG_ASSERT(nv->valuelen < scratch->max_len);
+ memcpy(scratch->value, nv->value, nv->valuelen);
+ scratch->value[nv->valuelen] = 0;
+
+ *pwas_added = 1;
+ existing = apr_table_get(headers, scratch->name);
+ if (existing) {
+ if (!nv->valuelen) /* not adding a 0-length value to existing */
+ return APR_SUCCESS;
+ if ((strlen(existing) + 2 + nv->valuelen + nv->namelen + 2)
+ > scratch->max_len) {
+ /* "name: existing, value" is too long */
return APR_EINVAL;
}
+ apr_table_merge(headers, scratch->name, scratch->value);
+ }
+ else {
+ h2_util_camel_case_header(scratch->name, nv->namelen);
+ apr_table_set(headers, scratch->name, scratch->value);
}
- if (!existing) *pwas_added = 1;
- hvalue = apr_pstrndup(pool, (const char*)nv->value, nv->valuelen);
- apr_table_mergen(headers, hname, hvalue);
-
return APR_SUCCESS;
}
apr_status_t h2_req_add_header(apr_table_t *headers, apr_pool_t *pool,
const char *name, size_t nlen,
const char *value, size_t vlen,
- size_t max_field_len, int *pwas_added)
+ h2_hd_scratch *scratch, int *pwas_added)
{
nghttp2_nv nv;
@@ -1759,7 +1770,7 @@ apr_status_t h2_req_add_header(apr_table_t *headers, apr_pool_t *pool,
nv.namelen = nlen;
nv.value = (uint8_t*)value;
nv.valuelen = vlen;
- return req_add_header(headers, pool, &nv, max_field_len, pwas_added);
+ return req_add_header(headers, pool, &nv, scratch, pwas_added);
}
/*******************************************************************************
diff --git a/modules/http2/h2_util.h b/modules/http2/h2_util.h
index d2e6548ba87..c2cab4afa45 100644
--- a/modules/http2/h2_util.h
+++ b/modules/http2/h2_util.h
@@ -397,14 +397,21 @@ apr_status_t h2_req_create_ngheader(h2_ngheader **ph, apr_pool_t *p,
const struct h2_request *req);
#endif
+typedef struct h2_hd_scratch {
+ size_t max_len; /* header field size name + ': ' + value */
+ char *name; /* max_len+1 sized */
+ char *value; /* max_len+1 sized */
+
+} h2_hd_scratch;
+
/**
* Add a HTTP/2 header and return the table key if it really was added
* and not ignored.
*/
-apr_status_t h2_req_add_header(apr_table_t *headers, apr_pool_t *pool,
+apr_status_t h2_req_add_header(apr_table_t *headers, apr_pool_t *pool,
const char *name, size_t nlen,
const char *value, size_t vlen,
- size_t max_field_len, int *pwas_added);
+ h2_hd_scratch *scratch, int *pwas_added);
/*******************************************************************************
* apr brigade helpers
diff --git a/test/modules/http2/test_200_header_invalid.py b/test/modules/http2/test_200_header_invalid.py
index 6b73301c282..1687e3d9818 100644
--- a/test/modules/http2/test_200_header_invalid.py
+++ b/test/modules/http2/test_200_header_invalid.py
@@ -133,7 +133,7 @@ def test_h2_200_11(self, env):
assert 431 == r.response["status"]
# test header field count, LimitRequestFields (default 100)
- # see #201: several headers with same name are mered and count only once
+ # see #201: several headers with same name are merged and counted
def test_h2_200_12(self, env):
url = env.mkurl("https", "cgi", "/")
opt = []
@@ -143,7 +143,7 @@ def test_h2_200_12(self, env):
r = env.curl_get(url, options=opt)
assert r.response["status"] == 200
r = env.curl_get(url, options=(opt + ["-H", "y: 2"]))
- assert r.response["status"] == 200
+ assert r.response["status"] == 431
# test header field count, LimitRequestFields (default 100)
# different header names count each

View File

@@ -1,74 +0,0 @@
Index: httpd-2.4.58/modules/http/http_filters.c
===================================================================
--- httpd-2.4.58.orig/modules/http/http_filters.c
+++ httpd-2.4.58/modules/http/http_filters.c
@@ -1353,6 +1353,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_
*/
apr_table_clear(r->headers_out);
apr_table_clear(r->err_headers_out);
+ r->content_type = r->content_encoding = NULL;
+ r->content_languages = NULL;
+ r->clength = r->chunked = 0;
apr_brigade_cleanup(b);
/* Don't recall ap_die() if we come back here (from its own internal
@@ -1369,8 +1372,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_
APR_BRIGADE_INSERT_TAIL(b, e);
e = apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(b, e);
- r->content_type = r->content_encoding = NULL;
- r->content_languages = NULL;
ap_set_content_length(r, 0);
recursive_error = 1;
}
@@ -1397,6 +1398,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_
if (!apr_is_empty_table(r->err_headers_out)) {
r->headers_out = apr_table_overlay(r->pool, r->err_headers_out,
r->headers_out);
+ apr_table_clear(r->err_headers_out);
}
/*
@@ -1416,6 +1418,17 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_
fixup_vary(r);
}
+
+ /*
+ * Control cachability for non-cacheable responses if not already set by
+ * some other part of the server configuration.
+ */
+ if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) {
+ char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
+ ap_recent_rfc822_date(date, r->request_time);
+ apr_table_addn(r->headers_out, "Expires", date);
+ }
+
/*
* Now remove any ETag response header field if earlier processing
* says so (such as a 'FileETag None' directive).
@@ -1428,6 +1441,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_
basic_http_header_check(r, &protocol);
ap_set_keepalive(r);
+ /* 204/304 responses don't have content related headers */
if (AP_STATUS_IS_HEADER_ONLY(r->status)) {
apr_table_unset(r->headers_out, "Transfer-Encoding");
apr_table_unset(r->headers_out, "Content-Length");
@@ -1470,16 +1484,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_
apr_table_setn(r->headers_out, "Content-Language", field);
}
- /*
- * Control cachability for non-cacheable responses if not already set by
- * some other part of the server configuration.
- */
- if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) {
- char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
- ap_recent_rfc822_date(date, r->request_time);
- apr_table_addn(r->headers_out, "Expires", date);
- }
-
/* This is a hack, but I can't find anyway around it. The idea is that
* we don't want to send out 0 Content-Lengths if it is a head request.
* This happens when modules try to outsmart the server, and return

View File

@@ -1,191 +0,0 @@
Index: httpd-2.4.58/include/util_script.h
===================================================================
--- httpd-2.4.58.orig/include/util_script.h
+++ httpd-2.4.58/include/util_script.h
@@ -225,6 +225,8 @@ AP_DECLARE(int) ap_scan_script_header_er
*/
AP_DECLARE(void) ap_args_to_table(request_rec *r, apr_table_t **table);
+#define AP_TRUST_CGILIKE_CL_ENVVAR "ap_trust_cgilike_cl"
+
#ifdef __cplusplus
}
#endif
Index: httpd-2.4.58/modules/aaa/mod_authnz_fcgi.c
===================================================================
--- httpd-2.4.58.orig/modules/aaa/mod_authnz_fcgi.c
+++ httpd-2.4.58/modules/aaa/mod_authnz_fcgi.c
@@ -571,6 +571,14 @@ static apr_status_t handle_response(cons
"parsing -> %d/%d",
fn, status, r->status);
+ /* FCGI has its own body framing mechanism which we don't
+ * match against any provided Content-Length, so let the
+ * core determine C-L vs T-E based on what's actually sent.
+ */
+ if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR))
+ apr_table_unset(r->headers_out, "Content-Length");
+ apr_table_unset(r->headers_out, "Transfer-Encoding");
+
if (rspbuf) { /* caller wants to see response body,
* if any
*/
Index: httpd-2.4.58/modules/generators/mod_cgi.c
===================================================================
--- httpd-2.4.58.orig/modules/generators/mod_cgi.c
+++ httpd-2.4.58/modules/generators/mod_cgi.c
@@ -935,9 +935,18 @@ static int cgi_handler(request_rec *r)
char sbuf[MAX_STRING_LEN];
int ret;
- if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf,
- APLOG_MODULE_INDEX)))
- {
+ ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf,
+ APLOG_MODULE_INDEX);
+
+ /* xCGI has its own body framing mechanism which we don't
+ * match against any provided Content-Length, so let the
+ * core determine C-L vs T-E based on what's actually sent.
+ */
+ if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR))
+ apr_table_unset(r->headers_out, "Content-Length");
+ apr_table_unset(r->headers_out, "Transfer-Encoding");
+
+ if (ret != OK) {
ret = log_script(r, conf, ret, dbuf, sbuf, bb, script_err);
/*
Index: httpd-2.4.58/modules/generators/mod_cgid.c
===================================================================
--- httpd-2.4.58.orig/modules/generators/mod_cgid.c
+++ httpd-2.4.58/modules/generators/mod_cgid.c
@@ -1616,9 +1616,18 @@ static int cgid_handler(request_rec *r)
b = apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
- if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf,
- APLOG_MODULE_INDEX)))
- {
+ ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf,
+ APLOG_MODULE_INDEX);
+
+ /* xCGI has its own body framing mechanism which we don't
+ * match against any provided Content-Length, so let the
+ * core determine C-L vs T-E based on what's actually sent.
+ */
+ if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR))
+ apr_table_unset(r->headers_out, "Content-Length");
+ apr_table_unset(r->headers_out, "Transfer-Encoding");
+
+ if (ret != OK) {
ret = log_script(r, conf, ret, dbuf, sbuf, bb, NULL);
/*
Index: httpd-2.4.58/modules/proxy/ajp_header.c
===================================================================
--- httpd-2.4.58.orig/modules/proxy/ajp_header.c
+++ httpd-2.4.58/modules/proxy/ajp_header.c
@@ -17,6 +17,8 @@
#include "ajp_header.h"
#include "ajp.h"
+#include "util_script.h"
+
APLOG_USE_MODULE(proxy_ajp);
static const char *response_trans_headers[] = {
@@ -669,6 +671,14 @@ static apr_status_t ajp_unmarshal_respon
}
}
+ /* AJP has its own body framing mechanism which we don't
+ * match against any provided Content-Length, so let the
+ * core determine C-L vs T-E based on what's actually sent.
+ */
+ if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR))
+ apr_table_unset(r->headers_out, "Content-Length");
+ apr_table_unset(r->headers_out, "Transfer-Encoding");
+
return APR_SUCCESS;
}
Index: httpd-2.4.58/modules/proxy/mod_proxy_fcgi.c
===================================================================
--- httpd-2.4.58.orig/modules/proxy/mod_proxy_fcgi.c
+++ httpd-2.4.58/modules/proxy/mod_proxy_fcgi.c
@@ -779,6 +779,15 @@ recv_again:
status = ap_scan_script_header_err_brigade_ex(r, ob,
NULL, APLOG_MODULE_INDEX);
+
+ /* FCGI has its own body framing mechanism which we don't
+ * match against any provided Content-Length, so let the
+ * core determine C-L vs T-E based on what's actually sent.
+ */
+ if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR))
+ apr_table_unset(r->headers_out, "Content-Length");
+ apr_table_unset(r->headers_out, "Transfer-Encoding");
+
/* suck in all the rest */
if (status != OK) {
apr_bucket *tmp_b;
Index: httpd-2.4.58/modules/proxy/mod_proxy_scgi.c
===================================================================
--- httpd-2.4.58.orig/modules/proxy/mod_proxy_scgi.c
+++ httpd-2.4.58/modules/proxy/mod_proxy_scgi.c
@@ -390,6 +390,14 @@ static int pass_response(request_rec *r,
return status;
}
+ /* SCGI has its own body framing mechanism which we don't
+ * match against any provided Content-Length, so let the
+ * core determine C-L vs T-E based on what's actually sent.
+ */
+ if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR))
+ apr_table_unset(r->headers_out, "Content-Length");
+ apr_table_unset(r->headers_out, "Transfer-Encoding");
+
conf = ap_get_module_config(r->per_dir_config, &proxy_scgi_module);
if (conf->sendfile && conf->sendfile != scgi_sendfile_off) {
short err = 1;
Index: httpd-2.4.58/modules/proxy/mod_proxy_uwsgi.c
===================================================================
--- httpd-2.4.58.orig/modules/proxy/mod_proxy_uwsgi.c
+++ httpd-2.4.58/modules/proxy/mod_proxy_uwsgi.c
@@ -404,6 +404,12 @@ static int uwsgi_response(request_rec *r
return HTTP_BAD_GATEWAY;
}
+ /* T-E wins over C-L */
+ if (apr_table_get(r->headers_out, "Transfer-Encoding")) {
+ apr_table_unset(r->headers_out, "Content-Length");
+ backend->close = 1;
+ }
+
if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
ap_set_content_type(r, apr_pstrdup(r->pool, buf));
}
Index: httpd-2.4.58/modules/http/http_filters.c
===================================================================
--- httpd-2.4.58.orig/modules/http/http_filters.c
+++ httpd-2.4.58/modules/http/http_filters.c
@@ -778,6 +778,18 @@ static APR_INLINE int check_headers(requ
struct check_header_ctx ctx;
core_server_config *conf =
ap_get_core_module_config(r->server->module_config);
+ const char *val;
+
+ if ((val = apr_table_get(r->headers_out, "Transfer-Encoding"))) {
+ if (apr_table_get(r->headers_out, "Content-Length")) {
+ apr_table_unset(r->headers_out, "Content-Length");
+ r->connection->keepalive = AP_CONN_CLOSE;
+ }
+ if (!ap_is_chunked(r->pool, val)) {
+ r->connection->keepalive = AP_CONN_CLOSE;
+ return 0;
+ }
+ }
ctx.r = r;
ctx.strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);

View File

@@ -1,45 +0,0 @@
Index: modules/http2/h2_session.c
===================================================================
--- a/modules/http2/h2_session.c (revision 1916778)
+++ b/modules/http2/h2_session.c (revision 1916779)
@@ -319,9 +319,13 @@
status = h2_stream_add_header(stream, (const char *)name, namelen,
(const char *)value, valuelen);
- if (status != APR_SUCCESS
- && (!stream->rtmp
- || stream->rtmp->http_status == H2_HTTP_STATUS_UNSET)) {
+ if (status != APR_SUCCESS &&
+ (!stream->rtmp ||
+ stream->rtmp->http_status == H2_HTTP_STATUS_UNSET ||
+ /* We accept a certain amount of failures in order to reply
+ * with an informative HTTP error response like 413. But if the
+ * client is too wrong, we fail the request a RESET of the stream */
+ stream->request_headers_failed > 100)) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
return 0;
Index: modules/http2/h2_stream.c
===================================================================
--- a/modules/http2/h2_stream.c (revision 1916778)
+++ b/modules/http2/h2_stream.c (revision 1916779)
@@ -813,6 +813,7 @@
cleanup:
if (error) {
+ ++stream->request_headers_failed;
set_error_response(stream, error);
return APR_EINVAL;
}
Index: modules/http2/h2_stream.h
===================================================================
--- a/modules/http2/h2_stream.h (revision 1916778)
+++ b/modules/http2/h2_stream.h (revision 1916779)
@@ -91,6 +91,7 @@
struct h2_request *rtmp; /* request being assembled */
apr_table_t *trailers_in; /* optional, incoming trailers */
int request_headers_added; /* number of request headers added */
+ int request_headers_failed; /* number of request headers failed to add */
#if AP_HAS_RESPONSE_BUCKETS
ap_bucket_response *response; /* the final, non-interim response or NULL */

View File

@@ -1,39 +0,0 @@
From b10cb2d69184843832d501a615abe3e8e5e256dc Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Mon, 24 Jun 2024 17:52:31 +0000
Subject: [PATCH] Merge r1918550 from trunk:
mod_proxy: escape for non-proxypass configuration
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1918559 13f79535-47bb-0310-9956-ffa450edef68
---
modules/proxy/mod_proxy.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
index c9cef7c44f5..17e39c95b8f 100644
--- a/modules/proxy/mod_proxy.c
+++ b/modules/proxy/mod_proxy.c
@@ -1314,15 +1314,18 @@ static int proxy_handler(request_rec *r)
}
if (!r->proxyreq) {
+ rc = DECLINED;
/* 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);
+ /* Still need to fixup/canonicalize r->filename */
+ rc = proxy_fixup(r);
}
- else {
- return DECLINED;
+ if (rc != OK) {
+ return rc;
}
} else if (strncmp(r->filename, "proxy:", 6) != 0) {
return DECLINED;

View File

@@ -1,208 +0,0 @@
From 6b8e043ce4f27114e6ae1b8176b629b7cb3fbbce Mon Sep 17 00:00:00 2001
From: Yann Ylavic <ylavic@apache.org>
Date: Wed, 26 Jun 2024 14:51:32 +0000
Subject: [PATCH] mod_proxy: Fixup UDS filename for mod_proxy called through
r->handler.
* modules/proxy/proxy_util.c:
Export ap_proxy_fixup_uds_filename() from fix_uds_filename.
Call it from ap_proxy_pre_request() even for rewritten balancer workers.
* modules/proxy/mod_proxy.h:
Declare ap_proxy_fixup_uds_filename()
* modules/proxy/mod_proxy.c:
Fixup UDS filename from r->handler in proxy_handler().
* include/ap_mmn.h:
Bump MMN minor for ap_proxy_fixup_uds_filename()
mod_proxy: follow up to r1918626: Simplify ap_proxy_fixup_uds_filename() and callers.
Merges r1918626, r1918647 from trunk
GH: closes #457
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1918666 13f79535-47bb-0310-9956-ffa450edef68
---
include/ap_mmn.h | 3 ++-
modules/proxy/mod_proxy.c | 33 ++++++++++++++++++------------
modules/proxy/mod_proxy.h | 8 ++++++++
modules/proxy/proxy_util.c | 41 ++++++++++++++++++++++----------------
4 files changed, 54 insertions(+), 31 deletions(-)
Index: httpd-2.4.58/modules/proxy/mod_proxy.c
===================================================================
--- httpd-2.4.58.orig/modules/proxy/mod_proxy.c
+++ httpd-2.4.58/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,22 +1296,28 @@ static int proxy_handler(request_rec *r)
return DECLINED;
}
- if (!r->proxyreq) {
- rc = DECLINED;
- /* 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);
- /* Still need to fixup/canonicalize r->filename */
+ /* 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);
}
if (rc != OK) {
- return rc;
+ 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 */
Index: httpd-2.4.58/modules/proxy/mod_proxy.h
===================================================================
--- httpd-2.4.58.orig/modules/proxy/mod_proxy.h
+++ httpd-2.4.58/modules/proxy/mod_proxy.h
@@ -993,6 +993,14 @@ PROXY_DECLARE(proxy_balancer_shared *) a
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
Index: httpd-2.4.58/modules/proxy/proxy_util.c
===================================================================
--- httpd-2.4.58.orig/modules/proxy/proxy_util.c
+++ httpd-2.4.58/modules/proxy/proxy_util.c
@@ -2316,7 +2316,7 @@ static int ap_proxy_retry_worker(const c
* 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;
@@ -2324,7 +2324,6 @@ static int fix_uds_filename(request_rec
!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;
@@ -2339,20 +2338,20 @@ static int fix_uds_filename(request_rec
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,
@@ -2371,9 +2370,6 @@ PROXY_DECLARE(int) ap_proxy_pre_request(
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) {
@@ -2403,9 +2399,6 @@ PROXY_DECLARE(int) ap_proxy_pre_request(
* 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;
- }
}
}
}
@@ -2415,6 +2408,20 @@ PROXY_DECLARE(int) ap_proxy_pre_request(
"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;
}

View File

@@ -1,51 +0,0 @@
From cc00cf6b4e37370897daddc307bf1deecf8fedfa Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Tue, 25 Jun 2024 20:20:05 +0000
Subject: [PATCH] Merge r1918623 from trunk:
fix comparison of local path on Windows
Submitted By: Yann Ylavic
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1918625 13f79535-47bb-0310-9956-ffa450edef68
---
modules/mappers/mod_rewrite.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
index 46ea16c8c64..e0390768267 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -653,6 +653,19 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs)
return 0;
}
+static int is_absolute_path(const char *path)
+{
+#ifndef WIN32
+ return (path[0] == '/');
+#else
+#define IS_SLASH(c) ((c) == '/' || (c) == '\\')
+ /* "//", "\\", "x:/" and "x:\" are absolute paths on Windows */
+ return ((IS_SLASH(path[0]) && path[1] == path[0])
+ || (apr_isalpha(path[0]) && path[1] == ':' && IS_SLASH(path[2])));
+#undef IS_SLASH
+#endif
+}
+
static const char c2x_table[] = "0123456789abcdef";
static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
@@ -4351,7 +4364,9 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p,
* (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 (!is_proxyreq
+ && !is_absolute_path(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));

View File

@@ -1,187 +0,0 @@
From 4326d6b9041a3bcb9b529f9163d0761c2d760700 Mon Sep 17 00:00:00 2001
From: Yann Ylavic <ylavic@apache.org>
Date: Wed, 26 Jun 2024 14:56:47 +0000
Subject: [PATCH] factor out IS_SLASH, perdir fix
in per-dir, the filename will be internally redirected, so / is OK too.
don't add / to / in the non-perdir
match AP_IS_SLASH macro
followup to 1918651
Merges r1918651, r1918652, r1918663 from trunk
Reviewed by: covener, ylavic, rpluem
GH: close #458
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1918668 13f79535-47bb-0310-9956-ffa450edef68
---
include/ap_mmn.h | 3 ++-
include/httpd.h | 11 +++++++++++
modules/mappers/mod_rewrite.c | 11 ++++-------
server/util.c | 31 ++++++++++---------------------
4 files changed, 27 insertions(+), 29 deletions(-)
Index: httpd-2.4.58/include/httpd.h
===================================================================
--- httpd-2.4.58.orig/include/httpd.h
+++ httpd-2.4.58/include/httpd.h
@@ -2663,6 +2663,17 @@ AP_DECLARE(const char *)ap_dir_fnmatch(a
*/
AP_DECLARE(int) ap_is_chunked(apr_pool_t *p, const char *line);
+/* Win32/NetWare/OS2 need to check for both forward and back slashes
+ * in ap_normalize_path() and ap_escape_url().
+ */
+#ifdef CASE_BLIND_FILESYSTEM
+#define AP_IS_SLASH(s) ((s == '/') || (s == '\\'))
+#define AP_SLASHES "/\\"
+#else
+#define AP_IS_SLASH(s) (s == '/')
+#define AP_SLASHES "/"
+#endif
+
#ifdef __cplusplus
}
#endif
Index: httpd-2.4.58/modules/mappers/mod_rewrite.c
===================================================================
--- httpd-2.4.58.orig/modules/mappers/mod_rewrite.c
+++ httpd-2.4.58/modules/mappers/mod_rewrite.c
@@ -655,14 +655,11 @@ static unsigned is_absolute_uri(char *ur
static int is_absolute_path(const char *path)
{
-#ifndef WIN32
+#ifndef CASE_BLIND_FILESYSTEM
return (path[0] == '/');
#else
-#define IS_SLASH(c) ((c) == '/' || (c) == '\\')
- /* "//", "\\", "x:/" and "x:\" are absolute paths on Windows */
- return ((IS_SLASH(path[0]) && path[1] == path[0])
- || (apr_isalpha(path[0]) && path[1] == ':' && IS_SLASH(path[2])));
-#undef IS_SLASH
+ return ((AP_IS_SLASH(path[0]) && path[1] == path[0])
+ || (apr_isalpha(path[0]) && path[1] == ':' && AP_IS_SLASH(path[2])));
#endif
}
@@ -4366,11 +4363,11 @@ static rule_return_type apply_rewrite_ru
*/
if (!is_proxyreq
&& !is_absolute_path(newuri)
+ && !AP_IS_SLASH(*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))) {
Index: httpd-2.4.58/server/util.c
===================================================================
--- httpd-2.4.58.orig/server/util.c
+++ httpd-2.4.58/server/util.c
@@ -75,17 +75,6 @@
*/
#include "test_char.h"
-/* Win32/NetWare/OS2 need to check for both forward and back slashes
- * in ap_normalize_path() and ap_escape_url().
- */
-#ifdef CASE_BLIND_FILESYSTEM
-#define IS_SLASH(s) ((s == '/') || (s == '\\'))
-#define SLASHES "/\\"
-#else
-#define IS_SLASH(s) (s == '/')
-#define SLASHES "/"
-#endif
-
/* we know core's module_index is 0 */
#undef APLOG_MODULE_INDEX
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
@@ -492,7 +481,7 @@ AP_DECLARE(apr_status_t) ap_pregsub_ex(a
/* Forward declare */
static char x2c(const char *what);
-#define IS_SLASH_OR_NUL(s) (s == '\0' || IS_SLASH(s))
+#define IS_SLASH_OR_NUL(s) (s == '\0' || AP_IS_SLASH(s))
/*
* Inspired by mod_jk's jk_servlet_normalize().
@@ -504,7 +493,7 @@ AP_DECLARE(int) ap_normalize_path(char *
int decode_unreserved = (flags & AP_NORMALIZE_DECODE_UNRESERVED) != 0;
int merge_slashes = (flags & AP_NORMALIZE_MERGE_SLASHES) != 0;
- if (!IS_SLASH(path[0])) {
+ if (!AP_IS_SLASH(path[0])) {
/* Besides "OPTIONS *", a request-target should start with '/'
* per RFC 7230 section 5.3, so anything else is invalid.
*/
@@ -545,12 +534,12 @@ AP_DECLARE(int) ap_normalize_path(char *
}
}
- if (w == 0 || IS_SLASH(path[w - 1])) {
+ if (w == 0 || AP_IS_SLASH(path[w - 1])) {
/* Collapse ///// sequences to / */
- if (merge_slashes && IS_SLASH(path[l])) {
+ if (merge_slashes && AP_IS_SLASH(path[l])) {
do {
l++;
- } while (IS_SLASH(path[l]));
+ } while (AP_IS_SLASH(path[l]));
continue;
}
@@ -579,7 +568,7 @@ AP_DECLARE(int) ap_normalize_path(char *
if (w > 1) {
do {
w--;
- } while (w && !IS_SLASH(path[w - 1]));
+ } while (w && !AP_IS_SLASH(path[w - 1]));
}
else {
/* Already at root, ignore and return a failure
@@ -1915,7 +1904,7 @@ static int unescape_url(char *url, const
char decoded;
decoded = x2c(y + 1);
if ((decoded == '\0')
- || (forbid_slashes && IS_SLASH(decoded))
+ || (forbid_slashes && AP_IS_SLASH(decoded))
|| (forbid && ap_strchr_c(forbid, decoded))) {
badpath = 1;
*x = decoded;
@@ -1923,7 +1912,7 @@ static int unescape_url(char *url, const
}
else if ((keep_unreserved && TEST_CHAR(decoded,
T_URI_UNRESERVED))
- || (keep_slashes && IS_SLASH(decoded))
+ || (keep_slashes && AP_IS_SLASH(decoded))
|| (reserved && ap_strchr_c(reserved, decoded))) {
*x++ = *y++;
*x++ = *y++;
@@ -1950,7 +1939,7 @@ static int unescape_url(char *url, const
AP_DECLARE(int) ap_unescape_url(char *url)
{
/* Traditional */
- return unescape_url(url, SLASHES, NULL, 0);
+ return unescape_url(url, AP_SLASHES, NULL, 0);
}
AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
{
@@ -1960,7 +1949,7 @@ AP_DECLARE(int) ap_unescape_url_keep2f(c
return unescape_url(url, NULL, NULL, 0);
} else {
/* reserve (do not decode) encoded slashes */
- return unescape_url(url, NULL, SLASHES, 0);
+ return unescape_url(url, NULL, AP_SLASHES, 0);
}
}
AP_DECLARE(int) ap_unescape_url_ex(char *url, unsigned int flags)

View File

@@ -1,17 +0,0 @@
Index: httpd-2.4.58/modules/mappers/mod_rewrite.c
===================================================================
--- httpd-2.4.58.orig/modules/mappers/mod_rewrite.c
+++ httpd-2.4.58/modules/mappers/mod_rewrite.c
@@ -4537,6 +4560,12 @@ static int apply_rewrite_list(request_re
return ACTION_STATUS_SET;
}
+
+ /* 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)
*/

View File

@@ -1,23 +0,0 @@
Index: httpd-2.4.58/docs/manual/mod/mod_rewrite.html.en
===================================================================
--- httpd-2.4.58.orig/docs/manual/mod/mod_rewrite.html.en
+++ httpd-2.4.58/docs/manual/mod/mod_rewrite.html.en
@@ -1451,6 +1451,18 @@ cannot use <code>$N</code> in the substi
<td>Force the <a class="glossarylink" href="../glossary.html#mime-type" title="see glossary">MIME-type</a> of the target file
to be the specified type. <em><a href="../rewrite/flags.html#flag_t">details ...</a></em></td>
</tr>
+ <tr>
+ <td>UnsafeAllow3F</td>
+ <td>Allows substitutions from URL's that may be unsafe.
+ <em><a href="../rewrite/flags.html#flag_unsafe_allow_3f">details ...</a></em>
+ </td>
+ </tr>
+ <tr>
+ <td>UnsafePrefixStat</td>
+ <td>Allows potentially unsafe substitutions from a leading variable or backreference to a filesystem path.</td>
+ <em><a href="../rewrite/flags.html#flag_unsafe_prefix_stat">details ...</a></em>
+ </td>
+ </tr>
</table>
<div class="note"><h3>Home directory expansion</h3>

View File

@@ -1,31 +0,0 @@
Index: httpd-2.4.58/docs/manual/rewrite/flags.html.en
===================================================================
--- httpd-2.4.58.orig/docs/manual/rewrite/flags.html.en
+++ httpd-2.4.58/docs/manual/rewrite/flags.html.en
@@ -820,8 +820,25 @@ otherwise the MIME-type set with this fl
re-processing (including subsequent rounds of mod_rewrite processing).
The <code>L</code> flag can be useful in this context to end the
<em>current</em> round of mod_rewrite processing.</p>
+</div>
-</div></div>
+<div class="section">
+ <h2><a name="flag_unsafe_allow_3f" id="flag_unsafe_allow_3f">UnsafeAllow3F</a></h2>
+ <p> 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.</p>
+</div>
+<div class="section" id="flag_unsafe_prefix_status">
+ <h2><a name="flag_unsafe_prefix_status" id="flag_unsafe_prefix_status">UnsafePrefixStat</a></h2>
+ <p> 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.</p>
+ </div>
+</div>
<div class="bottomlang">
<p><span>Available Languages: </span><a href="../en/rewrite/flags.html" title="English">&nbsp;en&nbsp;</a> |
<a href="../fr/rewrite/flags.html" hreflang="fr" rel="alternate" title="Français">&nbsp;fr&nbsp;</a></p>

View File

@@ -1,383 +0,0 @@
Index: httpd-2.4.58/modules/mappers/mod_rewrite.c
===================================================================
--- httpd-2.4.58.orig/modules/mappers/mod_rewrite.c
+++ httpd-2.4.58/modules/mappers/mod_rewrite.c
@@ -177,6 +177,8 @@ static const char* really_last_key = "re
#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 = "re
#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 = "re
#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_re
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_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(cm
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_setfl
++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;
@@ -4138,7 +4195,8 @@ static APR_INLINE void force_type_handle
/*
* 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;
@@ -4189,7 +4247,7 @@ static int apply_rewrite_rule(rewriterul
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
@@ -4240,7 +4298,7 @@ static int apply_rewrite_rule(rewriterul
}
}
else if (!rc) {
- return 0;
+ return RULE_RC_NOMATCH;
}
/* If some HTTP header was involved in the condition, remember it
@@ -4260,6 +4318,15 @@ static int apply_rewrite_rule(rewriterul
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=<cookie>] */
@@ -4277,7 +4344,7 @@ static int apply_rewrite_rule(rewriterul
r->status = p->forced_responsecode;
}
- return 2;
+ return RULE_RC_NOSUB;
}
/* Add the previously stripped per-directory location prefix, unless
@@ -4343,7 +4410,7 @@ static int apply_rewrite_rule(rewriterul
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
@@ -4358,7 +4425,7 @@ static int apply_rewrite_rule(rewriterul
r->filename));
r->status = p->forced_responsecode;
- return 1;
+ return RULE_RC_MATCH;
}
/* Special Rewriting Feature: Self-Reduction
@@ -4380,7 +4447,7 @@ static int apply_rewrite_rule(rewriterul
"with %s", p->forced_responsecode, r->filename));
r->status = p->forced_responsecode;
- return 1;
+ return RULE_RC_MATCH;
}
/* Finally remember the forced mime-type */
@@ -4389,7 +4456,7 @@ static int apply_rewrite_rule(rewriterul
/* Puuhhhhhhhh... WHAT COMPLICATED STUFF ;_)
* But now we're done for this particular rule.
*/
- return 1;
+ return RULE_RC_MATCH;
}
/*
@@ -4397,13 +4464,13 @@ static int apply_rewrite_rule(rewriterul
* 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;
@@ -4411,6 +4478,7 @@ static int apply_rewrite_list(request_re
ctx = apr_palloc(r->pool, sizeof(*ctx));
ctx->perdir = perdir;
ctx->r = r;
+ *lastsub = NULL;
/*
* Iterate over all existing rules
@@ -4438,7 +4506,12 @@ static int apply_rewrite_list(request_re
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 ) {
@@ -4458,6 +4531,12 @@ static int apply_rewrite_list(request_re
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)
*/
@@ -4468,7 +4547,7 @@ static int apply_rewrite_list(request_re
/*
* 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);
}
@@ -4657,6 +4736,7 @@ static int hook_uri2file(request_rec *r)
int rulestatus;
void *skipdata;
const char *oargs;
+ rewriterule_entry *lastsub = NULL;
/*
* retrieve the config structures
@@ -4768,7 +4848,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));
}
@@ -4806,6 +4886,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 */
@@ -4925,23 +5008,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!
*/
@@ -4950,7 +5039,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;
@@ -4995,6 +5086,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);
@@ -5079,7 +5171,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;
@@ -5108,6 +5200,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 */

View File

@@ -1,20 +0,0 @@
--- a/include/http_protocol.h 2024/06/24 17:52:31 1918559
+++ b/include/http_protocol.h 2024/06/24 17:54:34 1918560
@@ -439,6 +439,17 @@
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
*/

View File

@@ -1,11 +0,0 @@
--- a/server/config.c 2024/06/24 17:52:31 1918559
+++ b/server/config.c 2024/06/24 17:54:34 1918560
@@ -418,7 +418,7 @@
}
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,

View File

@@ -1,11 +0,0 @@
--- a/server/core.c 2024/06/24 17:52:31 1918559
+++ b/server/core.c 2024/06/24 17:54:34 1918560
@@ -4835,7 +4835,7 @@
/* 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

@@ -1,23 +0,0 @@
--- a/include/httpd.h 2024/06/24 17:52:31 1918559
+++ b/include/httpd.h 2024/06/24 17:54:34 1918560
@@ -667,6 +667,7 @@
*
*/
#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 @@
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

View File

@@ -1,17 +0,0 @@
--- a/modules/http/http_protocol.c 2024/06/24 17:52:31 1918559
+++ b/modules/http/http_protocol.c 2024/06/24 17:54:34 1918560
@@ -1097,8 +1097,14 @@
}
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)
{

View File

@@ -1,70 +0,0 @@
--- a/modules/http/mod_mime.c 2024/06/24 17:52:31 1918559
+++ b/modules/http/mod_mime.c 2024/06/24 17:54:34 1918560
@@ -759,7 +759,7 @@
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 @@
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 @@
/* 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 @@
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));
}
}
}

View File

@@ -1,15 +0,0 @@
--- a/modules/mappers/mod_actions.c 2024/06/24 17:52:31 1918559
+++ b/modules/mappers/mod_actions.c 2024/06/24 17:54:34 1918560
@@ -182,8 +182,10 @@
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);

View File

@@ -1,29 +0,0 @@
--- a/modules/mappers/mod_negotiation.c 2024/06/24 17:52:31 1918559
+++ b/modules/mappers/mod_negotiation.c 2024/06/24 17:54:34 1918560
@@ -1167,7 +1167,7 @@
* 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 @@
/* 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);
}
}

View File

@@ -1,11 +0,0 @@
--- a/modules/mappers/mod_rewrite.c 2024/06/24 17:52:31 1918559
+++ b/modules/mappers/mod_rewrite.c 2024/06/24 17:54:34 1918560
@@ -5333,7 +5333,7 @@
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 */

View File

@@ -1,28 +0,0 @@
--- a/modules/metadata/mod_headers.c 2024/06/24 17:52:31 1918559
+++ b/modules/metadata/mod_headers.c 2024/06/24 17:54:34 1918560
@@ -783,14 +783,14 @@
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 @@
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;

View File

@@ -1,20 +0,0 @@
--- a/modules/metadata/mod_mime_magic.c 2024/06/24 17:52:31 1918559
+++ b/modules/metadata/mod_mime_magic.c 2024/06/24 17:54:34 1918560
@@ -788,7 +788,7 @@
/* 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 @@
/* 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",

View File

@@ -1,27 +0,0 @@
--- a/modules/proxy/proxy_util.c 2024/06/25 17:29:06 1918606
+++ b/modules/proxy/proxy_util.c 2024/06/25 17:29:32 1918607
@@ -3113,6 +3113,13 @@
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);
}
@@ -4496,6 +4503,10 @@
/* 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, "]:",

View File

@@ -1,54 +0,0 @@
--- a/modules/mappers/mod_rewrite.c 2024/06/25 15:22:28 1918599
+++ b/modules/mappers/mod_rewrite.c 2024/06/25 15:28:00 1918600
@@ -4347,6 +4347,32 @@
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;
@@ -4356,18 +4382,6 @@
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

View File

@@ -1,266 +0,0 @@
Index: httpd-2.4.58/modules/cluster/mod_heartmonitor.c
===================================================================
--- httpd-2.4.58.orig/modules/cluster/mod_heartmonitor.c
+++ httpd-2.4.58/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);
Index: httpd-2.4.58/modules/dav/main/mod_dav.c
===================================================================
--- httpd-2.4.58.orig/modules/dav/main/mod_dav.c
+++ httpd-2.4.58/modules/dav/main/mod_dav.c
@@ -355,7 +355,7 @@ static int dav_error_response(request_re
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,
@@ -386,7 +386,7 @@ static int dav_error_response_tag(reques
{
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);
@@ -544,7 +544,7 @@ DAV_DECLARE(void) dav_begin_multistatus(
{
/* 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
@@ -2016,7 +2016,7 @@ static int dav_method_options(request_re
/* 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
@@ -3328,7 +3328,7 @@ static int dav_method_lock(request_rec *
(*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)
Index: httpd-2.4.58/modules/examples/mod_example_hooks.c
===================================================================
--- httpd-2.4.58.orig/modules/examples/mod_example_hooks.c
+++ httpd-2.4.58/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.
Index: httpd-2.4.58/modules/filters/mod_data.c
===================================================================
--- httpd-2.4.58.orig/modules/filters/mod_data.c
+++ httpd-2.4.58/modules/filters/mod_data.c
@@ -117,7 +117,7 @@ static apr_status_t data_out_filter(ap_f
}
}
- ap_set_content_type(r, "text/plain");
+ ap_set_content_type_ex(r, "text/plain", 1);
}
Index: httpd-2.4.58/modules/filters/mod_include.c
===================================================================
--- httpd-2.4.58.orig/modules/filters/mod_include.c
+++ httpd-2.4.58/modules/filters/mod_include.c
@@ -3972,7 +3972,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";
}
Index: httpd-2.4.58/modules/filters/mod_proxy_html.c
===================================================================
--- httpd-2.4.58.orig/modules/filters/mod_proxy_html.c
+++ httpd-2.4.58/modules/filters/mod_proxy_html.c
@@ -952,7 +952,7 @@ static apr_status_t proxy_html_filter(ap
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
@@ -968,7 +968,7 @@ static apr_status_t proxy_html_filter(ap
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);
Index: httpd-2.4.58/modules/generators/mod_cgi.c
===================================================================
--- httpd-2.4.58.orig/modules/generators/mod_cgi.c
+++ httpd-2.4.58/modules/generators/mod_cgi.c
@@ -1085,7 +1085,7 @@ static apr_status_t include_cgi(include_
/* 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);
Index: httpd-2.4.58/modules/generators/mod_cgid.c
===================================================================
--- httpd-2.4.58.orig/modules/generators/mod_cgid.c
+++ httpd-2.4.58/modules/generators/mod_cgid.c
@@ -1765,7 +1765,7 @@ static apr_status_t include_cgi(include_
/* 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);
Index: httpd-2.4.58/modules/generators/mod_info.c
===================================================================
--- httpd-2.4.58.orig/modules/generators/mod_info.c
+++ httpd-2.4.58/modules/generators/mod_info.c
@@ -784,7 +784,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"
Index: httpd-2.4.58/modules/generators/mod_status.c
===================================================================
--- httpd-2.4.58.orig/modules/generators/mod_status.c
+++ httpd-2.4.58/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;
}
Index: httpd-2.4.58/modules/http/http_filters.c
===================================================================
--- httpd-2.4.58.orig/modules/http/http_filters.c
+++ httpd-2.4.58/modules/http/http_filters.c
@@ -1261,7 +1261,7 @@ AP_DECLARE_NONSTD(int) ap_send_http_trac
}
}
- 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 */
Index: httpd-2.4.58/modules/http/http_protocol.c
===================================================================
--- httpd-2.4.58.orig/modules/http/http_protocol.c
+++ httpd-2.4.58/modules/http/http_protocol.c
@@ -1443,10 +1443,10 @@ AP_DECLARE(void) ap_send_error_response(
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)
Index: httpd-2.4.58/modules/ldap/util_ldap.c
===================================================================
--- httpd-2.4.58.orig/modules/ldap/util_ldap.c
+++ httpd-2.4.58/modules/ldap/util_ldap.c
@@ -171,7 +171,7 @@ static int util_ldap_handler(request_rec
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;
Index: httpd-2.4.58/modules/mappers/mod_imagemap.c
===================================================================
--- httpd-2.4.58.orig/modules/mappers/mod_imagemap.c
+++ httpd-2.4.58/modules/mappers/mod_imagemap.c
@@ -475,7 +475,7 @@ static int imap_reply(request_rec *r, co
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),
Index: httpd-2.4.58/modules/http/http_request.c
===================================================================
--- httpd-2.4.58.orig/modules/http/http_request.c
+++ httpd-2.4.58/modules/http/http_request.c
@@ -708,7 +708,7 @@ AP_DECLARE(void) ap_internal_fast_redire
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(r));
r->content_encoding = rr->content_encoding;
r->content_languages = rr->content_languages;
r->per_dir_config = rr->per_dir_config;
Index: httpd-2.4.58/modules/proxy/mod_proxy_balancer.c
===================================================================
--- httpd-2.4.58.orig/modules/proxy/mod_proxy_balancer.c
+++ httpd-2.4.58/modules/proxy/mod_proxy_balancer.c
@@ -1471,7 +1471,7 @@ static void balancer_display_page(reques
if (usexml) {
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

@@ -1,29 +0,0 @@
From a7d24b4ea9a6ea35878fd33075365328caafcf91 Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Mon, 15 Jul 2024 12:08:30 +0000
Subject: [PATCH] Merge r1919247 from trunk:
copy the trusted flag from the subrequest
Submitted By: covener
Reviewed By: covener, ylavic, gbechis
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919249 13f79535-47bb-0310-9956-ffa450edef68
---
modules/http/http_request.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/http/http_request.c b/modules/http/http_request.c
index 71ecc2bbab1..7e9477be1f1 100644
--- a/modules/http/http_request.c
+++ b/modules/http/http_request.c
@@ -708,7 +708,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_ex(r, rr->content_type, AP_REQUEST_IS_TRUSTED_CT(r));
+ 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;

View File

@@ -18,6 +18,6 @@ tdir=$(mktemp -d $tmpprefix); test $? = 0 || { echo >&2 Could not create tmpdir.
cut -f 1 -d '|' $F > $tdir/fc-all.$$ cut -f 1 -d '|' $F > $tdir/fc-all.$$
grep ^+ < $tdir/fc-all.$$ | cut -c2- | sort > $tdir/fc-in.$$ grep ^+ < $tdir/fc-all.$$ | cut -c2- | sort > $tdir/fc-in.$$
grep -- ^- < $tdir/fc-all.$$ | cut -c2- | sort > $tdir/fc-out.$$ grep -- ^- < $tdir/fc-all.$$ | cut -c2- | sort > $tdir/fc-out.$$
join -v 1 $tdir/fc-in.$$ $tdir/fc-out.$$ | xargs -ixx egrep "^\\+xx" $F join -v 1 $tdir/fc-in.$$ $tdir/fc-out.$$ | xargs -ixx grep -E "^\\+xx" $F
rm $tdir/fc-all.$$ $tdir/fc-in.$$ $tdir/fc-out.$$ rm $tdir/fc-all.$$ $tdir/fc-in.$$ $tdir/fc-out.$$
rmdir $tdir rmdir $tdir

View File

@@ -1,36 +0,0 @@
Index: httpd-2.4.58/modules/generators/mod_cgid.c
===================================================================
--- httpd-2.4.58.orig/modules/generators/mod_cgid.c
+++ httpd-2.4.58/modules/generators/mod_cgid.c
@@ -1625,7 +1625,12 @@ static int cgid_handler(request_rec *r)
*/
if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR))
apr_table_unset(r->headers_out, "Content-Length");
- apr_table_unset(r->headers_out, "Transfer-Encoding");
+
+ if (apr_table_get(r->headers_out, "Transfer-Encoding") != NULL) {
+ apr_brigade_cleanup(bb);
+ return log_scripterror(r, conf, HTTP_BAD_GATEWAY, 0, APLOGNO(10501)
+ "script sent Transfer-Encoding");
+ }
if (ret != OK) {
ret = log_script(r, conf, ret, dbuf, sbuf, bb, NULL);
Index: httpd-2.4.58/modules/generators/mod_cgi.c
===================================================================
--- httpd-2.4.58.orig/modules/generators/mod_cgi.c
+++ httpd-2.4.58/modules/generators/mod_cgi.c
@@ -944,7 +944,12 @@ static int cgi_handler(request_rec *r)
*/
if (!apr_table_get(r->subprocess_env, AP_TRUST_CGILIKE_CL_ENVVAR))
apr_table_unset(r->headers_out, "Content-Length");
- apr_table_unset(r->headers_out, "Transfer-Encoding");
+
+ if (apr_table_get(r->headers_out, "Transfer-Encoding") != NULL) {
+ apr_brigade_cleanup(bb);
+ return log_scripterror(r, conf, HTTP_BAD_GATEWAY, 0, APLOGNO(10501),
+ "script sent Transfer-Encoding");
+ }
if (ret != OK) {
ret = log_script(r, conf, ret, dbuf, sbuf, bb, script_err);

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
# #
# Copyright (c) 1996, 1997, 1998 S.u.S.E. GmbH # Copyright (c) 1996, 1997, 1998 S.u.S.E. GmbH
# Copyright (c) 1998, 1999, 2000, 2001 SuSE GmbH # Copyright (c) 1998, 1999, 2000, 2001 SuSE GmbH

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
# #
# spec file # spec file for package apache2
# #
# Copyright (c) 2023 SUSE LLC # Copyright (c) 2025 SUSE LLC
# #
# All modifications and additions to the file contributed by third parties # All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
%global upstream_name httpd %global upstream_name httpd
%global testsuite_name %{upstream_name}-framework %global testsuite_name %{upstream_name}-framework
%global tversion svn1901574 %global tversion svn1921782
%global flavor @BUILD_FLAVOR@%{nil} %global flavor @BUILD_FLAVOR@%{nil}
%define mpm %{nil} %define mpm %{nil}
%if "%{flavor}" == "prefork" || "%{flavor}" == "test_prefork" %if "%{flavor}" == "prefork" || "%{flavor}" == "test_prefork"
@@ -107,7 +107,7 @@
%define build_http2 1 %define build_http2 1
Name: apache2%{psuffix} Name: apache2%{psuffix}
Version: 2.4.58 Version: 2.4.63
Release: 0 Release: 0
Summary: The Apache HTTPD Server Summary: The Apache HTTPD Server
License: Apache-2.0 License: Apache-2.0
@@ -181,52 +181,20 @@ Patch2: apache2-logresolve-tmp-security.patch
Patch3: apache2-LimitRequestFieldSize-limits-headers.patch Patch3: apache2-LimitRequestFieldSize-limits-headers.patch
# [fate317766] backport of an upstream commit # [fate317766] backport of an upstream commit
Patch4: apache2-HttpContentLengthHeadZero-HttpExpectStrict.patch Patch4: apache2-HttpContentLengthHeadZero-HttpExpectStrict.patch
# FIX-UPSTREAM: bsc#1246477 CVE-2024-42516: HTTP response splitting
# FIX-UPSTREAM: CVE-2024-39573, bsc#1227271: potential SSRF in mod_rewrite Patch5: CVE-2024-42516.patch
# - https://svn.apache.org/viewvc?view=revision&revision=1918600 # FIX-UPSTREAM: bsc#1246305 CVE-2024-43204: SSRF when mod_proxy is loaded allows an attacker to send outbound proxy requests to a URL controlled by them
Patch5: apache2-CVE-2024-39573.patch Patch6: CVE-2024-43204.patch
# CVE-2023-38709 [bsc#1222330], HTTP response splitting # FIX-UPSTREAM: bsc#1246303 CVE-2024-47252: insufficient escaping of user-supplied data in mod_ssl allows an untrusted SSL/TLS client to insert escape characters into log files
Patch6: apache2-CVE-2023-38709.patch Patch7: CVE-2024-47252.patch
# CVE-2024-27316 [bsc#1221401], HTTP/2 CONTINUATION frames can be utilized for DoS attacks # FIX-UPSTREAM: bsc#1246302 CVE-2025-23048: access control bypass by trusted clients through TLS 1.3 session resumption in some mod_ssl configurations
Patch7: apache2-CVE-2024-27316.patch Patch8: CVE-2025-23048.patch
# CVE-2024-24795 [bsc#1222332], HTTP Response Splitting in multiple modules # FIX-UPSTREAM: bsc#1246307 CVE-2025-49630: denial of service can be triggered by untrusted clients causing an assertion in mod_proxy_http2
Patch8: apache2-CVE-2024-24795.patch Patch9: CVE-2025-49630.patch
# https://github.com/apache/httpd/pull/444/commits/c2fffd29b0f58bdc9caaaff4fec68e17a676f182 # FIX-UPSTREAM: bsc#1246169 CVE-2025-49812: Opossum Attack Application Layer Desynchronization using Opportunistic TLS
Patch9: apache2-issue-444.patch Patch10: CVE-2025-49812.patch
# FIX-UPSTREAM: CVE-2024-38477, bsc#1227270: null pointer dereference in mod_proxy # FIX-UPSTREAM: bsc#1246306 CVE-2025-53020: HTTP/2 denial of service due to late release of memory after effective lifetime
# - https://svn.apache.org/viewvc?view=revision&revision=1918607 Patch11: CVE-2025-53020.patch
Patch10: apache2-CVE-2024-38477.patch
# FIX-UPSTREAM: CVE-2024-38475, bsc#1227268: Improper escaping of output in mod_rewrite
# - https://svn.apache.org/viewvc?view=revision&revision=1918561
Patch11: apache2-CVE-2024-38475-1.patch
Patch12: apache2-CVE-2024-38475-2.patch
Patch13: apache2-CVE-2024-38475-3.patch
# FIX-UPSTREAM: CVE-2024-38476, bsc#1227269: Server may use exploitable/malicious
# backend application output to run local handlers via internal
# redirect
# - https://svn.apache.org/viewvc?view=revision&revision=1918560
Patch14: apache2-CVE-2024-38476-1.patch
Patch15: apache2-CVE-2024-38476-2.patch
Patch16: apache2-CVE-2024-38476-3.patch
Patch17: apache2-CVE-2024-38476-4.patch
Patch18: apache2-CVE-2024-38476-5.patch
Patch19: apache2-CVE-2024-38476-6.patch
Patch20: apache2-CVE-2024-38476-7.patch
Patch21: apache2-CVE-2024-38476-8.patch
Patch22: apache2-CVE-2024-38476-9.patch
Patch23: apache2-CVE-2024-38476-10.patch
Patch24: apache2-CVE-2024-38476-11.patch
# FIX-UPSTREAM: CVE-2024-38474, bsc#1227278: Substitution encoding issue in mod_rewrite
Patch25: apache2-CVE-2024-38474.patch
# FIX-UPSTREAM: CVE-2024-38473, bsc#1227276: Encoding problem in mod_proxy
Patch26: apache2-CVE-2024-38473-1.patch
Patch27: apache2-CVE-2024-38473-2.patch
Patch28: apache2-CVE-2024-38473-3.patch
Patch29: apache2-CVE-2024-38473-4.patch
# FIX-UPSTREAM: CVE-2024-39884, bsc#1227353: source code disclosure with handlers configured via AddType
Patch30: apache2-CVE-2024-39884.patch
# FIX-UPSTREAM: CVE-2024-40725, bsc#1229087: source code disclosure of local content
Patch31: apache2-CVE-2024-40725.patch
# PATCH: https://marc.info/?l=apache-httpd-users&m=147448312531134&w=2 # PATCH: https://marc.info/?l=apache-httpd-users&m=147448312531134&w=2
Patch100: apache-test-application-xml-type.patch Patch100: apache-test-application-xml-type.patch
@@ -310,6 +278,7 @@ BuildRequires: netcfg
# /SECTION # /SECTION
%if "%{mpm}" != "" %if "%{mpm}" != ""
Provides: apache2-MPM Provides: apache2-MPM
Requires: apache2
%endif %endif
%if "%{flavor}" == "" %if "%{flavor}" == ""
Requires: %{_sysconfdir}/mime.types Requires: %{_sysconfdir}/mime.types
@@ -346,7 +315,7 @@ Requires(pre): permissions
Requires(post): %fillup_prereq Requires(post): %fillup_prereq
Requires(post): grep Requires(post): grep
Requires(post): update-alternatives Requires(post): update-alternatives
Requires(postun):update-alternatives Requires(postun): update-alternatives
%endif %endif
%if %{test} || "%{flavor}" == "manual" %if %{test} || "%{flavor}" == "manual"
BuildArch: noarch BuildArch: noarch
@@ -360,8 +329,7 @@ is to provide a secure, efficient and extensible server that
provides HTTP services in sync with the current HTTP standards. provides HTTP services in sync with the current HTTP standards.
%prep %prep
%setup -q -n %{upstream_name}-%{version} -a20 %autosetup -p1 -n %{upstream_name}-%{version} -a20
%autopatch -p1
# #
# BUILD # BUILD
@@ -598,6 +566,8 @@ mkdir -p %{buildroot}%{_sysconfdir}/apache2/sysconfig.d
mkdir -p %{buildroot}/%{_fillupdir} mkdir -p %{buildroot}/%{_fillupdir}
install -m 644 %{SOURCE30} %{buildroot}%{_fillupdir}/sysconfig.apache2 install -m 644 %{SOURCE30} %{buildroot}%{_fillupdir}/sysconfig.apache2
# htdocsdir is used by default-server.conf
mkdir -p %{buildroot}%{htdocsdir}
mkdir -p %{buildroot}%{sysconfdir} mkdir -p %{buildroot}%{sysconfdir}
mkdir -p %{buildroot}%{sysconfdir}/conf.d mkdir -p %{buildroot}%{sysconfdir}/conf.d
for c in default-server.conf \ for c in default-server.conf \
@@ -782,6 +752,8 @@ apxs -q CFLAGS | grep "\\%{optflags}"
cp %{SOURCE21} mod_example.c cp %{SOURCE21} mod_example.c
apxs -c mod_example.c apxs -c mod_example.c
test_dir="$PWD/my-test-devel" test_dir="$PWD/my-test-devel"
# hack: %{_libdir} cannot be used in noarch packages, define shell variable _libdir, using apxs to find the real value
_libexecdir=$(apxs -q libdir)/apache2
echo "Try to load example module" echo "Try to load example module"
mkdir $test_dir mkdir $test_dir
cat > $test_dir/httpd.conf << EOF cat > $test_dir/httpd.conf << EOF
@@ -792,7 +764,7 @@ User $(id -un)
Group $(id -gn) Group $(id -gn)
Listen 60080 Listen 60080
DocumentRoot $test_dir DocumentRoot $test_dir
LoadModule authz_core_module %{libexecdir}-%{default_mpm}/mod_authz_core.so LoadModule authz_core_module ${_libexecdir}-%{default_mpm}/mod_authz_core.so
LoadModule example_module $PWD/.libs/mod_example.so LoadModule example_module $PWD/.libs/mod_example.so
<Location /hello> <Location /hello>
SetHandler example-handler SetHandler example-handler
@@ -827,15 +799,17 @@ function dep()
} }
# create a conf loading all MPM's modules # create a conf loading all MPM's modules
echo > $PWD/load-all-modules.conf echo > $PWD/load-all-modules.conf
# hack: %{_libdir} cannot be used in noarch packages, define shell variable _libdir, using apxs to find the real value
_libdir=$(apxs -q libdir)
# hack: sort -u to load mod_proxy before mod_proxy_http, mod_cache before mod_cache_disk, etc. # hack: sort -u to load mod_proxy before mod_proxy_http, mod_cache before mod_cache_disk, etc.
modules=$(find %{_libdir}/apache2-%{mpm}/ %{_libdir}/apache2/ -name *.so | sed 's:.*/mod_\(.*\).so:\1:' | sort -u) modules=$(find ${_libdir}/apache2-%{mpm}/ ${_libdir}/apache2/ -name *.so | sed 's:.*/mod_\(.*\).so:\1:' | sort -u)
# fix up dependencies # fix up dependencies
dep "lbmethod_bybusyness" "proxy" dep "lbmethod_bybusyness" "proxy"
dep "lbmethod_byrequests" "proxy" dep "lbmethod_byrequests" "proxy"
dep "lbmethod_bytraffic" "proxy" dep "lbmethod_bytraffic" "proxy"
dep "lbmethod_heartbeat" "proxy" dep "lbmethod_heartbeat" "proxy"
for m in $modules; do for m in $modules; do
path=$(find %{_libdir}/apache2-%{mpm}/ %{_libdir}/apache2/ -name mod_$m.so | head -n 1) path=$(find ${_libdir}/apache2-%{mpm}/ ${_libdir}/apache2/ -name mod_$m.so | head -n 1)
if ! grep -q "mod_$m.c" $PWD/load-all-modules.conf; then if ! grep -q "mod_$m.c" $PWD/load-all-modules.conf; then
echo "<IfModule !mod_$m.c>" >> $PWD/load-all-modules.conf echo "<IfModule !mod_$m.c>" >> $PWD/load-all-modules.conf
echo " LoadModule ${m}_module $path" >> $PWD/load-all-modules.conf echo " LoadModule ${m}_module $path" >> $PWD/load-all-modules.conf
@@ -883,6 +857,8 @@ exit 0
%attr(750,root,root) %dir %{logfiledir} %attr(750,root,root) %dir %{logfiledir}
%attr(750,%{httpduser},root) %dir %{proxycachedir} %attr(750,%{httpduser},root) %dir %{proxycachedir}
%attr(750,%{httpduser},root) %dir %{localstatedir} %attr(750,%{httpduser},root) %dir %{localstatedir}
%dir %{datadir}
%dir %{htdocsdir}
%dir %{libexecdir} %dir %{libexecdir}
%dir %{_libexecdir} %dir %{_libexecdir}
%attr(755,root,root) %{_libexecdir}/apache2_MMN %attr(755,root,root) %{_libexecdir}/apache2_MMN

BIN
httpd-2.4.58.tar.bz2 (Stored with Git LFS)

Binary file not shown.

View File

@@ -1,17 +0,0 @@
-----BEGIN PGP SIGNATURE-----
Comment: GPGTools - https://gpgtools.org
iQIzBAABCgAdFiEEJvUe+agvSstD8ZA+03fJ59GUTGYFAmUtUXcACgkQ03fJ59GU
TGZJnA/+KAE23IcOsePVK93RsfY2pCXvrQWH2vRaPQOV68lMMyI9I3D7Dd6ZbOIL
kfdcuMydaOzkwAzgM9dgfC2PF5rO/8LDHtieBRfLNVjcK7ngatZLzRU+2qARk4PG
bxfnpVzpnshBTkMuQ0C3nr6mi+bXQgdbbSLXGS5SOBqckBMfkpEXzArU8PU0EQwT
u3Id+eAqWtxXtwRKz+lRNwLzmyiXc8a1YwXJh5d2ldrL+WlFA1cts+k3nR5YPzF1
QsHLkoTuiAbXpRYHJg83AAENVxYPvwttIdthLeQtUgV6dcoiAuJzOt0/EBnUN5B3
J+T10z4zvXN0MogTVceAFfySZ6fQrR5PXs3raepDjo/AtVH9dvSQdXhpOGtyiCI9
4eabSL69Z7r+Nr3UzVLVYb4Uan5Z7G1UkKQNxJVJSR4mzitf1d3Fylw52ivBGnLv
OMcY1/b3Kx0m69dIiIlLPnG7UMgHwqgYcxJKomjI9opdobmpK42u8ZjOEYFoNAtk
sINfcehp83WwxdDuvpuSFNYWQXGhKONAZIyCW8lAuFWBG8oXra5osWY176OSUGTu
Ah+pM1NlbwL45r5kw+3t4L/3Hhx+dDqtI8jrQYReN/u4dBuIcqqLT1Ik2WjBuTyE
QiY/ZOzdxO7UAGYvgFyMHX+KsuqrxZKHd1JN2+TzHhEtstSICnE=
=CtTT
-----END PGP SIGNATURE-----

BIN
httpd-2.4.63.tar.bz2 (Stored with Git LFS) Normal file

Binary file not shown.

16
httpd-2.4.63.tar.bz2.asc Normal file
View File

@@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEqT1i7MPI6hLbIg7JNOp25nkUhagFAmeOpZMACgkQNOp25nkU
hajzCg/+I/j8u/tCFeaQAf5ZKyGZ8Kcpxf+/lP4Kr79emBwdROZFGP+ipfuyRpax
A8/WXTeVs6bWmg5edPIQAC1mDpj7rx2Pwa7xKV+/3/npQMPV4cqgbZfzgQD2NnoD
8Qs6pkjwF6ygn+4y/KQLF5MIh4G0lIkx/ddt+lHbt2FkJXT5JV1cyJ+kKrTLJdlB
RDMXcF2XleFFzApf9VCYWFPTlgmxAe4FG65JMwxh3WJeiX0vrLH+GnOyAXHotBOs
NbXQKQD5cM6/JzA3F4Jni/2co9Wsjg+zENx3hIjxJZvVtXRIC4BpmAJOeQIyoNwo
VVwe3Uo9Cz+ZFTYMecwnR/B5tm4IkQ0K9MXRK/jxxKds4CF/bnt0BClaSRqXrJJW
hwciu0Yw9nsCCQbz+vwMKVMRtQ1m2/Cl3+9K/9RYwdgfTQmNYcu3J+19trvRx2Vf
OVtwFNm2tps2YtOV1NAnr2huHt257WVis9ElCOwIpUqwJZvzLCG2VaSq0vlYZqP8
iQoQA25f9Ln34KdpF7BU2PO9LraFJNTHFIed3cd8L7U14H9iQ93mSUlibzY3HvK4
B3qeXmsn3YpJpgsvhOUPR7mTlhOsPSIdRW0vuLOrN5Rz3uVWRG8vpjCeZCYSYWBf
4KzbwEZ6n9dfc2D5N6Yx3uTdmKhAg1O1ryk7E6Sp+pVybFQrzsc=
=ttO/
-----END PGP SIGNATURE-----

BIN
httpd-framework-svn1901574.tar.bz2 (Stored with Git LFS)

Binary file not shown.

BIN
httpd-framework-svn1921782.tar.bz2 (Stored with Git LFS) Normal file

Binary file not shown.