-
Notifications
You must be signed in to change notification settings - Fork 7.5k
Description
A segmentation fault occurs when closing QUIC streams in the ngx_quic_close_streams() function due to unsafe pointer handling during tree iteration.
node = ngx_rbtree_min(tree->root, tree->sentinel);
while (node) {
qs = (ngx_quic_stream_t *) node;
node = ngx_rbtree_next(tree, node); # incorrect
sc = qs->connection;
qs->recv_state = NGX_QUIC_STREAM_RECV_RESET_RECVD;
qs->send_state = NGX_QUIC_STREAM_SEND_RESET_SENT;
if (sc == NULL) {
ngx_quic_close_stream(qs);
continue;
}
sc->read->error = 1;
sc->write->error = 1;
ngx_quic_set_event(sc->read);
ngx_quic_set_event(sc->write);
sc->close = 1;
sc->read->handler(sc->read);
}
In the ngx_quic_close_streams() function, there’s a loop that iterates through QUIC streams using a red-black tree. The next node is determined using:
node = ngx_rbtree_next(tree, node);
While processing the current stream, the function calls:
sc->read->handler(sc->read);
If the handler is ngx_http_request_handler, it triggers a chain of calls:
- ngx_http_request_handler()
- ngx_http_run_posted_requests()
- ngx_http_close_connection()
- ngx_http_v3_reset_stream()
- ngx_http_v3_send_cancel_stream()
Get another stream connection in ngx_http_v3_send_cancel_stream:
dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER);
- ngx_http_v3_close_uni_stream(dc)
- ngx_destroy_pool()
- ngx_quic_stream_cleanup_handler()
- ngx_quic_close_stream()
During this process, if ngx_http_v3_close_uni_stream() deletes the same node the loop saved earlier with ngx_rbtree_next(tree, node), a segmentation fault occurs because the pointer is no longer valid.
Segmentation Fault:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000558ae832bf73 in ngx_rbtree_min (sentinel=<optimized out>, node=0x0)
at src/core/ngx_rbtree.h:79
#0 0x0000558ae832bf73 in ngx_rbtree_min (sentinel=<optimized out>, node=0x0)
at src/core/ngx_rbtree.h:79
#1 ngx_rbtree_next (tree=tree@entry=0x7f16647a3450,
node=node@entry=0x7f16733bfc20) at src/core/ngx_rbtree.c:386
#2 0x0000558ae836bf72 in ngx_quic_close_streams (c=c@entry=0x7f168422ec48,
qc=qc@entry=0x7f16647a2c00) at src/event/quic/ngx_event_quic_streams.c:204
#3 0x0000558ae835ce57 in ngx_quic_close_connection (c=0x7f168422ec48, rc=-1)
at src/event/quic/ngx_event_quic.c:551
#4 0x0000558ae835fac2 in ngx_quic_recvmsg (ev=0x7f167e0f9940)
at src/event/quic/ngx_event_quic_udp.c:195
#5 0x0000558ae834d7bb in ngx_epoll_process_events (cycle=0x7f1691ac7150,
timer=<optimized out>, flags=<optimized out>)
at src/event/modules/ngx_epoll_module.c:901
Logical Error (breakpoint when ngx_quic_close_stream try destroy next node in ngx_quic_close_streams:
#2 0x000055e89bc06161 in ngx_quic_close_stream (qs=0x7f9d0bffd420)
at src/event/quic/ngx_event_quic_streams.c:1168
#3 0x000055e89bc60b25 in ngx_quic_stream_cleanup_handler (
data=0x7f9d1caae1a8) at src/event/quic/ngx_event_quic_streams.c:1122
#4 0x000055e89bc15326 in ngx_destroy_pool (pool=0x7f9cef1ecf40)
at src/core/ngx_palloc.c:57
#5 0x000055e89bcbe5ed in ngx_http_v3_close_uni_stream (
c=c@entry=0x7f9d1caae1a8) at src/http/v3/ngx_http_v3_uni.c:100
#6 0x000055e89bcbf596 in ngx_http_v3_send_cancel_stream (
c=c@entry=0x7f9d1cacdd48, stream_id=4)
at src/http/v3/ngx_http_v3_uni.c:566
#7 0x000055e89bcc278c in ngx_http_v3_reset_stream (c=c@entry=0x7f9d1cacdd48)
at src/http/v3/ngx_http_v3_request.c:423
#8 0x000055e89bc75561 in ngx_http_close_connection (c=0x7f9d1cacdd48)
at src/http/ngx_http_request.c:4130
#9 0x000055e89bc764a9 in ngx_http_run_posted_requests (c=0x7f9d1cacdd48)
at src/http/ngx_http_request.c:2667
#10 0x000055e89bc60f90 in ngx_quic_close_streams (c=c@entry=0x7f9d1ca5a010,
qc=qc@entry=0x7f9e7290a400) at src/event/quic/ngx_event_quic_streams.c:236
#11 0x000055e89bc51e67 in ngx_quic_close_connection (c=0x7f9d1ca5a010, rc=-1)
at src/event/quic/ngx_event_quic.c:551
#12 0x000055e89bc54ad2 in ngx_quic_recvmsg (ev=0x7f9d16a00880)
at src/event/quic/ngx_event_quic_udp.c:195
#13 0x000055e89bc427cb in ngx_epoll_process_events (cycle=0x7f9e88ac91d0,
timer=<optimized out>, flags=<optimized out>)
at src/event/modules/ngx_epoll_module.c:901