From 879b175a63ad141d42e1622a906f928015b94f7a Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Sep 29 2022 13:21:54 +0000 Subject: import httpd24-httpd-2.4.34-23.el7.5 --- diff --git a/SOURCES/httpd-2.4.34-CVE-2021-33193.patch b/SOURCES/httpd-2.4.34-CVE-2021-33193.patch new file mode 100644 index 0000000..eda488f --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2021-33193.patch @@ -0,0 +1,706 @@ +diff --git a/include/http_core.h b/include/http_core.h +index 8e10988..3ba8069 100644 +--- 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(server_rec* s, const char* proto); + 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; +diff --git a/include/http_protocol.h b/include/http_protocol.h +index 11c7b2d..e7abdd9 100644 +--- a/include/http_protocol.h ++++ b/include/http_protocol.h +@@ -53,6 +53,13 @@ AP_DECLARE_DATA extern ap_filter_rec_t *ap_old_write_func; + * or control the ones that eventually do. + */ + ++/** ++ * 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 +@@ -60,6 +67,20 @@ AP_DECLARE_DATA extern ap_filter_rec_t *ap_old_write_func; + */ + 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 +diff --git a/include/http_vhost.h b/include/http_vhost.h +index 473c9c7..d2d9c97 100644 +--- a/include/http_vhost.h ++++ b/include/http_vhost.h +@@ -99,6 +99,19 @@ AP_DECLARE(void) ap_update_vhost_given_ip(conn_rec *conn); + */ + 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. +diff --git a/server/core.c b/server/core.c +index 6dfd4d5..456336c 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -498,6 +498,8 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s) + conf->protocols = apr_array_make(a, 5, sizeof(const char *)); + conf->protocols_honor_order = -1; + ++ conf->strict_host_check= AP_CORE_CONFIG_UNSET; ++ + return (void *)conf; + } + +@@ -565,6 +567,12 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv) + + 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; + } + +@@ -4543,7 +4551,10 @@ AP_INIT_TAKE2("CGIVar", set_cgi_var, NULL, OR_FILEINFO, + 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"), +@@ -5578,4 +5589,3 @@ AP_DECLARE_MODULE(core) = { + core_cmds, /* command apr_table_t */ + register_hooks /* register hooks */ + }; +- +diff --git a/server/core_filters.c b/server/core_filters.c +index ddc2ff7..326996d 100644 +--- 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, +diff --git a/server/protocol.c b/server/protocol.c +index c77da24..867dc8a 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -609,8 +609,15 @@ AP_CORE_DECLARE(void) ap_parse_uri(request_rec *r, const char *uri) + } + + 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 *field) + + 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, apr_bucket_brigade *bb) + } + + 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 *r, apr_bucket_brigade *bb) + 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 *r, apr_bucket_brigade *bb) + /* 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(request_rec *r) + 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 *conn) + 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,33 @@ request_rec *ap_read_request(conn_rec *conn) + 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 +1444,38 @@ request_rec *ap_read_request(conn_rec *conn) + "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 +1491,8 @@ request_rec *ap_read_request(conn_rec *conn) + 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 +1505,81 @@ request_rec *ap_read_request(conn_rec *conn) + } + } + +- 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 +diff --git a/server/vhost.c b/server/vhost.c +index b23b2dd..6e233b5 100644 +--- 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(request_rec *r, const char *host, + } + + +-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 @@ static void check_hostalias(request_rec *r) + 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 @@ static void check_serverpath(request_rec *r) + * 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. + */ + +@@ -1134,11 +1148,17 @@ static APR_INLINE const char *construct_host_header(request_rec *r, + } + + 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 @@ AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) + 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 @@ AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) + /* 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/SOURCES/httpd-2.4.34-CVE-2021-34798.patch b/SOURCES/httpd-2.4.34-CVE-2021-34798.patch new file mode 100644 index 0000000..687c11e --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2021-34798.patch @@ -0,0 +1,13 @@ +diff --git a/server/scoreboard.c b/server/scoreboard.c +index 4343eba..46e3cad 100644 +--- a/server/scoreboard.c ++++ b/server/scoreboard.c +@@ -376,7 +376,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 --git a/SOURCES/httpd-2.4.34-CVE-2021-36160.patch b/SOURCES/httpd-2.4.34-CVE-2021-36160.patch new file mode 100644 index 0000000..715fca1 --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2021-36160.patch @@ -0,0 +1,45 @@ +diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c +index a4f192f..a678b1d 100644 +--- 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, proxy_worker * worker, + 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, proxy_worker * worker, + + 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 --git a/SOURCES/httpd-2.4.34-CVE-2021-39275.patch b/SOURCES/httpd-2.4.34-CVE-2021-39275.patch new file mode 100644 index 0000000..775db32 --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2021-39275.patch @@ -0,0 +1,21 @@ +diff --git a/server/util.c b/server/util.c +index 1549ab1..e53bdc1 100644 +--- a/server/util.c ++++ b/server/util.c +@@ -2460,13 +2460,12 @@ AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring) + * 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 --git a/SOURCES/httpd-2.4.34-CVE-2021-40438.patch b/SOURCES/httpd-2.4.34-CVE-2021-40438.patch index 57aa7ce..136eb1c 100644 --- a/SOURCES/httpd-2.4.34-CVE-2021-40438.patch +++ b/SOURCES/httpd-2.4.34-CVE-2021-40438.patch @@ -1,8 +1,26 @@ +diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c +index fb897a9..38dbb24 100644 +--- a/modules/mappers/mod_rewrite.c ++++ b/modules/mappers/mod_rewrite.c +@@ -619,6 +619,13 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs) + return 6; + } + break; ++ ++ case 'u': ++ case 'U': ++ if (!ap_cstr_casecmpn(uri, "nix:", 4)) { /* unix: */ ++ *sqs = 1; ++ return (uri[4] == '/' && uri[5] == '/') ? 7 : 5; ++ } + } + + return 0; diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c -index f383996..6a9ef55 100644 +index d00454e..9685e72 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c -@@ -1717,7 +1717,8 @@ PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url) +@@ -1710,7 +1710,8 @@ PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url) * the UDS path... ignore it */ if (!strncasecmp(url, "unix:", 5) && @@ -13,17 +31,94 @@ index f383996..6a9ef55 100644 const char *ret, *c; diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c -index 7714b6c..421f910 100644 +index a3999ec..1342cee 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c -@@ -2090,8 +2090,8 @@ static void fix_uds_filename(request_rec *r, char **url) - if (!r || !r->filename) return; +@@ -2060,33 +2060,45 @@ static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worke + * 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) && - (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, '|'))) { ++ !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'; +- *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 ++ || !urisock.hostname[0])) { ++ 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, +@@ -2104,7 +2116,9 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, + "%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) { +@@ -2135,7 +2149,9 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, + * 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 --git a/SOURCES/httpd-2.4.34-CVE-2021-44224.patch b/SOURCES/httpd-2.4.34-CVE-2021-44224.patch new file mode 100644 index 0000000..1a2f6d2 --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2021-44224.patch @@ -0,0 +1,330 @@ +diff --git a/include/http_protocol.h b/include/http_protocol.h +index 448ca53..8ed77ac 100644 +--- a/include/http_protocol.h ++++ b/include/http_protocol.h +@@ -96,6 +96,13 @@ AP_DECLARE(void) ap_get_mime_headers(request_rec *r); + AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, + apr_bucket_brigade *bb); + ++/** ++ * Run post_read_request hook and validate. ++ * @param r The current request ++ * @return OK or HTTP_... ++ */ ++AP_DECLARE(int) ap_post_read_request(request_rec *r); ++ + /* Finish up stuff after a request */ + + /** +diff --git a/modules/http/http_request.c b/modules/http/http_request.c +index 9e7c4db..e873aab 100644 +--- a/modules/http/http_request.c ++++ b/modules/http/http_request.c +@@ -681,7 +681,7 @@ static request_rec *internal_internal_redirect(const char *new_uri, + * to do their thing on internal redirects as well. Perhaps this is a + * misnamed function. + */ +- if ((access_status = ap_run_post_read_request(new))) { ++ if ((access_status = ap_post_read_request(new))) { + ap_die(access_status, new); + return NULL; + } +diff --git a/modules/http2/h2_request.c b/modules/http2/h2_request.c +index 8899c4f..03141d6 100644 +--- a/modules/http2/h2_request.c ++++ b/modules/http2/h2_request.c +@@ -313,7 +313,7 @@ request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c) + NULL, r, r->connection); + + if (access_status != HTTP_OK +- || (access_status = ap_run_post_read_request(r))) { ++ || (access_status = ap_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. + */ +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index 9685e72..8bffc37 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -584,11 +584,12 @@ static int proxy_detect(request_rec *r) + + if (conf->req && r->parsed_uri.scheme) { + /* but it might be something vhosted */ +- if (!(r->parsed_uri.hostname +- && !strcasecmp(r->parsed_uri.scheme, ap_http_scheme(r)) +- && ap_matches_request_vhost(r, r->parsed_uri.hostname, +- (apr_port_t)(r->parsed_uri.port_str ? r->parsed_uri.port +- : ap_default_port(r))))) { ++ if (!r->parsed_uri.hostname ++ || ap_cstr_casecmp(r->parsed_uri.scheme, ap_http_scheme(r)) != 0 ++ || !ap_matches_request_vhost(r, r->parsed_uri.hostname, ++ (apr_port_t)(r->parsed_uri.port_str ++ ? r->parsed_uri.port ++ : ap_default_port(r)))) { + r->proxyreq = PROXYREQ_PROXY; + r->uri = r->unparsed_uri; + r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL); +@@ -1743,6 +1744,7 @@ static const char * + struct proxy_alias *new; + char *f = cmd->path; + char *r = NULL; ++ const char *real; + char *word; + apr_table_t *params = apr_table_make(cmd->pool, 5); + const apr_array_header_t *arr; +@@ -1808,6 +1810,10 @@ static const char * + if (r == NULL) { + return "ProxyPass|ProxyPassMatch needs a path when not defined in a location"; + } ++ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, r))) { ++ return "ProxyPass|ProxyPassMatch uses an invalid \"unix:\" URL"; ++ } ++ + + /* if per directory, save away the single alias */ + if (cmd->path) { +@@ -1824,7 +1830,7 @@ static const char * + } + + new->fake = apr_pstrdup(cmd->pool, f); +- new->real = apr_pstrdup(cmd->pool, ap_proxy_de_socketfy(cmd->pool, r)); ++ new->real = apr_pstrdup(cmd->pool, real); + new->flags = flags; + if (use_regex) { + new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED); +@@ -2301,6 +2307,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) + proxy_worker *worker; + char *path = cmd->path; + char *name = NULL; ++ const char *real; + char *word; + apr_table_t *params = apr_table_make(cmd->pool, 5); + const apr_array_header_t *arr; +@@ -2341,6 +2348,9 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) + return "BalancerMember must define balancer name when outside section"; + if (!name) + return "BalancerMember must define remote proxy server"; ++ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, name))) { ++ return "BalancerMember uses an invalid \"unix:\" URL"; ++ } + + ap_str_tolower(path); /* lowercase scheme://hostname */ + +@@ -2353,7 +2363,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) + } + + /* Try to find existing worker */ +- worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, ap_proxy_de_socketfy(cmd->temp_pool, name)); ++ worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, real); + if (!worker) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147) + "Defining worker '%s' for balancer '%s'", +@@ -2442,7 +2452,13 @@ static const char * + } + } + else { +- worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, ap_proxy_de_socketfy(cmd->temp_pool, name)); ++ const char *real; ++ ++ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, name))) { ++ return "ProxySet uses an invalid \"unix:\" URL"; ++ } ++ ++ worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, real); + if (!worker) { + if (in_proxy_section) { + err = ap_proxy_define_worker(cmd->pool, &worker, NULL, +@@ -2584,8 +2600,14 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) + } + } + else { ++ const char *real; ++ ++ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, conf->p))) { ++ return " uses an invalid \"unix:\" URL"; ++ } ++ + worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf, +- ap_proxy_de_socketfy(cmd->temp_pool, (char*)conf->p)); ++ real); + if (!worker) { + err = ap_proxy_define_worker(cmd->pool, &worker, NULL, + sconf, conf->p, 0); +diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h +index 7141473..7164bfe 100644 +--- a/modules/proxy/mod_proxy.h ++++ b/modules/proxy/mod_proxy.h +@@ -698,6 +698,8 @@ typedef __declspec(dllimport) const char * + proxy_dir_conf *, const char *); + #endif + ++#define AP_PROXY_WORKER_NO_UDS (1u << 3) ++ + + /* Connection pool API */ + /** +@@ -710,6 +712,24 @@ typedef __declspec(dllimport) const char * + PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, + proxy_worker *worker); + ++ ++/** ++ * Get the worker from proxy configuration, looking for either PREFIXED or ++ * MATCHED or both types of workers according to given mask ++ * @param p memory pool used for finding worker ++ * @param balancer the balancer that the worker belongs to ++ * @param conf current proxy server configuration ++ * @param url url to find the worker from ++ * @param mask bitmask of AP_PROXY_WORKER_IS_* ++ * @return proxy_worker or NULL if not found ++ */ ++PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker_ex(apr_pool_t *p, ++ proxy_balancer *balancer, ++ proxy_server_conf *conf, ++ const char *url, ++ unsigned int mask); ++ ++ + /** + * Get the worker from proxy configuration + * @param p memory pool used for finding worker +@@ -722,6 +742,8 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, + proxy_balancer *balancer, + proxy_server_conf *conf, + const char *url); ++ ++ + /** + * Define and Allocate space for the worker to proxy configuration + * @param p memory pool to allocate worker from +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index fdb3a6d..a0556dd 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -1626,10 +1626,11 @@ PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, + return apr_pstrcat(p, "unix:", worker->s->uds_path, "|", worker->s->name, NULL); + } + +-PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, +- proxy_balancer *balancer, +- proxy_server_conf *conf, +- const char *url) ++PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker_ex(apr_pool_t *p, ++ proxy_balancer *balancer, ++ proxy_server_conf *conf, ++ const char *url, ++ unsigned int mask) + { + proxy_worker *worker; + proxy_worker *max_worker = NULL; +@@ -1645,7 +1646,12 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, + return NULL; + } + +- url = ap_proxy_de_socketfy(p, url); ++ if (!(mask & AP_PROXY_WORKER_NO_UDS)) { ++ url = ap_proxy_de_socketfy(p, url); ++ if (!url) { ++ return NULL; ++ } ++ } + + c = ap_strchr_c(url, ':'); + if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') { +@@ -1710,6 +1716,14 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, + return max_worker; + } + ++PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, ++ proxy_balancer *balancer, ++ proxy_server_conf *conf, ++ const char *url) ++{ ++ return ap_proxy_get_worker_ex(p, balancer, conf, url, 0); ++} ++ + /* + * To create a worker from scratch first we define the + * specifics of the worker; this is all local data. +@@ -2110,22 +2124,24 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, + + access_status = proxy_run_pre_request(worker, balancer, r, conf, url); + if (access_status == DECLINED && *balancer == NULL) { +- *worker = ap_proxy_get_worker(r->pool, NULL, conf, *url); ++ const int forward = (r->proxyreq == PROXYREQ_PROXY); ++ *worker = ap_proxy_get_worker_ex(r->pool, NULL, conf, *url, ++ forward ? AP_PROXY_WORKER_NO_UDS : 0); + if (*worker) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "%s: found worker %s for %s", + (*worker)->s->scheme, (*worker)->s->name, *url); +- *balancer = NULL; +- if (!fix_uds_filename(r, url)) { ++ ++ if (!forward && !fix_uds_filename(r, url)) { + return HTTP_INTERNAL_SERVER_ERROR; + } ++ + access_status = OK; + } +- else if (r->proxyreq == PROXYREQ_PROXY) { ++ else if (forward) { + if (conf->forward) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "*: found forward proxy worker for %s", *url); +- *balancer = NULL; + *worker = conf->forward; + access_status = OK; + /* +@@ -2139,8 +2155,8 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, + else if (r->proxyreq == PROXYREQ_REVERSE) { + if (conf->reverse) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, +- "*: using default reverse proxy worker for %s (no keepalive)", *url); +- *balancer = NULL; ++ "*: using default reverse proxy worker for %s " ++ "(no keepalive)", *url); + *worker = conf->reverse; + access_status = OK; + /* +diff --git a/server/protocol.c b/server/protocol.c +index ab1e316..a78eff6 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -1525,7 +1525,7 @@ request_rec *ap_read_request(conn_rec *conn) + /* we may have switched to another server */ + apply_server_config(r); + +- if ((access_status = ap_run_post_read_request(r))) { ++ if ((access_status = ap_post_read_request(r))) { + goto die; + } + +@@ -1582,6 +1582,27 @@ ignore: + return NULL; + } + ++AP_DECLARE(int) ap_post_read_request(request_rec *r) ++{ ++ int status; ++ ++ if ((status = ap_run_post_read_request(r))) { ++ return status; ++ } ++ ++ /* Enforce http(s) only scheme for non-forward-proxy requests */ ++ if (!r->proxyreq ++ && r->parsed_uri.scheme ++ && (ap_cstr_casecmpn(r->parsed_uri.scheme, "http", 4) != 0 ++ || (r->parsed_uri.scheme[4] != '\0' ++ && (apr_tolower(r->parsed_uri.scheme[4]) != 's' ++ || r->parsed_uri.scheme[5] != '\0')))) { ++ return HTTP_BAD_REQUEST; ++ } ++ ++ return OK; ++} ++ + /* if a request with a body creates a subrequest, remove original request's + * input headers which pertain to the body which has already been read. + * out-of-line helper function for ap_set_sub_req_protocol. diff --git a/SOURCES/httpd-2.4.34-CVE-2022-22719.patch b/SOURCES/httpd-2.4.34-CVE-2022-22719.patch new file mode 100644 index 0000000..1a0b26d --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2022-22719.patch @@ -0,0 +1,72 @@ +diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c +index 1afe333..62a70cf 100644 +--- a/modules/lua/lua_request.c ++++ b/modules/lua/lua_request.c +@@ -235,14 +235,16 @@ static int lua_read_body(request_rec *r, const char **rbuf, apr_off_t *size, + { + int rc = OK; + ++ *rbuf = NULL; ++ *size = 0; ++ + if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) { + return (rc); + } + if (ap_should_client_block(r)) { + + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +- char argsbuffer[HUGE_STRING_LEN]; +- apr_off_t rsize, len_read, rpos = 0; ++ apr_off_t len_read, rpos = 0; + apr_off_t length = r->remaining; + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +@@ -250,18 +252,18 @@ static int lua_read_body(request_rec *r, const char **rbuf, apr_off_t *size, + return APR_EINCOMPLETE; /* Only room for incomplete data chunk :( */ + } + *rbuf = (const char *) apr_pcalloc(r->pool, (apr_size_t) (length + 1)); +- *size = length; +- while ((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0) { +- if ((rpos + len_read) > length) { +- rsize = length - rpos; +- } +- else { +- rsize = len_read; +- } +- +- memcpy((char *) *rbuf + rpos, argsbuffer, (size_t) rsize); +- rpos += rsize; ++ while ((rpos < length) ++ && (len_read = ap_get_client_block(r, (char *) *rbuf + rpos, ++ length - rpos)) > 0) { ++ rpos += len_read; ++ } ++ if (len_read < 0) { ++ return APR_EINCOMPLETE; + } ++ *size = rpos; ++ } ++ else { ++ rc = DONE; + } + + return (rc); +@@ -278,6 +280,8 @@ static apr_status_t lua_write_body(request_rec *r, apr_file_t *file, apr_off_t * + { + apr_status_t rc = OK; + ++ *size = 0; ++ + if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) + return rc; + if (ap_should_client_block(r)) { +@@ -303,6 +307,9 @@ static apr_status_t lua_write_body(request_rec *r, apr_file_t *file, apr_off_t * + rpos += rsize; + } + } ++ else { ++ rc = DONE; ++ } + + return rc; + } diff --git a/SOURCES/httpd-2.4.34-CVE-2022-22721.patch b/SOURCES/httpd-2.4.34-CVE-2022-22721.patch new file mode 100644 index 0000000..3ef3778 --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2022-22721.patch @@ -0,0 +1,103 @@ +diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en +index df55e3b..2463a02 100644 +--- a/docs/manual/mod/core.html.en ++++ b/docs/manual/mod/core.html.en +@@ -2933,12 +2933,19 @@ from the client + Status:Core + Module:core + +-

Limit (in bytes) on maximum size of an XML-based request +- body. A value of 0 will disable any checking.

++

Limit (in bytes) on the maximum size of an XML-based request ++ body. A value of 0 will apply a hard limit (depending on ++ 32bit vs 64bit system) allowing for XML escaping within the bounds of ++ the system addressable memory, but it exists for compatibility only ++ and is not recommended since it does not account for memory consumed ++ elsewhere or concurrent requests, which might result in an overall ++ system out-of-memory. ++

+ +

Example:

+ +-
LimitXMLRequestBody 0
++
# Limit of 1 MiB
++    LimitXMLRequestBody 1073741824
+ + + +diff --git a/server/core.c b/server/core.c +index 456336c..de2b0d2 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -70,6 +70,8 @@ + /* LimitXMLRequestBody handling */ + #define AP_LIMIT_UNSET ((long) -1) + #define AP_DEFAULT_LIMIT_XML_BODY ((apr_size_t)1000000) ++/* Hard limit for ap_escape_html2() */ ++#define AP_MAX_LIMIT_XML_BODY ((apr_size_t)(APR_SIZE_MAX / 6 - 1)) + + #define AP_MIN_SENDFILE_BYTES (256) + +@@ -3686,6 +3688,11 @@ static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_, + if (conf->limit_xml_body < 0) + return "LimitXMLRequestBody requires a non-negative integer."; + ++ /* zero is AP_MAX_LIMIT_XML_BODY (implicitly) */ ++ if ((apr_size_t)conf->limit_xml_body > AP_MAX_LIMIT_XML_BODY) ++ return apr_psprintf(cmd->pool, "LimitXMLRequestBody must not exceed " ++ "%" APR_SIZE_T_FMT, AP_MAX_LIMIT_XML_BODY); ++ + return NULL; + } + +@@ -3774,6 +3781,8 @@ AP_DECLARE(apr_size_t) ap_get_limit_xml_body(const request_rec *r) + conf = ap_get_core_module_config(r->per_dir_config); + if (conf->limit_xml_body == AP_LIMIT_UNSET) + return AP_DEFAULT_LIMIT_XML_BODY; ++ if (conf->limit_xml_body == 0) ++ return AP_MAX_LIMIT_XML_BODY; + + return (apr_size_t)conf->limit_xml_body; + } +diff --git a/server/util.c b/server/util.c +index e53bdc1..263270e 100644 +--- a/server/util.c ++++ b/server/util.c +@@ -2037,11 +2037,14 @@ AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer) + + AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc) + { +- int i, j; ++ apr_size_t i, j; + char *x; + + /* first, count the number of extra characters */ +- for (i = 0, j = 0; s[i] != '\0'; i++) ++ for (i = 0, j = 0; s[i] != '\0'; i++) { ++ if (i + j > APR_SIZE_MAX - 6) { ++ abort(); ++ } + if (s[i] == '<' || s[i] == '>') + j += 3; + else if (s[i] == '&') +@@ -2050,6 +2053,7 @@ AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc) + j += 5; + else if (toasc && !apr_isascii(s[i])) + j += 5; ++ } + + if (j == 0) + return apr_pstrmemdup(p, s, i); +diff --git a/server/util_xml.c b/server/util_xml.c +index 4845194..22806fa 100644 +--- a/server/util_xml.c ++++ b/server/util_xml.c +@@ -85,7 +85,7 @@ AP_DECLARE(int) ap_xml_parse_input(request_rec * r, apr_xml_doc **pdoc) + } + + total_read += len; +- if (limit_xml_body && total_read > limit_xml_body) { ++ if (total_read > limit_xml_body) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00539) + "XML request body is larger than the configured " + "limit of %lu", (unsigned long)limit_xml_body); diff --git a/SOURCES/httpd-2.4.34-CVE-2022-23943.patch b/SOURCES/httpd-2.4.34-CVE-2022-23943.patch new file mode 100644 index 0000000..59038ea --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2022-23943.patch @@ -0,0 +1,377 @@ +diff --git a/modules/filters/libsed.h b/modules/filters/libsed.h +index 76cbc0c..0256b1e 100644 +--- a/modules/filters/libsed.h ++++ b/modules/filters/libsed.h +@@ -60,7 +60,7 @@ struct sed_label_s { + }; + + typedef apr_status_t (sed_err_fn_t)(void *data, const char *error); +-typedef apr_status_t (sed_write_fn_t)(void *ctx, char *buf, int sz); ++typedef apr_status_t (sed_write_fn_t)(void *ctx, char *buf, apr_size_t sz); + + typedef struct sed_commands_s sed_commands_t; + #define NWFILES 11 /* 10 plus one for standard output */ +@@ -69,7 +69,7 @@ struct sed_commands_s { + sed_err_fn_t *errfn; + void *data; + +- unsigned lsize; ++ apr_size_t lsize; + char *linebuf; + char *lbend; + const char *saveq; +@@ -116,15 +116,15 @@ struct sed_eval_s { + apr_int64_t lnum; + void *fout; + +- unsigned lsize; ++ apr_size_t lsize; + char *linebuf; + char *lspend; + +- unsigned hsize; ++ apr_size_t hsize; + char *holdbuf; + char *hspend; + +- unsigned gsize; ++ apr_size_t gsize; + char *genbuf; + char *lcomend; + +@@ -160,7 +160,7 @@ apr_status_t sed_init_eval(sed_eval_t *eval, sed_commands_t *commands, + sed_err_fn_t *errfn, void *data, + sed_write_fn_t *writefn, apr_pool_t *p); + apr_status_t sed_reset_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data); +-apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout); ++apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz, void *fout); + apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout); + apr_status_t sed_finalize_eval(sed_eval_t *eval, void *f); + void sed_destroy_eval(sed_eval_t *eval); +diff --git a/modules/filters/mod_sed.c b/modules/filters/mod_sed.c +index 346c210..8595e41 100644 +--- a/modules/filters/mod_sed.c ++++ b/modules/filters/mod_sed.c +@@ -51,7 +51,7 @@ typedef struct sed_filter_ctxt + apr_bucket_brigade *bbinp; + char *outbuf; + char *curoutbuf; +- int bufsize; ++ apr_size_t bufsize; + apr_pool_t *tpool; + int numbuckets; + } sed_filter_ctxt; +@@ -100,7 +100,7 @@ static void alloc_outbuf(sed_filter_ctxt* ctx) + /* append_bucket + * Allocate a new bucket from buf and sz and append to ctx->bb + */ +-static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, int sz) ++static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, apr_size_t sz) + { + apr_status_t status = APR_SUCCESS; + apr_bucket *b; +@@ -133,7 +133,7 @@ static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, int sz) + */ + static apr_status_t flush_output_buffer(sed_filter_ctxt *ctx) + { +- int size = ctx->curoutbuf - ctx->outbuf; ++ apr_size_t size = ctx->curoutbuf - ctx->outbuf; + char *out; + apr_status_t status = APR_SUCCESS; + if ((ctx->outbuf == NULL) || (size <=0)) +@@ -147,12 +147,12 @@ static apr_status_t flush_output_buffer(sed_filter_ctxt *ctx) + /* This is a call back function. When libsed wants to generate the output, + * this function will be invoked. + */ +-static apr_status_t sed_write_output(void *dummy, char *buf, int sz) ++static apr_status_t sed_write_output(void *dummy, char *buf, apr_size_t sz) + { + /* dummy is basically filter context. Context is passed during invocation + * of sed_eval_buffer + */ +- int remainbytes = 0; ++ apr_size_t remainbytes = 0; + apr_status_t status = APR_SUCCESS; + sed_filter_ctxt *ctx = (sed_filter_ctxt *) dummy; + if (ctx->outbuf == NULL) { +@@ -168,21 +168,29 @@ static apr_status_t sed_write_output(void *dummy, char *buf, int sz) + } + /* buffer is now full */ + status = append_bucket(ctx, ctx->outbuf, ctx->bufsize); +- /* old buffer is now used so allocate new buffer */ +- alloc_outbuf(ctx); +- /* if size is bigger than the allocated buffer directly add to output +- * brigade */ +- if ((status == APR_SUCCESS) && (sz >= ctx->bufsize)) { +- char* newbuf = apr_pmemdup(ctx->tpool, buf, sz); +- status = append_bucket(ctx, newbuf, sz); +- /* pool might get clear after append_bucket */ +- if (ctx->outbuf == NULL) { ++ if (status == APR_SUCCESS) { ++ /* if size is bigger than the allocated buffer directly add to output ++ * brigade */ ++ if (sz >= ctx->bufsize) { ++ char* newbuf = apr_pmemdup(ctx->tpool, buf, sz); ++ status = append_bucket(ctx, newbuf, sz); ++ if (status == APR_SUCCESS) { ++ /* old buffer is now used so allocate new buffer */ ++ alloc_outbuf(ctx); ++ } ++ else { ++ clear_ctxpool(ctx); ++ } ++ } ++ else { ++ /* old buffer is now used so allocate new buffer */ + alloc_outbuf(ctx); ++ memcpy(ctx->curoutbuf, buf, sz); ++ ctx->curoutbuf += sz; + } + } + else { +- memcpy(ctx->curoutbuf, buf, sz); +- ctx->curoutbuf += sz; ++ clear_ctxpool(ctx); + } + } + else { +diff --git a/modules/filters/sed1.c b/modules/filters/sed1.c +index f463ec9..d88a547 100644 +--- a/modules/filters/sed1.c ++++ b/modules/filters/sed1.c +@@ -71,7 +71,7 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n, + static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2); + static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + step_vars_storage *step_vars); +-static apr_status_t wline(sed_eval_t *eval, char *buf, int sz); ++static apr_status_t wline(sed_eval_t *eval, char *buf, apr_size_t sz); + static apr_status_t arout(sed_eval_t *eval); + + static void eval_errf(sed_eval_t *eval, const char *fmt, ...) +@@ -92,11 +92,11 @@ static void eval_errf(sed_eval_t *eval, const char *fmt, ...) + * grow_buffer + */ + static void grow_buffer(apr_pool_t *pool, char **buffer, +- char **spend, unsigned int *cursize, +- unsigned int newsize) ++ char **spend, apr_size_t *cursize, ++ apr_size_t newsize) + { + char* newbuffer = NULL; +- int spendsize = 0; ++ apr_size_t spendsize = 0; + if (*cursize >= newsize) + return; + /* Avoid number of times realloc is called. It could cause huge memory +@@ -124,7 +124,7 @@ static void grow_buffer(apr_pool_t *pool, char **buffer, + /* + * grow_line_buffer + */ +-static void grow_line_buffer(sed_eval_t *eval, int newsize) ++static void grow_line_buffer(sed_eval_t *eval, apr_size_t newsize) + { + grow_buffer(eval->pool, &eval->linebuf, &eval->lspend, + &eval->lsize, newsize); +@@ -133,7 +133,7 @@ static void grow_line_buffer(sed_eval_t *eval, int newsize) + /* + * grow_hold_buffer + */ +-static void grow_hold_buffer(sed_eval_t *eval, int newsize) ++static void grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize) + { + grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend, + &eval->hsize, newsize); +@@ -142,7 +142,7 @@ static void grow_hold_buffer(sed_eval_t *eval, int newsize) + /* + * grow_gen_buffer + */ +-static void grow_gen_buffer(sed_eval_t *eval, int newsize, ++static void grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize, + char **gspend) + { + if (gspend == NULL) { +@@ -156,9 +156,9 @@ static void grow_gen_buffer(sed_eval_t *eval, int newsize, + /* + * appendmem_to_linebuf + */ +-static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len) ++static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len) + { +- unsigned int reqsize = (eval->lspend - eval->linebuf) + len; ++ apr_size_t reqsize = (eval->lspend - eval->linebuf) + len; + if (eval->lsize < reqsize) { + grow_line_buffer(eval, reqsize); + } +@@ -169,21 +169,36 @@ static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len) + /* + * append_to_linebuf + */ +-static void append_to_linebuf(sed_eval_t *eval, const char* sz) ++static void append_to_linebuf(sed_eval_t *eval, const char* sz, ++ step_vars_storage *step_vars) + { +- int len = strlen(sz); ++ apr_size_t len = strlen(sz); ++ char *old_linebuf = eval->linebuf; + /* Copy string including null character */ + appendmem_to_linebuf(eval, sz, len + 1); + --eval->lspend; /* lspend will now point to NULL character */ ++ /* Sync step_vars after a possible linebuf expansion */ ++ if (step_vars && old_linebuf != eval->linebuf) { ++ if (step_vars->loc1) { ++ step_vars->loc1 = step_vars->loc1 - old_linebuf + eval->linebuf; ++ } ++ if (step_vars->loc2) { ++ step_vars->loc2 = step_vars->loc2 - old_linebuf + eval->linebuf; ++ } ++ if (step_vars->locs) { ++ step_vars->locs = step_vars->locs - old_linebuf + eval->linebuf; ++ } ++ } + } + + /* + * copy_to_linebuf + */ +-static void copy_to_linebuf(sed_eval_t *eval, const char* sz) ++static void copy_to_linebuf(sed_eval_t *eval, const char* sz, ++ step_vars_storage *step_vars) + { + eval->lspend = eval->linebuf; +- append_to_linebuf(eval, sz); ++ append_to_linebuf(eval, sz, step_vars); + } + + /* +@@ -191,8 +206,8 @@ static void copy_to_linebuf(sed_eval_t *eval, const char* sz) + */ + static void append_to_holdbuf(sed_eval_t *eval, const char* sz) + { +- int len = strlen(sz); +- unsigned int reqsize = (eval->hspend - eval->holdbuf) + len + 1; ++ apr_size_t len = strlen(sz); ++ apr_size_t reqsize = (eval->hspend - eval->holdbuf) + len + 1; + if (eval->hsize <= reqsize) { + grow_hold_buffer(eval, reqsize); + } +@@ -215,8 +230,8 @@ static void copy_to_holdbuf(sed_eval_t *eval, const char* sz) + */ + static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend) + { +- int len = strlen(sz); +- unsigned int reqsize = (*gspend - eval->genbuf) + len + 1; ++ apr_size_t len = strlen(sz); ++ apr_size_t reqsize = (*gspend - eval->genbuf) + len + 1; + if (eval->gsize < reqsize) { + grow_gen_buffer(eval, reqsize, gspend); + } +@@ -230,8 +245,8 @@ static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend) + */ + static void copy_to_genbuf(sed_eval_t *eval, const char* sz) + { +- int len = strlen(sz); +- unsigned int reqsize = len + 1; ++ apr_size_t len = strlen(sz); ++ apr_size_t reqsize = len + 1; + if (eval->gsize < reqsize) { + grow_gen_buffer(eval, reqsize, NULL); + } +@@ -353,7 +368,7 @@ apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout) + /* + * sed_eval_buffer + */ +-apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout) ++apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz, void *fout) + { + apr_status_t rv; + +@@ -383,7 +398,7 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void + + while (bufsz) { + char *n; +- int llen; ++ apr_size_t llen; + + n = memchr(buf, '\n', bufsz); + if (n == NULL) +@@ -442,7 +457,7 @@ apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout) + * buffer is not a newline. + */ + /* Assure space for NULL */ +- append_to_linebuf(eval, ""); ++ append_to_linebuf(eval, "", NULL); + } + + *eval->lspend = '\0'; +@@ -666,7 +681,7 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n, + lp = step_vars->loc2; + step_vars->loc2 = sp - eval->genbuf + eval->linebuf; + append_to_genbuf(eval, lp, &sp); +- copy_to_linebuf(eval, eval->genbuf); ++ copy_to_linebuf(eval, eval->genbuf, step_vars); + return rv; + } + +@@ -676,8 +691,8 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n, + static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2) + { + char *sp = asp; +- int n = al2 - al1; +- unsigned int reqsize = (sp - eval->genbuf) + n + 1; ++ apr_size_t n = al2 - al1; ++ apr_size_t reqsize = (sp - eval->genbuf) + n + 1; + + if (eval->gsize < reqsize) { + grow_gen_buffer(eval, reqsize, &sp); +@@ -733,7 +748,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + } + + p1++; +- copy_to_linebuf(eval, p1); ++ copy_to_linebuf(eval, p1, step_vars); + eval->jflag++; + break; + +@@ -743,12 +758,12 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + break; + + case GCOM: +- copy_to_linebuf(eval, eval->holdbuf); ++ copy_to_linebuf(eval, eval->holdbuf, step_vars); + break; + + case CGCOM: +- append_to_linebuf(eval, "\n"); +- append_to_linebuf(eval, eval->holdbuf); ++ append_to_linebuf(eval, "\n", step_vars); ++ append_to_linebuf(eval, eval->holdbuf, step_vars); + break; + + case HCOM: +@@ -879,7 +894,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + if (rv != APR_SUCCESS) + return rv; + } +- append_to_linebuf(eval, "\n"); ++ append_to_linebuf(eval, "\n", step_vars); + eval->pending = ipc->next; + break; + +@@ -951,7 +966,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + break; + case XCOM: + copy_to_genbuf(eval, eval->linebuf); +- copy_to_linebuf(eval, eval->holdbuf); ++ copy_to_linebuf(eval, eval->holdbuf, step_vars); + copy_to_holdbuf(eval, eval->genbuf); + break; + +@@ -1008,7 +1023,7 @@ static apr_status_t arout(sed_eval_t *eval) + /* + * wline + */ +-static apr_status_t wline(sed_eval_t *eval, char *buf, int sz) ++static apr_status_t wline(sed_eval_t *eval, char *buf, apr_size_t sz) + { + apr_status_t rv = APR_SUCCESS; + rv = eval->writefn(eval->fout, buf, sz); diff --git a/SOURCES/httpd-2.4.34-CVE-2022-26377.patch b/SOURCES/httpd-2.4.34-CVE-2022-26377.patch new file mode 100644 index 0000000..fff767b --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2022-26377.patch @@ -0,0 +1,26 @@ +diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c +index c3f5e5c..eb550e5 100644 +--- a/modules/proxy/mod_proxy_ajp.c ++++ b/modules/proxy/mod_proxy_ajp.c +@@ -249,9 +249,18 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, + /* read the first bloc of data */ + input_brigade = apr_brigade_create(p, r->connection->bucket_alloc); + tenc = apr_table_get(r->headers_in, "Transfer-Encoding"); +- if (tenc && (strcasecmp(tenc, "chunked") == 0)) { +- /* The AJP protocol does not want body data yet */ +- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00870) "request is chunked"); ++ if (tenc) { ++ if (ap_cstr_casecmp(tenc, "chunked") == 0) { ++ /* The AJP protocol does not want body data yet */ ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00870) ++ "request is chunked"); ++ } ++ else { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10396) ++ "%s Transfer-Encoding is not supported", ++ tenc); ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } + } else { + /* Get client provided Content-Length header */ + content_length = get_content_length(r); diff --git a/SOURCES/httpd-2.4.34-CVE-2022-28614.patch b/SOURCES/httpd-2.4.34-CVE-2022-28614.patch new file mode 100644 index 0000000..dad52fa --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2022-28614.patch @@ -0,0 +1,47 @@ +diff --git a/include/http_protocol.h b/include/http_protocol.h +index e1572dc..8ed77ac 100644 +--- a/include/http_protocol.h ++++ b/include/http_protocol.h +@@ -439,7 +439,27 @@ AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r); + */ + static APR_INLINE int ap_rputs(const char *str, request_rec *r) + { +- return ap_rwrite(str, (int)strlen(str), r); ++ apr_size_t len; ++ ++ len = strlen(str); ++ ++ for (;;) { ++ if (len <= INT_MAX) { ++ return ap_rwrite(str, (int)len, r); ++ } ++ else { ++ int rc; ++ ++ rc = ap_rwrite(str, INT_MAX, r); ++ if (rc < 0) { ++ return rc; ++ } ++ else { ++ str += INT_MAX; ++ len -= INT_MAX; ++ } ++ } ++ } + } + + /** +diff --git a/server/protocol.c b/server/protocol.c +index 476977f..a78eff6 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -2107,6 +2107,9 @@ AP_DECLARE(int) ap_rputc(int c, request_rec *r) + + AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r) + { ++ if (nbyte < 0) ++ return -1; ++ + if (r->connection->aborted) + return -1; + diff --git a/SOURCES/httpd-2.4.34-CVE-2022-28615.patch b/SOURCES/httpd-2.4.34-CVE-2022-28615.patch new file mode 100644 index 0000000..fb27a00 --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2022-28615.patch @@ -0,0 +1,22 @@ +diff --git a/server/util.c b/server/util.c +index 263270e..e3c79a9 100644 +--- a/server/util.c ++++ b/server/util.c +@@ -186,7 +186,7 @@ AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt, + */ + AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected) + { +- int x, y; ++ apr_size_t x, y; + + for (x = 0, y = 0; expected[y]; ++y, ++x) { + if ((!str[x]) && (expected[y] != '*')) +@@ -210,7 +210,7 @@ AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected) + + AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected) + { +- int x, y; ++ apr_size_t x, y; + + for (x = 0, y = 0; expected[y]; ++y, ++x) { + if (!str[x] && expected[y] != '*') diff --git a/SOURCES/httpd-2.4.34-CVE-2022-29404.patch b/SOURCES/httpd-2.4.34-CVE-2022-29404.patch new file mode 100644 index 0000000..708d3fc --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2022-29404.patch @@ -0,0 +1,125 @@ +diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en +index 2463a02..dc1eca5 100644 +--- a/docs/manual/mod/core.html.en ++++ b/docs/manual/mod/core.html.en +@@ -2746,16 +2746,16 @@ subrequests + Description:Restricts the total size of the HTTP request body sent + from the client + Syntax:LimitRequestBody bytes +-Default:LimitRequestBody 0 ++Default:LimitRequestBody 1073741824 + Context:server config, virtual host, directory, .htaccess + Override:All + Status:Core + Module:core ++Compatibility:In Apache HTTP Server 2.4.53 and earlier, the default value ++ was 0 (unlimited) + +-

This directive specifies the number of bytes from 0 +- (meaning unlimited) to 2147483647 (2GB) that are allowed in a +- request body. See the note below for the limited applicability +- to proxy requests.

++

This directive specifies the number of bytes ++ that are allowed in a request body. A value of 0 means unlimited.

+ +

The LimitRequestBody directive allows + the user to set a limit on the allowed size of an HTTP request +@@ -2781,12 +2781,6 @@ from the client + +

LimitRequestBody 102400
+ +- +-

For a full description of how this directive is interpreted by +- proxy requests, see the mod_proxy documentation.

+-
+- +- + +
top
+

LimitRequestFields Directive

+diff --git a/docs/manual/mod/mod_proxy.html.en b/docs/manual/mod/mod_proxy.html.en +index 2cc6ace..c9e4634 100644 +--- a/docs/manual/mod/mod_proxy.html.en ++++ b/docs/manual/mod/mod_proxy.html.en +@@ -459,9 +459,6 @@ ProxyPass "/examples" "http://backend.example.com/examples" timeout=10 + Content-Length header, but the server is configured to filter incoming + request bodies.

+ +-

LimitRequestBody only applies to +- request bodies that the server will spool to disk

+- +
top
+
+

Reverse Proxy Request Headers

+diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c +index 1ebb9cc..0174fee 100644 +--- a/modules/http/http_filters.c ++++ b/modules/http/http_filters.c +@@ -1696,6 +1696,7 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) + { + const char *tenc = apr_table_get(r->headers_in, "Transfer-Encoding"); + const char *lenp = apr_table_get(r->headers_in, "Content-Length"); ++ apr_off_t limit_req_body = ap_get_limit_req_body(r); + + r->read_body = read_policy; + r->read_chunked = 0; +@@ -1734,6 +1735,11 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) + return HTTP_REQUEST_ENTITY_TOO_LARGE; + } + ++ if (limit_req_body > 0 && (r->remaining > limit_req_body)) { ++ /* will be logged when the body is discarded */ ++ return HTTP_REQUEST_ENTITY_TOO_LARGE; ++ } ++ + #ifdef AP_DEBUG + { + /* Make sure ap_getline() didn't leave any droppings. */ +diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c +index 01dc509..a33b57b 100644 +--- a/modules/proxy/mod_proxy_http.c ++++ b/modules/proxy/mod_proxy_http.c +@@ -515,12 +515,9 @@ static int spool_reqbody_cl(apr_pool_t *p, + apr_bucket *e; + apr_off_t bytes, bytes_spooled = 0, fsize = 0; + apr_file_t *tmpfile = NULL; +- apr_off_t limit; + + body_brigade = apr_brigade_create(p, bucket_alloc); + +- limit = ap_get_limit_req_body(r); +- + while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) + { + /* If this brigade contains EOS, either stop or remove it. */ +@@ -535,17 +532,6 @@ static int spool_reqbody_cl(apr_pool_t *p, + apr_brigade_length(input_brigade, 1, &bytes); + + if (bytes_spooled + bytes > MAX_MEM_SPOOL) { +- /* +- * LimitRequestBody does not affect Proxy requests (Should it?). +- * Let it take effect if we decide to store the body in a +- * temporary file on disk. +- */ +- if (limit && (bytes_spooled + bytes > limit)) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01088) +- "Request body is larger than the configured " +- "limit of %" APR_OFF_T_FMT, limit); +- return HTTP_REQUEST_ENTITY_TOO_LARGE; +- } + /* can't spool any more in memory; write latest brigade to disk */ + if (tmpfile == NULL) { + const char *temp_dir; +diff --git a/server/core.c b/server/core.c +index de2b0d2..3223e04 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -65,7 +65,7 @@ + + /* LimitRequestBody handling */ + #define AP_LIMIT_REQ_BODY_UNSET ((apr_off_t) -1) +-#define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 0) ++#define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 1<<30) /* 1GB */ + + /* LimitXMLRequestBody handling */ + #define AP_LIMIT_UNSET ((long) -1) diff --git a/SOURCES/httpd-2.4.34-CVE-2022-30522.patch b/SOURCES/httpd-2.4.34-CVE-2022-30522.patch new file mode 100644 index 0000000..9734a23 --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2022-30522.patch @@ -0,0 +1,541 @@ +diff --git a/modules/filters/mod_sed.c b/modules/filters/mod_sed.c +index 8595e41..9b99a6b 100644 +--- a/modules/filters/mod_sed.c ++++ b/modules/filters/mod_sed.c +@@ -59,7 +59,7 @@ typedef struct sed_filter_ctxt + module AP_MODULE_DECLARE_DATA sed_module; + + /* This function will be call back from libsed functions if there is any error +- * happend during execution of sed scripts ++ * happened during execution of sed scripts + */ + static apr_status_t log_sed_errf(void *data, const char *error) + { +@@ -276,7 +276,7 @@ static apr_status_t sed_response_filter(ap_filter_t *f, + apr_bucket_brigade *bb) + { + apr_bucket *b; +- apr_status_t status; ++ apr_status_t status = APR_SUCCESS; + sed_config *cfg = ap_get_module_config(f->r->per_dir_config, + &sed_module); + sed_filter_ctxt *ctx = f->ctx; +@@ -301,9 +301,9 @@ static apr_status_t sed_response_filter(ap_filter_t *f, + return status; + ctx = f->ctx; + apr_table_unset(f->r->headers_out, "Content-Length"); +- } + +- ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); ++ ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); ++ } + + /* Here is the main logic. Iterate through all the buckets, read the + * content of the bucket, call sed_eval_buffer on the data. +@@ -325,63 +325,52 @@ static apr_status_t sed_response_filter(ap_filter_t *f, + * in sed's internal buffer which can't be flushed until new line + * character is arrived. + */ +- for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb);) { +- const char *buf = NULL; +- apr_size_t bytes = 0; ++ while (!APR_BRIGADE_EMPTY(bb)) { ++ b = APR_BRIGADE_FIRST(bb); + if (APR_BUCKET_IS_EOS(b)) { +- apr_bucket *b1 = APR_BUCKET_NEXT(b); + /* Now clean up the internal sed buffer */ + sed_finalize_eval(&ctx->eval, ctx); + status = flush_output_buffer(ctx); + if (status != APR_SUCCESS) { +- clear_ctxpool(ctx); +- return status; ++ break; + } ++ /* Move the eos bucket to ctx->bb brigade */ + APR_BUCKET_REMOVE(b); +- /* Insert the eos bucket to ctx->bb brigade */ + APR_BRIGADE_INSERT_TAIL(ctx->bb, b); +- b = b1; + } + else if (APR_BUCKET_IS_FLUSH(b)) { +- apr_bucket *b1 = APR_BUCKET_NEXT(b); +- APR_BUCKET_REMOVE(b); + status = flush_output_buffer(ctx); + if (status != APR_SUCCESS) { +- clear_ctxpool(ctx); +- return status; ++ break; + } ++ /* Move the flush bucket to ctx->bb brigade */ ++ APR_BUCKET_REMOVE(b); + APR_BRIGADE_INSERT_TAIL(ctx->bb, b); +- b = b1; +- } +- else if (APR_BUCKET_IS_METADATA(b)) { +- b = APR_BUCKET_NEXT(b); + } +- else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) +- == APR_SUCCESS) { +- apr_bucket *b1 = APR_BUCKET_NEXT(b); +- status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx); +- if (status != APR_SUCCESS) { +- clear_ctxpool(ctx); +- return status; ++ else { ++ if (!APR_BUCKET_IS_METADATA(b)) { ++ const char *buf = NULL; ++ apr_size_t bytes = 0; ++ ++ status = apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ); ++ if (status == APR_SUCCESS) { ++ status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx); ++ } ++ if (status != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, f->r, APLOGNO(10394) "error evaluating sed on output"); ++ break; ++ } + } +- APR_BUCKET_REMOVE(b); + apr_bucket_delete(b); +- b = b1; +- } +- else { +- apr_bucket *b1 = APR_BUCKET_NEXT(b); +- APR_BUCKET_REMOVE(b); +- b = b1; + } + } +- apr_brigade_cleanup(bb); +- status = flush_output_buffer(ctx); +- if (status != APR_SUCCESS) { +- clear_ctxpool(ctx); +- return status; ++ if (status == APR_SUCCESS) { ++ status = flush_output_buffer(ctx); + } + if (!APR_BRIGADE_EMPTY(ctx->bb)) { +- status = ap_pass_brigade(f->next, ctx->bb); ++ if (status == APR_SUCCESS) { ++ status = ap_pass_brigade(f->next, ctx->bb); ++ } + apr_brigade_cleanup(ctx->bb); + } + clear_ctxpool(ctx); +@@ -432,7 +421,7 @@ static apr_status_t sed_request_filter(ap_filter_t *f, + * the buckets in bbinp and read the data from buckets and invoke + * sed_eval_buffer on the data. libsed will generate its output using + * sed_write_output which will add data in ctx->bb. Do it until it have +- * atleast one bucket in ctx->bb. At the end of data eos bucket ++ * at least one bucket in ctx->bb. At the end of data eos bucket + * should be there. + * + * Once eos bucket is seen, then invoke sed_finalize_eval to clear the +@@ -474,8 +463,10 @@ static apr_status_t sed_request_filter(ap_filter_t *f, + if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) + == APR_SUCCESS) { + status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx); +- if (status != APR_SUCCESS) ++ if (status != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, f->r, APLOGNO(10395) "error evaluating sed on input"); + return status; ++ } + flush_output_buffer(ctx); + } + } +diff --git a/modules/filters/sed1.c b/modules/filters/sed1.c +index d88a547..ff17ef9 100644 +--- a/modules/filters/sed1.c ++++ b/modules/filters/sed1.c +@@ -87,18 +87,20 @@ static void eval_errf(sed_eval_t *eval, const char *fmt, ...) + } + + #define INIT_BUF_SIZE 1024 ++#define MAX_BUF_SIZE 1024*8192 + + /* + * grow_buffer + */ +-static void grow_buffer(apr_pool_t *pool, char **buffer, ++static apr_status_t grow_buffer(apr_pool_t *pool, char **buffer, + char **spend, apr_size_t *cursize, + apr_size_t newsize) + { + char* newbuffer = NULL; + apr_size_t spendsize = 0; +- if (*cursize >= newsize) +- return; ++ if (*cursize >= newsize) { ++ return APR_SUCCESS; ++ } + /* Avoid number of times realloc is called. It could cause huge memory + * requirement if line size is huge e.g 2 MB */ + if (newsize < *cursize * 2) { +@@ -107,6 +109,9 @@ static void grow_buffer(apr_pool_t *pool, char **buffer, + + /* Align it to 4 KB boundary */ + newsize = (newsize + ((1 << 12) - 1)) & ~((1 << 12) -1); ++ if (newsize > MAX_BUF_SIZE) { ++ return APR_ENOMEM; ++ } + newbuffer = apr_pcalloc(pool, newsize); + if (*spend && *buffer && (*cursize > 0)) { + spendsize = *spend - *buffer; +@@ -119,63 +124,77 @@ static void grow_buffer(apr_pool_t *pool, char **buffer, + if (spend != buffer) { + *spend = *buffer + spendsize; + } ++ return APR_SUCCESS; + } + + /* + * grow_line_buffer + */ +-static void grow_line_buffer(sed_eval_t *eval, apr_size_t newsize) ++static apr_status_t grow_line_buffer(sed_eval_t *eval, apr_size_t newsize) + { +- grow_buffer(eval->pool, &eval->linebuf, &eval->lspend, ++ return grow_buffer(eval->pool, &eval->linebuf, &eval->lspend, + &eval->lsize, newsize); + } + + /* + * grow_hold_buffer + */ +-static void grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize) ++static apr_status_t grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize) + { +- grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend, ++ return grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend, + &eval->hsize, newsize); + } + + /* + * grow_gen_buffer + */ +-static void grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize, ++static apr_status_t grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize, + char **gspend) + { ++ apr_status_t rc = 0; + if (gspend == NULL) { + gspend = &eval->genbuf; + } +- grow_buffer(eval->pool, &eval->genbuf, gspend, +- &eval->gsize, newsize); +- eval->lcomend = &eval->genbuf[71]; ++ rc = grow_buffer(eval->pool, &eval->genbuf, gspend, ++ &eval->gsize, newsize); ++ if (rc == APR_SUCCESS) { ++ eval->lcomend = &eval->genbuf[71]; ++ } ++ return rc; + } + + /* + * appendmem_to_linebuf + */ +-static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len) ++static apr_status_t appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len) + { ++ apr_status_t rc = 0; + apr_size_t reqsize = (eval->lspend - eval->linebuf) + len; + if (eval->lsize < reqsize) { +- grow_line_buffer(eval, reqsize); ++ rc = grow_line_buffer(eval, reqsize); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + } + memcpy(eval->lspend, sz, len); + eval->lspend += len; ++ return APR_SUCCESS; + } + + /* + * append_to_linebuf + */ +-static void append_to_linebuf(sed_eval_t *eval, const char* sz, ++static apr_status_t append_to_linebuf(sed_eval_t *eval, const char* sz, + step_vars_storage *step_vars) + { + apr_size_t len = strlen(sz); + char *old_linebuf = eval->linebuf; ++ apr_status_t rc = 0; + /* Copy string including null character */ +- appendmem_to_linebuf(eval, sz, len + 1); ++ rc = appendmem_to_linebuf(eval, sz, len + 1); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + --eval->lspend; /* lspend will now point to NULL character */ + /* Sync step_vars after a possible linebuf expansion */ + if (step_vars && old_linebuf != eval->linebuf) { +@@ -189,68 +208,84 @@ static void append_to_linebuf(sed_eval_t *eval, const char* sz, + step_vars->locs = step_vars->locs - old_linebuf + eval->linebuf; + } + } ++ return APR_SUCCESS; + } + + /* + * copy_to_linebuf + */ +-static void copy_to_linebuf(sed_eval_t *eval, const char* sz, ++static apr_status_t copy_to_linebuf(sed_eval_t *eval, const char* sz, + step_vars_storage *step_vars) + { + eval->lspend = eval->linebuf; +- append_to_linebuf(eval, sz, step_vars); ++ return append_to_linebuf(eval, sz, step_vars); + } + + /* + * append_to_holdbuf + */ +-static void append_to_holdbuf(sed_eval_t *eval, const char* sz) ++static apr_status_t append_to_holdbuf(sed_eval_t *eval, const char* sz) + { + apr_size_t len = strlen(sz); + apr_size_t reqsize = (eval->hspend - eval->holdbuf) + len + 1; ++ apr_status_t rc = 0; + if (eval->hsize <= reqsize) { +- grow_hold_buffer(eval, reqsize); ++ rc = grow_hold_buffer(eval, reqsize); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + } + memcpy(eval->hspend, sz, len + 1); + /* hspend will now point to NULL character */ + eval->hspend += len; ++ return APR_SUCCESS; + } + + /* + * copy_to_holdbuf + */ +-static void copy_to_holdbuf(sed_eval_t *eval, const char* sz) ++static apr_status_t copy_to_holdbuf(sed_eval_t *eval, const char* sz) + { + eval->hspend = eval->holdbuf; +- append_to_holdbuf(eval, sz); ++ return append_to_holdbuf(eval, sz); + } + + /* + * append_to_genbuf + */ +-static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend) ++static apr_status_t append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend) + { + apr_size_t len = strlen(sz); + apr_size_t reqsize = (*gspend - eval->genbuf) + len + 1; ++ apr_status_t rc = 0; + if (eval->gsize < reqsize) { +- grow_gen_buffer(eval, reqsize, gspend); ++ rc = grow_gen_buffer(eval, reqsize, gspend); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + } + memcpy(*gspend, sz, len + 1); + /* *gspend will now point to NULL character */ + *gspend += len; ++ return APR_SUCCESS; + } + + /* + * copy_to_genbuf + */ +-static void copy_to_genbuf(sed_eval_t *eval, const char* sz) ++static apr_status_t copy_to_genbuf(sed_eval_t *eval, const char* sz) + { + apr_size_t len = strlen(sz); + apr_size_t reqsize = len + 1; ++ apr_status_t rc = APR_SUCCESS;; + if (eval->gsize < reqsize) { +- grow_gen_buffer(eval, reqsize, NULL); ++ rc = grow_gen_buffer(eval, reqsize, NULL); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + } + memcpy(eval->genbuf, sz, len + 1); ++ return rc; + } + + /* +@@ -397,6 +432,7 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz + } + + while (bufsz) { ++ apr_status_t rc = 0; + char *n; + apr_size_t llen; + +@@ -411,7 +447,10 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz + break; + } + +- appendmem_to_linebuf(eval, buf, llen + 1); ++ rc = appendmem_to_linebuf(eval, buf, llen + 1); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + --eval->lspend; + /* replace new line character with NULL */ + *eval->lspend = '\0'; +@@ -426,7 +465,10 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz + + /* Save the leftovers for later */ + if (bufsz) { +- appendmem_to_linebuf(eval, buf, bufsz); ++ apr_status_t rc = appendmem_to_linebuf(eval, buf, bufsz); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + } + + return APR_SUCCESS; +@@ -448,6 +490,7 @@ apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout) + /* Process leftovers */ + if (eval->lspend > eval->linebuf) { + apr_status_t rv; ++ apr_status_t rc = 0; + + if (eval->lreadyflag) { + eval->lreadyflag = 0; +@@ -457,7 +500,10 @@ apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout) + * buffer is not a newline. + */ + /* Assure space for NULL */ +- append_to_linebuf(eval, "", NULL); ++ rc = append_to_linebuf(eval, "", NULL); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + } + + *eval->lspend = '\0'; +@@ -655,11 +701,15 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n, + sp = eval->genbuf; + rp = rhsbuf; + sp = place(eval, sp, lp, step_vars->loc1); ++ if (sp == NULL) { ++ return APR_EGENERAL; ++ } + while ((c = *rp++) != 0) { + if (c == '&') { + sp = place(eval, sp, step_vars->loc1, step_vars->loc2); +- if (sp == NULL) ++ if (sp == NULL) { + return APR_EGENERAL; ++ } + } + else if (c == '\\') { + c = *rp++; +@@ -675,13 +725,19 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n, + *sp++ = c; + if (sp >= eval->genbuf + eval->gsize) { + /* expand genbuf and set the sp appropriately */ +- grow_gen_buffer(eval, eval->gsize + 1024, &sp); ++ rv = grow_gen_buffer(eval, eval->gsize + 1024, &sp); ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } + } + } + lp = step_vars->loc2; + step_vars->loc2 = sp - eval->genbuf + eval->linebuf; +- append_to_genbuf(eval, lp, &sp); +- copy_to_linebuf(eval, eval->genbuf, step_vars); ++ rv = append_to_genbuf(eval, lp, &sp); ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } ++ rv = copy_to_linebuf(eval, eval->genbuf, step_vars); + return rv; + } + +@@ -695,7 +751,10 @@ static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2) + apr_size_t reqsize = (sp - eval->genbuf) + n + 1; + + if (eval->gsize < reqsize) { +- grow_gen_buffer(eval, reqsize, &sp); ++ apr_status_t rc = grow_gen_buffer(eval, reqsize, &sp); ++ if (rc != APR_SUCCESS) { ++ return NULL; ++ } + } + memcpy(sp, al1, n); + return sp + n; +@@ -748,7 +807,8 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + } + + p1++; +- copy_to_linebuf(eval, p1, step_vars); ++ rv = copy_to_linebuf(eval, p1, step_vars); ++ if (rv != APR_SUCCESS) return rv; + eval->jflag++; + break; + +@@ -758,21 +818,27 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + break; + + case GCOM: +- copy_to_linebuf(eval, eval->holdbuf, step_vars); ++ rv = copy_to_linebuf(eval, eval->holdbuf, step_vars); ++ if (rv != APR_SUCCESS) return rv; + break; + + case CGCOM: +- append_to_linebuf(eval, "\n", step_vars); +- append_to_linebuf(eval, eval->holdbuf, step_vars); ++ rv = append_to_linebuf(eval, "\n", step_vars); ++ if (rv != APR_SUCCESS) return rv; ++ rv = append_to_linebuf(eval, eval->holdbuf, step_vars); ++ if (rv != APR_SUCCESS) return rv; + break; + + case HCOM: +- copy_to_holdbuf(eval, eval->linebuf); ++ rv = copy_to_holdbuf(eval, eval->linebuf); ++ if (rv != APR_SUCCESS) return rv; + break; + + case CHCOM: +- append_to_holdbuf(eval, "\n"); +- append_to_holdbuf(eval, eval->linebuf); ++ rv = append_to_holdbuf(eval, "\n"); ++ if (rv != APR_SUCCESS) return rv; ++ rv = append_to_holdbuf(eval, eval->linebuf); ++ if (rv != APR_SUCCESS) return rv; + break; + + case ICOM: +@@ -894,7 +960,8 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + if (rv != APR_SUCCESS) + return rv; + } +- append_to_linebuf(eval, "\n", step_vars); ++ rv = append_to_linebuf(eval, "\n", step_vars); ++ if (rv != APR_SUCCESS) return rv; + eval->pending = ipc->next; + break; + +@@ -965,9 +1032,12 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + eval->linebuf); + break; + case XCOM: +- copy_to_genbuf(eval, eval->linebuf); +- copy_to_linebuf(eval, eval->holdbuf, step_vars); +- copy_to_holdbuf(eval, eval->genbuf); ++ rv = copy_to_genbuf(eval, eval->linebuf); ++ if (rv != APR_SUCCESS) return rv; ++ rv = copy_to_linebuf(eval, eval->holdbuf, step_vars); ++ if (rv != APR_SUCCESS) return rv; ++ rv = copy_to_holdbuf(eval, eval->genbuf); ++ if (rv != APR_SUCCESS) return rv; + break; + + case YCOM: diff --git a/SOURCES/httpd-2.4.34-CVE-2022-30556.patch b/SOURCES/httpd-2.4.34-CVE-2022-30556.patch new file mode 100644 index 0000000..bc469bd --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2022-30556.patch @@ -0,0 +1,233 @@ +diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c +index 62a70cf..4b1147a 100644 +--- a/modules/lua/lua_request.c ++++ b/modules/lua/lua_request.c +@@ -2189,23 +2189,20 @@ static int lua_websocket_greet(lua_State *L) + return 0; + } + +-static apr_status_t lua_websocket_readbytes(conn_rec* c, char* buffer, +- apr_off_t len) ++static apr_status_t lua_websocket_readbytes(conn_rec* c, ++ apr_bucket_brigade *brigade, ++ char* buffer, apr_off_t len) + { +- apr_bucket_brigade *brigade = apr_brigade_create(c->pool, c->bucket_alloc); ++ apr_size_t delivered; + apr_status_t rv; ++ + rv = ap_get_brigade(c->input_filters, brigade, AP_MODE_READBYTES, + APR_BLOCK_READ, len); + if (rv == APR_SUCCESS) { +- if (!APR_BRIGADE_EMPTY(brigade)) { +- apr_bucket* bucket = APR_BRIGADE_FIRST(brigade); +- const char* data = NULL; +- apr_size_t data_length = 0; +- rv = apr_bucket_read(bucket, &data, &data_length, APR_BLOCK_READ); +- if (rv == APR_SUCCESS) { +- memcpy(buffer, data, len); +- } +- apr_bucket_delete(bucket); ++ delivered = len; ++ rv = apr_brigade_flatten(brigade, buffer, &delivered); ++ if ((rv == APR_SUCCESS) && (delivered < len)) { ++ rv = APR_INCOMPLETE; + } + } + apr_brigade_cleanup(brigade); +@@ -2235,35 +2232,28 @@ static int lua_websocket_peek(lua_State *L) + + static int lua_websocket_read(lua_State *L) + { +- apr_socket_t *sock; + apr_status_t rv; + int do_read = 1; + int n = 0; +- apr_size_t len = 1; + apr_size_t plen = 0; + unsigned short payload_short = 0; + apr_uint64_t payload_long = 0; + unsigned char *mask_bytes; + char byte; +- int plaintext; +- +- ++ apr_bucket_brigade *brigade; ++ conn_rec* c; ++ + request_rec *r = ap_lua_check_request_rec(L, 1); +- plaintext = ap_lua_ssl_is_https(r->connection) ? 0 : 1; ++ c = r->connection; + +- + mask_bytes = apr_pcalloc(r->pool, 4); +- sock = ap_get_conn_socket(r->connection); ++ ++ brigade = apr_brigade_create(r->pool, c->bucket_alloc); + + while (do_read) { + do_read = 0; + /* Get opcode and FIN bit */ +- if (plaintext) { +- rv = apr_socket_recv(sock, &byte, &len); +- } +- else { +- rv = lua_websocket_readbytes(r->connection, &byte, 1); +- } ++ rv = lua_websocket_readbytes(c, brigade, &byte, 1); + if (rv == APR_SUCCESS) { + unsigned char ubyte, fin, opcode, mask, payload; + ubyte = (unsigned char)byte; +@@ -2273,12 +2263,7 @@ static int lua_websocket_read(lua_State *L) + opcode = ubyte & 0xf; + + /* Get the payload length and mask bit */ +- if (plaintext) { +- rv = apr_socket_recv(sock, &byte, &len); +- } +- else { +- rv = lua_websocket_readbytes(r->connection, &byte, 1); +- } ++ rv = lua_websocket_readbytes(c, brigade, &byte, 1); + if (rv == APR_SUCCESS) { + ubyte = (unsigned char)byte; + /* Mask is the first bit */ +@@ -2289,40 +2274,25 @@ static int lua_websocket_read(lua_State *L) + + /* Extended payload? */ + if (payload == 126) { +- len = 2; +- if (plaintext) { +- /* XXX: apr_socket_recv does not receive len bits, only up to len bits! */ +- rv = apr_socket_recv(sock, (char*) &payload_short, &len); +- } +- else { +- rv = lua_websocket_readbytes(r->connection, +- (char*) &payload_short, 2); +- } +- payload_short = ntohs(payload_short); ++ rv = lua_websocket_readbytes(c, brigade, ++ (char*) &payload_short, 2); + +- if (rv == APR_SUCCESS) { +- plen = payload_short; +- } +- else { ++ if (rv != APR_SUCCESS) { + return 0; + } ++ ++ plen = ntohs(payload_short); + } + /* Super duper extended payload? */ + if (payload == 127) { +- len = 8; +- if (plaintext) { +- rv = apr_socket_recv(sock, (char*) &payload_long, &len); +- } +- else { +- rv = lua_websocket_readbytes(r->connection, +- (char*) &payload_long, 8); +- } +- if (rv == APR_SUCCESS) { +- plen = ap_ntoh64(&payload_long); +- } +- else { ++ rv = lua_websocket_readbytes(c, brigade, ++ (char*) &payload_long, 8); ++ ++ if (rv != APR_SUCCESS) { + return 0; + } ++ ++ plen = ap_ntoh64(&payload_long); + } + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03210) + "Websocket: Reading %" APR_SIZE_T_FMT " (%s) bytes, masking is %s. %s", +@@ -2331,46 +2301,27 @@ static int lua_websocket_read(lua_State *L) + mask ? "on" : "off", + fin ? "This is a final frame" : "more to follow"); + if (mask) { +- len = 4; +- if (plaintext) { +- rv = apr_socket_recv(sock, (char*) mask_bytes, &len); +- } +- else { +- rv = lua_websocket_readbytes(r->connection, +- (char*) mask_bytes, 4); +- } ++ rv = lua_websocket_readbytes(c, brigade, ++ (char*) mask_bytes, 4); ++ + if (rv != APR_SUCCESS) { + return 0; + } + } + if (plen < (HUGE_STRING_LEN*1024) && plen > 0) { + apr_size_t remaining = plen; +- apr_size_t received; +- apr_off_t at = 0; + char *buffer = apr_palloc(r->pool, plen+1); + buffer[plen] = 0; + +- if (plaintext) { +- while (remaining > 0) { +- received = remaining; +- rv = apr_socket_recv(sock, buffer+at, &received); +- if (received > 0 ) { +- remaining -= received; +- at += received; +- } +- } +- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, +- "Websocket: Frame contained %" APR_OFF_T_FMT " bytes, pushed to Lua stack", +- at); +- } +- else { +- rv = lua_websocket_readbytes(r->connection, buffer, +- remaining); +- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, +- "Websocket: SSL Frame contained %" APR_SIZE_T_FMT " bytes, "\ +- "pushed to Lua stack", +- remaining); ++ rv = lua_websocket_readbytes(c, brigade, buffer, remaining); ++ ++ if (rv != APR_SUCCESS) { ++ return 0; + } ++ ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, ++ "Websocket: Frame contained %" APR_SIZE_T_FMT \ ++ " bytes, pushed to Lua stack", remaining); + if (mask) { + for (n = 0; n < plen; n++) { + buffer[n] ^= mask_bytes[n%4]; +@@ -2382,14 +2333,25 @@ static int lua_websocket_read(lua_State *L) + return 2; + } + +- + /* Decide if we need to react to the opcode or not */ + if (opcode == 0x09) { /* ping */ + char frame[2]; +- plen = 2; ++ apr_bucket *b; ++ + frame[0] = 0x8A; + frame[1] = 0; +- apr_socket_send(sock, frame, &plen); /* Pong! */ ++ ++ /* Pong! */ ++ b = apr_bucket_transient_create(frame, 2, c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(brigade, b); ++ ++ rv = ap_pass_brigade(c->output_filters, brigade); ++ apr_brigade_cleanup(brigade); ++ ++ if (rv != APR_SUCCESS) { ++ return 0; ++ } ++ + do_read = 1; + } + } diff --git a/SOURCES/httpd-2.4.34-CVE-2022-31813.patch b/SOURCES/httpd-2.4.34-CVE-2022-31813.patch new file mode 100644 index 0000000..bae0bf8 --- /dev/null +++ b/SOURCES/httpd-2.4.34-CVE-2022-31813.patch @@ -0,0 +1,230 @@ +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 42a963f..713825d 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -3566,12 +3566,14 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + char **old_cl_val, + char **old_te_val) + { ++ int rc = OK; + conn_rec *c = r->connection; + int counter; + char *buf; ++ apr_table_t *saved_headers_in = r->headers_in; ++ const char *saved_host = apr_table_get(saved_headers_in, "Host"); + const apr_array_header_t *headers_in_array; + const apr_table_entry_t *headers_in; +- apr_table_t *saved_headers_in; + apr_bucket *e; + int do_100_continue; + conn_rec *origin = p_conn->connection; +@@ -3608,6 +3610,52 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + ap_xlate_proto_to_ascii(buf, strlen(buf)); + e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(header_brigade, e); ++ ++ /* ++ * Make a copy on r->headers_in for the request we make to the backend, ++ * modify the copy in place according to our configuration and connection ++ * handling, use it to fill in the forwarded headers' brigade, and finally ++ * restore the saved/original ones in r->headers_in. ++ * ++ * Note: We need to take r->pool for apr_table_copy as the key / value ++ * pairs in r->headers_in have been created out of r->pool and ++ * p might be (and actually is) a longer living pool. ++ * This would trigger the bad pool ancestry abort in apr_table_copy if ++ * apr is compiled with APR_POOL_DEBUG. ++ * ++ * icing: if p indeed lives longer than r->pool, we should allocate ++ * all new header values from r->pool as well and avoid leakage. ++ */ ++ r->headers_in = apr_table_copy(r->pool, saved_headers_in); ++ ++ /* Return the original Transfer-Encoding and/or Content-Length values ++ * then drop the headers, they must be set by the proxy handler based ++ * on the actual body being forwarded. ++ */ ++ if ((*old_te_val = (char *)apr_table_get(r->headers_in, ++ "Transfer-Encoding"))) { ++ apr_table_unset(r->headers_in, "Transfer-Encoding"); ++ } ++ if ((*old_cl_val = (char *)apr_table_get(r->headers_in, ++ "Content-Length"))) { ++ apr_table_unset(r->headers_in, "Content-Length"); ++ } ++ ++ /* Clear out hop-by-hop request headers not to forward */ ++ if (ap_proxy_clear_connection(r, r->headers_in) < 0) { ++ rc = HTTP_BAD_REQUEST; ++ goto cleanup; ++ } ++ ++ /* RFC2616 13.5.1 says we should strip these */ ++ apr_table_unset(r->headers_in, "Keep-Alive"); ++ apr_table_unset(r->headers_in, "Upgrade"); ++ apr_table_unset(r->headers_in, "Trailer"); ++ apr_table_unset(r->headers_in, "TE"); ++ ++ /* We used to send `Host: ` always first, so let's keep it that ++ * way. No telling which legacy backend is relying no this. ++ */ + if (dconf->preserve_host == 0) { + if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */ + if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) { +@@ -3629,7 +3677,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + /* don't want to use r->hostname, as the incoming header might have a + * port attached + */ +- const char* hostname = apr_table_get(r->headers_in,"Host"); ++ const char* hostname = saved_host; + if (!hostname) { + hostname = r->server->server_hostname; + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01092) +@@ -3643,21 +3691,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + ap_xlate_proto_to_ascii(buf, strlen(buf)); + e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(header_brigade, e); +- +- /* +- * Save the original headers in here and restore them when leaving, since +- * we will apply proxy purpose only modifications (eg. clearing hop-by-hop +- * headers, add Via or X-Forwarded-* or Expect...), whereas the originals +- * will be needed later to prepare the correct response and logging. +- * +- * Note: We need to take r->pool for apr_table_copy as the key / value +- * pairs in r->headers_in have been created out of r->pool and +- * p might be (and actually is) a longer living pool. +- * This would trigger the bad pool ancestry abort in apr_table_copy if +- * apr is compiled with APR_POOL_DEBUG. +- */ +- saved_headers_in = r->headers_in; +- r->headers_in = apr_table_copy(r->pool, saved_headers_in); ++ apr_table_unset(r->headers_in, "Host"); + + /* handle Via */ + if (conf->viaopt == via_block) { +@@ -3732,8 +3766,6 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + */ + if (dconf->add_forwarded_headers) { + if (PROXYREQ_REVERSE == r->proxyreq) { +- const char *buf; +- + /* Add X-Forwarded-For: so that the upstream has a chance to + * determine, where the original request came from. + */ +@@ -3743,8 +3775,9 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + /* Add X-Forwarded-Host: so that upstream knows what the + * original request hostname was. + */ +- if ((buf = apr_table_get(r->headers_in, "Host"))) { +- apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf); ++ if (saved_host) { ++ apr_table_mergen(r->headers_in, "X-Forwarded-Host", ++ saved_host); + } + + /* Add X-Forwarded-Server: so that upstream knows what the +@@ -3756,11 +3789,28 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + } + } + +- proxy_run_fixups(r); +- if (ap_proxy_clear_connection(r, r->headers_in) < 0) { +- return HTTP_BAD_REQUEST; ++ /* Do we want to strip Proxy-Authorization ? ++ * If we haven't used it, then NO ++ * If we have used it then MAYBE: RFC2616 says we MAY propagate it. ++ * So let's make it configurable by env. ++ */ ++ if (r->user != NULL /* we've authenticated */ ++ && !apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { ++ apr_table_unset(r->headers_in, "Proxy-Authorization"); + } + ++ /* for sub-requests, ignore freshness/expiry headers */ ++ if (r->main) { ++ apr_table_unset(r->headers_in, "If-Match"); ++ apr_table_unset(r->headers_in, "If-Modified-Since"); ++ apr_table_unset(r->headers_in, "If-Range"); ++ apr_table_unset(r->headers_in, "If-Unmodified-Since"); ++ apr_table_unset(r->headers_in, "If-None-Match"); ++ } ++ ++ /* run hook to fixup the request we are about to send */ ++ proxy_run_fixups(r); ++ + creds = apr_table_get(r->notes, "proxy-basic-creds"); + if (creds) { + apr_table_mergen(r->headers_in, "Proxy-Authorization", creds); +@@ -3771,55 +3821,8 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + headers_in = (const apr_table_entry_t *) headers_in_array->elts; + for (counter = 0; counter < headers_in_array->nelts; counter++) { + if (headers_in[counter].key == NULL +- || headers_in[counter].val == NULL +- +- /* Already sent */ +- || !strcasecmp(headers_in[counter].key, "Host") +- +- /* Clear out hop-by-hop request headers not to send +- * RFC2616 13.5.1 says we should strip these headers +- */ +- || !strcasecmp(headers_in[counter].key, "Keep-Alive") +- || !strcasecmp(headers_in[counter].key, "TE") +- || !strcasecmp(headers_in[counter].key, "Trailer") +- || !strcasecmp(headers_in[counter].key, "Upgrade") +- +- ) { +- continue; +- } +- /* Do we want to strip Proxy-Authorization ? +- * If we haven't used it, then NO +- * If we have used it then MAYBE: RFC2616 says we MAY propagate it. +- * So let's make it configurable by env. +- */ +- if (!strcasecmp(headers_in[counter].key,"Proxy-Authorization")) { +- if (r->user != NULL) { /* we've authenticated */ +- if (!apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { +- continue; +- } +- } +- } +- +- /* Skip Transfer-Encoding and Content-Length for now. +- */ +- if (!strcasecmp(headers_in[counter].key, "Transfer-Encoding")) { +- *old_te_val = headers_in[counter].val; +- continue; +- } +- if (!strcasecmp(headers_in[counter].key, "Content-Length")) { +- *old_cl_val = headers_in[counter].val; +- continue; +- } +- +- /* for sub-requests, ignore freshness/expiry headers */ +- if (r->main) { +- if ( !strcasecmp(headers_in[counter].key, "If-Match") +- || !strcasecmp(headers_in[counter].key, "If-Modified-Since") +- || !strcasecmp(headers_in[counter].key, "If-Range") +- || !strcasecmp(headers_in[counter].key, "If-Unmodified-Since") +- || !strcasecmp(headers_in[counter].key, "If-None-Match")) { +- continue; +- } ++ || headers_in[counter].val == NULL) { ++ continue; + } + + buf = apr_pstrcat(p, headers_in[counter].key, ": ", +@@ -3830,11 +3833,9 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + APR_BRIGADE_INSERT_TAIL(header_brigade, e); + } + +- /* Restore the original headers in (see comment above), +- * we won't modify them anymore. +- */ ++cleanup: + r->headers_in = saved_headers_in; +- return OK; ++ return rc; + } + + PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc, diff --git a/SPECS/httpd.spec b/SPECS/httpd.spec index 9205b9d..c192171 100644 --- a/SPECS/httpd.spec +++ b/SPECS/httpd.spec @@ -51,7 +51,7 @@ Summary: Apache HTTP Server Name: %{?scl:%scl_prefix}httpd Version: 2.4.34 -Release: 23%{?dist}.2 +Release: 23%{?dist}.5 URL: http://httpd.apache.org/ Source0: http://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source1: index.html @@ -182,6 +182,36 @@ Patch213: httpd-2.4.34-CVE-2021-40438.patch Patch214: httpd-2.4.34-CVE-2021-44790.patch # https://bugzilla.redhat.com/show_bug.cgi?id=2064321 Patch215: httpd-2.4.34-CVE-2022-22720.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1996513 +Patch216: httpd-2.4.34-CVE-2021-33193.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2007192 +Patch217: httpd-2.4.34-CVE-2021-34798.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2007196 +Patch218: httpd-2.4.34-CVE-2021-39275.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2007200 +Patch219: httpd-2.4.34-CVE-2021-36160.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2035029 +Patch220: httpd-2.4.34-CVE-2021-44224.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2065236 +Patch221: httpd-2.4.34-CVE-2022-22719.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2066263 +Patch222: httpd-2.4.34-CVE-2022-23943.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2066794 +Patch223: httpd-2.4.34-CVE-2022-22721.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2096999 +Patch224: httpd-2.4.34-CVE-2022-26377.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2097017 +Patch225: httpd-2.4.34-CVE-2022-28614.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2097033 +Patch226: httpd-2.4.34-CVE-2022-28615.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2097453 +Patch227: httpd-2.4.34-CVE-2022-29404.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2097460 +Patch228: httpd-2.4.34-CVE-2022-30522.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2097482 +Patch229: httpd-2.4.34-CVE-2022-30556.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2098249 +Patch230: httpd-2.4.34-CVE-2022-31813.patch License: ASL 2.0 Group: System Environment/Daemons @@ -404,6 +434,21 @@ export LD_LIBRARY_PATH=%{_libdir}:$LD_LIBRARY_PATH %patch213 -p1 -b .CVE-2021-40438 %patch214 -p1 -b .CVE-2021-44790 %patch215 -p1 -b .CVE-2022-22720 +%patch216 -p1 -b .CVE-2021-33193 +%patch217 -p1 -b .CVE-2021-34798 +%patch218 -p1 -b .CVE-2021-39275 +%patch219 -p1 -b .CVE-2021-36160 +%patch220 -p1 -b .CVE-2021-44224 +%patch221 -p1 -b .CVE-2022-22719 +%patch222 -p1 -b .CVE-2022-23943 +%patch223 -p1 -b .CVE-2022-22721 +%patch224 -p1 -b .CVE-2022-26377 +%patch225 -p1 -b .CVE-2022-28614 +%patch226 -p1 -b .CVE-2022-28615 +%patch227 -p1 -b .CVE-2022-29404 +%patch228 -p1 -b .CVE-2022-30522 +%patch229 -p1 -b .CVE-2022-30556 +%patch230 -p1 -b .CVE-2022-31813 # Patch in the vendor string and the release string sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h @@ -1062,6 +1107,45 @@ rm -rf $RPM_BUILD_ROOT %endif %changelog +* Tue Sep 20 2022 Luboš Uhliarik - 2.4.34-23.5 +- Related: #2035029 - CVE-2021-44224 httpd24-httpd: httpd: possible NULL + dereference or SSRF in forward proxy configurations + +* Thu Sep 15 2022 Luboš Uhliarik - 2.4.34-23.4 +- Resolves: #2022319 - proxy rewrite to unix socket fails fix + +* Wed Sep 07 2022 Luboš Uhliarik - 2.4.34-23.3 +- Resolves: #1996513 - CVE-2021-33193 httpd24-httpd: httpd: Request splitting + via HTTP/2 method injection and mod_proxy +- Resolves: #2007192 - CVE-2021-34798 httpd24-httpd: httpd: NULL pointer + dereference via malformed requests +- Resolves: #2007196 - CVE-2021-39275 httpd24-httpd: httpd: out-of-bounds + write in ap_escape_quotes() via malicious input +- Resolves: #2007200 - CVE-2021-36160 httpd24-httpd: httpd: mod_proxy_uwsgi: + out-of-bounds read via a crafted request uri-path +- Resolves: #2035029 - CVE-2021-44224 httpd24-httpd: httpd: possible NULL + dereference or SSRF in forward proxy configurations +- Resolves: #2065236 - CVE-2022-22719 httpd24-httpd: httpd: mod_lua: Use of + uninitialized value of in r:parsebody +- Resolves: #2066263 - CVE-2022-23943 httpd24-httpd: httpd: mod_sed: Read/write + beyond bounds +- Resolves: #2066794 - CVE-2022-22721 httpd24-httpd: httpd: core: Possible + buffer overflow with very large or unlimited LimitXMLRequestBody +- Resolves: #2096999 - CVE-2022-26377 httpd24-httpd: httpd: mod_proxy_ajp: + Possible request smuggling +- Resolves: #2097017 - CVE-2022-28614 httpd24-httpd: httpd: out-of-bounds read + via ap_rwrite() +- Resolves: #2097033 - CVE-2022-28615 httpd24-httpd: httpd: out-of-bounds read + in ap_strcmp_match() +- Resolves: #2097453 - CVE-2022-29404 httpd24-httpd: httpd: mod_lua: DoS in + r:parsebody +- Resolves: #2097460 - CVE-2022-30522 httpd24-httpd: httpd: mod_sed: DoS + vulnerability +- Resolves: #2097482 - CVE-2022-30556 httpd24-httpd: httpd: mod_lua: Information + disclosure with websockets +- Resolves: #2098249 - CVE-2022-31813 httpd24-httpd: httpd: mod_proxy: + X-Forwarded-For dropped by hop-by-hop mechanism + * Wed Mar 23 2022 Luboš Uhliarik - 2.4.34-23.2 - Resolves: #2065438 - CVE-2022-22720 httpd24-httpd: httpd: HTTP request smuggling vulnerability in Apache HTTP Server 2.4.52 and earlier