diff -Nru apache2-2.4.41/debian/changelog apache2-2.4.41/debian/changelog
--- apache2-2.4.41/debian/changelog 2021-06-17 18:27:53.000000000 +0000
+++ apache2-2.4.41/debian/changelog 2021-09-23 16:58:57.000000000 +0000
@@ -1,3 +1,52 @@
+apache2 (2.4.41-4ubuntu3.5) focal-security; urgency=medium
+
+ * SECURITY UPDATE: request splitting over HTTP/2
+ - debian/patches/CVE-2021-33193-pre1.patch: process early errors via a
+ dummy HTTP/1.1 request as well in modules/http2/h2.h,
+ modules/http2/h2_request.c, modules/http2/h2_session.c,
+ modules/http2/h2_stream.c.
+ - debian/patches/CVE-2021-33193-pre2.patch: sync with github standalone
+ version 1.15.17 in modules/http2/h2_bucket_beam.c,
+ modules/http2/h2_config.c, modules/http2/h2_config.h,
+ modules/http2/h2_h2.c, modules/http2/h2_headers.c,
+ modules/http2/h2_headers.h, modules/http2/h2_mplx.c,
+ modules/http2/h2_request.c, modules/http2/h2_stream.h,
+ modules/http2/h2_task.c, modules/http2/h2_task.h,
+ modules/http2/h2_version.h.
+ - debian/patches/CVE-2021-33193.patch: refactor request parsing in
+ include/ap_mmn.h, include/http_core.h, include/http_protocol.h,
+ include/http_vhost.h, modules/http2/h2_request.c, server/core.c,
+ server/core_filters.c, server/protocol.c, server/vhost.c.
+ - CVE-2021-33193
+ * SECURITY UPDATE: NULL deref via malformed requests
+ - debian/patches/CVE-2021-34798.patch: add NULL check in
+ server/scoreboard.c.
+ - CVE-2021-34798
+ * SECURITY UPDATE: DoS in mod_proxy_uwsgi
+ - debian/patches/CVE-2021-36160.patch: fix PATH_INFO setting for
+ generic worker in modules/proxy/mod_proxy_uwsgi.c.
+ - CVE-2021-36160
+ * SECURITY UPDATE: buffer overflow in ap_escape_quotes
+ - debian/patches/CVE-2021-39275.patch: fix ap_escape_quotes
+ substitution logic in server/util.c.
+ - CVE-2021-39275
+ * SECURITY UPDATE: arbitrary origin server via crafted request uri-path
+ - debian/patches/CVE-2021-40438-pre1.patch: faster unix socket path
+ parsing in the "proxy:" URL in modules/proxy/mod_proxy.c,
+ modules/proxy/proxy_util.c.
+ - debian/patches/CVE-2021-40438.patch: add sanity checks on the
+ configured UDS path in modules/proxy/proxy_util.c.
+ - CVE-2021-40438
+
+ -- Marc Deslauriers Thu, 23 Sep 2021 12:58:57 -0400
+
+apache2 (2.4.41-4ubuntu3.4) focal; urgency=medium
+
+ * d/p/lp-1930430-Backport-r1865740.patch: fix OCSP in proxy mode
+ (LP: #1930430)
+
+ -- Christian Ehrhardt Mon, 05 Jul 2021 09:16:56 +0200
+
apache2 (2.4.41-4ubuntu3.3) focal-security; urgency=medium
* SECURITY UPDATE: mod_proxy_http denial of service.
diff -Nru apache2-2.4.41/debian/patches/CVE-2021-33193.patch apache2-2.4.41/debian/patches/CVE-2021-33193.patch
--- apache2-2.4.41/debian/patches/CVE-2021-33193.patch 1970-01-01 00:00:00.000000000 +0000
+++ apache2-2.4.41/debian/patches/CVE-2021-33193.patch 2021-09-23 16:58:57.000000000 +0000
@@ -0,0 +1,918 @@
+Backport of:
+
+From ecebcc035ccd8d0e2984fe41420d9e944f456b3c Mon Sep 17 00:00:00 2001
+From: Stefan Eissing
+Date: Thu, 27 May 2021 13:08:21 +0000
+Subject: [PATCH] Merged
+ r1734009,r1734231,r1734281,r1838055,r1838079,r1840229,r1876664,r1876674,r1876784,r1879078,r1881620,r1887311,r1888871
+ from trunk:
+
+ *) core: Split ap_create_request() from ap_read_request(). [Graham Leggett]
+
+ *) core, h2: common ap_parse_request_line() and ap_check_request_header()
+ code. [Yann Ylavic]
+
+ *) core: Add StrictHostCheck to allow unconfigured hostnames to be
+ rejected. [Eric Covener]
+
+
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1890245 13f79535-47bb-0310-9956-ffa450edef68
+---
+ CHANGES | 8 +
+ docs/manual/mod/core.xml | 36 ++++
+ include/ap_mmn.h | 5 +-
+ include/http_core.h | 6 +
+ include/http_protocol.h | 21 +++
+ include/http_vhost.h | 13 ++
+ modules/http2/h2_request.c | 108 +-----------
+ server/core.c | 14 +-
+ server/core_filters.c | 5 -
+ server/protocol.c | 328 +++++++++++++++++++++++--------------
+ server/vhost.c | 38 ++++-
+ 11 files changed, 337 insertions(+), 245 deletions(-)
+
+#diff --git a/CHANGES b/CHANGES
+#index 7256c1db243..484877551ed 100644
+#--- a/CHANGES
+#+++ b/CHANGES
+#@@ -1,6 +1,14 @@
+# -*- coding: utf-8 -*-
+# Changes with Apache 2.4.49
+#
+#+ *) core: Split ap_create_request() from ap_read_request(). [Graham Leggett]
+#+
+#+ *) core, h2: common ap_parse_request_line() and ap_check_request_header()
+#+ code. [Yann Ylavic]
+#+
+#+ *) core: Add StrictHostCheck to allow unconfigured hostnames to be
+#+ rejected. [Eric Covener]
+#+
+# Changes with Apache 2.4.48
+#
+# *) mod_proxy_wstunnel: Add ProxyWebsocketFallbackToProxyHttp to opt-out the
+#diff --git a/docs/manual/mod/core.xml b/docs/manual/mod/core.xml
+#index 6b9f1f03859..b576c532fce 100644
+#--- a/docs/manual/mod/core.xml
+#+++ b/docs/manual/mod/core.xml
+#@@ -5206,6 +5206,42 @@ recognized methods to modules.
+# AllowMethods
+#
+#
+#+
+#+StrictHostCheck
+#+Controls whether the server requires the requested hostname be
+#+ listed enumerated in the virtual host handling the request
+#+
+#+StrictHostCheck ON|OFF
+#+StrictHostCheck OFF
+#+server configvirtual host
+#+
+#+Added in 2.5.1
+#+
+#+
+#+ By default, the server will respond to requests for any hostname,
+#+ including requests addressed to unexpected or unconfigured hostnames.
+#+ While this is convenient, it is sometimes desirable to limit what hostnames
+#+ a backend application handles since it will often generate self-referential
+#+ responses.
+#+
+#+ By setting StrictHostCheck to ON,
+#+ the server will return an HTTP 400 error if the requested hostname
+#+ hasn't been explicitly listed by either ServerName or ServerAlias in the virtual host that best matches the
+#+ details of the incoming connection.
+#+
+#+ This directive also allows matching of the requested hostname to hostnames
+#+ specified within the opening VirtualHost
+#+ tag, which is a relatively obscure configuration mechanism that acts like
+#+ additional ServerAlias entries.
+#+
+#+ This directive has no affect in non-default virtual hosts. The value
+#+ inherited from the global server configuration, or the default virtualhost
+#+ for the ip:port the underlying connection, determine the effective value.
+#+
+#+
+#+
+#
+# MergeSlashes
+# Controls whether the server merges consecutive slashes in URLs.
+--- a/include/http_core.h
++++ b/include/http_core.h
+@@ -741,6 +741,7 @@ typedef struct {
+ #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 @@ AP_DECLARE(void) ap_set_server_protocol(
+ 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 @@ AP_DECLARE_DATA extern ap_filter_rec_t *
+ */
+
+ /**
++ * 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 @@ AP_DECLARE_DATA extern ap_filter_rec_t *
+ 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_given_i
+ 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/modules/http2/h2_request.c
++++ b/modules/http2/h2_request.c
+@@ -207,75 +207,12 @@ h2_request *h2_request_clone(apr_pool_t
+ return dst;
+ }
+
+-#if !AP_MODULE_MAGIC_AT_LEAST(20150222, 13)
+-static request_rec *my_ap_create_request(conn_rec *c)
+-{
+- apr_pool_t *p;
+- request_rec *r;
+-
+- apr_pool_create(&p, c->pool);
+- apr_pool_tag(p, "request");
+- r = apr_pcalloc(p, sizeof(request_rec));
+- AP_READ_REQUEST_ENTRY((intptr_t)r, (uintptr_t)c);
+- r->pool = p;
+- r->connection = c;
+- r->server = c->base_server;
+-
+- r->user = NULL;
+- r->ap_auth_type = NULL;
+-
+- r->allowed_methods = ap_make_method_list(p, 2);
+-
+- r->headers_in = apr_table_make(r->pool, 5);
+- r->trailers_in = apr_table_make(r->pool, 5);
+- r->subprocess_env = apr_table_make(r->pool, 25);
+- r->headers_out = apr_table_make(r->pool, 12);
+- r->err_headers_out = apr_table_make(r->pool, 5);
+- r->trailers_out = apr_table_make(r->pool, 5);
+- r->notes = apr_table_make(r->pool, 5);
+-
+- r->request_config = ap_create_request_config(r->pool);
+- /* Must be set before we run create request hook */
+-
+- r->proto_output_filters = c->output_filters;
+- r->output_filters = r->proto_output_filters;
+- r->proto_input_filters = c->input_filters;
+- r->input_filters = r->proto_input_filters;
+- ap_run_create_request(r);
+- r->per_dir_config = r->server->lookup_defaults;
+-
+- r->sent_bodyct = 0; /* bytect isn't for body */
+-
+- r->read_length = 0;
+- 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,
+- * until some module interjects and changes the value.
+- */
+- r->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
+-
+- r->useragent_addr = c->client_addr;
+- r->useragent_ip = c->client_ip;
+-
+- return r;
+-}
+-#endif
+-
+ request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
+ {
+- int access_status;
++ int access_status = HTTP_OK;
+
+-#if AP_MODULE_MAGIC_AT_LEAST(20150222, 13)
+ request_rec *r = ap_create_request(c);
+-#else
+- request_rec *r = my_ap_create_request(c);
+-#endif
+
+-#if AP_MODULE_MAGIC_AT_LEAST(20200331, 3)
+ ap_run_pre_read_request(r, c);
+
+ /* Time to populate r with the data we have. */
+@@ -304,49 +241,6 @@ request_rec *h2_request_create_rec(const
+ r->status = HTTP_OK;
+ goto die;
+ }
+-#else
+- {
+- const char *s;
+-
+- r->headers_in = apr_table_clone(r->pool, req->headers);
+- ap_run_pre_read_request(r, c);
+-
+- /* Time to populate r with the data we have. */
+- r->request_time = req->request_time;
+- r->method = apr_pstrdup(r->pool, req->method);
+- /* Provide quick information about the request method as soon as known */
+- r->method_number = ap_method_number_of(r->method);
+- if (r->method_number == M_GET && r->method[0] == 'H') {
+- r->header_only = 1;
+- }
+- ap_parse_uri(r, req->path ? req->path : "");
+- r->protocol = (char*)"HTTP/2.0";
+- r->proto_num = HTTP_VERSION(2, 0);
+- r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
+- r->method, req->path ? req->path : "");
+-
+- /* Start with r->hostname = NULL, ap_check_request_header() will get it
+- * form Host: header, otherwise we get complains about port numbers.
+- */
+- r->hostname = NULL;
+- ap_update_vhost_from_headers(r);
+-
+- /* we may have switched to another server */
+- r->per_dir_config = r->server->lookup_defaults;
+-
+- s = apr_table_get(r->headers_in, "Expect");
+- if (s && s[0]) {
+- if (ap_cstr_casecmp(s, "100-continue") == 0) {
+- r->expecting_100 = 1;
+- }
+- else {
+- r->status = HTTP_EXPECTATION_FAILED;
+- access_status = r->status;
+- goto die;
+- }
+- }
+- }
+-#endif
+
+ /* we may have switched to another server */
+ r->per_dir_config = r->server->lookup_defaults;
+--- a/server/core.c
++++ b/server/core.c
+@@ -492,6 +492,8 @@ static void *create_core_server_config(a
+ conf->protocols_honor_order = -1;
+ conf->merge_slashes = AP_CORE_CONFIG_UNSET;
+
++ conf->strict_host_check= AP_CORE_CONFIG_UNSET;
++
+ return (void *)conf;
+ }
+
+@@ -558,6 +560,12 @@ static void *merge_core_server_configs(a
+ 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;
+ }
+
+@@ -4510,6 +4518,10 @@ AP_INIT_FLAG("QualifyRedirectURL", set_q
+ "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"),
+@@ -5483,4 +5495,3 @@ AP_DECLARE_MODULE(core) = {
+ core_cmds, /* command apr_table_t */
+ register_hooks /* register hooks */
+ };
+-
+--- a/server/core_filters.c
++++ b/server/core_filters.c
+@@ -84,11 +84,6 @@ struct core_output_filter_ctx {
+ 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
+@@ -609,8 +609,15 @@ AP_CORE_DECLARE(void) ap_parse_uri(reque
+ }
+
+ 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.
+@@ -645,13 +652,6 @@ static int field_name_len(const char *fi
+
+ 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);
+@@ -711,6 +711,20 @@ static int read_request_line(request_rec
+ }
+
+ 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;
+
+@@ -742,7 +756,6 @@ static int read_request_line(request_rec
+ 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])
+@@ -773,7 +786,6 @@ static int read_request_line(request_rec
+ /* 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])
+@@ -866,6 +878,14 @@ rrl_done:
+ 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) {
+@@ -973,6 +993,79 @@ rrl_failed:
+ 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)
+ {
+@@ -1256,16 +1349,10 @@ AP_DECLARE(void) ap_get_mime_headers(req
+ 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");
+@@ -1304,6 +1391,7 @@ request_rec *ap_read_request(conn_rec *c
+ 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,
+@@ -1314,12 +1402,34 @@ request_rec *ap_read_request(conn_rec *c
+ 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:
+@@ -1335,49 +1445,38 @@ request_rec *ap_read_request(conn_rec *c
+ "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");
+@@ -1393,13 +1492,8 @@ request_rec *ap_read_request(conn_rec *c
+ 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
+@@ -1412,88 +1506,79 @@ request_rec *ap_read_request(conn_rec *c
+ }
+ }
+
+- 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_run_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;
+ }
+
+ /* if a request with a body creates a subrequest, remove original request's
+--- 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
+@@ -973,7 +974,13 @@ AP_DECLARE(int) ap_matches_request_vhost
+ }
+
+
+-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
+@@ -1051,11 +1058,18 @@ static void check_hostalias(request_rec
+ 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;
+ }
+
+
+@@ -1072,7 +1086,7 @@ static void check_serverpath(request_rec
+ * 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.
+ */
+
+@@ -1136,10 +1150,16 @@ static APR_INLINE const char *construct_
+
+ 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) {
+ /*
+@@ -1152,8 +1172,8 @@ AP_DECLARE(void) ap_update_vhost_from_he
+ 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) {
+ /*
+@@ -1174,10 +1194,16 @@ AP_DECLARE(void) ap_update_vhost_from_he
+ /* 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 -Nru apache2-2.4.41/debian/patches/CVE-2021-33193-pre1.patch apache2-2.4.41/debian/patches/CVE-2021-33193-pre1.patch
--- apache2-2.4.41/debian/patches/CVE-2021-33193-pre1.patch 1970-01-01 00:00:00.000000000 +0000
+++ apache2-2.4.41/debian/patches/CVE-2021-33193-pre1.patch 2021-09-23 16:58:57.000000000 +0000
@@ -0,0 +1,175 @@
+From f7173e91099ce59dc1654e5a94b3cde7a892f7fa Mon Sep 17 00:00:00 2001
+From: Ruediger Pluem
+Date: Mon, 16 Nov 2020 12:24:12 +0000
+Subject: [PATCH] Merge r1881620, r1881635 from trunk:
+
+Process early errors via a dummy HTTP/1.1 request as well
+
+Process early errors via a dummy HTTP/1.1 request as well to ensure
+that the request gets logged correctly and possible custom error
+pages are considered. The previous way of directly sending a HTTP/2
+answer with the HTTP status code appropriate for the error is more
+efficient, but does not log the request nor sents a possible custom
+error page.
+
+* modules/http2/h2.h: Add http_status to h2_request struct and define
+ H2_HTTP_STATUS_UNSET.
+
+* modules/http2/h2_request.c(h2_request_create_rec): Check if
+ http_status is set for the request and die with the
+ status code it contains if set.
+
+* modules/http2/h2_session.c(on_header_cb): Adjust the error condition
+ now that we mark early errors via http_status: Only return an error
+ if the status is not success and http_status is not H2_HTTP_STATUS_UNSET.
+
+* modules/http2/h2_stream.c(set_error_response): Set http_status
+ on the request instead of creating headers for a response and a
+ respective brigade.
+
+Github: closes #137
+
+
+* Changelog for r1881620
+
+Submitted by: rpluem
+Reviewed by: rpluem, giovanni, ylavic
+
+Github: closes #142
+
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1883475 13f79535-47bb-0310-9956-ffa450edef68
+---
+ CHANGES | 4 ++++
+ STATUS | 10 ----------
+ modules/http2/h2.h | 11 +++++++++++
+ modules/http2/h2_request.c | 18 +++++++++++++-----
+ modules/http2/h2_session.c | 4 +++-
+ modules/http2/h2_stream.c | 11 +----------
+ 6 files changed, 32 insertions(+), 26 deletions(-)
+
+#diff --git a/CHANGES b/CHANGES
+#index 2603312f31c..92c4d1d85eb 100644
+#--- a/CHANGES
+#+++ b/CHANGES
+#@@ -1,6 +1,10 @@
+# -*- coding: utf-8 -*-
+# Changes with Apache 2.4.47
+#
+#+ *) mod_http2: Log requests and sent the configured error response in case of
+#+ early detected errors like too many or too long headers.
+#+ [Ruediger Pluem, Stefan Eissing]
+#+
+# *) mod_md: lowered the required minimal libcurl version from 7.50 to 7.29
+# as proposed by . [Stefan Eissing]
+#
+#diff --git a/STATUS b/STATUS
+#index 3591db74edc..e5416fc7bca 100644
+#--- a/STATUS
+#+++ b/STATUS
+#@@ -154,16 +154,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
+# 2.4.x patch: http://people.apache.org/~covener/patches/wstunnel-decline.diff
+# +1 covener, jim, rpluem, jfclere
+#
+#- *) mod_http2: Log requests and sent the configured error response in case of
+#- early detected errors like too many or too long headers.
+#- Trunk version of patch:
+#- https://svn.apache.org/r1881620
+#- https://svn.apache.org/r1881635
+#- Backport version for 2.4.x of patch:
+#- https://github.com/apache/httpd/pull/142
+#- https://github.com/apache/httpd/pull/142.diff
+#- +1: rpluem, giovanni, ylavic
+#-
+# *) core: Avoid a core dump if 'AllowOverride nonfatal' is used in a configuration
+# file.
+# Trunk version of patch:
+--- a/modules/http2/h2.h
++++ b/modules/http2/h2.h
+@@ -141,8 +141,19 @@ struct h2_request {
+ unsigned int chunked : 1; /* iff requst body needs to be forwarded as chunked */
+ unsigned int serialize : 1; /* iff this request is written in HTTP/1.1 serialization */
+ apr_off_t raw_bytes; /* RAW network bytes that generated this request - if known. */
++ int http_status; /* Store a possible HTTP status code that gets
++ * defined before creating the dummy HTTP/1.1
++ * request e.g. due to an error already
++ * detected.
++ */
+ };
+
++/*
++ * A possible HTTP status code is not defined yet. See the http_status field
++ * in struct h2_request above for further explanation.
++ */
++#define H2_HTTP_STATUS_UNSET (0)
++
+ typedef struct h2_headers h2_headers;
+
+ struct h2_headers {
+--- a/modules/http2/h2_request.c
++++ b/modules/http2/h2_request.c
+@@ -79,11 +79,12 @@ apr_status_t h2_request_rcreate(h2_reque
+ }
+
+ req = apr_pcalloc(pool, sizeof(*req));
+- req->method = apr_pstrdup(pool, r->method);
+- req->scheme = scheme;
+- req->authority = authority;
+- req->path = path;
+- req->headers = apr_table_make(pool, 10);
++ req->method = apr_pstrdup(pool, r->method);
++ req->scheme = scheme;
++ req->authority = authority;
++ req->path = path;
++ req->headers = apr_table_make(pool, 10);
++ req->http_status = H2_HTTP_STATUS_UNSET;
+ if (r->server) {
+ req->serialize = h2_config_rgeti(r, H2_CONF_SER_HEADERS);
+ }
+@@ -324,6 +325,13 @@ request_rec *h2_request_create_rec(const
+ }
+ }
+
++ if (req->http_status != H2_HTTP_STATUS_UNSET) {
++ access_status = req->http_status;
++ r->status = HTTP_OK;
++ /* Be safe and close the connection */
++ c->keepalive = AP_CONN_CLOSE;
++ }
++
+ /*
+ * 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
+--- a/modules/http2/h2_session.c
++++ b/modules/http2/h2_session.c
+@@ -311,7 +311,9 @@ static int on_header_cb(nghttp2_session
+
+ status = h2_stream_add_header(stream, (const char *)name, namelen,
+ (const char *)value, valuelen);
+- if (status != APR_SUCCESS && !h2_stream_is_ready(stream)) {
++ if (status != APR_SUCCESS
++ && (!stream->rtmp
++ || stream->rtmp->http_status == H2_HTTP_STATUS_UNSET)) {
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
+ }
+ return 0;
+--- a/modules/http2/h2_stream.c
++++ b/modules/http2/h2_stream.c
+@@ -639,16 +639,7 @@ void h2_stream_set_request(h2_stream *st
+ static void set_error_response(h2_stream *stream, int http_status)
+ {
+ if (!h2_stream_is_ready(stream)) {
+- conn_rec *c = stream->session->c;
+- apr_bucket *b;
+- h2_headers *response;
+-
+- response = h2_headers_die(http_status, stream->request, stream->pool);
+- prep_output(stream);
+- b = apr_bucket_eos_create(c->bucket_alloc);
+- APR_BRIGADE_INSERT_HEAD(stream->out_buffer, b);
+- b = h2_bucket_headers_create(c->bucket_alloc, response);
+- APR_BRIGADE_INSERT_HEAD(stream->out_buffer, b);
++ stream->rtmp->http_status = http_status;
+ }
+ }
+
diff -Nru apache2-2.4.41/debian/patches/CVE-2021-33193-pre2.patch apache2-2.4.41/debian/patches/CVE-2021-33193-pre2.patch
--- apache2-2.4.41/debian/patches/CVE-2021-33193-pre2.patch 1970-01-01 00:00:00.000000000 +0000
+++ apache2-2.4.41/debian/patches/CVE-2021-33193-pre2.patch 2021-09-23 16:58:57.000000000 +0000
@@ -0,0 +1,521 @@
+Backport of:
+
+From c0c8c96a8c6bb923589942d8b7754b81a0377cee Mon Sep 17 00:00:00 2001
+From: Stefan Eissing
+Date: Wed, 24 Mar 2021 14:28:49 +0000
+Subject: [PATCH] *) mod_http2: sync with github standalone version 1.15.17
+ - Log requests and sent the configured error response in case of early
+ detected errors like too many or too long headers. [Ruediger Pluem]
+ - new option 'H2OutputBuffering on/off' which controls the buffering of
+ stream output. The default is on, which is the behaviour of older
+ mod-h2 versions. When off, all bytes are made available immediately to
+ the main connection for sending them out to the client. This fixes
+ interop issues with certain flavours of gRPC, see also
+ .
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1888011 13f79535-47bb-0310-9956-ffa450edef68
+---
+ docs/manual/mod/mod_http2.xml | 22 ++++++
+ modules/http2/h2_bucket_beam.c | 1 +
+ modules/http2/h2_config.c | 24 ++++++
+ modules/http2/h2_config.h | 1 +
+ modules/http2/h2_h2.c | 1 +
+ modules/http2/h2_headers.c | 15 ++++
+ modules/http2/h2_headers.h | 5 ++
+ modules/http2/h2_mplx.c | 17 ----
+ modules/http2/h2_request.c | 138 ++++++++++++++++++++++-----------
+ modules/http2/h2_stream.h | 3 +-
+ modules/http2/h2_task.c | 18 +++--
+ modules/http2/h2_task.h | 1 +
+ modules/http2/h2_version.h | 5 +-
+ 13 files changed, 180 insertions(+), 71 deletions(-)
+
+#diff --git a/docs/manual/mod/mod_http2.xml b/docs/manual/mod/mod_http2.xml
+#index 5cf8d0acccc..287e774d33c 100644
+#--- a/docs/manual/mod/mod_http2.xml
+#+++ b/docs/manual/mod/mod_http2.xml
+#@@ -981,4 +981,26 @@ H2TLSCoolDownSecs 0
+#
+#
+#
+#+
+#+
+#+ H2OutputBuffering
+#+ Determine buffering behaviour of output
+#+ H2OutputBuffering on/off
+#+ H2OutputBuffering on
+#+
+#+ server config
+#+ virtual host
+#+
+#+ Available in version 2.4.48 and later.
+#+
+#+
+#+
+#+ The option 'H2OutputBuffering on/off' controls the buffering of stream output.
+#+ The default is on, which is the behaviour of previous versions. When off, all
+#+ bytes are made available immediately to the main connection for sending them
+#+ out to the client. This fixes interop issues with certain flavours of gRPC.
+#+
+#+
+#+
+#+
+#
+--- a/modules/http2/h2_bucket_beam.c
++++ b/modules/http2/h2_bucket_beam.c
+@@ -1039,6 +1039,7 @@ transfer:
+ H2_BLIST_INSERT_TAIL(&beam->hold_list, bsender);
+
+ remain -= bsender->length;
++ beam->received_bytes += bsender->length;
+ ++transferred;
+ ++transferred_buckets;
+ continue;
+--- a/modules/http2/h2_config.c
++++ b/modules/http2/h2_config.c
+@@ -78,6 +78,7 @@ typedef struct h2_config {
+ int early_hints; /* support status code 103 */
+ int padding_bits;
+ int padding_always;
++ int output_buffered;
+ } h2_config;
+
+ typedef struct h2_dir_config {
+@@ -115,6 +116,7 @@ static h2_config defconf = {
+ 0, /* early hints, http status 103 */
+ 0, /* padding bits */
+ 1, /* padding always */
++ 1, /* strean output buffered */
+ };
+
+ static h2_dir_config defdconf = {
+@@ -159,6 +161,7 @@ void *h2_config_create_svr(apr_pool_t *p
+ conf->early_hints = DEF_VAL;
+ conf->padding_bits = DEF_VAL;
+ conf->padding_always = DEF_VAL;
++ conf->output_buffered = DEF_VAL;
+ return conf;
+ }
+
+@@ -193,6 +196,7 @@ static void *h2_config_merge(apr_pool_t
+ }
+ n->push_diary_size = H2_CONFIG_GET(add, base, push_diary_size);
+ n->copy_files = H2_CONFIG_GET(add, base, copy_files);
++ n->output_buffered = H2_CONFIG_GET(add, base, output_buffered);
+ if (add->push_list && base->push_list) {
+ n->push_list = apr_array_append(pool, base->push_list, add->push_list);
+ }
+@@ -287,6 +291,8 @@ static apr_int64_t h2_srv_config_geti64(
+ return H2_CONFIG_GET(conf, &defconf, padding_bits);
+ case H2_CONF_PADDING_ALWAYS:
+ return H2_CONFIG_GET(conf, &defconf, padding_always);
++ case H2_CONF_OUTPUT_BUFFER:
++ return H2_CONFIG_GET(conf, &defconf, output_buffered);
+ default:
+ return DEF_VAL;
+ }
+@@ -352,6 +358,9 @@ static void h2_srv_config_seti(h2_config
+ case H2_CONF_PADDING_ALWAYS:
+ H2_CONFIG_SET(conf, padding_always, val);
+ break;
++ case H2_CONF_OUTPUT_BUFFER:
++ H2_CONFIG_SET(conf, output_buffered, val);
++ break;
+ default:
+ break;
+ }
+@@ -905,6 +914,19 @@ static const char *h2_conf_set_padding(c
+ return NULL;
+ }
+
++static const char *h2_conf_set_output_buffer(cmd_parms *cmd,
++ void *dirconf, const char *value)
++{
++ if (!strcasecmp(value, "On")) {
++ CONFIG_CMD_SET(cmd, dirconf, H2_CONF_OUTPUT_BUFFER, 1);
++ return NULL;
++ }
++ else if (!strcasecmp(value, "Off")) {
++ CONFIG_CMD_SET(cmd, dirconf, H2_CONF_OUTPUT_BUFFER, 0);
++ return NULL;
++ }
++ return "value must be On or Off";
++}
+
+ void h2_get_num_workers(server_rec *s, int *minw, int *maxw)
+ {
+@@ -976,6 +998,8 @@ const command_rec h2_cmds[] = {
+ RSRC_CONF, "on to enable interim status 103 responses"),
+ AP_INIT_TAKE1("H2Padding", h2_conf_set_padding, NULL,
+ RSRC_CONF, "set payload padding"),
++ AP_INIT_TAKE1("H2OutputBuffering", h2_conf_set_output_buffer, NULL,
++ RSRC_CONF, "set stream output buffer on/off"),
+ AP_END_CMD
+ };
+
+--- a/modules/http2/h2_config.h
++++ b/modules/http2/h2_config.h
+@@ -44,6 +44,7 @@ typedef enum {
+ H2_CONF_EARLY_HINTS,
+ H2_CONF_PADDING_BITS,
+ H2_CONF_PADDING_ALWAYS,
++ H2_CONF_OUTPUT_BUFFER,
+ } h2_config_var_t;
+
+ struct apr_hash_t;
+--- a/modules/http2/h2_h2.c
++++ b/modules/http2/h2_h2.c
+@@ -749,6 +749,7 @@ static int h2_h2_late_fixups(request_rec
+ if (task) {
+ /* check if we copy vs. setaside files in this location */
+ task->output.copy_files = h2_config_rgeti(r, H2_CONF_COPY_FILES);
++ task->output.buffered = h2_config_rgeti(r, H2_CONF_OUTPUT_BUFFER);
+ if (task->output.copy_files) {
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
+ "h2_secondary_out(%s): copy_files on", task->id);
+--- a/modules/http2/h2_headers.c
++++ b/modules/http2/h2_headers.c
+@@ -64,6 +64,7 @@ apr_bucket * h2_bucket_headers_make(apr_
+
+ b = apr_bucket_shared_make(b, br, 0, 0);
+ b->type = &h2_bucket_type_headers;
++ b->length = h2_headers_length(r);
+
+ return b;
+ }
+@@ -125,6 +126,20 @@ h2_headers *h2_headers_create(int status
+ return headers;
+ }
+
++static int add_header_lengths(void *ctx, const char *name, const char *value)
++{
++ apr_size_t *plen = ctx;
++ *plen += strlen(name) + strlen(value);
++ return 1;
++}
++
++apr_size_t h2_headers_length(h2_headers *headers)
++{
++ apr_size_t len = 0;
++ apr_table_do(add_header_lengths, &len, headers->headers, NULL);
++ return len;
++}
++
+ h2_headers *h2_headers_rcreate(request_rec *r, int status,
+ apr_table_t *header, apr_pool_t *pool)
+ {
+--- a/modules/http2/h2_headers.h
++++ b/modules/http2/h2_headers.h
+@@ -82,4 +82,9 @@ h2_headers *h2_headers_die(apr_status_t
+
+ int h2_headers_are_response(h2_headers *headers);
+
++/**
++ * Give the number of bytes of all contained header strings.
++ */
++apr_size_t h2_headers_length(h2_headers *headers);
++
+ #endif /* defined(__mod_h2__h2_headers__) */
+--- a/modules/http2/h2_mplx.c
++++ b/modules/http2/h2_mplx.c
+@@ -91,10 +91,6 @@ apr_status_t h2_mplx_m_child_init(apr_po
+
+ static void mst_check_data_for(h2_mplx *m, h2_stream *stream, int mplx_is_locked);
+
+-static void mst_stream_output_consumed(void *ctx, h2_bucket_beam *beam, apr_off_t length)
+-{
+-}
+-
+ static void mst_stream_input_ev(void *ctx, h2_bucket_beam *beam)
+ {
+ h2_stream *stream = ctx;
+@@ -299,18 +295,6 @@ static int m_stream_destroy_iter(void *c
+ stream->task = NULL;
+ secondary = task->c;
+ if (secondary) {
+- /* On non-serialized requests, the IO logging has not accounted for any
+- * meta data send over the network: response headers and h2 frame headers. we
+- * counted this on the stream and need to add this now.
+- * This is supposed to happen before the EOR bucket triggers the
+- * logging of the transaction. *fingers crossed* */
+- if (task->request && !task->request->serialize && h2_task_logio_add_bytes_out) {
+- apr_off_t unaccounted = stream->out_frame_octets - stream->out_data_octets;
+- if (unaccounted > 0) {
+- h2_task_logio_add_bytes_out(secondary, unaccounted);
+- }
+- }
+-
+ if (m->s->keep_alive_max == 0 || secondary->keepalives < m->s->keep_alive_max) {
+ reuse_secondary = ((m->spare_secondary->nelts < (m->limit_active * 3 / 2))
+ && !task->rst_error);
+@@ -540,7 +524,6 @@ static apr_status_t t_out_open(h2_mplx *
+ "h2_mplx(%s): out open", stream->task->id);
+ }
+
+- h2_beam_on_consumed(stream->output, NULL, mst_stream_output_consumed, stream);
+ h2_beam_on_produced(stream->output, mst_output_produced, stream);
+ if (stream->task->output.copy_files) {
+ h2_beam_on_file_beam(stream->output, h2_beam_no_files, NULL);
+--- a/modules/http2/h2_request.c
++++ b/modules/http2/h2_request.c
+@@ -267,9 +267,7 @@ static request_rec *my_ap_create_request
+
+ request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
+ {
+- int access_status = HTTP_OK;
+- const char *rpath;
+- const char *s;
++ int access_status;
+
+ #if AP_MODULE_MAGIC_AT_LEAST(20150222, 13)
+ request_rec *r = ap_create_request(c);
+@@ -277,59 +275,88 @@ request_rec *h2_request_create_rec(const
+ request_rec *r = my_ap_create_request(c);
+ #endif
+
+- r->headers_in = apr_table_clone(r->pool, req->headers);
+-
++#if AP_MODULE_MAGIC_AT_LEAST(20200331, 3)
+ ap_run_pre_read_request(r, c);
+-
++
+ /* Time to populate r with the data we have. */
+ r->request_time = req->request_time;
+- r->method = apr_pstrdup(r->pool, req->method);
+- /* Provide quick information about the request method as soon as known */
+- r->method_number = ap_method_number_of(r->method);
+- if (r->method_number == M_GET && r->method[0] == 'H') {
+- r->header_only = 1;
+- }
+- r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
++ r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
+ req->method, req->path ? req->path : "");
+ r->headers_in = apr_table_clone(r->pool, req->headers);
+
+- rpath = (req->path ? req->path : "");
+- ap_parse_uri(r, rpath);
+- r->protocol = (char*)"HTTP/2.0";
+- r->proto_num = HTTP_VERSION(2, 0);
+-
+- r->the_request = apr_psprintf(r->pool, "%s %s %s",
+- r->method, rpath, r->protocol);
+-
+- /* update what we think the virtual host is based on the headers we've
+- * now read. may update status.
+- * Leave r->hostname empty, vhost will parse if form our Host: header,
+- * otherwise we get complains about port numbers.
++ /* Start with r->hostname = NULL, ap_check_request_header() will get it
++ * form Host: header, otherwise we get complains about port numbers.
+ */
+ r->hostname = NULL;
+- ap_update_vhost_from_headers(r);
+- r->protocol = "HTTP/2.0";
+- r->proto_num = HTTP_VERSION(2, 0);
+
+- /* we may have switched to another server */
+- r->per_dir_config = r->server->lookup_defaults;
+-
+- s = apr_table_get(r->headers_in, "Expect");
+- if (s && s[0]) {
+- if (ap_cstr_casecmp(s, "100-continue") == 0) {
+- r->expecting_100 = 1;
++ /* Validate HTTP/1 request and select vhost. */
++ if (!ap_parse_request_line(r) || !ap_check_request_header(r)) {
++ /* we may have switched to another server still */
++ r->per_dir_config = r->server->lookup_defaults;
++ if (req->http_status != H2_HTTP_STATUS_UNSET) {
++ access_status = req->http_status;
++ /* Be safe and close the connection */
++ c->keepalive = AP_CONN_CLOSE;
+ }
+ else {
+- r->status = HTTP_EXPECTATION_FAILED;
+- ap_send_error_response(r, 0);
++ access_status = r->status;
++ }
++ r->status = HTTP_OK;
++ goto die;
++ }
++#else
++ {
++ const char *s;
++
++ r->headers_in = apr_table_clone(r->pool, req->headers);
++ ap_run_pre_read_request(r, c);
++
++ /* Time to populate r with the data we have. */
++ r->request_time = req->request_time;
++ r->method = apr_pstrdup(r->pool, req->method);
++ /* Provide quick information about the request method as soon as known */
++ r->method_number = ap_method_number_of(r->method);
++ if (r->method_number == M_GET && r->method[0] == 'H') {
++ r->header_only = 1;
+ }
++ ap_parse_uri(r, req->path ? req->path : "");
++ r->protocol = (char*)"HTTP/2.0";
++ r->proto_num = HTTP_VERSION(2, 0);
++ r->the_request = apr_psprintf(r->pool, "%s %s HTTP/2.0",
++ r->method, req->path ? req->path : "");
++
++ /* Start with r->hostname = NULL, ap_check_request_header() will get it
++ * form Host: header, otherwise we get complains about port numbers.
++ */
++ r->hostname = NULL;
++ ap_update_vhost_from_headers(r);
++
++ /* we may have switched to another server */
++ r->per_dir_config = r->server->lookup_defaults;
++
++ s = apr_table_get(r->headers_in, "Expect");
++ if (s && s[0]) {
++ if (ap_cstr_casecmp(s, "100-continue") == 0) {
++ r->expecting_100 = 1;
++ }
++ else {
++ r->status = HTTP_EXPECTATION_FAILED;
++ access_status = r->status;
++ goto die;
++ }
++ }
+ }
++#endif
++
++ /* we may have switched to another server */
++ r->per_dir_config = r->server->lookup_defaults;
+
+ if (req->http_status != H2_HTTP_STATUS_UNSET) {
+ access_status = req->http_status;
+ r->status = HTTP_OK;
+ /* Be safe and close the connection */
+ c->keepalive = AP_CONN_CLOSE;
++ goto die;
+ }
+
+ /*
+@@ -341,28 +368,47 @@ request_rec *h2_request_create_rec(const
+ ap_add_input_filter_handle(ap_http_input_filter_handle,
+ NULL, r, r->connection);
+
+- if (access_status != HTTP_OK
+- || (access_status = ap_run_post_read_request(r))) {
++ if ((access_status = ap_run_post_read_request(r))) {
+ /* Request check post hooks failed. An example of this would be a
+ * request for a vhost where h2 is disabled --> 421.
+ */
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03367)
+ "h2_request: access_status=%d, request_create failed",
+ access_status);
+- ap_die(access_status, r);
+- ap_update_child_status(c->sbh, SERVER_BUSY_LOG, r);
+- ap_run_log_transaction(r);
+- r = NULL;
+- goto traceout;
++ goto die;
+ }
+
+ AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method,
+ (char *)r->uri, (char *)r->server->defn_name,
+ r->status);
+ return r;
+-traceout:
++
++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;
++#if AP_MODULE_MAGIC_AT_LEAST(20180905, 1)
++ eor_bb = ap_acquire_brigade(c);
++ APR_BRIGADE_INSERT_TAIL(eor_bb,
++ ap_bucket_eor_create(c->bucket_alloc, r));
++ ap_pass_brigade(c->output_filters, eor_bb);
++ ap_release_brigade(c, eor_bb);
++#else
++ eor_bb = apr_brigade_create(c->pool, c->bucket_alloc);
++ APR_BRIGADE_INSERT_TAIL(eor_bb,
++ ap_bucket_eor_create(c->bucket_alloc, r));
++ ap_pass_brigade(c->output_filters, eor_bb);
++ apr_brigade_destroy(eor_bb);
++#endif
++ }
++
++ r = NULL;
+ AP_READ_REQUEST_FAILURE((uintptr_t)r);
+- return r;
++ return NULL;
+ }
+
+
+--- a/modules/http2/h2_stream.h
++++ b/modules/http2/h2_stream.h
+@@ -92,7 +92,8 @@ struct h2_stream {
+ unsigned int input_eof : 1; /* no more request data coming */
+ unsigned int out_checked : 1; /* output eof was double checked */
+ unsigned int push_policy; /* which push policy to use for this request */
+-
++ unsigned int input_buffering : 1; /* buffer request bodies for efficiency */
++
+ struct h2_task *task; /* assigned task to fullfill request */
+
+ const h2_priority *pref_priority; /* preferred priority for this stream */
+--- a/modules/http2/h2_task.c
++++ b/modules/http2/h2_task.c
+@@ -89,6 +89,14 @@ static apr_status_t open_output(h2_task
+ return h2_mplx_t_out_open(task->mplx, task->stream_id, task->output.beam);
+ }
+
++static void output_consumed(void *ctx, h2_bucket_beam *beam, apr_off_t length)
++{
++ h2_task *task = ctx;
++ if (task && h2_task_logio_add_bytes_out) {
++ h2_task_logio_add_bytes_out(task->c, length);
++ }
++}
++
+ static apr_status_t send_out(h2_task *task, apr_bucket_brigade* bb, int block)
+ {
+ apr_off_t written, left;
+@@ -108,9 +116,6 @@ static apr_status_t send_out(h2_task *ta
+ status = APR_SUCCESS;
+ }
+ if (status == APR_SUCCESS) {
+- if (h2_task_logio_add_bytes_out) {
+- h2_task_logio_add_bytes_out(task->c, written);
+- }
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, task->c,
+ "h2_task(%s): send_out done", task->id);
+ }
+@@ -183,7 +188,9 @@ send:
+ }
+ }
+
+- if (APR_SUCCESS == rv && !task->output.opened && flush) {
++ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, task->c,
++ "h2_secondary_out(%s): buffered=%d", task->id, task->output.buffered);
++ if (APR_SUCCESS == rv && !task->output.opened && (flush || !task->output.buffered)) {
+ /* got a flush or could not write all, time to tell someone to read */
+ rv = open_output(task);
+ }
+@@ -596,7 +603,8 @@ apr_status_t h2_task_do(h2_task *task, a
+
+ h2_beam_buffer_size_set(task->output.beam, task->output.max_buffer);
+ h2_beam_send_from(task->output.beam, task->pool);
+-
++ h2_beam_on_consumed(task->output.beam, NULL, output_consumed, task);
++
+ h2_ctx_create_for(c, task);
+ apr_table_setn(c->notes, H2_TASK_ID_NOTE, task->id);
+
+--- a/modules/http2/h2_task.h
++++ b/modules/http2/h2_task.h
+@@ -71,6 +71,7 @@ struct h2_task {
+ unsigned int opened : 1;
+ unsigned int sent_response : 1;
+ unsigned int copy_files : 1;
++ unsigned int buffered : 1;
+ struct h2_response_parser *rparser;
+ apr_bucket_brigade *bb;
+ apr_size_t max_buffer;
diff -Nru apache2-2.4.41/debian/patches/CVE-2021-34798.patch apache2-2.4.41/debian/patches/CVE-2021-34798.patch
--- apache2-2.4.41/debian/patches/CVE-2021-34798.patch 1970-01-01 00:00:00.000000000 +0000
+++ apache2-2.4.41/debian/patches/CVE-2021-34798.patch 2021-09-23 16:58:27.000000000 +0000
@@ -0,0 +1,33 @@
+From fa7b2a5250e54363b3a6c8ac3aaa7de4e8da9b2e Mon Sep 17 00:00:00 2001
+From: Yann Ylavic
+Date: Tue, 7 Sep 2021 16:05:31 +0000
+Subject: [PATCH] Merge r1878092 from trunk:
+
+Fix a NULL pointer dereference
+
+* server/scoreboard.c (ap_increment_counts): In certain cases like certain
+ invalid requests r->method might be NULL here. r->method_number defaults
+ to M_GET and hence is M_GET in these cases.
+
+Submitted by: rpluem
+Reviewed by: covener, ylavic, jfclere
+
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1893051 13f79535-47bb-0310-9956-ffa450edef68
+---
+ server/scoreboard.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/server/scoreboard.c b/server/scoreboard.c
+index b40b45df590..12dd56abead 100644
+--- a/server/scoreboard.c
++++ b/server/scoreboard.c
+@@ -388,7 +388,7 @@ AP_DECLARE(void) ap_increment_counts(ap_sb_handle_t *sb, request_rec *r)
+ if (pfn_ap_logio_get_last_bytes != NULL) {
+ bytes = pfn_ap_logio_get_last_bytes(r->connection);
+ }
+- else if (r->method_number == M_GET && r->method[0] == 'H') {
++ else if (r->method_number == M_GET && r->method && r->method[0] == 'H') {
+ bytes = 0;
+ }
+ else {
diff -Nru apache2-2.4.41/debian/patches/CVE-2021-36160.patch apache2-2.4.41/debian/patches/CVE-2021-36160.patch
--- apache2-2.4.41/debian/patches/CVE-2021-36160.patch 1970-01-01 00:00:00.000000000 +0000
+++ apache2-2.4.41/debian/patches/CVE-2021-36160.patch 2021-09-23 16:58:32.000000000 +0000
@@ -0,0 +1,73 @@
+From 6d9672bf096592fe16c1840f73fa947fd458ee68 Mon Sep 17 00:00:00 2001
+From: Yann Ylavic
+Date: Fri, 3 Sep 2021 17:00:07 +0000
+Subject: [PATCH] Merge r1892805 from trunk:
+
+mod_proxy_uwsgi: Fix PATH_INFO setting for generic worker.
+
+When the generic "proxy:reverse" worker is selected for an uwsgi scheme, the
+worker name is irrelevant so uwscgi_handler() should point to the PATH_INFO
+directly from the given URL.
+
+
+Submitted by: ylavic
+Reviewed by: ylavic, covener, rpluem
+
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1892875 13f79535-47bb-0310-9956-ffa450edef68
+---
+ changes-entries/uwsgi_path_info.txt | 1 +
+ modules/proxy/mod_proxy_uwsgi.c | 22 +++++-----------------
+ 2 files changed, 6 insertions(+), 17 deletions(-)
+ create mode 100644 changes-entries/uwsgi_path_info.txt
+
+#diff --git a/changes-entries/uwsgi_path_info.txt b/changes-entries/uwsgi_path_info.txt
+#new file mode 100644
+#index 00000000000..4591366cbe0
+#--- /dev/null
+#+++ b/changes-entries/uwsgi_path_info.txt
+#@@ -0,0 +1 @@
+#+ *) mod_proxy_uwsgi: Fix PATH_INFO setting for generic worker. [Yann Ylavic]
+--- a/modules/proxy/mod_proxy_uwsgi.c
++++ b/modules/proxy/mod_proxy_uwsgi.c
+@@ -453,11 +453,8 @@ static int uwsgi_handler(request_rec *r,
+ const char *proxyname, apr_port_t proxyport)
+ {
+ int status;
+- int delta = 0;
+- int decode_status;
+ proxy_conn_rec *backend = NULL;
+ apr_pool_t *p = r->pool;
+- size_t w_len;
+ char server_portstr[32];
+ char *u_path_info;
+ apr_uri_t *uri;
+@@ -469,23 +466,14 @@ static int uwsgi_handler(request_rec *r,
+
+ uri = apr_palloc(r->pool, sizeof(*uri));
+
+- /* ADD PATH_INFO */
+-#if AP_MODULE_MAGIC_AT_LEAST(20111130,0)
+- w_len = strlen(worker->s->name);
+-#else
+- w_len = strlen(worker->name);
+-#endif
+- u_path_info = r->filename + 6 + w_len;
+- if (u_path_info[0] != '/') {
+- delta = 1;
+- }
+- decode_status = ap_unescape_url(url + w_len - delta);
+- if (decode_status) {
++ /* ADD PATH_INFO (unescaped) */
++ u_path_info = ap_strchr(url + sizeof(UWSGI_SCHEME) + 2, '/');
++ if (!u_path_info || ap_unescape_url(u_path_info) != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10100)
+- "unable to decode uri: %s", url + w_len - delta);
++ "unable to decode uwsgi uri: %s", url);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+- apr_table_add(r->subprocess_env, "PATH_INFO", url + w_len - delta);
++ apr_table_add(r->subprocess_env, "PATH_INFO", u_path_info);
+
+
+ /* Create space for state information */
diff -Nru apache2-2.4.41/debian/patches/CVE-2021-39275.patch apache2-2.4.41/debian/patches/CVE-2021-39275.patch
--- apache2-2.4.41/debian/patches/CVE-2021-39275.patch 1970-01-01 00:00:00.000000000 +0000
+++ apache2-2.4.41/debian/patches/CVE-2021-39275.patch 2021-09-23 16:58:40.000000000 +0000
@@ -0,0 +1,83 @@
+Backport of:
+
+From ac62c7e7436560cf4f7725ee586364ce95c07804 Mon Sep 17 00:00:00 2001
+From: Graham Leggett
+Date: Sat, 21 Aug 2021 21:35:04 +0000
+Subject: [PATCH] Backport:
+
+ *) core: fix ap_escape_quotes substitution logic
+ trunk patch: https://svn.apache.org/r1892418
+ 2.4.x patch: svn merge -c 1892418 ^/httpd/httpd/trunk .
+ +1: covener, rpluem, ylavic
+
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1892511 13f79535-47bb-0310-9956-ffa450edef68
+---
+ CHANGES | 10 ++++++----
+ STATUS | 5 -----
+ server/util.c | 7 +++----
+ 3 files changed, 9 insertions(+), 13 deletions(-)
+
+#diff --git a/CHANGES b/CHANGES
+#index f410ed66c7b..f33b68e78d5 100644
+#--- a/CHANGES
+#+++ b/CHANGES
+#@@ -1,6 +1,8 @@
+# -*- coding: utf-8 -*-
+# Changes with Apache 2.4.49
+#
+#+ *) core: fix ap_escape_quotes substitution logic. [Eric Covener]
+#+
+# *) Easy patches: synch 2.4.x and trunk
+# - mod_auth_basic: Use ap_cstr_casecmp instead of strcasecmp.
+# - mod_ldap: log and abort locking errors.
+#@@ -14,10 +16,10 @@ Changes with Apache 2.4.49
+# - core: remove extra whitespace in HTTP_NOT_IMPLEMENTED
+# [Christophe Jaillet]
+#
+#- * core/mpm: add hook 'child_stopping` that gets called when the MPM is
+#- stopping a child process. The additional `graceful` parameter allows
+#- registered hooks to free resources early during a graceful shutdown.
+#- [Yann Ylavic, Stefan Eissing]
+#+ *) core/mpm: add hook 'child_stopping` that gets called when the MPM is
+#+ stopping a child process. The additional `graceful` parameter allows
+#+ registered hooks to free resources early during a graceful shutdown.
+#+ [Yann Ylavic, Stefan Eissing]
+#
+# *) mod_proxy: Fix icomplete initialization of BalancerMember(s) from the
+# balancer-manager, which can lead to a crash. [Yann Ylavic]
+#diff --git a/STATUS b/STATUS
+#index a7b8bae4198..98d9d93a883 100644
+#--- a/STATUS
+#+++ b/STATUS
+#@@ -142,11 +142,6 @@ RELEASE SHOWSTOPPERS:
+# PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
+# [ start all new proposals below, under PATCHES PROPOSED. ]
+#
+#- *) core: fix ap_escape_quotes substitution logic
+#- trunk patch: https://svn.apache.org/r1892418
+#- 2.4.x patch: svn merge -c 1892418 ^/httpd/httpd/trunk .
+#- +1: covener, rpluem, ylavic
+#-
+# *) Add dav_get_provider(), dav_open_lockdb(), dav_close_lockdb() and
+# dav_get_resource() to mod_dav.h.
+# trunk patch: http://svn.apache.org/r1879305
+--- a/server/util.c
++++ b/server/util.c
+@@ -2466,13 +2466,12 @@ AP_DECLARE(char *) ap_escape_quotes(apr_
+ * in front of every " that doesn't already have one.
+ */
+ while (*inchr != '\0') {
+- if ((*inchr == '\\') && (inchr[1] != '\0')) {
+- *outchr++ = *inchr++;
+- *outchr++ = *inchr++;
+- }
+ if (*inchr == '"') {
+ *outchr++ = '\\';
+ }
++ if ((*inchr == '\\') && (inchr[1] != '\0')) {
++ *outchr++ = *inchr++;
++ }
+ if (*inchr != '\0') {
+ *outchr++ = *inchr++;
+ }
diff -Nru apache2-2.4.41/debian/patches/CVE-2021-40438.patch apache2-2.4.41/debian/patches/CVE-2021-40438.patch
--- apache2-2.4.41/debian/patches/CVE-2021-40438.patch 1970-01-01 00:00:00.000000000 +0000
+++ apache2-2.4.41/debian/patches/CVE-2021-40438.patch 2021-09-23 16:58:54.000000000 +0000
@@ -0,0 +1,136 @@
+From d4901cb32133bc0e59ad193a29d1665597080d67 Mon Sep 17 00:00:00 2001
+From: Ruediger Pluem
+Date: Wed, 8 Sep 2021 07:00:09 +0000
+Subject: [PATCH] Merge r1892986, r1892987 from trunk:
+
+mod_proxy: Follow up to r1892814.
+
+* modules/proxy/proxy_util.c(fix_uds_filename):
+ Sanity checks on the configured UDS path, fail with 500 if invalid since
+ continuing through proxy processing wouldn't work as expected.
+
+
+
+mod_proxy: Follow up to r1892986: APLOGNO()
+
+Stefan get out of this body! :)
+
+
+Submitted by: ylavic
+Reviewed by: rpluem, ylavic, covener
+
+Github: closes #265
+
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1893101 13f79535-47bb-0310-9956-ffa450edef68
+---
+ STATUS | 9 -------
+ modules/proxy/proxy_util.c | 55 +++++++++++++++++++++++---------------
+ 2 files changed, 34 insertions(+), 30 deletions(-)
+
+#diff --git a/STATUS b/STATUS
+#index 34ffe2d785a..a0897138054 100644
+#--- a/STATUS
+#+++ b/STATUS
+#@@ -146,15 +146,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
+# 2.4.x patch: svn merge -c 1878092 ^/httpd/httpd/trunk .
+# +1: covener, ylavic, jfclere
+#
+#- *) mod_proxy: Sanity checks on the configured UDS path, fail with 500 if
+#- invalid since continuing through proxy processing wouldn't work as expected.
+#- Trunk version of patch:
+#- https://svn.apache.org/r1892986
+#- https://svn.apache.org/r1892987
+#- Backport version for 2.4.x of patch:
+#- https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/265.diff
+#- +1: rpluem, ylavic, covener
+#-
+# *) mod_proxy: Axe unused ap_filter_input_pending in 2.4.x (only) after r1892971.
+# 2.4.x patch: http://people.apache.org/~ylavic/patches/ap_filter_input_pending-unused.patch
+# +1: ylavic, icing, covener
+--- a/modules/proxy/proxy_util.c
++++ b/modules/proxy/proxy_util.c
+@@ -2088,33 +2088,42 @@ static int ap_proxy_retry_worker(const c
+ * were passed a UDS url (eg: from mod_proxy) and adjust uds_path
+ * as required.
+ */
+-static void fix_uds_filename(request_rec *r, char **url)
++static int fix_uds_filename(request_rec *r, char **url)
+ {
+- char *ptr, *ptr2;
+- if (!r || !r->filename) return;
++ char *uds_url = r->filename + 6, *origin_url;
+
+ if (!strncmp(r->filename, "proxy:", 6) &&
+- !ap_cstr_casecmpn(r->filename + 6, "unix:", 5) &&
+- (ptr2 = r->filename + 6 + 5, ptr = ap_strchr(ptr2, '|'))) {
++ !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;
+- *ptr = '\0';
+- rv = apr_uri_parse(r->pool, ptr2, &urisock);
+- if (rv == APR_SUCCESS) {
+- char *rurl = ptr+1;
+- char *sockpath = ap_runtime_dir_relative(r->pool, urisock.path);
+- apr_table_setn(r->notes, "uds_path", sockpath);
+- *url = apr_pstrdup(r->pool, rurl); /* so we get the scheme for the uds */
+- /* r->filename starts w/ "proxy:", so add after that */
+- memmove(r->filename+6, rurl, strlen(rurl)+1);
+- ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
+- "*: rewrite of url due to UDS(%s): %s (%s)",
+- sockpath, *url, r->filename);
++
++ *origin_url = '\0';
++ rv = apr_uri_parse(r->pool, uds_url, &urisock);
++ *origin_url++ = '|';
++
++ if (rv == APR_SUCCESS && urisock.path && !urisock.hostname) {
++ uds_path = ap_runtime_dir_relative(r->pool, urisock.path);
+ }
+- else {
+- *ptr = '|';
++ if (!uds_path) {
++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10292)
++ "Invalid proxy UDS filename (%s)", r->filename);
++ return 0;
+ }
++ 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);
+ }
++ return 1;
+ }
+
+ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
+@@ -2132,7 +2141,9 @@ PROXY_DECLARE(int) ap_proxy_pre_request(
+ "%s: found worker %s for %s",
+ (*worker)->s->scheme, (*worker)->s->name, *url);
+ *balancer = NULL;
+- fix_uds_filename(r, url);
++ if (!fix_uds_filename(r, url)) {
++ return HTTP_INTERNAL_SERVER_ERROR;
++ }
+ access_status = OK;
+ }
+ else if (r->proxyreq == PROXYREQ_PROXY) {
+@@ -2163,7 +2174,9 @@ PROXY_DECLARE(int) ap_proxy_pre_request(
+ * regarding the Connection header in the request.
+ */
+ apr_table_setn(r->subprocess_env, "proxy-nokeepalive", "1");
+- fix_uds_filename(r, url);
++ if (!fix_uds_filename(r, url)) {
++ return HTTP_INTERNAL_SERVER_ERROR;
++ }
+ }
+ }
+ }
diff -Nru apache2-2.4.41/debian/patches/CVE-2021-40438-pre1.patch apache2-2.4.41/debian/patches/CVE-2021-40438-pre1.patch
--- apache2-2.4.41/debian/patches/CVE-2021-40438-pre1.patch 1970-01-01 00:00:00.000000000 +0000
+++ apache2-2.4.41/debian/patches/CVE-2021-40438-pre1.patch 2021-09-23 16:58:47.000000000 +0000
@@ -0,0 +1,59 @@
+Backport of:
+
+From 496c863776c68bd08cdbeb7d8fa5935ba63b76c2 Mon Sep 17 00:00:00 2001
+From: Yann Ylavic
+Date: Fri, 3 Sep 2021 16:52:38 +0000
+Subject: [PATCH] Merge r1892814, r1892853 from trunk:
+
+mod_proxy: Faster unix socket path parsing in the "proxy:" URL.
+
+The actual r->filename format is "[proxy:]unix:path|url" for UDS, no need to
+strstr(,"unix:") since it's at the start of the string.
+
+
+mod_proxy: Follow up to r1892814.
+
+Save some few cycles in ap_proxy_de_socketfy() too.
+
+
+Submitted by: ylavic
+Reviewed by: ylavic, covener, rpluem
+
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1892874 13f79535-47bb-0310-9956-ffa450edef68
+---
+ changes-entries/fix_uds_filename.txt | 2 ++
+ modules/proxy/mod_proxy.c | 2 +-
+ modules/proxy/proxy_util.c | 4 ++--
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+ create mode 100644 changes-entries/fix_uds_filename.txt
+
+#--- /dev/null
+#+++ b/changes-entries/fix_uds_filename.txt
+#@@ -0,0 +1,2 @@
+#+ *) mod_proxy: Faster unix socket path parsing in the "proxy:" URL.
+#+ [Yann Ylavic]
+--- a/modules/proxy/mod_proxy.c
++++ b/modules/proxy/mod_proxy.c
+@@ -1703,7 +1703,7 @@ PROXY_DECLARE(const char *) ap_proxy_de_
+ * the UDS path... ignore it
+ */
+ if (!strncasecmp(url, "unix:", 5) &&
+- ((ptr = ap_strchr_c(url, '|')) != NULL)) {
++ ((ptr = ap_strchr_c(url + 5, '|')) != NULL)) {
+ /* move past the 'unix:...|' UDS path info */
+ const char *ret, *c;
+
+--- a/modules/proxy/proxy_util.c
++++ b/modules/proxy/proxy_util.c
+@@ -2094,8 +2094,8 @@ static void fix_uds_filename(request_rec
+ if (!r || !r->filename) return;
+
+ if (!strncmp(r->filename, "proxy:", 6) &&
+- (ptr2 = ap_strcasestr(r->filename, "unix:")) &&
+- (ptr = ap_strchr(ptr2, '|'))) {
++ !ap_cstr_casecmpn(r->filename + 6, "unix:", 5) &&
++ (ptr2 = r->filename + 6 + 5, ptr = ap_strchr(ptr2, '|'))) {
+ apr_uri_t urisock;
+ apr_status_t rv;
+ *ptr = '\0';
diff -Nru apache2-2.4.41/debian/patches/lp-1930430-Backport-r1865740.patch apache2-2.4.41/debian/patches/lp-1930430-Backport-r1865740.patch
--- apache2-2.4.41/debian/patches/lp-1930430-Backport-r1865740.patch 1970-01-01 00:00:00.000000000 +0000
+++ apache2-2.4.41/debian/patches/lp-1930430-Backport-r1865740.patch 2021-07-05 07:15:29.000000000 +0000
@@ -0,0 +1,32 @@
+From c11b1cd3b11f073ab1b5d1d670cec9db21144683 Mon Sep 17 00:00:00 2001
+From: Graham Leggett
+Date: Wed, 1 Jan 2020 23:05:42 +0000
+Subject: [PATCH] Backport r1865740. mod_ssl: OCSP does not apply to proxy
+ mode.
+
+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1872226 13f79535-47bb-0310-9956-ffa450edef68
+
+Origin: backport, https://github.com/apache/httpd/commit/c11b1cd3b11f
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1930430
+Last-Update: 2021-07-05
+X-Backport-Note: skipped non functional changes to status (doesn't exist) and changes (does't match)
+
+---
+ CHANGES | 2 ++
+ STATUS | 5 -----
+ modules/ssl/ssl_engine_kernel.c | 4 ++--
+ 3 files changed, 4 insertions(+), 7 deletions(-)
+
+--- a/modules/ssl/ssl_engine_kernel.c
++++ b/modules/ssl/ssl_engine_kernel.c
+@@ -1836,8 +1836,8 @@ int ssl_callback_SSLVerify(int ok, X509_
+ /*
+ * Perform OCSP-based revocation checks
+ */
+- if (ok && ((sc->server->ocsp_mask & SSL_OCSPCHECK_CHAIN) ||
+- (errdepth == 0 && (sc->server->ocsp_mask & SSL_OCSPCHECK_LEAF)))) {
++ if (ok && ((mctx->ocsp_mask & SSL_OCSPCHECK_CHAIN) ||
++ (errdepth == 0 && (mctx->ocsp_mask & SSL_OCSPCHECK_LEAF)))) {
+ /* If there was an optional verification error, it's not
+ * possible to perform OCSP validation since the issuer may be
+ * missing/untrusted. Fail in that case. */
diff -Nru apache2-2.4.41/debian/patches/series apache2-2.4.41/debian/patches/series
--- apache2-2.4.41/debian/patches/series 2021-06-17 18:27:53.000000000 +0000
+++ apache2-2.4.41/debian/patches/series 2021-09-23 16:58:57.000000000 +0000
@@ -27,3 +27,12 @@
CVE-2021-26690.patch
CVE-2021-26691.patch
CVE-2021-30641.patch
+lp-1930430-Backport-r1865740.patch
+CVE-2021-34798.patch
+CVE-2021-36160.patch
+CVE-2021-39275.patch
+CVE-2021-40438-pre1.patch
+CVE-2021-40438.patch
+CVE-2021-33193-pre1.patch
+CVE-2021-33193-pre2.patch
+CVE-2021-33193.patch