diff --git a/changes-entries/h2_cleanup.txt b/changes-entries/h2_cleanup.txt new file mode 100644 index 0000000000000000000000000000000000000000..5366b4adfc66509afdd47918fcc5e1500a88fb87 --- /dev/null +++ b/changes-entries/h2_cleanup.txt @@ -0,0 +1,2 @@ + * mod_http2: improved early cleanup of streams. + [Stefan Eissing] diff --git a/debian/changelog b/debian/changelog index 3497ab0baf9528bcd3b76c9fee19de055334e371..15a21ed3f188df14ae7cb9579283fe8500d059b0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +apache2 (2.4.54-ok6) yangtze; urgency=medium + + * CVE-2023-45802 安全更新 + + -- liqinglin <1217876069@qq.com> Thu, 18 Jan 2024 21:19:27 +0800 + apache2 (2.4.54-ok6) yangtze; urgency=medium * CVE-2023-27522 安全更新 diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c index 25e8e440846fd34280f1d7f201bc9d4be1324dbb..a3dd275591fe2bdec41454af46ca72c287eaa731 100644 --- a/modules/http2/h2_mplx.c +++ b/modules/http2/h2_mplx.c @@ -1059,14 +1059,32 @@ static int reset_is_acceptable(h2_stream *stream) return 1; /* otherwise, be forgiving */ } -apr_status_t h2_mplx_m_client_rst(h2_mplx *m, int stream_id) +apr_status_t h2_mplx_c1_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 && !reset_is_acceptable(stream)) { + 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->c1, + 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->c1, + 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); + m_stream_cleanup(m, stream); + m_be_annoyed(m); + } + else if (!reset_is_acceptable(stream)) { status = m_be_annoyed(m); } H2_MPLX_LEAVE(m); diff --git a/modules/http2/h2_mplx.h b/modules/http2/h2_mplx.h index c61629d5701303a35b2e3c61531cf3b43186f577..ad2f07ba86b12a6055ec93f057d666c68485bad9 100644 --- a/modules/http2/h2_mplx.h +++ b/modules/http2/h2_mplx.h @@ -211,8 +211,8 @@ void h2_mplx_s_task_done(h2_mplx *m, struct h2_task *task, struct h2_task **ptas /** * Opens the output for the given stream with the specified response. */ -apr_status_t h2_mplx_t_out_open(h2_mplx *mplx, int stream_id, - struct h2_bucket_beam *beam); +apr_status_t h2_mplx_c1_client_rst(h2_mplx *m, int stream_id, + struct h2_stream *stream); /** * Get the stream that belongs to the given task. diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c index 4ccf255f3e37fb3824f8aade46706071a6c935a1..fe67c773e797649dbbe56d031cd58dfdf95aaf77 100644 --- a/modules/http2/h2_session.c +++ b/modules/http2/h2_session.c @@ -391,6 +391,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. */ @@ -399,7 +403,7 @@ 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_m_client_rst(session->mplx, frame->hd.stream_id); + h2_mplx_m_client_rst(session->mplx, frame->hd.stream_id,stream); ++session->streams_reset; } break; @@ -779,6 +783,16 @@ static apr_status_t session_cleanup(h2_session *session, const char *trigger) "connection disappeared without proper " "goodbye, clients will be confused, should not happen")); } + if (!h2_iq_empty(session->ready_to_process)) { + int sid; + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, + H2_SSSN_LOG(APLOGNO(), session, + "cleanup, resetting %d streams in ready-to-process"), + h2_iq_count(session->ready_to_process)); + while ((sid = h2_iq_shift(session->ready_to_process)) > 0) { + h2_mplx_c1_client_rst(session->mplx, sid, get_stream(session, sid)); + } + } transit(session, trigger, H2_SESSION_ST_CLEANUP); h2_mplx_m_release_and_join(session->mplx, session->iowait); diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c index 4fec5377f72ec540b02ba6067381dc73e2bd1009..49d89cb0c33853da9fa1d38e5a707e4f2350698d 100644 --- a/modules/http2/h2_stream.c +++ b/modules/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])