httpd/backport-CVE-2023-43622-fixed-a-bug-in-handling-of-stream-timeouts.patch

135 lines
4.9 KiB
Diff
Raw Normal View History

From 582c533c1728459eef5f8ec1a64b81fb093b26a8 Mon Sep 17 00:00:00 2001
From: SteFan Eissing <icing@apache.org>
Date: Mon, 16 Oct 2023 06:18:30 +0000
Subject: [PATCH] mod_http2: fixed a bug in handling of stream timeouts.
Conflict:NA
Reference:https://github.com/apache/httpd/commit/582c533c1728459eef5f8ec1a64b81fb093b26a8
---
changes-entries/h2_stream_timeout.txt | 2 ++
modules/http2/h2_mplx.c | 25 +++++++++++++++++++++++++
modules/http2/h2_mplx.h | 5 +++++
modules/http2/h2_session.c | 10 +++++++++-
modules/http2/h2_stream.c | 8 ++++++++
modules/http2/h2_stream.h | 2 ++
6 files changed, 51 insertions(+), 1 deletion(-)
create mode 100644 changes-entries/h2_stream_timeout.txt
diff --git a/changes-entries/h2_stream_timeout.txt b/changes-entries/h2_stream_timeout.txt
new file mode 100644
index 0000000..ab39b42
--- /dev/null
+++ b/changes-entries/h2_stream_timeout.txt
@@ -0,0 +1,2 @@
+* mod_http2: fixed a bug in handing of stream timeouts.
+ [Stefan Eissing]
diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c
index b4855af..e150cc3 100644
--- a/modules/http2/h2_mplx.c
+++ b/modules/http2/h2_mplx.c
@@ -394,6 +394,31 @@ apr_status_t h2_mplx_c1_streams_do(h2_mplx *m, h2_mplx_stream_cb *cb, void *ctx)
return APR_SUCCESS;
}
+typedef struct {
+ int stream_count;
+ int stream_want_send;
+} stream_iter_aws_t;
+
+static int m_stream_want_send_data(void *ctx, void *stream)
+{
+ stream_iter_aws_t *x = ctx;
+ ++x->stream_count;
+ if (h2_stream_wants_send_data(stream))
+ ++x->stream_want_send;
+ return 1;
+}
+
+int h2_mplx_c1_all_streams_want_send_data(h2_mplx *m)
+{
+ stream_iter_aws_t x;
+ x.stream_count = 0;
+ x.stream_want_send = 0;
+ H2_MPLX_ENTER(m);
+ h2_ihash_iter(m->streams, m_stream_want_send_data, &x);
+ H2_MPLX_LEAVE(m);
+ return x.stream_count && (x.stream_count == x.stream_want_send);
+}
+
static int m_report_stream_iter(void *ctx, void *val) {
h2_mplx *m = ctx;
h2_stream *stream = val;
diff --git a/modules/http2/h2_mplx.h b/modules/http2/h2_mplx.h
index f565a09..730bb16 100644
--- a/modules/http2/h2_mplx.h
+++ b/modules/http2/h2_mplx.h
@@ -193,6 +193,11 @@ typedef int h2_mplx_stream_cb(struct h2_stream *s, void *userdata);
*/
apr_status_t h2_mplx_c1_streams_do(h2_mplx *m, h2_mplx_stream_cb *cb, void *ctx);
+/**
+ * Return != 0 iff all open streams want to send data
+ */
+int h2_mplx_c1_all_streams_want_send_data(h2_mplx *m)
+
/**
* A stream has been RST_STREAM by the client. Abort
* any processing going on and remove from processing
diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c
index f740373..8aeff3c 100644
--- a/modules/http2/h2_session.c
+++ b/modules/http2/h2_session.c
@@ -1931,7 +1931,15 @@ apr_status_t h2_session_process(h2_session *session, int async)
status = h2_mplx_c1_poll(session->mplx, session->s->timeout,
on_stream_input, on_stream_output, session);
if (APR_STATUS_IS_TIMEUP(status)) {
- if (session->open_streams == 0) {
+ /* If we timeout without streams open, no new request from client
+ * arrived.
+ * If we timeout without nghttp2 wanting to write something, bug
+ * all open streams have something to send, it means we are
+ * blocked on HTTP/2 flow control and the client did not send
+ * WINDOW_UPDATEs to us. */
+ if (session->open_stream == 0 ||
+ (!h2_session_want_send(session) &&
+ h2_mplx_c1_all_streams_want_send_data(session->m))) {
h2_session_dispatch_event(session, H2_SESSION_EV_CONN_TIMEOUT, status, NULL);
break;
}
diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c
index 17e5d34..c81c3e4 100644
--- a/modules/http2/h2_stream.c
+++ b/modules/http2/h2_stream.c
@@ -1185,6 +1185,14 @@ int h2_stream_is_ready(h2_stream *stream)
return 0;
}
+int h2_stream_wants_send_data(h2_stream *stream)
+{
+ H2_STRM_ASSERT_MAGIC(stream, H2_STRM_MAGIC_OK);
+ return h2_stream_is_ready(stream) &&
+ ((stream->out_buffer && !APR_BRIGADE_EMPTY(stream->out_buffer)) ||
+ (stream->output && !h2_beam_empty(stream->output)));
+}
+
int h2_stream_is_at(const h2_stream *stream, h2_stream_state_t state)
{
return stream->state == state;
diff --git a/modules/http2/h2_stream.h b/modules/http2/h2_stream.h
index 695d56a..647ef2d 100644
--- a/modules/http2/h2_stream.h
+++ b/modules/http2/h2_stream.h
@@ -317,6 +317,8 @@ const char *h2_stream_state_str(const h2_stream *stream);
*/
int h2_stream_is_ready(h2_stream *stream);
+int h2_stream_wants_send_data(h2_stream *stream);
+
#define H2_STRM_MSG(s, msg) \
"h2_stream(%d-%lu-%d,%s): "msg, s->session->child_num, \
(unsigned long)s->session->id, s->id, h2_stream_state_str(s)
--
2.23.0