summaryrefslogtreecommitdiffstats
path: root/debian
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-07 04:28:40 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-07 04:28:40 +0000
commit27bd2efa7497013c63c4adf082aef7618195ff83 (patch)
tree640d9b473180dbb9c767e2ca738545cb71e15f76 /debian
parentAdding debian version 2.4.38-3+deb10u8. (diff)
downloadapache2-27bd2efa7497013c63c4adf082aef7618195ff83.tar.xz
apache2-27bd2efa7497013c63c4adf082aef7618195ff83.zip
Adding debian version 2.4.38-3+deb10u9.debian/2.4.38-3+deb10u9
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'debian')
-rw-r--r--debian/.gitlab-ci.yml8
-rw-r--r--debian/changelog13
-rw-r--r--debian/gbp.conf3
-rw-r--r--debian/patches/CVE-2006-20001.patch37
-rw-r--r--debian/patches/CVE-2021-33193.patch702
-rw-r--r--debian/patches/CVE-2022-36760.patch27
-rw-r--r--debian/patches/CVE-2022-37436.patch125
-rw-r--r--debian/patches/series4
-rw-r--r--debian/perl-framework/t/security/CVE-2019-0215.t47
-rw-r--r--debian/perl-framework/t/security/CVE-2020-1927.t60
10 files changed, 1026 insertions, 0 deletions
diff --git a/debian/.gitlab-ci.yml b/debian/.gitlab-ci.yml
new file mode 100644
index 0000000..e90a48f
--- /dev/null
+++ b/debian/.gitlab-ci.yml
@@ -0,0 +1,8 @@
+include:
+- 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/changelog b/debian/changelog
index 64570c6..c5cbe51 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,16 @@
+apache2 (2.4.38-3+deb10u9) buster-security; urgency=medium
+
+ * Non-maintainer upload by the LTS Team.
+ * CVE-2006-20001: Fix error path for "Not" prefix parsing.
+ * CVE-2022-36760: HTTP Requests vulnerability in mod_proxy_ajp
+ * CVE-2022-37436: Early truncation of response headers
+ * CVE-2021-33193: mod_proxy HTTP/2 validation bypass
+ * Add tests from master branch for CVE-2019-0215, CVE-2020-1927
+ * Update debian/gbp.conf to use the branch "debian/buster"
+ * Add debian/.gitlab-ci.yml
+
+ -- Lee Garrett <debian@rocketjump.eu> Thu, 02 Mar 2023 15:26:27 +0100
+
apache2 (2.4.38-3+deb10u8) buster; urgency=medium
* Non-maintainer upload.
diff --git a/debian/gbp.conf b/debian/gbp.conf
new file mode 100644
index 0000000..d8c79b8
--- /dev/null
+++ b/debian/gbp.conf
@@ -0,0 +1,3 @@
+[DEFAULT]
+debian-branch = debian/buster
+merge-mode = replace
diff --git a/debian/patches/CVE-2006-20001.patch b/debian/patches/CVE-2006-20001.patch
new file mode 100644
index 0000000..0ba150b
--- /dev/null
+++ b/debian/patches/CVE-2006-20001.patch
@@ -0,0 +1,37 @@
+From 7469547c3f617717ca545d0f7c56d01134703813 Mon Sep 17 00:00:00 2001
+From: Eric Covener <covener@apache.org>
+Date: Tue, 10 Jan 2023 13:21:48 +0000
+Subject: [PATCH] Merge r1906487 from trunk:
+
+* modules/dav/main/util.c (dav_process_if_header): Fix error
+ path for "Not" prefix parsing.
+
+
+Submitted By: jorton
+Reviewed By: jorton, covener, rpluem
+
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1906543 13f79535-47bb-0310-9956-ffa450edef68
+---
+ STATUS | 8 --------
+ modules/dav/main/util.c | 8 +++++++-
+ 2 files changed, 7 insertions(+), 9 deletions(-)
+
+--- a/modules/dav/main/util.c
++++ b/modules/dav/main/util.c
+@@ -746,8 +746,14 @@
+ "for the same state.");
+ }
+ condition = DAV_IF_COND_NOT;
++ list += 2;
++ }
++ else {
++ return dav_new_error(r->pool, HTTP_BAD_REQUEST,
++ DAV_ERR_IF_UNK_CHAR, 0,
++ "Invalid \"If:\" header: "
++ "Unexpected character in List");
+ }
+- list += 2;
+ break;
+
+ case ' ':
diff --git a/debian/patches/CVE-2021-33193.patch b/debian/patches/CVE-2021-33193.patch
new file mode 100644
index 0000000..d2737b8
--- /dev/null
+++ b/debian/patches/CVE-2021-33193.patch
@@ -0,0 +1,702 @@
+Description: Fix for CVE-2021-33193: mod_proxy HTTP/2 validation bypass
+ A crafted method sent through HTTP/2 will bypass validation and be forwarded by
+ mod_proxy, which can lead to request splitting or cache poisoning.
+Origin: other, https://git.centos.org/rpms/httpd/blob/c496dea5e0b6e82a9f503e973fc5d5ea93a94180/f/SOURCES/httpd-2.4.37-CVE-2021-33193.patch
+Forwarded: not-needed
+Applied-Upstream: 2.4.49, https://github.com/apache/httpd/commit/ecebcc035ccd8d0e2984fe41420d9e944f456b3c
+Last-Update: 2023-02-24
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+--- a/include/http_core.h
++++ b/include/http_core.h
+@@ -741,6 +741,7 @@
+ #define AP_HTTP_METHODS_REGISTERED 2
+ char http_methods;
+ unsigned int merge_slashes;
++ unsigned int strict_host_check;
+ } core_server_config;
+
+ /* for AddOutputFiltersByType in core.c */
+@@ -769,6 +770,11 @@
+ typedef struct core_output_filter_ctx core_output_filter_ctx_t;
+ typedef struct core_filter_ctx core_ctx_t;
+
++struct core_filter_ctx {
++ apr_bucket_brigade *b;
++ apr_bucket_brigade *tmpbb;
++};
++
+ typedef struct core_net_rec {
+ /** Connection to the client */
+ apr_socket_t *client_socket;
+--- a/include/http_protocol.h
++++ b/include/http_protocol.h
+@@ -54,6 +54,13 @@
+ */
+
+ /**
++ * Read an empty request and set reasonable defaults.
++ * @param c The current connection
++ * @return The new request_rec
++ */
++AP_DECLARE(request_rec *) ap_create_request(conn_rec *c);
++
++/**
+ * Read a request and fill in the fields.
+ * @param c The current connection
+ * @return The new request_rec
+@@ -61,6 +68,20 @@
+ request_rec *ap_read_request(conn_rec *c);
+
+ /**
++ * Parse and validate the request line.
++ * @param r The current request
++ * @return 1 on success, 0 on failure
++ */
++AP_DECLARE(int) ap_parse_request_line(request_rec *r);
++
++/**
++ * Validate the request header and select vhost.
++ * @param r The current request
++ * @return 1 on success, 0 on failure
++ */
++AP_DECLARE(int) ap_check_request_header(request_rec *r);
++
++/**
+ * Read the mime-encoded headers.
+ * @param r The current request
+ */
+--- a/include/http_vhost.h
++++ b/include/http_vhost.h
+@@ -100,6 +100,19 @@
+ AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r);
+
+ /**
++ * Updates r->server with the best name-based virtual host match, within
++ * the chain of matching virtual hosts selected by ap_update_vhost_given_ip.
++ * @param r The current request
++ * @param require_match 1 to return an HTTP error if the requested hostname is
++ * not explicitly matched to a VirtualHost.
++ * @return return HTTP_OK unless require_match was specified and the requested
++ * hostname did not match any ServerName, ServerAlias, or VirtualHost
++ * address-spec.
++ */
++AP_DECLARE(int) ap_update_vhost_from_headers_ex(request_rec *r, int require_match);
++
++
++/**
+ * Match the host in the header with the hostname of the server for this
+ * request.
+ * @param r The current request
+--- a/server/core.c
++++ b/server/core.c
+@@ -494,6 +494,8 @@
+ conf->protocols_honor_order = -1;
+ conf->merge_slashes = AP_CORE_CONFIG_UNSET;
+
++ conf->strict_host_check= AP_CORE_CONFIG_UNSET;
++
+ return (void *)conf;
+ }
+
+@@ -559,7 +561,13 @@
+ base->protocols_honor_order :
+ virt->protocols_honor_order);
+ AP_CORE_MERGE_FLAG(merge_slashes, conf, base, virt);
+-
++
++ conf->strict_host_check = (virt->strict_host_check != AP_CORE_CONFIG_UNSET)
++ ? virt->strict_host_check
++ : base->strict_host_check;
++
++ AP_CORE_MERGE_FLAG(strict_host_check, conf, base, virt);
++
+ return conf;
+ }
+
+@@ -4518,7 +4526,10 @@
+ AP_INIT_FLAG("QualifyRedirectURL", set_qualify_redirect_url, NULL, OR_FILEINFO,
+ "Controls whether HTTP authorization headers, normally hidden, will "
+ "be passed to scripts"),
+-
++AP_INIT_FLAG("StrictHostCheck", set_core_server_flag,
++ (void *)APR_OFFSETOF(core_server_config, strict_host_check),
++ RSRC_CONF,
++ "Controls whether a hostname match is required"),
+ AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower,
+ (void *)APR_OFFSETOF(core_dir_config, mime_type), OR_FILEINFO,
+ "a mime type that overrides other configured type"),
+@@ -5492,4 +5503,3 @@
+ core_cmds, /* command apr_table_t */
+ register_hooks /* register hooks */
+ };
+-
+--- a/server/core_filters.c
++++ b/server/core_filters.c
+@@ -84,11 +84,6 @@
+ apr_size_t bytes_written;
+ };
+
+-struct core_filter_ctx {
+- apr_bucket_brigade *b;
+- apr_bucket_brigade *tmpbb;
+-};
+-
+
+ apr_status_t ap_core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
+ ap_input_mode_t mode, apr_read_type_e block,
+--- a/server/protocol.c
++++ b/server/protocol.c
+@@ -611,8 +611,15 @@
+ }
+
+ r->args = r->parsed_uri.query;
+- r->uri = r->parsed_uri.path ? r->parsed_uri.path
+- : apr_pstrdup(r->pool, "/");
++ if (r->parsed_uri.path) {
++ r->uri = r->parsed_uri.path;
++ }
++ else if (r->method_number == M_OPTIONS) {
++ r->uri = apr_pstrdup(r->pool, "*");
++ }
++ else {
++ r->uri = apr_pstrdup(r->pool, "/");
++ }
+
+ #if defined(OS2) || defined(WIN32)
+ /* Handle path translations for OS/2 and plug security hole.
+@@ -649,13 +656,6 @@
+
+ static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
+ {
+- enum {
+- rrl_none, rrl_badmethod, rrl_badwhitespace, rrl_excesswhitespace,
+- rrl_missinguri, rrl_baduri, rrl_badprotocol, rrl_trailingtext,
+- rrl_badmethod09, rrl_reject09
+- } deferred_error = rrl_none;
+- char *ll;
+- char *uri;
+ apr_size_t len;
+ int num_blank_lines = DEFAULT_LIMIT_BLANK_LINES;
+ core_server_config *conf = ap_get_core_module_config(r->server->module_config);
+@@ -720,6 +720,20 @@
+ }
+
+ r->request_time = apr_time_now();
++ return 1;
++}
++
++AP_DECLARE(int) ap_parse_request_line(request_rec *r)
++{
++ core_server_config *conf = ap_get_core_module_config(r->server->module_config);
++ int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
++ enum {
++ rrl_none, rrl_badmethod, rrl_badwhitespace, rrl_excesswhitespace,
++ rrl_missinguri, rrl_baduri, rrl_badprotocol, rrl_trailingtext,
++ rrl_badmethod09, rrl_reject09
++ } deferred_error = rrl_none;
++ apr_size_t len = 0;
++ char *uri, *ll;
+
+ r->method = r->the_request;
+
+@@ -751,7 +765,6 @@
+ if (deferred_error == rrl_none)
+ deferred_error = rrl_missinguri;
+ r->protocol = uri = "";
+- len = 0;
+ goto rrl_done;
+ }
+ else if (strict && ll[0] && apr_isspace(ll[1])
+@@ -782,7 +795,6 @@
+ /* Verify URI terminated with a single SP, or mark as specific error */
+ if (!ll) {
+ r->protocol = "";
+- len = 0;
+ goto rrl_done;
+ }
+ else if (strict && ll[0] && apr_isspace(ll[1])
+@@ -875,6 +887,14 @@
+ r->header_only = 1;
+
+ ap_parse_uri(r, uri);
++ if (r->status == HTTP_OK
++ && (r->parsed_uri.path != NULL)
++ && (r->parsed_uri.path[0] != '/')
++ && (r->method_number != M_OPTIONS
++ || strcmp(r->parsed_uri.path, "*") != 0)) {
++ /* Invalid request-target per RFC 7230 section 5.3 */
++ r->status = HTTP_BAD_REQUEST;
++ }
+
+ /* With the request understood, we can consider HTTP/0.9 specific errors */
+ if (r->proto_num == HTTP_VERSION(0, 9) && deferred_error == rrl_none) {
+@@ -982,6 +1002,79 @@
+ return 0;
+ }
+
++AP_DECLARE(int) ap_check_request_header(request_rec *r)
++{
++ core_server_config *conf;
++ int strict_host_check;
++ const char *expect;
++ int access_status;
++
++ conf = ap_get_core_module_config(r->server->module_config);
++
++ /* update what we think the virtual host is based on the headers we've
++ * now read. may update status.
++ */
++ strict_host_check = (conf->strict_host_check == AP_CORE_CONFIG_ON);
++ access_status = ap_update_vhost_from_headers_ex(r, strict_host_check);
++ if (strict_host_check && access_status != HTTP_OK) {
++ if (r->server == ap_server_conf) {
++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10156)
++ "Requested hostname '%s' did not match any ServerName/ServerAlias "
++ "in the global server configuration ", r->hostname);
++ }
++ else {
++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10157)
++ "Requested hostname '%s' did not match any ServerName/ServerAlias "
++ "in the matching virtual host (default vhost for "
++ "current connection is %s:%u)",
++ r->hostname, r->server->defn_name, r->server->defn_line_number);
++ }
++ r->status = access_status;
++ }
++ if (r->status != HTTP_OK) {
++ return 0;
++ }
++
++ if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1, 1)))
++ || ((r->proto_num == HTTP_VERSION(1, 1))
++ && !apr_table_get(r->headers_in, "Host"))) {
++ /*
++ * Client sent us an HTTP/1.1 or later request without telling us the
++ * hostname, either with a full URL or a Host: header. We therefore
++ * need to (as per the 1.1 spec) send an error. As a special case,
++ * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
++ * a Host: header, and the server MUST respond with 400 if it doesn't.
++ */
++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00569)
++ "client sent HTTP/1.1 request without hostname "
++ "(see RFC2616 section 14.23): %s", r->uri);
++ r->status = HTTP_BAD_REQUEST;
++ return 0;
++ }
++
++ if (((expect = apr_table_get(r->headers_in, "Expect")) != NULL)
++ && (expect[0] != '\0')) {
++ /*
++ * The Expect header field was added to HTTP/1.1 after RFC 2068
++ * as a means to signal when a 100 response is desired and,
++ * unfortunately, to signal a poor man's mandatory extension that
++ * the server must understand or return 417 Expectation Failed.
++ */
++ if (ap_cstr_casecmp(expect, "100-continue") == 0) {
++ r->expecting_100 = 1;
++ }
++ else {
++ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00570)
++ "client sent an unrecognized expectation value "
++ "of Expect: %s", expect);
++ r->status = HTTP_EXPECTATION_FAILED;
++ return 0;
++ }
++ }
++
++ return 1;
++}
++
+ static int table_do_fn_check_lengths(void *r_, const char *key,
+ const char *value)
+ {
+@@ -1265,16 +1358,10 @@
+ apr_brigade_destroy(tmp_bb);
+ }
+
+-request_rec *ap_read_request(conn_rec *conn)
++AP_DECLARE(request_rec *) ap_create_request(conn_rec *conn)
+ {
+ request_rec *r;
+ apr_pool_t *p;
+- const char *expect;
+- int access_status;
+- apr_bucket_brigade *tmp_bb;
+- apr_socket_t *csd;
+- apr_interval_time_t cur_timeout;
+-
+
+ apr_pool_create(&p, conn->pool);
+ apr_pool_tag(p, "request");
+@@ -1313,6 +1400,7 @@
+ r->read_body = REQUEST_NO_BODY;
+
+ r->status = HTTP_OK; /* Until further notice */
++ r->header_only = 0;
+ r->the_request = NULL;
+
+ /* Begin by presuming any module can make its own path_info assumptions,
+@@ -1323,12 +1411,33 @@
+ r->useragent_addr = conn->client_addr;
+ r->useragent_ip = conn->client_ip;
+
++ return r;
++}
++
++/* Apply the server's timeout/config to the connection/request. */
++static void apply_server_config(request_rec *r)
++{
++ apr_socket_t *csd;
++
++ csd = ap_get_conn_socket(r->connection);
++ apr_socket_timeout_set(csd, r->server->timeout);
++
++ r->per_dir_config = r->server->lookup_defaults;
++}
++
++request_rec *ap_read_request(conn_rec *conn)
++{
++ int access_status;
++ apr_bucket_brigade *tmp_bb;
++
++ request_rec *r = ap_create_request(conn);
+ tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+
+ ap_run_pre_read_request(r, conn);
+
+ /* Get the request... */
+- if (!read_request_line(r, tmp_bb)) {
++ if (!read_request_line(r, tmp_bb) || !ap_parse_request_line(r)) {
++ apr_brigade_cleanup(tmp_bb);
+ switch (r->status) {
+ case HTTP_REQUEST_URI_TOO_LARGE:
+ case HTTP_BAD_REQUEST:
+@@ -1344,49 +1453,38 @@
+ "request failed: malformed request line");
+ }
+ access_status = r->status;
+- r->status = HTTP_OK;
+- ap_die(access_status, r);
+- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
+- ap_run_log_transaction(r);
+- r = NULL;
+- apr_brigade_destroy(tmp_bb);
+- goto traceout;
++ goto die_unusable_input;
++
+ case HTTP_REQUEST_TIME_OUT:
++ /* Just log, no further action on this connection. */
+ ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, NULL);
+ if (!r->connection->keepalives)
+ ap_run_log_transaction(r);
+- apr_brigade_destroy(tmp_bb);
+- goto traceout;
+- default:
+- apr_brigade_destroy(tmp_bb);
+- r = NULL;
+- goto traceout;
++ break;
+ }
++ /* Not worth dying with. */
++ conn->keepalive = AP_CONN_CLOSE;
++ apr_pool_destroy(r->pool);
++ goto ignore;
+ }
++ apr_brigade_cleanup(tmp_bb);
+
+ /* We may have been in keep_alive_timeout mode, so toggle back
+ * to the normal timeout mode as we fetch the header lines,
+ * as necessary.
+ */
+- csd = ap_get_conn_socket(conn);
+- apr_socket_timeout_get(csd, &cur_timeout);
+- if (cur_timeout != conn->base_server->timeout) {
+- apr_socket_timeout_set(csd, conn->base_server->timeout);
+- cur_timeout = conn->base_server->timeout;
+- }
++ apply_server_config(r);
+
+ if (!r->assbackwards) {
+ const char *tenc;
+
+ ap_get_mime_headers_core(r, tmp_bb);
++ apr_brigade_cleanup(tmp_bb);
+ if (r->status != HTTP_OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00567)
+ "request failed: error reading the headers");
+- ap_send_error_response(r, 0);
+- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
+- ap_run_log_transaction(r);
+- apr_brigade_destroy(tmp_bb);
+- goto traceout;
++ access_status = r->status;
++ goto die_unusable_input;
+ }
+
+ tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
+@@ -1402,13 +1500,8 @@
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02539)
+ "client sent unknown Transfer-Encoding "
+ "(%s): %s", tenc, r->uri);
+- r->status = HTTP_BAD_REQUEST;
+- conn->keepalive = AP_CONN_CLOSE;
+- ap_send_error_response(r, 0);
+- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
+- ap_run_log_transaction(r);
+- apr_brigade_destroy(tmp_bb);
+- goto traceout;
++ access_status = HTTP_BAD_REQUEST;
++ goto die_unusable_input;
+ }
+
+ /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23
+@@ -1421,88 +1514,81 @@
+ }
+ }
+
+- apr_brigade_destroy(tmp_bb);
+-
+- /* update what we think the virtual host is based on the headers we've
+- * now read. may update status.
+- */
+- ap_update_vhost_from_headers(r);
+- access_status = r->status;
+-
+- /* Toggle to the Host:-based vhost's timeout mode to fetch the
+- * request body and send the response body, if needed.
+- */
+- if (cur_timeout != r->server->timeout) {
+- apr_socket_timeout_set(csd, r->server->timeout);
+- cur_timeout = r->server->timeout;
+- }
+-
+- /* we may have switched to another server */
+- r->per_dir_config = r->server->lookup_defaults;
+-
+- if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1, 1)))
+- || ((r->proto_num == HTTP_VERSION(1, 1))
+- && !apr_table_get(r->headers_in, "Host"))) {
+- /*
+- * Client sent us an HTTP/1.1 or later request without telling us the
+- * hostname, either with a full URL or a Host: header. We therefore
+- * need to (as per the 1.1 spec) send an error. As a special case,
+- * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
+- * a Host: header, and the server MUST respond with 400 if it doesn't.
+- */
+- access_status = HTTP_BAD_REQUEST;
+- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00569)
+- "client sent HTTP/1.1 request without hostname "
+- "(see RFC2616 section 14.23): %s", r->uri);
+- }
+-
+ /*
+ * Add the HTTP_IN filter here to ensure that ap_discard_request_body
+ * called by ap_die and by ap_send_error_response works correctly on
+ * status codes that do not cause the connection to be dropped and
+ * in situations where the connection should be kept alive.
+ */
+-
+ ap_add_input_filter_handle(ap_http_input_filter_handle,
+ NULL, r, r->connection);
+
+- if (access_status != HTTP_OK
+- || (access_status = ap_post_read_request(r))) {
+- ap_die(access_status, r);
+- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
+- ap_run_log_transaction(r);
+- r = NULL;
+- goto traceout;
++ /* Validate Host/Expect headers and select vhost. */
++ if (!ap_check_request_header(r)) {
++ /* we may have switched to another server still */
++ apply_server_config(r);
++ access_status = r->status;
++ goto die_before_hooks;
+ }
+
+- if (((expect = apr_table_get(r->headers_in, "Expect")) != NULL)
+- && (expect[0] != '\0')) {
+- /*
+- * The Expect header field was added to HTTP/1.1 after RFC 2068
+- * as a means to signal when a 100 response is desired and,
+- * unfortunately, to signal a poor man's mandatory extension that
+- * the server must understand or return 417 Expectation Failed.
+- */
+- if (strcasecmp(expect, "100-continue") == 0) {
+- r->expecting_100 = 1;
+- }
+- else {
+- r->status = HTTP_EXPECTATION_FAILED;
+- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00570)
+- "client sent an unrecognized expectation value of "
+- "Expect: %s", expect);
+- ap_send_error_response(r, 0);
+- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
+- ap_run_log_transaction(r);
+- goto traceout;
+- }
++ /* we may have switched to another server */
++ apply_server_config(r);
++
++ if ((access_status = ap_run_post_read_request(r))) {
++ goto die;
+ }
+
+- AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method, (char *)r->uri, (char *)r->server->defn_name, r->status);
++ AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method,
++ (char *)r->uri, (char *)r->server->defn_name,
++ r->status);
++
+ return r;
+- traceout:
++
++ /* Everything falls through on failure */
++
++die_unusable_input:
++ /* Input filters are in an undeterminate state, cleanup (including
++ * CORE_IN's socket) such that any further attempt to read is EOF.
++ */
++ {
++ ap_filter_t *f = conn->input_filters;
++ while (f) {
++ if (f->frec == ap_core_input_filter_handle) {
++ core_net_rec *net = f->ctx;
++ apr_brigade_cleanup(net->in_ctx->b);
++ break;
++ }
++ ap_remove_input_filter(f);
++ f = f->next;
++ }
++ conn->input_filters = r->input_filters = f;
++ conn->keepalive = AP_CONN_CLOSE;
++ }
++
++die_before_hooks:
++ /* First call to ap_die() (non recursive) */
++ r->status = HTTP_OK;
++
++die:
++ ap_die(access_status, r);
++
++ /* ap_die() sent the response through the output filters, we must now
++ * end the request with an EOR bucket for stream/pipeline accounting.
++ */
++ {
++ apr_bucket_brigade *eor_bb;
++ eor_bb = apr_brigade_create(conn->pool, conn->bucket_alloc);
++ APR_BRIGADE_INSERT_TAIL(eor_bb,
++ ap_bucket_eor_create(conn->bucket_alloc, r));
++ ap_pass_brigade(conn->output_filters, eor_bb);
++ apr_brigade_cleanup(eor_bb);
++ }
++
++ignore:
++ r = NULL;
++
+ AP_READ_REQUEST_FAILURE((uintptr_t)r);
+- return r;
++ return NULL;
+ }
+
+ AP_DECLARE(int) ap_post_read_request(request_rec *r)
+--- a/server/vhost.c
++++ b/server/vhost.c
+@@ -34,6 +34,7 @@
+ #include "http_vhost.h"
+ #include "http_protocol.h"
+ #include "http_core.h"
++#include "http_main.h"
+
+ #if APR_HAVE_ARPA_INET_H
+ #include <arpa/inet.h>
+@@ -973,7 +974,13 @@
+ }
+
+
+-static void check_hostalias(request_rec *r)
++/*
++ * Updates r->server from ServerName/ServerAlias. Per the interaction
++ * of ip and name-based vhosts, it only looks in the best match from the
++ * connection-level ip-based matching.
++ * Returns HTTP_BAD_REQUEST if there was no match.
++ */
++static int update_server_from_aliases(request_rec *r)
+ {
+ /*
+ * Even if the request has a Host: header containing a port we ignore
+@@ -1050,11 +1057,18 @@
+ goto found;
+ }
+
+- return;
++ if (!r->connection->vhost_lookup_data) {
++ if (matches_aliases(r->server, host)) {
++ s = r->server;
++ goto found;
++ }
++ }
++ return HTTP_BAD_REQUEST;
+
+ found:
+ /* s is the first matching server, we're done */
+ r->server = s;
++ return HTTP_OK;
+ }
+
+
+@@ -1071,7 +1085,7 @@
+ * This is in conjunction with the ServerPath code in http_core, so we
+ * get the right host attached to a non- Host-sending request.
+ *
+- * See the comment in check_hostalias about how each vhost can be
++ * See the comment in update_server_from_aliases about how each vhost can be
+ * listed multiple times.
+ */
+
+@@ -1135,10 +1149,16 @@
+
+ AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r)
+ {
++ ap_update_vhost_from_headers_ex(r, 0);
++}
++
++AP_DECLARE(int) ap_update_vhost_from_headers_ex(request_rec *r, int require_match)
++{
+ core_server_config *conf = ap_get_core_module_config(r->server->module_config);
+ const char *host_header = apr_table_get(r->headers_in, "Host");
+ int is_v6literal = 0;
+ int have_hostname_from_url = 0;
++ int rc = HTTP_OK;
+
+ if (r->hostname) {
+ /*
+@@ -1151,8 +1171,8 @@
+ else if (host_header != NULL) {
+ is_v6literal = fix_hostname(r, host_header, conf->http_conformance);
+ }
+- if (r->status != HTTP_OK)
+- return;
++ if (!require_match && r->status != HTTP_OK)
++ return HTTP_OK;
+
+ if (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE) {
+ /*
+@@ -1173,10 +1193,16 @@
+ /* check if we tucked away a name_chain */
+ if (r->connection->vhost_lookup_data) {
+ if (r->hostname)
+- check_hostalias(r);
++ rc = update_server_from_aliases(r);
+ else
+ check_serverpath(r);
+ }
++ else if (require_match && r->hostname) {
++ /* check the base server config */
++ rc = update_server_from_aliases(r);
++ }
++
++ return rc;
+ }
+
+ /**
diff --git a/debian/patches/CVE-2022-36760.patch b/debian/patches/CVE-2022-36760.patch
new file mode 100644
index 0000000..ebeefa3
--- /dev/null
+++ b/debian/patches/CVE-2022-36760.patch
@@ -0,0 +1,27 @@
+From d93e61e3e9622bacff746772cb9c97fdcaed8baf Mon Sep 17 00:00:00 2001
+From: Eric Covener <covener@apache.org>
+Date: Tue, 10 Jan 2023 13:20:55 +0000
+Subject: [PATCH] Merge r1906540 from trunk:
+
+cleanup on error
+
+
+Reviewed By: rpluem, gbechis, covener
+
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1906542 13f79535-47bb-0310-9956-ffa450edef68
+---
+ modules/proxy/mod_proxy_ajp.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/modules/proxy/mod_proxy_ajp.c
++++ b/modules/proxy/mod_proxy_ajp.c
+@@ -255,6 +255,8 @@
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10396)
+ "%s Transfer-Encoding is not supported",
+ tenc);
++ /* We had a failure: Close connection to backend */
++ conn->close = 1;
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ } else {
diff --git a/debian/patches/CVE-2022-37436.patch b/debian/patches/CVE-2022-37436.patch
new file mode 100644
index 0000000..a123959
--- /dev/null
+++ b/debian/patches/CVE-2022-37436.patch
@@ -0,0 +1,125 @@
+From 8b6d55f6a047acf62675e32606b037f5eea8ccc7 Mon Sep 17 00:00:00 2001
+From: Eric Covener <covener@apache.org>
+Date: Tue, 10 Jan 2023 13:20:09 +0000
+Subject: [PATCH] Merge r1906539 from trunk:
+
+fail on bad header
+
+Submitted By: covener
+Reviewed By: covener, rpluem, gbechis
+
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1906541 13f79535-47bb-0310-9956-ffa450edef68
+---
+ modules/proxy/mod_proxy_http.c | 46 ++++++++++++++++++++--------------
+ server/protocol.c | 2 ++
+ 2 files changed, 29 insertions(+), 19 deletions(-)
+
+--- a/modules/proxy/mod_proxy_http.c
++++ b/modules/proxy/mod_proxy_http.c
+@@ -1011,7 +1011,7 @@
+ * any sense at all, since we depend on buffer still containing
+ * what was read by ap_getline() upon return.
+ */
+-static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
++static apr_status_t ap_proxy_read_headers(request_rec *r, request_rec *rr,
+ char *buffer, int size,
+ conn_rec *c, int *pread_len)
+ {
+@@ -1043,19 +1043,26 @@
+ rc = ap_proxygetline(tmp_bb, buffer, size, rr,
+ AP_GETLINE_FOLD | AP_GETLINE_NOSPC_EOL, &len);
+
+- if (len <= 0)
+- break;
+
+- if (APR_STATUS_IS_ENOSPC(rc)) {
+- /* The header could not fit in the provided buffer, warn.
+- * XXX: falls through with the truncated header, 5xx instead?
+- */
+- int trunc = (len > 128 ? 128 : len) / 2;
+- ap_log_rerror(APLOG_MARK, APLOG_WARNING, rc, r, APLOGNO(10124)
+- "header size is over the limit allowed by "
+- "ResponseFieldSize (%d bytes). "
+- "Bad response header: '%.*s[...]%s'",
+- size, trunc, buffer, buffer + len - trunc);
++ if (rc != APR_SUCCESS) {
++ if (APR_STATUS_IS_ENOSPC(rc)) {
++ int trunc = (len > 128 ? 128 : len) / 2;
++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, rc, r, APLOGNO(10124)
++ "header size is over the limit allowed by "
++ "ResponseFieldSize (%d bytes). "
++ "Bad response header: '%.*s[...]%s'",
++ size, trunc, buffer, buffer + len - trunc);
++ }
++ else {
++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, rc, r, APLOGNO(10404)
++ "Error reading headers from backend");
++ }
++ r->headers_out = NULL;
++ return rc;
++ }
++
++ if (len <= 0) {
++ break;
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, "%s", buffer);
+@@ -1078,7 +1085,7 @@
+ if (psc->badopt == bad_error) {
+ /* Nope, it wasn't even an extra HTTP header. Give up. */
+ r->headers_out = NULL;
+- return;
++ return APR_EINVAL;
+ }
+ else if (psc->badopt == bad_body) {
+ /* if we've already started loading headers_out, then
+@@ -1092,13 +1099,13 @@
+ "in headers returned by %s (%s)",
+ r->uri, r->method);
+ *pread_len = len;
+- return;
++ return APR_SUCCESS;
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01099)
+ "No HTTP headers returned by %s (%s)",
+ r->uri, r->method);
+- return;
++ return APR_SUCCESS;
+ }
+ }
+ }
+@@ -1128,6 +1135,7 @@
+ process_proxy_header(r, dconf, buffer, value);
+ saw_headers = 1;
+ }
++ return APR_SUCCESS;
+ }
+
+
+@@ -1398,10 +1406,10 @@
+ "Set-Cookie", NULL);
+
+ /* shove the headers direct into r->headers_out */
+- ap_proxy_read_headers(r, backend->r, buffer, response_field_size, origin,
+- &pread_len);
++ rc = ap_proxy_read_headers(r, backend->r, buffer, response_field_size,
++ origin, &pread_len);
+
+- if (r->headers_out == NULL) {
++ if (rc != APR_SUCCESS || r->headers_out == NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01106)
+ "bad HTTP/%d.%d header returned by %s (%s)",
+ major, minor, r->uri, r->method);
+--- a/server/protocol.c
++++ b/server/protocol.c
+@@ -508,6 +508,8 @@
+ /* PR#43039: We shouldn't accept NULL bytes within the line */
+ bytes_handled = strlen(*s);
+ if (bytes_handled < *read) {
++ ap_log_data(APLOG_MARK, APLOG_DEBUG, ap_server_conf,
++ "NULL bytes in header", *s, *read, 0);
+ *read = bytes_handled;
+ if (rv == APR_SUCCESS) {
+ rv = APR_EINVAL;
diff --git a/debian/patches/series b/debian/patches/series
index 5ac5730..c430013 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -49,3 +49,7 @@ CVE-2022-29404.patch
CVE-2022-30522.patch
CVE-2022-30556.patch
CVE-2022-31813.patch
+CVE-2006-20001.patch
+CVE-2022-36760.patch
+CVE-2022-37436.patch
+CVE-2021-33193.patch
diff --git a/debian/perl-framework/t/security/CVE-2019-0215.t b/debian/perl-framework/t/security/CVE-2019-0215.t
new file mode 100644
index 0000000..978c1ef
--- /dev/null
+++ b/debian/perl-framework/t/security/CVE-2019-0215.t
@@ -0,0 +1,47 @@
+use strict;
+use warnings FATAL => 'all';
+
+use Apache::Test;
+use Apache::TestUtil;
+use Apache::TestRequest;
+
+my $vars = Apache::Test::vars();
+
+plan tests => 2, need $vars->{ssl_module_name}, need_lwp,
+ qw(LWP::Protocol::https);
+
+my $r;
+
+Apache::TestRequest::user_agent(ssl_opts => {SSL_version => 'TLSv13'});
+Apache::TestRequest::scheme('https');
+Apache::TestRequest::module('ssl_optional_cc');
+
+$r = GET "/require/none/";
+my $tls13_works = $r->is_success;
+
+# Forget the above user agent settings, start fresh
+Apache::TestRequest::user_agent(reset => 1);
+
+# If TLS 1.3 worked, run the tests using it and expect 403.
+# Older TLS versions seem to show the TLS alert client side as a 500.
+my $expected_status;
+if ($tls13_works) {
+ Apache::TestRequest::user_agent(ssl_opts => {SSL_version => 'TLSv13'});
+ $expected_status = 403;
+ t_debug "Using TLSv13, expecting status 403";
+} else {
+ t_debug "Using TLS before TLSv13, expecting status 500";
+ $expected_status = 500;
+}
+
+Apache::TestRequest::user_agent_keepalive(1);
+Apache::TestRequest::scheme('https');
+Apache::TestRequest::module('ssl_optional_cc');
+
+$r = GET "/require/any/";
+
+ok t_cmp($r->code, $expected_status, "first access denied without client cert");
+
+$r = GET "/require/any/";
+
+ok t_cmp($r->code, $expected_status, "second access denied without client cert");
diff --git a/debian/perl-framework/t/security/CVE-2020-1927.t b/debian/perl-framework/t/security/CVE-2020-1927.t
new file mode 100644
index 0000000..523feb6
--- /dev/null
+++ b/debian/perl-framework/t/security/CVE-2020-1927.t
@@ -0,0 +1,60 @@
+use strict;
+use warnings FATAL => 'all';
+
+use Apache::Test;
+use Apache::TestRequest;
+use Apache::TestUtil;
+use MIME::Base64;
+use Data::Dumper;
+use HTTP::Response;
+use Socket;
+
+plan tests => 1, need_min_apache_version('2.4.42');
+
+my $sock = Apache::TestRequest::vhost_socket("core");
+if (!$sock) {
+ print "# failed to connect\n";
+ ok(0);
+ next;
+}
+
+my $req = sprintf "GET /CVE-2020-1927/%%0D%%0Ahttp://127.0.0.1/ HTTP/1.1\r\nHost: merge-disabled\r\nConnection: close\r\n\r\n";
+print "# SENDING to " . peer($sock) . "\n# $req\n";
+$sock->print("$req");
+$sock->flush();
+sleep(0.1);
+$req = escape($req);
+print "# SENDING to " . peer($sock) . "\n# $req\n";
+
+my $response_data = "";
+my $buf;
+while ($sock->read($buf, 10000) > 0) {
+ $response_data .= $buf;
+}
+my $response = HTTP::Response->parse($response_data);
+if (! defined $response) {
+ die "HTTP::Response->parse failed";
+}
+ok t_cmp($response->code, 404, "regex didn't match and redirect");
+
+sub escape
+{
+ my $in = shift;
+ $in =~ s{\\}{\\\\}g;
+ $in =~ s{\r}{\\r}g;
+ $in =~ s{\n}{\\n}g;
+ $in =~ s{\t}{\\t}g;
+ $in =~ s{([\x00-\x1f])}{sprintf("\\x%02x", ord($1))}ge;
+ return $in;
+}
+
+sub peer
+{
+ my $sock = shift;
+ my $hersockaddr = getpeername($sock);
+ return "<disconnected>" if !$hersockaddr;
+ my ($port, $iaddr) = sockaddr_in($hersockaddr);
+ my $herhostname = gethostbyaddr($iaddr, AF_INET);
+ my $herstraddr = inet_ntoa($iaddr);
+ return "$herstraddr:$port";
+}