Skip to content

Segfault when trying to call ExDataFreeOcspResponse after .NET module has been unloaded #123140

@ulrichb

Description

@ulrichb

Description

TL;DR: In EnsureOpenSsl11Initialized(), free_func pointers are registered which get dangling after the .NET module has been unloaded. When OpenSSL later tries to call this free_func, we get a segfault. It seems that CRYPTO_free_ex_index() calls are missing.

We have the following process/module scenario:

  • OpenSSL is the entrypoint (openssl cms ... command with -engine pkcs11).
  • => The libp11 OpenSSL engine (pkcs11.so) gets dynamically loaded by OpenSSL.
  • By configuration, libp11 dynamically loads our PKCS#11 module (libSignPath.Cryptoki.so)
  • (Note that the following segmentation fault can only reproduced with recent OpenSSL and libp11 versions, e.g. on Debian 13 with OpenSSL 3.5.4 and libp11 0.4.13.)

The segmentation fault happens during unloading (when OpenSSL's cms_main calls CMS_ContentInfo_free()).

Full stack trace (linked OpenSSL is 3.5.4)
func                        file                            addr
??                                                          0x7acfe4f0dc70   
CRYPTO_free_ex_data         crypto/ex_data.c:406            0x7acfe6695813  
x509_cb                     crypto/x509/x_x509.c:85         0x7acfe6858665  
ossl_asn1_item_embed_free   crypto/asn1/tasn_fre.c:117      0x7acfe6520842  
ossl_asn1_template_free     crypto/asn1/tasn_fre.c:146      0x7acfe6520980  
ossl_asn1_item_embed_free   crypto/asn1/tasn_fre.c:70       0x7acfe652064f  
ossl_asn1_template_free     crypto/asn1/tasn_fre.c:141      0x7acfe6520923  
ossl_asn1_item_embed_free   crypto/asn1/tasn_fre.c:114      0x7acfe6520805  
ossl_asn1_template_free     crypto/asn1/tasn_fre.c:146      0x7acfe6520980  
ossl_asn1_item_embed_free   crypto/asn1/tasn_fre.c:114      0x7acfe6520805  
ASN1_item_free              crypto/asn1/tasn_fre.c:20       0x7acfe652046a  
CMS_ContentInfo_free        crypto/cms/cms_lib.c:27         0x7acfe659d29b  
cms_main                    apps/cms.c:1320                 0x5fb2c34d66ea  
do_cmd                      apps/openssl.c:428              0x5fb2c34f0c50  
main                        apps/openssl.c:309              0x5fb2c34f0812  

When the segfault happens, the mentioned .NET module libSignPath.Cryptoki.so already got unloaded (confirmed via LD_DEBUG=libs tracing).

On the stack trace, OpenSSL is in the process of freeing X.509 objects, which it used in the openssl cms command. On these X.509 objects, .NET attached OpenSSL "exdata" (registered at EnsureOpenSsl11Initialized() (using class index CRYPTO_EX_INDEX_X509). .NET registers ExDataFreeOcspResponse() as free_func.

Now OpenSSL (in the process of freeing X.509 objects) tries to call the registered free_func, which got unloaded. => Segfault.

We confirmed this by remembering the free_func pointer in ossl_crypto_get_ex_new_index_ex() for ExDataFreeOcspResponse() and seeing that the segfault happens due to accessing exactly this address.

So the problem is that .NET does not unregister the registered free_funcs. That is possible via CRYPTO_free_ex_index(), which is also recommended in the OpenSSL docs "if a dynamic library can be unloaded":

If a dynamic library can be unloaded, it should call CRYPTO_free_ex_index() when this is done. This will replace the callbacks with no-ops so that applications don't crash. Any existing exdata will be leaked.

Reproduction Steps

See above for a description of the necessary steps. Unfortunately we don't have a minimal reproduction sample.

Expected behavior

No segfault 😆

Actual behavior

See above.

Regression?

No response

Known Workarounds

A (very) hacky workaround is to run CRYPTO_free_ex_index(3, 1 /* index may vary! */); CRYPTO_free_ex_index(2, 1 /* index may vary! */); from the .NET process before module unloading.

Configuration

.NET 9 (AOT) in Debian 13 Linux container, AMD64.

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions