From e8667ed3143a4faa0f21666ed6f2bd4c946381c6 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Wed, 22 May 2024 10:49:23 +0000 Subject: [PATCH] import CS mod_http2-1.15.7-10.module_el8+1009+c203647a --- SOURCES/mod_http2-1.15.7-CVE-2023-45802.patch | 217 ++++++++++++++++++ SOURCES/mod_http2-1.15.7-CVE-2024-27316.patch | 55 +++++ SPECS/mod_http2.spec | 16 +- 3 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 SOURCES/mod_http2-1.15.7-CVE-2023-45802.patch create mode 100644 SOURCES/mod_http2-1.15.7-CVE-2024-27316.patch diff --git a/SOURCES/mod_http2-1.15.7-CVE-2023-45802.patch b/SOURCES/mod_http2-1.15.7-CVE-2023-45802.patch new file mode 100644 index 0000000..298794a --- /dev/null +++ b/SOURCES/mod_http2-1.15.7-CVE-2023-45802.patch @@ -0,0 +1,217 @@ +diff --git a/mod_http2/h2_mplx.c b/mod_http2/h2_mplx.c +index 33ea45e..f49b58e 100644 +--- a/mod_http2/h2_mplx.c ++++ b/mod_http2/h2_mplx.c +@@ -352,10 +352,11 @@ apr_status_t h2_mplx_stream_do(h2_mplx *m, h2_mplx_stream_cb *cb, void *ctx) + { + stream_iter_ctx_t x; + +- H2_MPLX_ENTER(m); +- + x.cb = cb; + x.ctx = ctx; ++ ++ H2_MPLX_ENTER(m); ++ + h2_ihash_iter(m->streams, stream_iter_wrap, &x); + + H2_MPLX_LEAVE(m); +@@ -1143,14 +1144,33 @@ int h2_mplx_awaits_data(h2_mplx *m) + return waiting; + } + +-apr_status_t h2_mplx_client_rst(h2_mplx *m, int stream_id) ++apr_status_t h2_mplx_client_rst(h2_mplx *m, int stream_id, h2_stream *stream) + { +- h2_stream *stream; + apr_status_t status = APR_SUCCESS; +- ++ int registered; ++ + H2_MPLX_ENTER_ALWAYS(m); +- stream = h2_ihash_get(m->streams, stream_id); +- if (stream && stream->task) { ++ registered = (h2_ihash_get(m->streams, stream_id) != NULL); ++ ++ if (!stream) { ++ /* a RST might arrive so late, we have already forgotten ++ * about it. Seems ok. */ ++ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, ++ H2_MPLX_MSG(m, "RST on unknown stream %d"), stream_id); ++ AP_DEBUG_ASSERT(!registered); ++ } ++ else if (!registered) { ++ /* a RST on a stream that mplx has not been told about, but ++ * which the session knows. Very early and annoying. */ ++ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, ++ H2_STRM_MSG(stream, "very early RST, drop")); ++ h2_stream_set_monitor(stream, NULL); ++ h2_stream_rst(stream, H2_ERR_STREAM_CLOSED); ++ h2_stream_dispatch(stream, H2_SEV_EOS_SENT); ++ stream_cleanup(m, stream); ++ mplx_be_annoyed(m); ++ } ++ else if (stream->task) { + status = mplx_be_annoyed(m); + } + H2_MPLX_LEAVE(m); +diff --git a/mod_http2/h2_mplx.h b/mod_http2/h2_mplx.h +index 8a4f63f..6d838e5 100644 +--- a/mod_http2/h2_mplx.h ++++ b/mod_http2/h2_mplx.h +@@ -204,7 +204,8 @@ typedef int h2_mplx_stream_cb(struct h2_stream *s, void *ctx); + + apr_status_t h2_mplx_stream_do(h2_mplx *m, h2_mplx_stream_cb *cb, void *ctx); + +-apr_status_t h2_mplx_client_rst(h2_mplx *m, int stream_id); ++apr_status_t h2_mplx_client_rst(h2_mplx *m, int stream_id, ++ struct h2_stream *stream); + + /******************************************************************************* + * Output handling of streams. +@@ -287,6 +288,9 @@ APR_RING_INSERT_TAIL((b), ap__b, h2_mplx, link); \ + */ + #define H2_MPLX_REMOVE(e) APR_RING_REMOVE((e), link) + ++#define H2_MPLX_MSG(m, msg) \ ++ "h2_mplx(%lu): "msg, (unsigned long)m->id ++ + /******************************************************************************* + * h2_mplx DoS protection + ******************************************************************************/ +diff --git a/mod_http2/h2_proxy_session.c b/mod_http2/h2_proxy_session.c +index 97a4a2a..8478b16 100644 +--- a/mod_http2/h2_proxy_session.c ++++ b/mod_http2/h2_proxy_session.c +@@ -677,7 +677,7 @@ static apr_status_t session_start(h2_proxy_session *session) + apr_socket_t *s; + + s = ap_get_conn_socket(session->c); +-#if (!defined(WIN32) && !defined(NETWARE)) || defined(DOXYGEN) ++#if !defined(WIN32) && !defined(NETWARE) + if (s) { + ap_sock_disable_nagle(s); + } +@@ -1515,9 +1515,20 @@ static int done_iter(void *udata, void *val) + { + cleanup_iter_ctx *ctx = udata; + h2_proxy_stream *stream = val; +- int touched = (stream->data_sent || ++ int touched = (stream->data_sent || + stream->id <= ctx->session->last_stream_id); +- ctx->done(ctx->session, stream->r, APR_ECONNABORTED, touched); ++ ++ if (touched && stream->output) { ++ apr_bucket *b = ap_bucket_error_create(HTTP_BAD_GATEWAY, NULL, ++ stream->r->pool, ++ ctx->session->c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(stream->output, b); ++ b = apr_bucket_eos_create(ctx->session->c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(stream->output, b); ++ ap_pass_brigade(stream->r->output_filters, stream->output); ++ } ++ ctx->done(ctx->session, stream->r, APR_ECONNABORTED, touched); ++ + return 1; + } + +diff --git a/mod_http2/h2_session.c b/mod_http2/h2_session.c +index a5cc306..090bba6 100644 +--- a/mod_http2/h2_session.c ++++ b/mod_http2/h2_session.c +@@ -389,6 +389,10 @@ static int on_frame_recv_cb(nghttp2_session *ng2s, + session->id, (int)frame->hd.stream_id, + (int)frame->rst_stream.error_code); + stream = get_stream(session, frame->hd.stream_id); ++ if (stream) { ++ rv = h2_stream_recv_frame(stream, NGHTTP2_RST_STREAM, frame->hd.flags, ++ frame->hd.length + H2_FRAME_HDR_LEN); ++ } + if (stream && stream->initiated_on) { + /* A stream reset on a request we sent it. Normal, when the + * client does not want it. */ +@@ -397,7 +401,8 @@ static int on_frame_recv_cb(nghttp2_session *ng2s, + else { + /* A stream reset on a request it sent us. Could happen in a browser + * when the user navigates away or cancels loading - maybe. */ +- h2_mplx_client_rst(session->mplx, frame->hd.stream_id); ++ h2_mplx_client_rst(session->mplx, frame->hd.stream_id, ++ stream); + ++session->streams_reset; + } + break; +@@ -778,6 +783,17 @@ static apr_status_t session_cleanup(h2_session *session, const char *trigger) + "goodbye, clients will be confused, should not happen")); + } + ++ if (!h2_iq_empty(session->in_process)) { ++ int sid; ++ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, ++ H2_SSSN_LOG(APLOGNO(), session, ++ "cleanup, resetting %d streams in in_process"), ++ h2_iq_count(session->in_process)); ++ while ((sid = h2_iq_shift(session->in_process)) > 0) { ++ h2_mplx_client_rst(session->mplx, sid, get_stream(session, sid)); ++ } ++ } ++ + transit(session, trigger, H2_SESSION_ST_CLEANUP); + h2_mplx_release_and_join(session->mplx, session->iowait); + session->mplx = NULL; +diff --git a/mod_http2/h2_stream.c b/mod_http2/h2_stream.c +index 6136baa..397f890 100644 +--- a/mod_http2/h2_stream.c ++++ b/mod_http2/h2_stream.c +@@ -120,7 +120,7 @@ static int trans_on_event[][H2_SS_MAX] = { + { S_XXX, S_ERR, S_ERR, S_CL_L, S_CLS, S_XXX, S_XXX, S_XXX, },/* EV_CLOSED_L*/ + { S_ERR, S_ERR, S_ERR, S_CL_R, S_ERR, S_CLS, S_NOP, S_NOP, },/* EV_CLOSED_R*/ + { S_CLS, S_CLS, S_CLS, S_CLS, S_CLS, S_CLS, S_NOP, S_NOP, },/* EV_CANCELLED*/ +-{ S_NOP, S_XXX, S_XXX, S_XXX, S_XXX, S_CLS, S_CLN, S_XXX, },/* EV_EOS_SENT*/ ++{ S_NOP, S_XXX, S_XXX, S_XXX, S_XXX, S_CLS, S_CLN, S_NOP, },/* EV_EOS_SENT*/ + }; + + static int on_map(h2_stream_state_t state, int map[H2_SS_MAX]) +diff --git a/mod_http2/mod_proxy_http2.c b/mod_http2/mod_proxy_http2.c +index 844653e..b98298e 100644 +--- a/mod_http2/mod_proxy_http2.c ++++ b/mod_http2/mod_proxy_http2.c +@@ -67,7 +67,7 @@ typedef struct h2_proxy_ctx { + unsigned flushall : 1; + + request_rec *r; /* the request processed in this ctx */ +- apr_status_t r_status; /* status of request work */ ++ int r_status; /* status of request work */ + int r_done; /* request was processed, not necessarily successfully */ + int r_may_retry; /* request may be retried */ + h2_proxy_session *session; /* current http2 session against backend */ +@@ -403,7 +403,7 @@ run_connect: + "setup new connection: is_ssl=%d %s %s %s", + ctx->p_conn->is_ssl, ctx->p_conn->ssl_hostname, + locurl, ctx->p_conn->hostname); +- ctx->r_status = status; ++ ctx->r_status = ap_map_http_request_error(status, HTTP_SERVICE_UNAVAILABLE); + goto cleanup; + } + +@@ -418,7 +418,7 @@ run_connect: + if (ctx->master->aborted) goto cleanup; + status = ctx_run(ctx); + +- if (ctx->r_status != APR_SUCCESS && ctx->r_may_retry && !ctx->master->aborted) { ++ if (ctx->r_status != OK && ctx->r_may_retry && !ctx->owner->aborted) { + /* Not successfully processed, but may retry, tear down old conn and start over */ + if (ctx->p_conn) { + ctx->p_conn->close = 1; +@@ -453,6 +453,12 @@ cleanup: + ap_set_module_config(ctx->owner->conn_config, &proxy_http2_module, NULL); + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, ctx->owner, + APLOGNO(03377) "leaving handler"); ++ if (ctx->r_status != OK) { ++ ap_die(ctx->r_status, r); ++ } ++ else if (status != APR_SUCCESS) { ++ ap_die(ap_map_http_request_error(status, HTTP_SERVICE_UNAVAILABLE), r); ++ } + return ctx->r_status; + } + diff --git a/SOURCES/mod_http2-1.15.7-CVE-2024-27316.patch b/SOURCES/mod_http2-1.15.7-CVE-2024-27316.patch new file mode 100644 index 0000000..fa3174d --- /dev/null +++ b/SOURCES/mod_http2-1.15.7-CVE-2024-27316.patch @@ -0,0 +1,55 @@ +From 134e28ae5abc997fe064995627b3ebe247a5d5d8 Mon Sep 17 00:00:00 2001 +From: Stefan Eissing +Date: Fri, 23 Feb 2024 15:13:56 +0100 +Subject: [PATCH] RESET stream after 100 failed incoming headers + +--- + mod_http2/h2_session.c | 10 +++++++--- + mod_http2/h2_stream.c | 1 + + mod_http2/h2_stream.h | 1 + + 3 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/mod_http2/h2_session.c b/mod_http2/h2_session.c +index a5cc306..4b38518 100644 +--- a/mod_http2/h2_session.c ++++ b/mod_http2/h2_session.c +@@ -311,7 +311,12 @@ static int on_header_cb(nghttp2_session *ngh2, const nghttp2_frame *frame, + + status = h2_stream_add_header(stream, (const char *)name, namelen, + (const char *)value, valuelen); +- if (status != APR_SUCCESS && !h2_stream_is_ready(stream)) { ++ if (status != APR_SUCCESS ++ && (!h2_stream_is_ready(stream) || ++ /* We accept a certain amount of failures in order to reply ++ * with an informative HTTP error response like 413. But of the ++ * client is too wrong, we fail the request an RESET the stream */ ++ stream->request_headers_failed > 100)) { + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + } + return 0; +diff --git a/mod_http2/h2_stream.c b/mod_http2/h2_stream.c +index 6136baa..d3c4d99 100644 +--- a/mod_http2/h2_stream.c ++++ b/mod_http2/h2_stream.c +@@ -733,6 +733,7 @@ apr_status_t h2_stream_add_header(h2_stream *stream, + } + + if (error) { ++ ++stream->request_headers_failed; + set_error_response(stream, error); + return APR_EINVAL; + } +diff --git a/mod_http2/h2_stream.h b/mod_http2/h2_stream.h +index 79cb39d..4ddf1a2 100644 +--- a/mod_http2/h2_stream.h ++++ b/mod_http2/h2_stream.h +@@ -75,7 +75,8 @@ struct h2_stream { + struct h2_request *rtmp; /* request being assembled */ + apr_table_t *trailers; /* optional incoming trailers */ + int request_headers_added; /* number of request headers added */ +- ++ int request_headers_failed; /* number of request headers failed to add */ ++ + struct h2_bucket_beam *input; + apr_bucket_brigade *in_buffer; + int in_window_size; diff --git a/SPECS/mod_http2.spec b/SPECS/mod_http2.spec index be36599..7acc926 100644 --- a/SPECS/mod_http2.spec +++ b/SPECS/mod_http2.spec @@ -3,7 +3,7 @@ Name: mod_http2 Version: 1.15.7 -Release: 8%{?dist}.3 +Release: 10%{?dist} Summary: module implementing HTTP/2 for Apache 2 Group: System Environment/Daemons License: ASL 2.0 @@ -16,6 +16,10 @@ Patch4: mod_http2-1.15.7-CVE-2021-44224.patch Patch5: mod_http2-1.15.7-SNI.patch # https://bugzilla.redhat.com/show_bug.cgi?id=2176209 Patch6: mod_http2-1.15.7-CVE-2023-25690.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2243877 +Patch7: mod_http2-1.15.7-CVE-2023-45802.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2268277 +Patch8: mod_http2-1.15.7-CVE-2024-27316.patch BuildRequires: pkgconfig, httpd-devel >= 2.4.20, libnghttp2-devel >= 1.7.0, openssl-devel >= 1.0.2 Requires: httpd-mmn = %{_httpd_mmn} @@ -33,6 +37,8 @@ top of libnghttp2 for httpd 2.4 servers. %patch4 -p1 -b .CVE-2021-44224 %patch5 -p1 -b .SNI %patch6 -p1 -b .CVE-2023-25690 +%patch7 -p1 -b .CVE-2023-45802 +%patch8 -p1 -b .CVE-2024-27316 %build %configure @@ -59,6 +65,14 @@ make check %{_httpd_moddir}/mod_proxy_http2.so %changelog +* Fri Apr 05 2024 Luboš Uhliarik - 1.15.7-10 +- Resolves: RHEL-29817 - httpd:2.4/mod_http2: httpd: CONTINUATION frames + DoS (CVE-2024-27316) + +* Fri Feb 02 2024 Luboš Uhliarik - 1.15.7-9.3 +- Resolves: RHEL-13367 - httpd:2.4/mod_http2: reset requests exhaust memory + (incomplete fix of CVE-2023-44487)(CVE-2023-45802) + * Sat Mar 18 2023 Luboš Uhliarik - 1.15.7-8.3 - Resolves: #2177748 - CVE-2023-25690 httpd:2.4/httpd: HTTP request splitting with mod_rewrite and mod_proxy