Opened 11 months ago
Last modified 7 months ago
#2585 closed defect
segfault in quic — at Initial Version
Reported by: | Owned by: | ||
---|---|---|---|
Priority: | major | Milestone: | nginx-1.26 |
Component: | http/3 | Version: | 1.25.x |
Keywords: | segfault, quic | Cc: | |
uname -a: | Linux c-d050-u2651-40 5.15.0-40-lowlatency #43-Ubuntu SMP PREEMPT Thu Jun 16 17:07:13 UTC 2022 x86_64 x86_64 x86_64 GNU/L | ||
nginx -V: |
nginx version: nginx/1.25.4
built by gcc 11.2.0 (Ubuntu 11.2.0-19ubuntu1) built with OpenSSL 3.0.2 15 Mar 2022 TLS SNI support enabled configure arguments: --prefix=/cdn/nginx_quic --with-cc-opt='-O0 -g -ggdb -march=core2' --with-debug --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --with-ipv6 --with-http_geoip_module --with-http_realip_module --with-http_ssl_module --without-http_charset_module --without-http_ssi_module --without-http_userid_module --without-http_autoindex_module --without-http_scgi_module --without-http_uwsgi_module --without-http_fastcgi_module --without-http_limit_conn_module --without-http_split_clients_module --without-http_limit_req_module --with-http_stub_status_module --with-http_v2_module --with-http_v3_module --with-http_slice_module --with-stream_ssl_module |
Description
warning: Can't open file /dev/zero (deleted) during file-backed mapping note processing
[New LWP 138846]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `nginx: worker process '.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007fcd4014a214 in EVP_CIPHER_CTX_is_encrypting () from /lib/x86_64-linux-gnu/libcrypto.so.3
(gdb) bt
#0 0x00007fcd4014a214 in EVP_CIPHER_CTX_is_encrypting () from /lib/x86_64-linux-gnu/libcrypto.so.3
#1 0x00005646ac29ff3f in ngx_quic_crypto_common (s=0x5646adeb3470, out=0x7ffd2593ad28, nonce=0x7ffd2593ab4c "", in=0x7ffd2593ab20, ad=0x7ffd2593ab30, log=0x5646af2d8100)
at src/event/quic/ngx_event_quic_protection.c:493
#2 0x00005646ac29fea3 in ngx_quic_crypto_open (s=0x5646adeb3470, out=0x7ffd2593ad28, nonce=0x7ffd2593ab4c "", in=0x7ffd2593ab20, ad=0x7ffd2593ab30, log=0x5646af2d8100)
at src/event/quic/ngx_event_quic_protection.c:458
#3 0x00005646ac2a1f09 in ngx_quic_decrypt (pkt=0x7ffd2593ac60, largest_pn=0x5646ae310a58) at src/event/quic/ngx_event_quic_protection.c:1190
#4 0x00005646ac298727 in ngx_quic_handle_payload (c=0x7fcd2fd48790, pkt=0x7ffd2593ac60) at src/event/quic/ngx_event_quic.c:982
#5 0x00005646ac29801f in ngx_quic_handle_packet (c=0x7fcd2fd48790, conf=0x0, pkt=0x7ffd2593ac60) at src/event/quic/ngx_event_quic.c:843
#6 0x00005646ac2979ab in ngx_quic_handle_datagram (c=0x7fcd2fd48790, b=0x7ffd2593ae90, conf=0x0) at src/event/quic/ngx_event_quic.c:693
#7 0x00005646ac296d31 in ngx_quic_input_handler (rev=0x7fcd2fb07310) at src/event/quic/ngx_event_quic.c:436
#8 0x00005646ac29a093 in ngx_quic_recvmsg (ev=0x7fcd2fb07070) at src/event/quic/ngx_event_quic_udp.c:195
#9 0x00005646ac2821f2 in ngx_epoll_process_events (cycle=0x5646add304c0, timer=98, flags=1) at src/event/modules/ngx_epoll_module.c:901
#10 0x00005646ac26e5b7 in ngx_process_events_and_timers (cycle=0x5646add304c0) at src/event/ngx_event.c:248
#11 0x00005646ac27f562 in ngx_worker_process_cycle (cycle=0x5646add304c0, data=0x1a) at src/os/unix/ngx_process_cycle.c:721
#12 0x00005646ac27ba5c in ngx_spawn_process (cycle=0x5646add304c0, proc=0x5646ac27f468 <ngx_worker_process_cycle>, data=0x1a, name=0x5646ac360c62 "worker process", respawn=-3) at src/os/unix/ngx_process.c:199
#13 0x00005646ac27e2bf in ngx_start_worker_processes (cycle=0x5646add304c0, n=48, type=-3) at src/os/unix/ngx_process_cycle.c:344
#14 0x00005646ac27d92e in ngx_master_process_cycle (cycle=0x5646add304c0) at src/os/unix/ngx_process_cycle.c:130
#15 0x00005646ac234ab0 in main (argc=1, argv=0x7ffd2593b718) at src/core/nginx.c:384
(gdb) d 1
No breakpoint number 1.
(gdb) f 1
#1 0x00005646ac29ff3f in ngx_quic_crypto_common (s=0x5646adeb3470, out=0x7ffd2593ad28, nonce=0x7ffd2593ab4c "", in=0x7ffd2593ab20, ad=0x7ffd2593ab30, log=0x5646af2d8100)
at src/event/quic/ngx_event_quic_protection.c:493
warning: Source file is more recent than executable.
493 enc = EVP_CIPHER_CTX_encrypting(ctx);
(gdb) p ctx
$1 = (EVP_CIPHER_CTX *) 0x0
(gdb) f 2
#2 0x00005646ac29fea3 in ngx_quic_crypto_open (s=0x5646adeb3470, out=0x7ffd2593ad28, nonce=0x7ffd2593ab4c "", in=0x7ffd2593ab20, ad=0x7ffd2593ab30, log=0x5646af2d8100)
at src/event/quic/ngx_event_quic_protection.c:458
458 return ngx_quic_crypto_common(s, out, nonce, in, ad, log);
(gdb) p s
$2 = (ngx_quic_secret_t *) 0x5646adeb3470
(gdb) p *s
$3 = {secret = {len = 0, data = '\000' <repeats 47 times>}, iv = {len = 0, data = '\000' <repeats 11 times>}, hp = {len = 0, data = '\000' <repeats 47 times>}, ctx = 0x0, hp_ctx = 0x0}
(gdb) f 3
#3 0x00005646ac2a1f09 in ngx_quic_decrypt (pkt=0x7ffd2593ac60, largest_pn=0x5646ae310a58) at src/event/quic/ngx_event_quic_protection.c:1190
1190 if (ngx_quic_crypto_open(secret, &pkt->payload, nonce, &in, &ad, pkt->log)
(gdb) p secret->ctx
$4 = (EVP_CIPHER_CTX *) 0x0
(gdb) p *secret
$5 = {secret = {len = 0, data = '\000' <repeats 47 times>}, iv = {len = 0, data = '\000' <repeats 11 times>}, hp = {len = 0, data = '\000' <repeats 47 times>}, ctx = 0x0, hp_ctx = 0x0}
(gdb)
(gdb) p *secret
$5 = {secret = {len = 0, data = '\000' <repeats 47 times>}, iv = {len = 0, data = '\000' <repeats 11 times>}, hp = {len = 0, data = '\000' <repeats 47 times>}, ctx = 0x0, hp_ctx = 0x0}
(gdb) p pkt->keys->secrets[pkt->level].client
$6 = {secret = {len = 32, data = "\253\354ѫV\006\220\355Qa\221\334\324\377>=\027\273\016z\177\277Q4\025\n\225\026a\262\066\263", '\000' <repeats 15 times>}, iv = {len = 12,
data = "\224h5\025C\265\066\357E\253rZ"}, hp = {len = 16, data = "&P\314ԏ혎X\275\071\222\300\356Ӓ", '\000' <repeats 31 times>}, ctx = 0x5646adea0970, hp_ctx = 0x5646af284220}
(gdb) p pkt->keys->secrets[pkt->level].client->ctx
$7 = (EVP_CIPHER_CTX *) 0x5646adea0970
(gdb) p pkt->keys->next_key.client
$9 = {secret = {len = 0, data = '\000' <repeats 47 times>}, iv = {len = 0, data = '\000' <repeats 11 times>}, hp = {len = 0, data = '\000' <repeats 47 times>}, ctx = 0x0, hp_ctx = 0x0}
(gdb) p/t pkt->flags
$12 = 1111101
(gdb)
(gdb) p key_phase
$13 = 1
(gdb) p pkt->key_phase
$14 = 0
(gdb)
Looking at the backtrace, I saw problem appears in ngx_quic_crypto_common trying to call EVP_CIPHER_CTX_encrypting(ctx) with ctx pointing to NULL.
Tracing back through ngx_quic_crypto_common(), ngx_quic_crypto_open(), way don to ngx_quic_decrypt() we can see that this i actually secret->ctx is NULL.
Further we see that secret is taken from pkt->keys->secrets[pkt->level].client (line 1115 in ngx_quic_decrypt()) where ctx is has non zero value = 0x5646adea0970, but on line 1147
it overriden by secret = &pkt->keys->next_key.client; which has cts NULL. So it seems that key is about to be updated, but pkt->keys->next_key is to zero initialized structure.
I see that this could happen in ngx_quic_keys_switch() and ngx_quic_keys_cleanup(), so probably some wrong sequence makes worker to crash. I'm not yet so familiar yet with quic protocol
and its nginx implementation.
example configuration identical to real one, where the problem appeared