How to properly uninitialize OpenSSL

d:\cfiles\projects\winssl\openssl-1.0.1l\crypto\err\err.c

Latching on to this, it looks like some error state (or strings) needs to be free’d.


How to properly uninitialize OpenSSL

The code for startup and shutdown is shown below (including FIPS). If you do things like load DH parameters, then you will need to clean them up, too.

Dr. Henson was very helpful with his suggestion of calling ERR_remove_state for each thread. See Order of Cleanup to avoid memory leaks? on the OpenSSL mailing list.

Startup

  • SSL_library_init();
  • SSL_load_error_strings();
  • FIPS_mode_set(1);
  • CRYPTO_set_id_callback(<fn>);
  • CRYPTO_set_locking_callback(<fn>);

Shutdown

  • FIPS_mode_set(0);
  • CRYPTO_set_locking_callback(NULL);
  • CRYPTO_set_id_callback(NULL);
  • ENGINE_cleanup();
  • CONF_modules_unload();
  • ERR_free_strings();
  • EVP_cleanup();
  • CRYPTO_cleanup_all_ex_data();

And, for each thread:

  • ERR_remove_state();

You only need CRYPTO_set_id_callback and CRYPTO_set_locking_callback if your program is multi-threaded. See the Openssl threads(3) man page.

I believe you can call SSL_COMP_free_compression_methods in OpenSSL 1.0.2 and above. That addresses some of the complaint below. But its not available in OpenSSL 1.0.1 and below.


SSL_COMP_get_compression_methods()…

Yeah, this causes a leak. Its well known and due to ssl_comp_methods being lazily allocated but never freed. See OpenSSL Issue 2561: Memory leak with SSL built-in compressions.

Some of the OpenSSL devs don’t feel its worth their time to fix it. See Small memory leak on multithreaded server on the OpenSSL mailing list.

The following is one of the dev’s position on it:

A fixed amount of memory that is not deallocated and is independent of
the number of operations performed, is NOT a memory leak. Libraries
to allocate memory for the lifetime of the process during one time
initialization or first use of a function. This is normal.

Tracking this down is a waste of time IMHO.

And here’s another thread about that particular leak: Preferred way to free ssl_comp_methods?. And here’s that same dev’s response:

Why is anyone obsessed about freeing memory that is assigned to static
pointers at most once. There’s no “memory leak” associated with such
allocations because the amount of extra memory used is fixed.

What he failed to realize is Java and .Net will load/unload the library many times during a program’s lifecycle, so that small amount of “who cares” can grow unbounded.

When he was told about the alternate use case, here was his reply. I guess, he is suggesting that Oracle and Java re-architect their languages. Or don’t use OpenSSL in them.

Unloading of shared libraries is generally unsafe.

Here was the response of one of the folks who maintain a Java VM:

As the maintainer of an “alternative” JavaVM I can confirm that we
absolutely had to support library unloading because one customer was
using it heavily – and that was quite a few years ago. Early Sun VMs
didn’t support library unloading, but then those VMs also did not
garbage-collect obsolete classes either.


Here a section on fixing the ssl_comp_methods leak.

In all cases, you will need to add the patch described below.

For a program to do it manually, just add a function named free_compressions (or similar) and call it on shutdown like all the other methods listed above. The function needs to be exported.

To do it automatically under Linux, its takes a little trickery. You have to use a GCC extension: __attribute__ ((destructor)).

/* Add to end of <openssl dir>/ssl/ssl_ciph.c */
#if !defined(OPENSSL_NO_COMP) && defined(__GNU_C__)
void free_compressions(void) __attribute__ ((destructor));
void free_compressions(void)
{
    if (ssl_comp_methods != NULL)
        {
        sk_SSL_COMP_free(ssl_comp_methods);
        ssl_comp_methods = NULL;
        }
}
#endif 

To do it automatically under Windows, you have to do it in DllMain. But you have to be careful about what you do in DllMain, and how you do it. So maybe something like:

/* Add to end of <openssl dir>/ssl/ssl.h*/
#if !defined(OPENSSL_NO_COMP) && defined(WIN32)
__declspec(dllexport)
    void free_compressions(void);
#endof

/* Add to end of <openssl dir>/ssl/ssl_ciph.c */
#if !defined(OPENSSL_NO_COMP) && defined(WIN32)
void free_compressions(void)
{
    if (ssl_comp_methods != NULL)
        {
        sk_SSL_COMP_free(ssl_comp_methods);
        ssl_comp_methods = NULL;
        }
}
#endif 

—–

Why is this thread being downvoted? The thread I linked is a lot less detailed and it got 10 upvotes (plus one from me). Did you guys become a lot more strict in the last few years?

Looking at the close reason (which you can’t do at the moment), the close vote was cast with the reason:

Questions seeking debugging help (“why isn’t this code working?”) must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself.

Normally that applies. But in your case it does not; and its not readily apparent to those not familiar with the issue. In fact, you could write a simple program that just initializes and then unitializes the library and it will probably leak…

As a matter of policy, the site can’t make a rule “Always provide relevant code except for some OpenSSL memory leaks” (which is effectively what we need to handle your case).

Leave a Comment