]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: mux-quic: Fix memleak on QUIC stream buffer for unacknowledged data
authorFrédéric Lécaille <flecaille@haproxy.com>
Sat, 20 Aug 2022 16:59:36 +0000 (18:59 +0200)
committerFrédéric Lécaille <flecaille@haproxy.com>
Sat, 20 Aug 2022 17:08:31 +0000 (19:08 +0200)
Some clients send CONNECTION_CLOSE frame without acknowledging the STREAM
data haproxy has sent. In this case, when closing the connection if
there were remaining data in QUIC stream buffers, they were not released.

Add a <closing> boolean option to qc_stream_desc_free() to force the
stream buffer memory releasing upon closing connection.

Thank you to Tristan for having reported such a memory leak issue in GH #1801.

Must be backported to 2.6.

include/haproxy/quic_stream.h
src/quic_stream.c
src/xprt_quic.c

index 1107e86f2e52874e04ec55a28fcc311720662f62..cb30b1ae4a9484da3126358eb8719f37561d3e95 100644 (file)
@@ -12,7 +12,7 @@ struct qc_stream_desc *qc_stream_desc_new(uint64_t id, enum qcs_type, void *ctx,
                                           struct quic_conn *qc);
 void qc_stream_desc_release(struct qc_stream_desc *stream);
 int qc_stream_desc_ack(struct qc_stream_desc **stream, size_t offset, size_t len);
-void qc_stream_desc_free(struct qc_stream_desc *stream);
+void qc_stream_desc_free(struct qc_stream_desc *stream, int closing);
 
 struct buffer *qc_stream_buf_get(struct qc_stream_desc *stream);
 struct buffer *qc_stream_buf_alloc(struct qc_stream_desc *stream,
index 205ee76aa5544c5216536cf0cfa8bc6936288764..abd977c5bf67e39f709da79095e5f3df4f47bd1b 100644 (file)
@@ -63,7 +63,7 @@ void qc_stream_desc_release(struct qc_stream_desc *stream)
 
        if (LIST_ISEMPTY(&stream->buf_list)) {
                /* if no buffer left we can free the stream. */
-               qc_stream_desc_free(stream);
+               qc_stream_desc_free(stream, 0);
        }
        else {
                /* A released stream does not use <stream.buf>. */
@@ -131,7 +131,7 @@ int qc_stream_desc_ack(struct qc_stream_desc **stream, size_t offset, size_t len
 
        /* Free stream instance if already released and no buffers left. */
        if (s->release && LIST_ISEMPTY(&s->buf_list)) {
-               qc_stream_desc_free(s);
+               qc_stream_desc_free(s, 0);
                *stream = NULL;
        }
 
@@ -139,10 +139,10 @@ int qc_stream_desc_ack(struct qc_stream_desc **stream, size_t offset, size_t len
 }
 
 /* Free the stream descriptor <stream> content. This function should be used
- * when all its data have been acknowledged or on full connection closing. It
- * must only be called after the stream is released.
+ * when all its data have been acknowledged or on full connection closing if <closing>
+ * boolean is set to 1. It must only be called after the stream is released.
  */
-void qc_stream_desc_free(struct qc_stream_desc *stream)
+void qc_stream_desc_free(struct qc_stream_desc *stream, int closing)
 {
        struct qc_stream_buf *buf, *buf_back;
        struct quic_conn *qc = stream->qc;
@@ -154,7 +154,7 @@ void qc_stream_desc_free(struct qc_stream_desc *stream)
 
        /* free remaining stream buffers */
        list_for_each_entry_safe(buf, buf_back, &stream->buf_list, list) {
-               if (!(b_data(&buf->buf))) {
+               if (!(b_data(&buf->buf)) || closing) {
                        b_free(&buf->buf);
                        LIST_DELETE(&buf->list);
                        pool_free(pool_head_quic_stream_buf, buf);
index e1f731da74c4f868205afb057b42663e9cc459c8..f6497f102a5e3e1754e7988ae3e56da861dae8ae 100644 (file)
@@ -4457,7 +4457,7 @@ static void quic_conn_release(struct quic_conn *qc)
                 * qc_stream_desc_free will liberate the stream instance.
                 */
                BUG_ON(!stream->release);
-               qc_stream_desc_free(stream);
+               qc_stream_desc_free(stream, 1);
        }
 
        /* Purge Rx packet list. */