summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debian/changelog17
-rw-r--r--debian/patches/0052-CVE-2023-27522-HTTP-Response-Smuggling-mod_proxy_uws.patch120
-rw-r--r--debian/patches/0053-CVE-2023-25690-1.patch170
-rw-r--r--debian/patches/0054-CVE-2023-25690-2.patch35
-rw-r--r--debian/patches/0055-CVE-2023-25690-Regression-1.patch131
-rw-r--r--debian/patches/0056-CVE-2023-25690-Regression-2.patch138
-rw-r--r--debian/patches/0057-CVE-2023-25690-Regression-3.patch24
-rw-r--r--debian/patches/series8
-rw-r--r--debian/perl-framework/t/modules/buffer.t9
-rw-r--r--debian/salsa-ci.yml13
-rw-r--r--debian/tests/CVE-2023-25690110
-rw-r--r--debian/tests/control8
-rw-r--r--debian/tests/uwsgi142
13 files changed, 917 insertions, 8 deletions
diff --git a/debian/changelog b/debian/changelog
index c5cbe51..ee0857b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,20 @@
+apache2 (2.4.38-3+deb10u10) buster-security; urgency=medium
+
+ * Non-maintainer upload by the LTS Team.
+ * CVE-2023-27522: HTTP Response Smuggling in mod_proxy_uwsgi
+ (Closes: #1032476)
+ * CVE-2023-25690: Some mod_proxy configurations allow a HTTP
+ Request Smuggling attack. Configurations are affected
+ when mod_proxy is enabled along with some form of RewriteRule
+ or ProxyPassMatch in which a non-specific pattern matches
+ some portion of the user-supplied request-target (URL)
+ data and is then re-inserted into the proxied request-target
+ using variable substitution. (Closes: #1032476)
+ * Backport perl-framework testsuite from sid
+ * Backport regression fix for CVE-2023-25690
+
+ -- Bastien Roucariès <rouca@debian.org> Fri, 21 Apr 2023 22:01:00 +0000
+
apache2 (2.4.38-3+deb10u9) buster-security; urgency=medium
* Non-maintainer upload by the LTS Team.
diff --git a/debian/patches/0052-CVE-2023-27522-HTTP-Response-Smuggling-mod_proxy_uws.patch b/debian/patches/0052-CVE-2023-27522-HTTP-Response-Smuggling-mod_proxy_uws.patch
new file mode 100644
index 0000000..f39fa72
--- /dev/null
+++ b/debian/patches/0052-CVE-2023-27522-HTTP-Response-Smuggling-mod_proxy_uws.patch
@@ -0,0 +1,120 @@
+From: Eric Covener <covener@apache.org>
+Date: Sun, 5 Mar 2023 20:22:52 +0000
+Subject: CVE-2023-27522: HTTP Response Smuggling mod_proxy_uwsgi
+
+HTTP Response Smuggling vulnerability in Apache HTTP Server via mod_proxy_uwsgi.
+This issue affects Apache HTTP Server: from 2.4.30 through 2.4.55.
+Special characters in the origin response header can truncate/split the response forwarded to the client.
+
+mod_proxy_uwsgi: Stricter backend HTTP response parsing/validation
+
+Reviewed By: ylavic, covener, gbechis, rpluem
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1908094 13f79535-47bb-0310-9956-ffa450edef68
+origin: https://github.com/apache/httpd/commit/d753ea76b5972a85349b68c31b59d04c60014f2d.patch
+bug-debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1032476
+bug-debian-security: https://security-tracker.debian.org/tracker/CVE-2023-27522
+bug-cve: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-27522
+---
+ .../proxy_uwsgi_response_validation.txt | 2 +
+ modules/proxy/mod_proxy_uwsgi.c | 49 +++++++++++++++-------
+ 2 files changed, 37 insertions(+), 14 deletions(-)
+ create mode 100644 changes-entries/proxy_uwsgi_response_validation.txt
+
+diff --git a/changes-entries/proxy_uwsgi_response_validation.txt b/changes-entries/proxy_uwsgi_response_validation.txt
+new file mode 100644
+index 0000000..2cdb6c6
+--- /dev/null
++++ b/changes-entries/proxy_uwsgi_response_validation.txt
+@@ -0,0 +1,2 @@
++ *) mod_proxy_uwsgi: Stricter backend HTTP response parsing/validation.
++ [Yann Ylavic]
+diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c
+index ebe16e8..9ba10b9 100644
+--- a/modules/proxy/mod_proxy_uwsgi.c
++++ b/modules/proxy/mod_proxy_uwsgi.c
+@@ -303,18 +303,16 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
+ pass_bb = apr_brigade_create(r->pool, c->bucket_alloc);
+
+ len = ap_getline(buffer, sizeof(buffer), rp, 1);
+-
+ if (len <= 0) {
+- /* oops */
++ /* invalid or empty */
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+-
+ backend->worker->s->read += len;
+-
+- if (len >= sizeof(buffer) - 1) {
+- /* oops */
++ if ((apr_size_t)len >= sizeof(buffer)) {
++ /* too long */
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
++
+ /* Position of http status code */
+ if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
+ status_start = 9;
+@@ -323,8 +321,8 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
+ status_start = 7;
+ }
+ else {
+- /* oops */
+- return HTTP_INTERNAL_SERVER_ERROR;
++ /* not HTTP */
++ return HTTP_BAD_GATEWAY;
+ }
+ status_end = status_start + 3;
+
+@@ -344,21 +342,44 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
+ }
+ r->status_line = apr_pstrdup(r->pool, &buffer[status_start]);
+
+- /* start parsing headers */
++ /* parse headers */
+ while ((len = ap_getline(buffer, sizeof(buffer), rp, 1)) > 0) {
++ if ((apr_size_t)len >= sizeof(buffer)) {
++ /* too long */
++ len = -1;
++ break;
++ }
+ value = strchr(buffer, ':');
+- /* invalid header skip */
+- if (!value)
+- continue;
+- *value = '\0';
+- ++value;
++ if (!value) {
++ /* invalid header */
++ len = -1;
++ break;
++ }
++ *value++ = '\0';
++ if (*ap_scan_http_token(buffer)) {
++ /* invalid name */
++ len = -1;
++ break;
++ }
+ while (apr_isspace(*value))
+ ++value;
+ for (end = &value[strlen(value) - 1];
+ end > value && apr_isspace(*end); --end)
+ *end = '\0';
++ if (*ap_scan_http_field_content(value)) {
++ /* invalid value */
++ len = -1;
++ break;
++ }
+ apr_table_add(r->headers_out, buffer, value);
+ }
++ if (len < 0) {
++ /* Reset headers, but not to NULL because things below the chain expect
++ * this to be non NULL e.g. the ap_content_length_filter.
++ */
++ r->headers_out = apr_table_make(r->pool, 1);
++ return HTTP_BAD_GATEWAY;
++ }
+
+ if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
+ ap_set_content_type(r, apr_pstrdup(r->pool, buf));
diff --git a/debian/patches/0053-CVE-2023-25690-1.patch b/debian/patches/0053-CVE-2023-25690-1.patch
new file mode 100644
index 0000000..a7370c7
--- /dev/null
+++ b/debian/patches/0053-CVE-2023-25690-1.patch
@@ -0,0 +1,170 @@
+From 8789f6bb926fa4c33b4231a8444340515c82bdff Mon Sep 17 00:00:00 2001
+From: Eric Covener <covener@apache.org>
+Date: Sun, 5 Mar 2023 20:28:43 +0000
+Subject: [PATCH] [1/2] Fix CVE-2023-25690: HTTP Request Smuggling in mod_proxy*
+
+ don't forward invalid query strings
+
+ Submitted by: rpluem
+
+Reviewed By: covener, fielding, rpluem, gbechis
+bug: https://httpd.apache.org/security/vulnerabilities_24.html#CVE-2023-25690
+bug-debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1032476
+bug-debian-security: https://security-tracker.debian.org/tracker/CVE-2023-25690
+origin: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1908096 13f79535-47bb-0310-9956-ffa450edef68
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1908096 13f79535-47bb-0310-9956-ffa450edef68
+---
+ modules/http2/mod_proxy_http2.c | 10 ++++++++++
+ modules/mappers/mod_rewrite.c | 22 ++++++++++++++++++++++
+ modules/proxy/mod_proxy_ajp.c | 10 ++++++++++
+ modules/proxy/mod_proxy_balancer.c | 10 ++++++++++
+ modules/proxy/mod_proxy_http.c | 10 ++++++++++
+ modules/proxy/mod_proxy_wstunnel.c | 10 ++++++++++
+ 6 files changed, 72 insertions(+)
+
+diff --git a/modules/http2/mod_proxy_http2.c b/modules/http2/mod_proxy_http2.c
+index 3faf03472bb..aa299b937a5 100644
+--- a/modules/http2/mod_proxy_http2.c
++++ b/modules/http2/mod_proxy_http2.c
+@@ -158,6 +158,16 @@ static int proxy_http2_canon(request_rec *r, char *url)
+ path = ap_proxy_canonenc(r->pool, url, (int)strlen(url),
+ enc_path, 0, r->proxyreq);
+ search = r->args;
++ if (search && *(ap_scan_vchar_obstext(search))) {
++ /*
++ * We have a raw control character or a ' ' in r->args.
++ * Correct encoding was missed.
++ */
++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO()
++ "To be forwarded query string contains control "
++ "characters or spaces");
++ return HTTP_FORBIDDEN;
++ }
+ }
+ break;
+ case PROXYREQ_PROXY:
+diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
+index 943996560e5..f6398f19386 100644
+--- a/modules/mappers/mod_rewrite.c
++++ b/modules/mappers/mod_rewrite.c
+@@ -4729,6 +4729,17 @@ static int hook_uri2file(request_rec *r)
+ unsigned skip;
+ apr_size_t flen;
+
++ if (r->args && *(ap_scan_vchar_obstext(r->args))) {
++ /*
++ * We have a raw control character or a ' ' in r->args.
++ * Correct encoding was missed.
++ */
++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10410)
++ "Rewritten query string contains control "
++ "characters or spaces");
++ return HTTP_FORBIDDEN;
++ }
++
+ if (ACTION_STATUS == rulestatus) {
+ int n = r->status;
+
+@@ -5013,6 +5024,17 @@ static int hook_fixup(request_rec *r)
+ if (rulestatus) {
+ unsigned skip;
+
++ if (r->args && *(ap_scan_vchar_obstext(r->args))) {
++ /*
++ * We have a raw control character or a ' ' in r->args.
++ * Correct encoding was missed.
++ */
++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10411)
++ "Rewritten query string contains control "
++ "characters or spaces");
++ return HTTP_FORBIDDEN;
++ }
++
+ if (ACTION_STATUS == rulestatus) {
+ int n = r->status;
+
+diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
+index 1449acad733..e46bd903a36 100644
+--- a/modules/proxy/mod_proxy_ajp.c
++++ b/modules/proxy/mod_proxy_ajp.c
+@@ -69,6 +69,16 @@ static int proxy_ajp_canon(request_rec *r, char *url)
+ path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
+ r->proxyreq);
+ search = r->args;
++ if (search && *(ap_scan_vchar_obstext(search))) {
++ /*
++ * We have a raw control character or a ' ' in r->args.
++ * Correct encoding was missed.
++ */
++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10406)
++ "To be forwarded query string contains control "
++ "characters or spaces");
++ return HTTP_FORBIDDEN;
++ }
+ }
+ if (path == NULL)
+ return HTTP_BAD_REQUEST;
+diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
+index f6fb6345ae3..7f990084336 100644
+--- a/modules/proxy/mod_proxy_balancer.c
++++ b/modules/proxy/mod_proxy_balancer.c
+@@ -106,6 +106,16 @@ static int proxy_balancer_canon(request_rec *r, char *url)
+ path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
+ r->proxyreq);
+ search = r->args;
++ if (search && *(ap_scan_vchar_obstext(search))) {
++ /*
++ * We have a raw control character or a ' ' in r->args.
++ * Correct encoding was missed.
++ */
++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10407)
++ "To be forwarded query string contains control "
++ "characters or spaces");
++ return HTTP_FORBIDDEN;
++ }
+ }
+ if (path == NULL)
+ return HTTP_BAD_REQUEST;
+diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
+index ec4e7fb06b5..51d19a0a21b 100644
+--- a/modules/proxy/mod_proxy_http.c
++++ b/modules/proxy/mod_proxy_http.c
+@@ -125,6 +125,16 @@ static int proxy_http_canon(request_rec *r, char *url)
+ path = ap_proxy_canonenc(r->pool, url, strlen(url),
+ enc_path, 0, r->proxyreq);
+ search = r->args;
++ if (search && *(ap_scan_vchar_obstext(search))) {
++ /*
++ * We have a raw control character or a ' ' in r->args.
++ * Correct encoding was missed.
++ */
++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10408)
++ "To be forwarded query string contains control "
++ "characters or spaces");
++ return HTTP_FORBIDDEN;
++ }
+ }
+ break;
+ case PROXYREQ_PROXY:
+diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c
+index bcbba42f9a4..88f86a49dbb 100644
+--- a/modules/proxy/mod_proxy_wstunnel.c
++++ b/modules/proxy/mod_proxy_wstunnel.c
+@@ -114,6 +114,16 @@ static int proxy_wstunnel_canon(request_rec *r, char *url)
+ path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
+ r->proxyreq);
+ search = r->args;
++ if (search && *(ap_scan_vchar_obstext(search))) {
++ /*
++ * We have a raw control character or a ' ' in r->args.
++ * Correct encoding was missed.
++ */
++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10409)
++ "To be forwarded query string contains control "
++ "characters or spaces");
++ return HTTP_FORBIDDEN;
++ }
+ }
+ if (path == NULL)
+ return HTTP_BAD_REQUEST;
+
diff --git a/debian/patches/0054-CVE-2023-25690-2.patch b/debian/patches/0054-CVE-2023-25690-2.patch
new file mode 100644
index 0000000..978be78
--- /dev/null
+++ b/debian/patches/0054-CVE-2023-25690-2.patch
@@ -0,0 +1,35 @@
+From 8b93a6512f14f5f68887ddfe677e91233ed79fb0 Mon Sep 17 00:00:00 2001
+From: Ruediger Pluem <rpluem@apache.org>
+Date: Mon, 6 Mar 2023 10:00:09 +0000
+Subject: [PATCH] [2/2] Fix CVE-2023-25690: HTTP Request Smuggling in mod_proxy*
+
+* modules/http2/mod_proxy_http2.c: Fix missing APLOGNO.
+
+Submitted by: jorton
+Reviewed by: rpluem
+
+Note: mod_proxy_http2 is CTR on 2.4.x.
+
+bug: https://httpd.apache.org/security/vulnerabilities_24.html#CVE-2023-25690
+bug-debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1032476
+bug-debian-security: https://security-tracker.debian.org/tracker/CVE-2023-25690
+origin: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1908118 13f79535-47bb-0310-9956-ffa450edef68
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1908118 13f79535-47bb-0310-9956-ffa450edef68
+---
+ modules/http2/mod_proxy_http2.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/modules/http2/mod_proxy_http2.c b/modules/http2/mod_proxy_http2.c
+index aa299b937a5..2a9967e5d57 100644
+--- a/modules/http2/mod_proxy_http2.c
++++ b/modules/http2/mod_proxy_http2.c
+@@ -163,7 +163,7 @@ static int proxy_http2_canon(request_rec *r, char *url)
+ * We have a raw control character or a ' ' in r->args.
+ * Correct encoding was missed.
+ */
+- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO()
++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10412)
+ "To be forwarded query string contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+
diff --git a/debian/patches/0055-CVE-2023-25690-Regression-1.patch b/debian/patches/0055-CVE-2023-25690-Regression-1.patch
new file mode 100644
index 0000000..d57a71c
--- /dev/null
+++ b/debian/patches/0055-CVE-2023-25690-Regression-1.patch
@@ -0,0 +1,131 @@
+From 815cf05bb2d506f44a35b65e93de393d5410c779 Mon Sep 17 00:00:00 2001
+From: Yann Ylavic <ylavic@apache.org>
+Date: Tue, 1 Mar 2022 13:26:03 +0000
+Subject: [PATCH] mod_rewrite: URI-to-filename rewrites to transparently handle
+ proxy mappings.
+
+Since mod_rewrite works on r->filename and mod_proxy's mapping=servlet|decoded
+sets its "proxy:" URL there at pre_translate_name stage (i.e. before
+mod_rewrite's translate_name hook), users have to match the full proxy URL in
+their RewriteRules to handle proxy mappings, which is not very friendly nor
+consistent with how proxy non-mapping requests have to be matched.
+
+Let's use r->filename = r->uri in hook_uri2file() for pre_trans'ed reverse
+proxy requests, and restore r->filename to its original value if the request
+was finally DECLINED (like in hook_fixup).
+
+But if a proxy mapping gets rewritten to a non-proxy request, clear any
+proxy specific r->proxyreq or r->handler so that processing continues
+accordingly.
+
+
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1898509 13f79535-47bb-0310-9956-ffa450edef68
+---
+ changes-entries/rewrite_vs_proxy_mapping.txt | 2 ++
+ modules/mappers/mod_rewrite.c | 38 +++++++++++++++-----
+ 2 files changed, 32 insertions(+), 8 deletions(-)
+ create mode 100644 changes-entries/rewrite_vs_proxy_mapping.txt
+
+Index: apache2/changes-entries/rewrite_vs_proxy_mapping.txt
+===================================================================
+--- /dev/null
++++ apache2/changes-entries/rewrite_vs_proxy_mapping.txt
+@@ -0,0 +1,2 @@
++ *) mod_rewrite: Make URI-to-filename rewrites work transparently with
++ proxy early mappings (mapping=servlet/decoded). [Yann Ylavic]
+\ No newline at end of file
+Index: apache2/modules/mappers/mod_rewrite.c
+===================================================================
+--- apache2.orig/modules/mappers/mod_rewrite.c
++++ apache2/modules/mappers/mod_rewrite.c
+@@ -4575,6 +4575,7 @@ static int hook_uri2file(request_rec *r)
+ unsigned int port;
+ int rulestatus;
+ void *skipdata;
++ char *ofilename;
+ const char *oargs;
+
+ /*
+@@ -4628,7 +4629,10 @@ static int hook_uri2file(request_rec *r)
+ /*
+ * remember the original query string for later check, since we don't
+ * want to apply URL-escaping when no substitution has changed it.
++ * also, we'll restore original r->filename if we decline this
++ * request.
+ */
++ ofilename = r->filename;
+ oargs = r->args;
+
+ /*
+@@ -4671,13 +4675,15 @@ static int hook_uri2file(request_rec *r)
+ apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URI, var);
+
+ if (!(saved_rulestatus = apr_table_get(r->notes,"mod_rewrite_rewritten"))) {
+- /* if filename was not initially set,
+- * we start with the requested URI
++ /* If r->filename was not initially set or if it's a pre_trans reverse
++ * "proxy:" scheme, we start with the requested URI.
+ */
+- if (r->filename == NULL) {
++ if (r->filename == NULL || (r->proxyreq == PROXYREQ_REVERSE &&
++ strncmp(r->filename, "proxy:", 6) == 0)) {
+ r->filename = apr_pstrdup(r->pool, r->uri);
+- rewritelog((r, 2, NULL, "init rewrite engine with requested uri %s",
+- r->filename));
++ rewritelog((r, 2, NULL, "init rewrite engine with requested uri "
++ "%s. Original filename = %s", r->filename,
++ ((ofilename) ? ofilename : "n/a")));
+ }
+ else {
+ rewritelog((r, 2, NULL, "init rewrite engine with passed filename "
+@@ -4701,6 +4707,7 @@ static int hook_uri2file(request_rec *r)
+ if (rulestatus) {
+ unsigned skip;
+ apr_size_t flen;
++ int to_proxyreq;
+
+ if (r->args && *(ap_scan_vchar_obstext(r->args))) {
+ /*
+@@ -4721,7 +4728,19 @@ static int hook_uri2file(request_rec *r)
+ }
+
+ flen = r->filename ? strlen(r->filename) : 0;
+- if (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0) {
++ to_proxyreq = (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0);
++
++ /* If a pre_trans reverse "proxy:" filename gets rewritten to
++ * a non-proxy one this is not a proxy request anymore.
++ */
++ if (r->proxyreq == PROXYREQ_REVERSE && !to_proxyreq) {
++ if (r->handler && strcmp(r->handler, "proxy-server") == 0) {
++ r->handler = NULL;
++ }
++ r->proxyreq = PROXYREQ_NONE;
++ }
++
++ if (to_proxyreq) {
+ /* it should be go on as an internal proxy request */
+
+ /* check if the proxy module is enabled, so
+@@ -4888,7 +4907,9 @@ static int hook_uri2file(request_rec *r)
+ }
+ }
+ else {
+- rewritelog((r, 1, NULL, "pass through %s", r->filename));
++ rewritelog((r, 1, NULL, "pass through %s, filename %s",
++ r->filename, ((ofilename) ? ofilename : "n/a")));
++ r->filename = ofilename;
+ return DECLINED;
+ }
+ }
+@@ -5234,7 +5255,8 @@ static int hook_fixup(request_rec *r)
+ }
+ }
+ else {
+- rewritelog((r, 1, dconf->directory, "pass through %s", r->filename));
++ rewritelog((r, 1, dconf->directory, "pass through %s, filename %s",
++ r->filename, ((ofilename) ? ofilename : "n/a")));
+ r->filename = ofilename;
+ return DECLINED;
+ }
diff --git a/debian/patches/0056-CVE-2023-25690-Regression-2.patch b/debian/patches/0056-CVE-2023-25690-Regression-2.patch
new file mode 100644
index 0000000..55eaa6b
--- /dev/null
+++ b/debian/patches/0056-CVE-2023-25690-Regression-2.patch
@@ -0,0 +1,138 @@
+From 07b802c934b841d376733a3e2ecfa55f6b0ee994 Mon Sep 17 00:00:00 2001
+From: Eric Covener <covener@apache.org>
+Date: Sat, 11 Mar 2023 20:57:52 +0000
+Subject: [PATCH] allow decoded chars when they will be escaped
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1908296 13f79535-47bb-0310-9956-ffa450edef68
+---
+ changes-entries/rewrite-escape.diff | 3 ++
+ modules/mappers/mod_rewrite.c | 45 +++++++++++++++++------------
+ 2 files changed, 30 insertions(+), 18 deletions(-)
+ create mode 100644 changes-entries/rewrite-escape.diff
+
+Index: apache2/changes-entries/rewrite-escape.diff
+===================================================================
+--- /dev/null
++++ apache2/changes-entries/rewrite-escape.diff
+@@ -0,0 +1,3 @@
++ *) mod_rewrite: Re-allow some proxy and redirect substitutions flagged as
++ 403 errors in 2.4.56. [Eric Covener]
++
+Index: apache2/modules/mappers/mod_rewrite.c
+===================================================================
+--- apache2.orig/modules/mappers/mod_rewrite.c
++++ apache2/modules/mappers/mod_rewrite.c
+@@ -4705,14 +4705,19 @@ static int hook_uri2file(request_rec *r)
+ }
+
+ if (rulestatus) {
+- unsigned skip;
+- apr_size_t flen;
+- int to_proxyreq;
+-
+- if (r->args && *(ap_scan_vchar_obstext(r->args))) {
++ unsigned skip_absolute = is_absolute_uri(r->filename, NULL);
++ apr_size_t flen = r->filename ? strlen(r->filename) : 0;
++ int to_proxyreq = (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0);
++ int will_escape = (to_proxyreq || skip_absolute)
++ && (rulestatus != ACTION_NOESCAPE);
++
++ if (r->args
++ && !will_escape
++ && *(ap_scan_vchar_obstext(r->args))) {
+ /*
+ * We have a raw control character or a ' ' in r->args.
+- * Correct encoding was missed.
++ * Correct encoding was missed and we're not going to escape
++ * it before returning.
+ */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10410)
+ "Rewritten query string contains control "
+@@ -4727,9 +4732,6 @@ static int hook_uri2file(request_rec *r)
+ return n;
+ }
+
+- flen = r->filename ? strlen(r->filename) : 0;
+- to_proxyreq = (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0);
+-
+ /* If a pre_trans reverse "proxy:" filename gets rewritten to
+ * a non-proxy one this is not a proxy request anymore.
+ */
+@@ -4782,15 +4784,15 @@ static int hook_uri2file(request_rec *r)
+ r->filename));
+ return OK;
+ }
+- else if ((skip = is_absolute_uri(r->filename, NULL)) > 0) {
++ else if (skip_absolute > 0) {
+ int n;
+
+ /* it was finally rewritten to a remote URL */
+
+ if (rulestatus != ACTION_NOESCAPE) {
+ rewritelog((r, 1, NULL, "escaping %s for redirect",
+- r->filename));
+- r->filename = escape_absolute_uri(r->pool, r->filename, skip);
++ r->filename));
++ r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute);
+ }
+
+ /* append the QUERY_STRING part */
+@@ -5016,9 +5018,17 @@ static int hook_fixup(request_rec *r)
+ */
+ rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory);
+ if (rulestatus) {
+- unsigned skip;
++ unsigned skip_absolute = is_absolute_uri(r->filename, NULL);
++ int to_proxyreq = 0;
++ int will_escape = 0;
+
+- if (r->args && *(ap_scan_vchar_obstext(r->args))) {
++ l = strlen(r->filename);
++ to_proxyreq = l > 6 && strncmp(r->filename, "proxy:", 6) == 0;
++ will_escape = skip_absolute && (rulestatus != ACTION_NOESCAPE);
++
++ if (r->args
++ && !will_escape
++ && *(ap_scan_vchar_obstext(r->args))) {
+ /*
+ * We have a raw control character or a ' ' in r->args.
+ * Correct encoding was missed.
+@@ -5036,8 +5046,7 @@ static int hook_fixup(request_rec *r)
+ return n;
+ }
+
+- l = strlen(r->filename);
+- if (l > 6 && strncmp(r->filename, "proxy:", 6) == 0) {
++ if (to_proxyreq) {
+ /* it should go on as an internal proxy request */
+
+ /* make sure the QUERY_STRING and
+@@ -5061,7 +5070,7 @@ static int hook_fixup(request_rec *r)
+ "%s [OK]", r->filename));
+ return OK;
+ }
+- else if ((skip = is_absolute_uri(r->filename, NULL)) > 0) {
++ else if (skip_absolute > 0) {
+ /* it was finally rewritten to a remote URL */
+
+ /* because we are in a per-dir context
+@@ -5070,7 +5079,7 @@ static int hook_fixup(request_rec *r)
+ */
+ if (dconf->baseurl != NULL) {
+ /* skip 'scheme://' */
+- cp = r->filename + skip;
++ cp = r->filename + skip_absolute;
+
+ if ((cp = ap_strchr(cp, '/')) != NULL && *(++cp)) {
+ rewritelog((r, 2, dconf->directory,
+@@ -5114,8 +5123,8 @@ static int hook_fixup(request_rec *r)
+ /* now prepare the redirect... */
+ if (rulestatus != ACTION_NOESCAPE) {
+ rewritelog((r, 1, dconf->directory, "escaping %s for redirect",
+- r->filename));
+- r->filename = escape_absolute_uri(r->pool, r->filename, skip);
++ r->filename));
++ r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute);
+ }
+
+ /* append the QUERY_STRING part */
diff --git a/debian/patches/0057-CVE-2023-25690-Regression-3.patch b/debian/patches/0057-CVE-2023-25690-Regression-3.patch
new file mode 100644
index 0000000..431f145
--- /dev/null
+++ b/debian/patches/0057-CVE-2023-25690-Regression-3.patch
@@ -0,0 +1,24 @@
+From 1a4aac3d209f4314bcb511d73cf12f8c25c8c984 Mon Sep 17 00:00:00 2001
+From: Eric Covener <covener@apache.org>
+Date: Sat, 11 Mar 2023 21:29:11 +0000
+Subject: [PATCH] followup to r1908296: only for redirects
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1908299 13f79535-47bb-0310-9956-ffa450edef68
+---
+ modules/mappers/mod_rewrite.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+Index: apache2/modules/mappers/mod_rewrite.c
+===================================================================
+--- apache2.orig/modules/mappers/mod_rewrite.c
++++ apache2/modules/mappers/mod_rewrite.c
+@@ -4708,8 +4708,7 @@ static int hook_uri2file(request_rec *r)
+ unsigned skip_absolute = is_absolute_uri(r->filename, NULL);
+ apr_size_t flen = r->filename ? strlen(r->filename) : 0;
+ int to_proxyreq = (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0);
+- int will_escape = (to_proxyreq || skip_absolute)
+- && (rulestatus != ACTION_NOESCAPE);
++ int will_escape = skip_absolute && (rulestatus != ACTION_NOESCAPE);
+
+ if (r->args
+ && !will_escape
diff --git a/debian/patches/series b/debian/patches/series
index c430013..839511c 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -53,3 +53,11 @@ CVE-2006-20001.patch
CVE-2022-36760.patch
CVE-2022-37436.patch
CVE-2021-33193.patch
+0052-CVE-2023-27522-HTTP-Response-Smuggling-mod_proxy_uws.patch
+0053-CVE-2023-25690-1.patch
+0054-CVE-2023-25690-2.patch
+0055-CVE-2023-25690-Regression-1.patch
+0056-CVE-2023-25690-Regression-2.patch
+0057-CVE-2023-25690-Regression-3.patch
+
+
diff --git a/debian/perl-framework/t/modules/buffer.t b/debian/perl-framework/t/modules/buffer.t
index 84cc5bc..e508f37 100644
--- a/debian/perl-framework/t/modules/buffer.t
+++ b/debian/perl-framework/t/modules/buffer.t
@@ -24,10 +24,15 @@ foreach my $t (@testcases) {
## Big query ##
# 'foo' is 3 bytes, so 'foo' x 1000000 is ~3M, which is way over the default 'BufferSize'
- $r = POST($t->[0], content => $t->[1] x 1000000);
+ ### FIXME - testing with to x 10000 is confusing LWP's full-duplex
+ ### handling: https://github.com/libwww-perl/libwww-perl/issues/299
+ ### throttled down to a size which seems to work reliably for now
+ my $bigsize = 100000;
+
+ $r = POST($t->[0], content => $t->[1] x $bigsize);
# Checking for return code
ok t_cmp($r->code, 200, "Checking return code is '200'");
# Checking for content
- ok t_cmp($r->content, $t->[1] x 1000000, $r->content . ' equals ' . $t->[1]);
+ ok t_is_equal($r->content, $t->[1] x $bigsize);
}
diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml
index f1f5897..e90a48f 100644
--- a/debian/salsa-ci.yml
+++ b/debian/salsa-ci.yml
@@ -1,7 +1,8 @@
----
-variables:
- RELEASE: 'buster'
-
include:
- - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
- - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
+- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/recipes/debian.yml
+
+variables:
+ RELEASE: 'buster'
+ SALSA_CI_COMPONENTS: 'main contrib non-free'
+ SALSA_CI_DISABLE_REPROTEST: 1
+ SALSA_CI_DISABLE_LINTIAN: 1
diff --git a/debian/tests/CVE-2023-25690 b/debian/tests/CVE-2023-25690
new file mode 100644
index 0000000..2aa916f
--- /dev/null
+++ b/debian/tests/CVE-2023-25690
@@ -0,0 +1,110 @@
+#!/bin/bash
+
+# test CVE-2023-25690
+set -eux
+
+RC=0
+fail () {
+ echo "FAIL: $@" >&2
+ RC=1
+}
+
+
+function exit_handler()
+{
+ # fix cp: cannot access '/tmp/autopkgtest-lxc.x06nhp9r/downtmp/CVE-2023-25690-artifacts/apache2': Permission denied
+ chmod -R a+rwX "$AUTOPKGTEST_ARTIFACTS/apache2" || true
+ systemctl status apache2.service || true
+ systemctl stop apache2 || true
+ cat $AUTOPKGTEST_ARTIFACTS/apache2/error.log || true
+ cat $AUTOPKGTEST_ARTIFACTS/apache2/access.log || true
+ cat $AUTOPKGTEST_ARTIFACTS/apache2/error.8080.log || true
+ cat $AUTOPKGTEST_ARTIFACTS/apache2/access.8080.log || true
+}
+trap exit_handler EXIT
+
+
+a2enmod proxy
+a2enmod proxy_http
+a2enmod rewrite
+
+rsync -a /var/log/apache2 "$AUTOPKGTEST_ARTIFACTS"
+rm /var/log/apache2/*
+mount -o bind "$AUTOPKGTEST_ARTIFACTS/apache2" /var/log/apache2
+
+tee /etc/apache2/ports.conf <<'EOF'
+Listen 80
+Listen 8080
+EOF
+
+
+tee /etc/apache2/sites-available/000-default.conf <<'EOF'
+<VirtualHost *:8080>
+ # The ServerName directive sets the request scheme, hostname and port that
+ # the server uses to identify itself. This is used when creating
+ # redirection URLs. In the context of virtual hosts, the ServerName
+ # specifies what hostname must appear in the request's Host: header to
+ # match this virtual host. For the default virtual host (this file) this
+ # value is not decisive as it is used as a last resort host regardless.
+ # However, you must set it for any further virtual host explicitly.
+ #ServerName www.example.com
+
+ ServerAdmin webmaster@localhost
+ DocumentRoot /var/www/html
+
+ # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
+ # error, crit, alert, emerg.
+ # It is also possible to configure the loglevel for particular
+ # modules, e.g.
+ #LogLevel info ssl:warn
+
+ ErrorLog ${APACHE_LOG_DIR}/error.8080.log
+ CustomLog ${APACHE_LOG_DIR}/access.8080.log combined
+
+ # For most configuration files from conf-available/, which are
+ # enabled or disabled at a global level, it is possible to
+ # include a line for only one particular virtual host. For example the
+ # following line enables the CGI configuration for this host only
+ # after it has been globally disabled with "a2disconf".
+ #Include conf-available/serve-cgi-bin.conf
+</VirtualHost>
+<VirtualHost *:80>
+ # The ServerName directive sets the request scheme, hostname and port that
+ # the server uses to identify itself. This is used when creating
+ # redirection URLs. In the context of virtual hosts, the ServerName
+ # specifies what hostname must appear in the request's Host: header to
+ # match this virtual host. For the default virtual host (this file) this
+ # value is not decisive as it is used as a last resort host regardless.
+ # However, you must set it for any further virtual host explicitly.
+ #ServerName www.example.com
+
+ ServerAdmin webmaster@localhost
+ DocumentRoot /var/www/html
+
+ # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
+ # error, crit, alert, emerg.
+ # It is also possible to configure the loglevel for particular
+ # modules, e.g.
+ #LogLevel info ssl:warn
+ LogLevel alert rewrite:trace6
+ LogLevel error proxy:trace6
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+ CustomLog ${APACHE_LOG_DIR}/access.log combined
+
+ RewriteEngine on
+ RewriteRule "^/here/(.*)" "http://localhost:8080/index.html?$1" [P]
+ ProxyPassReverse "/here/" "http://localhost:8080/"
+</VirtualHost>
+EOF
+
+systemctl restart apache2
+
+CHOKEURL="http://localhost/here/index.html%20HTTP/1.1%0d%0aHost:%20localhost%0d%0aConnection:%20keep-alive%0d%0a%0d%0aGET%20/BAD.html%20HTTP/1.1%0d%0aFoo:%20bar HTTP/1.1"
+wget -S -q --output-document - "$CHOKEURL" || true
+(wget -S -q --output-document /dev/null "$CHOKEURL" 2>&1 || true)
+(wget -S -q --output-document /dev/null "$CHOKEURL" 2>&1 || true) | grep -e '^[[:space:]]*HTTP/1.1 4[[:digit:]][[:digit:]] '
+
+cat $AUTOPKGTEST_ARTIFACTS/apache2/access.8080.log | grep '] "GET /BAD.html HTTP/1.1"' && exit 1
+
+exit 0
+
diff --git a/debian/tests/control b/debian/tests/control
index cb45689..e2d3875 100644
--- a/debian/tests/control
+++ b/debian/tests/control
@@ -27,3 +27,11 @@ Tests: chroot
Features: no-build-needed
Restrictions: needs-root allow-stderr breaks-testbed
Depends: apache2, wget, dpkg-dev
+
+Tests: uwsgi
+Restrictions: allow-stderr, needs-root
+Depends: apache2, libapache2-mod-proxy-uwsgi, uwsgi, wget, uwsgi-plugin-python, rsync, netcat-openbsd | netcat-traditional
+
+Tests: CVE-2023-25690
+Restrictions: allow-stderr, needs-root
+Depends: apache2, rsync, curl, wget
diff --git a/debian/tests/uwsgi b/debian/tests/uwsgi
new file mode 100644
index 0000000..fd51b82
--- /dev/null
+++ b/debian/tests/uwsgi
@@ -0,0 +1,142 @@
+#!/bin/bash
+set -eux
+
+RC=0
+fail () {
+ echo "FAIL: $@" >&2
+ RC=1
+}
+
+
+function exit_handler()
+{
+ systemctl stop apache2 || true
+ if test -f /run/uwsgi/uwsgi.pid; then
+ kill -TERM $(cat /run/uwsgi/uwsgi.pid)
+ fi
+ cat $AUTOPKGTEST_ARTIFACTS/apache2/error.log || true
+ cat $AUTOPKGTEST_ARTIFACTS/apache2/access.log || true
+ cat $AUTOPKGTEST_ARTIFACTS/apache2/uwsgi.log || true
+ cat $AUTOPKGTEST_ARTIFACTS/apache2/uwsgi.error.log || true
+}
+trap exit_handler EXIT
+
+
+a2enmod proxy
+a2enmod proxy_uwsgi
+
+rsync -a /var/log/apache2 "$AUTOPKGTEST_ARTIFACTS"
+rm /var/log/apache2/*
+mount -o bind "$AUTOPKGTEST_ARTIFACTS/apache2" /var/log/apache2
+
+tee /etc/apache2/sites-available/000-default.conf <<'EOF'
+<VirtualHost *:80>
+ # The ServerName directive sets the request scheme, hostname and port that
+ # the server uses to identify itself. This is used when creating
+ # redirection URLs. In the context of virtual hosts, the ServerName
+ # specifies what hostname must appear in the request's Host: header to
+ # match this virtual host. For the default virtual host (this file) this
+ # value is not decisive as it is used as a last resort host regardless.
+ # However, you must set it for any further virtual host explicitly.
+ #ServerName www.example.com
+
+ ServerAdmin webmaster@localhost
+ DocumentRoot /var/www/html
+
+ # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
+ # error, crit, alert, emerg.
+ # It is also possible to configure the loglevel for particular
+ # modules, e.g.
+ #LogLevel info ssl:warn
+
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+ CustomLog ${APACHE_LOG_DIR}/access.log combined
+
+ # For most configuration files from conf-available/, which are
+ # enabled or disabled at a global level, it is possible to
+ # include a line for only one particular virtual host. For example the
+ # following line enables the CGI configuration for this host only
+ # after it has been globally disabled with "a2disconf".
+ #Include conf-available/serve-cgi-bin.conf
+ ProxyPass "/uwsgi" "unix:/run/uwsgi/test.socket|uwsgi://localhost"
+</VirtualHost>
+EOF
+
+systemctl restart apache2
+
+test -d /etc/uwsgi/ || mkdir /etc/uwsgi
+
+
+
+tee /etc/systemd/system/uwsgi-app@.socket <<EOF
+[Unit]
+Description=Socket for uWSGI app %i
+
+[Socket]
+ListenStream=/run/uwsgi/%i.socket
+SocketUser=www-%i
+SocketGroup=www-data
+SocketMode=0660
+
+[Install]
+WantedBy=sockets.target
+EOF
+
+tee /etc/systemd/system/uwsgi-app@.service <<EOF
+[Unit]
+Description=%i uWSGI app
+After=syslog.target
+
+[Service]
+ExecStart=/usr/bin/uwsgi \
+ --ini /etc/uwsgi/apps-available/%i.ini \
+ --socket /run/uwsgi/%i.socket
+User=www-%i
+Group=www-data
+Restart=on-failure
+KillSignal=SIGQUIT
+Type=notify
+StandardError=file:/var/log/apache2/uwsgi.error.log
+StandardOutput=file:/var/log/apache2/uwsgi.log
+NotifyAccess=all
+EOF
+
+systemctl daemon-reload
+
+useradd uwsgi_test
+useradd www-test
+
+tee /etc/uwsgi/apps-available/test.ini <<EOF
+[uwsgi]
+chdir=/tmp
+master=True
+cheap=True
+die-on-idle=True
+manage-script-name=True
+plugin=python
+wsgi-file=/tmp/uwsgi.py
+EOF
+
+
+tee /tmp/uwsgi.py <<'EOF'
+import wsgiref.headers as h
+def application(env, start_response):
+ buggy_header=('buggy','buggy#\r\nbuggy2:buggy2')
+ start_response('200 OK', [('Content-Type','text/html'),buggy_header])
+ ret = b"Hello World Headers {}".format(env)
+ return [ret]
+EOF
+chown www-test.www-test /tmp/uwsgi.py
+chmod +x /tmp/uwsgi.py
+
+systemctl enable uwsgi-app@test.socket
+systemctl enable uwsgi-app@test.service
+systemctl start uwsgi-app@test.socket
+systemctl restart apache2
+
+
+wget -S -q --output-document - http://localhost/uwsgi
+wget -q --output-document - http://localhost/uwsgi | grep "^Hello World"
+
+exit $RC
+-