curl · Report #3682666
Use-after-free in `curl_easy_ssls_export()` during callback re-entrancy
How it was found
Summary:
curl_easy_ssls_export() iterates the SSL session list and invokes a caller-provided callback for each entry. If that callback calls curl_easy_ssls_import() on the same easy handle, the import path can evict and free the current session node while the export loop still holds it. The subsequent Curl_node_next(n) dereferences freed memory and triggers AddressSanitizer as a heap-use-after-free. I reproduced this on curl GitHub HEAD 54ded66618a2388e88e715c5eb4477d1083582ef. The relevant code path is lib/vtls/vtls_scache.c, primarily Curl_ssl_session_export() around line 1214 with the related eviction path in cf_scache_peer_add_session() around line 781.
Affected version
Reproduced on libcurl built from curl GitHub HEAD 54ded66618a2388e88e715c5eb4477d1083582ef on Linux x86_64. The build used the OpenSSL backend with clang, AddressSanitizer, UndefinedBehaviorSanitizer, and configure options --disable-shared --enable-ssls-export --with-openssl.
Steps To Reproduce:
- Build the tested curl source with OpenSSL and
--enable-ssls-export, for example:
autoreconf -fi
CC=clang CFLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -g -O1" \
LDFLAGS="-fsanitize=address,undefined" \
./configure --disable-shared --enable-ssls-export --with-openssl
make -j"$(nproc)"
- Compile the attached
poc.cagainst the freshly built static libcurl:
clang -fsanitize=address,undefined -fno-omit-frame-pointer -g -O1 \
-I./include -I./lib \
poc.c ./lib/.libs/libcurl.a \
-lssl -lcrypto -lz -lpthread -ldl \
-o /tmp/poc_curl_ssls_export_uaf
- Run the PoC:
ASAN_OPTIONS="halt_on_error=0:print_stacktrace=1:detect_leaks=0" \
UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=0" \
/tmp/poc_curl_ssls_export_uaf
- The PoC imports TLS session entries for the same peer and then calls
curl_easy_ssls_export(). During the export callback it re-enterscurl_easy_ssls_import()on the same easy handle, mutating the session list while the export code still holds the current node.
Observed sanitizer output:
ERROR: AddressSanitizer: heap-use-after-free
#0 Curl_node_next /src/curl/lib/llist.c:246
#1 Curl_ssl_session_export /src/curl/lib/vtls/vtls_scache.c:1214
Impact
An application using the SSL session export/import API can trigger a heap use-after-free in libcurl. In the tested build this is a reliable crash. In non-instrumented builds, dereferencing a freed list node may also lead to memory corruption, depending on allocator state and surrounding heap layout.