import CS mod_http2-1.15.7-10.module_el8+1009+c203647a
This commit is contained in:
parent
f716275667
commit
e8667ed314
217
SOURCES/mod_http2-1.15.7-CVE-2023-45802.patch
Normal file
217
SOURCES/mod_http2-1.15.7-CVE-2023-45802.patch
Normal file
@ -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;
|
||||
}
|
||||
|
55
SOURCES/mod_http2-1.15.7-CVE-2024-27316.patch
Normal file
55
SOURCES/mod_http2-1.15.7-CVE-2024-27316.patch
Normal file
@ -0,0 +1,55 @@
|
||||
From 134e28ae5abc997fe064995627b3ebe247a5d5d8 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Eissing <stefan@eissing.org>
|
||||
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;
|
@ -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 <luhliari@redhat.com> - 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 <luhliari@redhat.com> - 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 <luhliari@redhat.com> - 1.15.7-8.3
|
||||
- Resolves: #2177748 - CVE-2023-25690 httpd:2.4/httpd: HTTP request splitting
|
||||
with mod_rewrite and mod_proxy
|
||||
|
Loading…
Reference in New Issue
Block a user