curl_global_cleanup/curl_global_init cycle leads to non-working SSL with libressl
glandium opened this issue · 3 comments
I did this
Here the backstory: git-cinnabar uses curl via libgit's http.c, and because it avoids doing too many modifications to it, it ends up calling curl_global_init and curl_global_cleanup multiple times. This has always worked properly for git-cinnabar users... until macOS Sonoma, where things broke.
I'm not sure what older versions of macOS had, but it now uses curl 8.4.0 with libressl 3.3.6. It might have been using older versions of libressl before, or maybe openssl, I don't know. Anyways, what happens is that the call to EVP_cleanup()
in ossl_cleanup()
frees ciphers and digests lists, but the call to OPENSSL_init_ssl
in ossl_init
doesn't fill new cipher and digests lists, because they are statically initialized once, ever (their initialization uses pthread_once).
This causes SSL failures after calling curl_global_cleanup and curl_global_init.
This can be easily reproduced by taking docs/examples/https.c
and apply this patch to it:
--- docs/examples/https.c
+++ docs/examples/https.c
@@ -34,6 +34,8 @@
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
+ curl_global_cleanup();
+ curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl) {
This doesn't require macOS Sonoma to reproduce: this breaks similarly when running on a Linux host with curl 8.5.0 built against a manually built libressl 3.8.2.
The curl_global_cleanup manual says "You should call curl_global_cleanup once for each call you make to curl_global_init, after you are done using libcurl.", which implies the testcase is not doing anything illegal.
I expected the following
No response
curl/libcurl version
8.4.0
operating system
macOS Sonoma 14.2
Thanks for you report.
Possibly related: #11611
One theory is doing the same change for ossl_cleanup()
:
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -1755,7 +1755,7 @@ static int ossl_init(void)
static void ossl_cleanup(void)
{
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
- !defined(LIBRESSL_VERSION_NUMBER)
+ (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
/* OpenSSL 1.1 deprecates all these cleanup functions and
turns them into no-ops in OpenSSL 1.0 compatibility mode */
#else
Or reverting #11611 if all else fails.
Both options work.