You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Thread 1 "curl" received signal SIGSEGV, Segmentation fault.
0x00007ffff7f2fbbd in verifystatus (cf=0x55555559d790, data=0x5555555a1db0) at /usr/src/debug/curl/curl/lib/vtls/openssl.c:2386
2386 len = SSL_get_tlsext_status_ocsp_resp(octx->ssl, &status);
(gdb) bt
#0 0x00007ffff7f2fbbd in verifystatus (cf=0x55555559d790, data=0x5555555a1db0) at /usr/src/debug/curl/curl/lib/vtls/openssl.c:2386
#1 Curl_oss_check_peer_cert (cf=cf@entry=0x55555559d790, data=data@entry=0x5555555a1db0, octx=0x5555555a18e8, peer=0x5555555a18c0) at /usr/src/debug/curl/curl/lib/vtls/openssl.c:4699
#2 0x00007ffff7f319df in Curl_vquic_tls_verify_peer (ctx=<optimized out>, cf=0x55555559d790, data=0x5555555a1db0, peer=<optimized out>) at /usr/src/debug/curl/curl/lib/vquic/vquic-tls.c:315
#3 cf_osslq_verify_peer (cf=0x55555559d790, data=0x5555555a1db0) at /usr/src/debug/curl/curl/lib/vquic/curl_osslq.c:475
#4 cf_osslq_connect (cf=0x55555559d790, data=0x5555555a1db0, blocking=<optimized out>, done=0x7fffffffdce4) at /usr/src/debug/curl/curl/lib/vquic/curl_osslq.c:1636
#5 0x00007ffff7ec6172 in Curl_conn_cf_connect (cf=<optimized out>, data=0x5555555a1db0, blocking=false, done=0x7fffffffdce4) at /usr/src/debug/curl/curl/lib/cfilters.c:307
#6 Curl_conn_cf_connect (cf=<optimized out>, data=<optimized out>, blocking=false, done=<optimized out>) at /usr/src/debug/curl/curl/lib/cfilters.c:302
#7 baller_connect (cf=<optimized out>, data=<optimized out>, baller=0x55555559c250, now=0x7fffffffdb30, connected=0x7fffffffdce4) at /usr/src/debug/curl/curl/lib/connect.c:562
#8 is_connected (cf=0x55555559d760, data=0x5555555a1db0, connected=0x7fffffffdce4) at /usr/src/debug/curl/curl/lib/connect.c:619
#9 cf_he_connect (cf=0x55555559d760, data=0x5555555a1db0, blocking=<optimized out>, done=<optimized out>) at /usr/src/debug/curl/curl/lib/connect.c:904
#10 0x00007ffff7ec7100 in Curl_conn_cf_connect (cf=<optimized out>, data=0x5555555a1db0, blocking=false, done=0x7fffffffdce4) at /usr/src/debug/curl/curl/lib/cfilters.c:307
#11 Curl_conn_cf_connect (cf=<optimized out>, data=0x5555555a1db0, blocking=false, done=0x7fffffffdce4) at /usr/src/debug/curl/curl/lib/cfilters.c:302
#12 cf_setup_connect (cf=0x55555559d6e0, data=0x5555555a1db0, blocking=false, done=0x7fffffffdce4) at /usr/src/debug/curl/curl/lib/connect.c:1199
#13 0x00007ffff7eb47be in Curl_conn_cf_connect (cf=<optimized out>, data=0x5555555a1db0, blocking=false, done=0x7fffffffdce4) at /usr/src/debug/curl/curl/lib/cfilters.c:307
#14 Curl_conn_cf_connect (cf=<optimized out>, data=0x5555555a1db0, blocking=false, done=0x7fffffffdce4) at /usr/src/debug/curl/curl/lib/cfilters.c:302
#15 cf_hc_baller_connect (b=<optimized out>, cf=0x55555559b1a0, data=0x5555555a1db0, done=0x7fffffffdce4) at /usr/src/debug/curl/curl/lib/cf-https-connect.c:135
#16 cf_hc_connect (cf=0x55555559b1a0, data=0x5555555a1db0, blocking=<optimized out>, done=0x7fffffffdce4) at /usr/src/debug/curl/curl/lib/cf-https-connect.c:273
#17 0x00007ffff7ebe1b6 in Curl_conn_connect (data=0x5555555a1db0, sockindex=<optimized out>, blocking=<optimized out>, done=0x7fffffffdce4) at /usr/src/debug/curl/curl/lib/cfilters.c:353
#18 0x00007ffff7eff870 in multi_runsingle (multi=multi@entry=0x5555555998c0, nowp=nowp@entry=0x7fffffffdd90, data=data@entry=0x5555555a1db0) at /usr/src/debug/curl/curl/lib/multi.c:2128
#19 0x00007ffff7f01f3d in curl_multi_perform (multi=0x5555555998c0, running_handles=0x7fffffffdf38) at /usr/src/debug/curl/curl/lib/multi.c:2760
#20 0x00007ffff7ed061c in easy_transfer (multi=<optimized out>) at /usr/src/debug/curl/curl/lib/easy.c:675
#21 easy_perform (events=false, data=0x5555555a1db0) at /usr/src/debug/curl/curl/lib/easy.c:769
#22 curl_easy_perform (data=0x5555555a1db0) at /usr/src/debug/curl/curl/lib/easy.c:788
#23 0x0000555555558ea7 in serial_transfers (global=0x7fffffffe150, share=0x55555559a630) at /usr/src/debug/curl/curl/src/tool_operate.c:2498
#24 run_all_transfers (global=0x7fffffffe150, share=0x55555559a630, result=CURLE_OK) at /usr/src/debug/curl/curl/src/tool_operate.c:2685
#25 operate (global=0x7fffffffe150, argc=<optimized out>, argv=<optimized out>) at /usr/src/debug/curl/curl/src/tool_operate.c:2801
#26 main (argc=<optimized out>, argv=<optimized out>) at /usr/src/debug/curl/curl/src/tool_main.c:273
The cause of this is actually rather interesting and turns out to be a near miss on a potentially bad security issue.
The root cause is actually a type confusion, I'm fuzzy as to where exactly types are confused because of the amount of indirection and casting of ctx pointers in the connection filters.
In lib/vquic/curl_ngtcp2.cCurl_cf_ngtcp2_create creates a cfilter with the ctx being a struct cf_ngtcp2_ctx*, later in qng_verify_peer this cfilter is passed to Curl_vquic_tls_verify_peer from lib/vquic/vquic-tls.c which appears to be a middle man between all the different TLS libraries. In Curl_vquic_tls_verify_peer the same cfilter is passed to Curl_oss_check_peer_cert which lives in lib/vtls/openssl.c, the problem appears to be that all the functions in lib/vtls/openssl.c expect a struct ssl_connect_data* in their cfilter ctx. So Curl_oss_check_peer_cert eventually calls verifystatus with the cfilter and verifystatus finally casts the ctx to a struct ssl_connect_data*, tries to get connssl->backend, cast it to a struct ossl_ctx* and access octx->ssl and crashes. I tried tracing the calls to figure out if this was a case of the wrong cfilter being passed in from vquic-tls.c (it seems like they can be chained) but eventually gave up and decided someone with more experience will know where to look quicker than I.
As for the actual crash it luckily can only ever be a NULL pointer dereference because the backend field of struct ssl_connect_data is at offset 0x30 and in struct cf_ngtcp2_ctx that happens to land in the padding section of a struct sockaddr_storage (apparently the large amounts of padding is something to do with alignments and from looking at the glibc source the padding is almost 128 bytes, I couldn't find any other libc's that changed this but didn't look very hard). This object was allocated with calloc so this padding space is guaranteed to be zero'd and so this can only every be a NULL pointer deference. Every other QUIC backend used structs that happened to have a struct sockaddr_storage in the same place with the exception of the msh3 one which I didn't investigate farther as it is experimental.
As for where the actual bug is I think it's vquic-tls.c not passing in the right cfilter that these TLS backends are expecting, I traced the other functions that vquic-tls.c calls with a cfilter for the OpenSSL backend and I can't tell if we just got lucky and only the verifystatus function actually used the cfilter's ctx but the rest were also assuming it was holding their internal structs or if openssl.c was supposed to be doing something to the cfilter it was passed to access the right struct but my energy ran out and I decided to just file this bug report instead. :P
I did this
The cause of this is actually rather interesting and turns out to be a near miss on a potentially bad security issue.
The root cause is actually a type confusion, I'm fuzzy as to where exactly types are confused because of the amount of indirection and casting of ctx pointers in the connection filters.
In
lib/vquic/curl_ngtcp2.c
Curl_cf_ngtcp2_create
creates a cfilter with the ctx being astruct cf_ngtcp2_ctx*
, later inqng_verify_peer
this cfilter is passed toCurl_vquic_tls_verify_peer
fromlib/vquic/vquic-tls.c
which appears to be a middle man between all the different TLS libraries. InCurl_vquic_tls_verify_peer
the same cfilter is passed toCurl_oss_check_peer_cert
which lives inlib/vtls/openssl.c
, the problem appears to be that all the functions inlib/vtls/openssl.c
expect astruct ssl_connect_data*
in their cfilter ctx. SoCurl_oss_check_peer_cert
eventually callsverifystatus
with the cfilter andverifystatus
finally casts the ctx to astruct ssl_connect_data*
, tries to getconnssl->backend
, cast it to astruct ossl_ctx*
and accessoctx->ssl
and crashes. I tried tracing the calls to figure out if this was a case of the wrong cfilter being passed in fromvquic-tls.c
(it seems like they can be chained) but eventually gave up and decided someone with more experience will know where to look quicker than I.As for the actual crash it luckily can only ever be a NULL pointer dereference because the
backend
field ofstruct ssl_connect_data
is at offset 0x30 and instruct cf_ngtcp2_ctx
that happens to land in the padding section of astruct sockaddr_storage
(apparently the large amounts of padding is something to do with alignments and from looking at the glibc source the padding is almost 128 bytes, I couldn't find any other libc's that changed this but didn't look very hard). This object was allocated withcalloc
so this padding space is guaranteed to be zero'd and so this can only every be a NULL pointer deference. Every other QUIC backend used structs that happened to have astruct sockaddr_storage
in the same place with the exception of the msh3 one which I didn't investigate farther as it is experimental.As for where the actual bug is I think it's
vquic-tls.c
not passing in the right cfilter that these TLS backends are expecting, I traced the other functions thatvquic-tls.c
calls with a cfilter for the OpenSSL backend and I can't tell if we just got lucky and only theverifystatus
function actually used the cfilter's ctx but the rest were also assuming it was holding their internal structs or ifopenssl.c
was supposed to be doing something to the cfilter it was passed to access the right struct but my energy ran out and I decided to just file this bug report instead. :PI expected the following
No crash.
curl/libcurl version
Also happens on master.
operating system
Linux 6.9.6-arch1-1 #1 SMP PREEMPT_DYNAMIC Fri, 21 Jun 2024 19:49:19 +0000 x86_64 GNU/Linux
The text was updated successfully, but these errors were encountered: