Skip to content

Commit

Permalink
BUG/MEDIUM: h3: fix incorrect snd_buf return value
Browse files Browse the repository at this point in the history
h3_resp_data_send() is used to transcode HTX data into H3 data frames.
If QCS Tx buffer is not aligned when first invoked, two separate frames
may be built, first until buffer end, then with remaining space in
front.

If buffer space is not enough for at least the H3 frame header, -1 is
returned with the flag QC_SF_BLK_MROOM set to await for more room. An
issue arises if this occurs for the second frame : -1 is returned even
though HTX data were properly transcoded and removed on the first step.
This causes snd_buf callback to return an incorrect value to the stream
layer, which in the end will corrupt the channel output buffer.

To fix this, stop considering that not enough remaining space is an
error case. Instead, return 0 if this is encountered for the first frame
or the HTX removed block size for the second one. As QC_SF_BLK_MROOM is
set, this will correctly interrupt H3 encoding. Label err is thus only
properly limited to fatal error which should cause a connection closure.
A new BUG_ON() has been added which should prevent similar issues in the
future.

This issue was detected using the following client :
 $ ngtcp2-client --no-quic-dump --no-http-dump --exit-on-all-streams-close \
   127.0.0.1 20443 -n2 "http://127.0.0.1:20443/?s=50k"

This triggers the following CHECK_IF statement. Note that it may be
necessary to disable fast forwarding to enforce snd_buf usage.

Thread 1 "haproxy" received signal SIGILL, Illegal instruction.
0x00005555558bc48a in co_data (c=0x5555561ed428) at include/haproxy/channel.h:130
130             CHECK_IF_HOT(c->output > c_data(c));
[ ## gdb ## ] bt
 #0  0x00005555558bc48a in co_data (c=0x5555561ed428) at include/haproxy/channel.h:130
 joyent#1  0x00005555558c1d69 in sc_conn_send (sc=0x5555561f92d0) at src/stconn.c:1637
 joyent#2  0x00005555558c2683 in sc_conn_io_cb (t=0x5555561f7f10, ctx=0x5555561f92d0, state=32832) at src/stconn.c:1824
 haproxy#3  0x000055555590c48f in run_tasks_from_lists (budgets=0x7fffffffdaa0) at src/task.c:596
 haproxy#4  0x000055555590cf88 in process_runnable_tasks () at src/task.c:876
 haproxy#5  0x00005555558aae3b in run_poll_loop () at src/haproxy.c:3049
 haproxy#6  0x00005555558ab57e in run_thread_poll_loop (data=0x555555d9fa00 <ha_thread_info>) at src/haproxy.c:3251
 haproxy#7  0x00005555558ad053 in main (argc=6, argv=0x7fffffffddd8) at src/haproxy.c:3948

In case CHECK_IF are not activated, it may cause crash or incorrect
transfers.

This was introduced by the following commit
  commit 2144d24
  BUG/MINOR: h3: close connection on sending alloc errors

This must be backported wherever the above patch is.

(cherry picked from commit 14673fe)
[wt: adjusted context in h3_resp_data_send]
Signed-off-by: Willy Tarreau <[email protected]>
  • Loading branch information
a-denoyelle authored and wtarreau committed Jan 5, 2024
1 parent 8ff3edf commit f2915cd
Showing 1 changed file with 6 additions and 2 deletions.
8 changes: 6 additions & 2 deletions src/h3.c
Original file line number Diff line number Diff line change
Expand Up @@ -1776,7 +1776,10 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx)
return -1;
}

/* Returns the total of bytes sent. */
/* Returns the total of bytes sent. This corresponds to the
* total bytes of HTX block removed. A negative error code is returned in case
* of a fatal error which should caused a connection closure.
*/
static int h3_resp_data_send(struct qcs *qcs, struct buffer *buf, size_t count)
{
struct htx *htx;
Expand Down Expand Up @@ -1853,7 +1856,7 @@ static int h3_resp_data_send(struct qcs *qcs, struct buffer *buf, size_t count)
if (b_size(&outbuf) <= hsize) {
TRACE_STATE("not enough room for data frame", H3_EV_TX_DATA, qcs->qcc->conn, qcs);
qcs->flags |= QC_SF_BLK_MROOM;
goto err;
goto end;
}

if (b_size(&outbuf) < hsize + fsize)
Expand Down Expand Up @@ -1881,6 +1884,7 @@ static int h3_resp_data_send(struct qcs *qcs, struct buffer *buf, size_t count)
return total;

err:
BUG_ON(total); /* Must return HTX removed size if at least on frame encoded. */
TRACE_DEVEL("leaving on error", H3_EV_TX_DATA, qcs->qcc->conn, qcs);
return -1;
}
Expand Down

0 comments on commit f2915cd

Please sign in to comment.