Search code examples
openssl

OpenSSL 3 OSSL_PROVIDER_unload throwing UNKNOWN SIGNAL in library deconstrutor


I'm writing a library and I have to use legacy algorithms and since these have been separated in the legacy provider in OpenSSL 3 I have to load the legacy provider with:

legacy = OSSL_PROVIDER_load(NULL, "legacy");

I'm calling this in a C constructor to be able to execute the necessary logic while the library is loaded:

OSSL_PROVIDER *legacy;

__attribute__ ((constructor)) void init(void) {...}

With the gcc address sanitizer I can see the fault trace:

==3355==ERROR: AddressSanitizer: UNKNOWN SIGNAL on unknown address 0x7ffee77f0e70 (pc 0x7fdde43056cc bp 0x000000000001 sp 0x7ffee77f1220 T0)
    #0 0x7fdde43056cc in pthread_rwlock_rdlock (/lib/x86_64-linux-gnu/libc.so.6+0x9a6cc)
    #1 0x7fdde4672dac in CRYPTO_THREAD_read_lock (/lib/x86_64-linux-gnu/libcrypto.so.3+0x1c1dac)
    #2 0x7fdde4666305  (/lib/x86_64-linux-gnu/libcrypto.so.3+0x1b5305)
    #3 0x7fdde4679244  (/lib/x86_64-linux-gnu/libcrypto.so.3+0x1c8244)
    #4 0x7fdde467a68b in OSSL_PROVIDER_unload (/lib/x86_64-linux-gnu/libcrypto.so.3+0x1c968b)
    #5 0x5573818b1011 in fini /globalplatform/globalplatform/src/init.c:71
    #6 0x7fdde53a424d  (/lib64/ld-linux-x86-64.so.2+0x624d)
    #7 0x7fdde42b0494  (/lib/x86_64-linux-gnu/libc.so.6+0x45494)
    #8 0x7fdde42b060f in exit (/lib/x86_64-linux-gnu/libc.so.6+0x4560f)
    #9 0x7fdde4294d96  (/lib/x86_64-linux-gnu/libc.so.6+0x29d96)
    #10 0x7fdde4294e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f)
    #11 0x55738188b044 in _start (/globalplatform/globalplatform/src/cryptoTest+0x16044)

Any ideas what could cause this?


Solution

  • I found a solution in the meanwhile on my own. I found the issue on GitHub. The summary is that OpenSSL is cleaning up its resources automatically most likely with OPENSSL_cleanup. My allocated provider seems to be cleared already by OpenSSL, but since my code has a reference to it must be also cleared. The solution is the instruct OpenSSL not to tidy up when the library is unloaded and do it manually:

    __attribute__ ((constructor)) void init(void) {
      OPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, NULL);
      # NOTE: error handling left out, it should be checked for NULL
      legacy = OSSL_PROVIDER_load(NULL, "legacy");
      deflt = OSSL_PROVIDER_load(NULL, "default");
    }
    
    __attribute__ ((destructor)) void fini(void) {
      if (legacy != NULL) {
        OSSL_PROVIDER_unload(legacy);
      }
      if (deflt != NULL) {
        OSSL_PROVIDER_unload(deflt);
      }
      OPENSSL_cleanup();
    }