Skip to content

Segmentation fault in ngx_quic_close_streams() #369

@morf

Description

@morf

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions