[PATCH] Manually cleanup OpenSSL from dovecot_openssl_common_global_unref()
OpenSSL 1.1 features a cleanup function that is automatically run on shutdown
using atexit(3). This function frees all OpenSSL-allocated resources.
In dovecot, OpenSSL is loaded indirectly using dlopen(3) against the relevant
dovecot crypto module and is finally unloaded using dlclose(3). Until
OpenSSL 1.0.1c this worked fine, however OpenSSL 1.0.1c makes sure[1] that the
library stays loaded after the initial dlclose() so that the atexit(3)
handlers can run on shutdown. This, together with the fact that dovecot
uses custom allocation functions for OpenSSL and has already partially
free()'d some of OpenSSL's resources in module_free(), leads to a
segfault at process shutdown[2].
We fix this by explicitly calling OPENSSL_cleanup() during module unload. This
is safe to do, as long as we will never want to subsequently re-initialize
OpenSSL.
[1] https://github.com/openssl/openssl/commit/4af9f7fe79ff82b90c16969b7e58714350...
[2] https://buildd.debian.org/status/fetch.php?pkg=dovecot&arch=amd64&ver=1:2.2.26.0-2&stamp=1478873022
Signed-off-by: Apollon Oikonomopoulos
Am 13.11.2016 um 19:04 schrieb Apollon Oikonomopoulos:
OpenSSL 1.1 features a cleanup function that is automatically run on shutdown using atexit(3). This function frees all OpenSSL-allocated resources.
In dovecot, OpenSSL is loaded indirectly using dlopen(3) against the relevant dovecot crypto module and is finally unloaded using dlclose(3). Until OpenSSL 1.0.1c this worked fine, however OpenSSL 1.0.1c makes sure[1] that the library stays loaded after the initial dlclose() so that the atexit(3) handlers can run on shutdown. This, together with the fact that dovecot uses custom allocation functions for OpenSSL and has already partially free()'d some of OpenSSL's resources in module_free(), leads to a segfault at process shutdown[2].
We fix this by explicitly calling OPENSSL_cleanup() during module unload. This is safe to do, as long as we will never want to subsequently re-initialize OpenSSL.
[1] https://github.com/openssl/openssl/commit/4af9f7fe79ff82b90c16969b7e58714350... [2] https://buildd.debian.org/status/fetch.php?pkg=dovecot&arch=amd64&ver=1:2.2.26.0-2&stamp=1478873022
Signed-off-by: Apollon Oikonomopoulos
--- src/lib-ssl-iostream/dovecot-openssl-common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib-ssl-iostream/dovecot-openssl-common.c b/src/lib-ssl-iostream/dovecot-openssl-common.c index 51ea3ad..2bf6307 100644 --- a/src/lib-ssl-iostream/dovecot-openssl-common.c +++ b/src/lib-ssl-iostream/dovecot-openssl-common.c @@ -101,6 +101,9 @@ bool dovecot_openssl_common_global_unref(void) ERR_remove_thread_state(NULL); #endif ERR_free_strings(); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + OPENSSL_cleanup(); +#endif return FALSE; }
I could at least confirm the observation (segfault on build) and the fix solve it as promised. Andreas
On 13.11.2016 20:04, Apollon Oikonomopoulos wrote:
OpenSSL 1.1 features a cleanup function that is automatically run on shutdown using atexit(3). This function frees all OpenSSL-allocated resources.
In dovecot, OpenSSL is loaded indirectly using dlopen(3) against the relevant dovecot crypto module and is finally unloaded using dlclose(3). Until OpenSSL 1.0.1c this worked fine, however OpenSSL 1.0.1c makes sure[1] that the library stays loaded after the initial dlclose() so that the atexit(3) handlers can run on shutdown. This, together with the fact that dovecot uses custom allocation functions for OpenSSL and has already partially free()'d some of OpenSSL's resources in module_free(), leads to a segfault at process shutdown[2].
We fix this by explicitly calling OPENSSL_cleanup() during module unload. This is safe to do, as long as we will never want to subsequently re-initialize OpenSSL.
[1] https://github.com/openssl/openssl/commit/4af9f7fe79ff82b90c16969b7e58714350... [2] https://buildd.debian.org/status/fetch.php?pkg=dovecot&arch=amd64&ver=1:2.2.26.0-2&stamp=1478873022
Signed-off-by: Apollon Oikonomopoulos
--- src/lib-ssl-iostream/dovecot-openssl-common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib-ssl-iostream/dovecot-openssl-common.c b/src/lib-ssl-iostream/dovecot-openssl-common.c index 51ea3ad..2bf6307 100644 --- a/src/lib-ssl-iostream/dovecot-openssl-common.c +++ b/src/lib-ssl-iostream/dovecot-openssl-common.c @@ -101,6 +101,9 @@ bool dovecot_openssl_common_global_unref(void) ERR_remove_thread_state(NULL); #endif ERR_free_strings(); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + OPENSSL_cleanup(); +#endif return FALSE; }
Hi! Your patch is being reviewed. Aki
Hi, This patch: On 15/11/2016 10:46 PM, Aki Tuomi wrote:
On 13.11.2016 20:04, Apollon Oikonomopoulos wrote:
OpenSSL 1.1 features a cleanup function that is automatically run on shutdown using atexit(3). This function frees all OpenSSL-allocated resources.
In dovecot, OpenSSL is loaded indirectly using dlopen(3) against the relevant dovecot crypto module and is finally unloaded using dlclose(3). Until OpenSSL 1.0.1c this worked fine, however OpenSSL 1.0.1c makes sure[1] that the library stays loaded after the initial dlclose() so that the atexit(3) handlers can run on shutdown. This, together with the fact that dovecot uses custom allocation functions for OpenSSL and has already partially free()'d some of OpenSSL's resources in module_free(), leads to a segfault at process shutdown[2].
We fix this by explicitly calling OPENSSL_cleanup() during module unload. This is safe to do, as long as we will never want to subsequently re-initialize OpenSSL.
[1] https://github.com/openssl/openssl/commit/4af9f7fe79ff82b90c16969b7e58714350... [2] https://buildd.debian.org/status/fetch.php?pkg=dovecot&arch=amd64&ver=1:2.2.26.0-2&stamp=1478873022
Signed-off-by: Apollon Oikonomopoulos
--- src/lib-ssl-iostream/dovecot-openssl-common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib-ssl-iostream/dovecot-openssl-common.c b/src/lib-ssl-iostream/dovecot-openssl-common.c index 51ea3ad..2bf6307 100644 --- a/src/lib-ssl-iostream/dovecot-openssl-common.c +++ b/src/lib-ssl-iostream/dovecot-openssl-common.c @@ -101,6 +101,9 @@ bool dovecot_openssl_common_global_unref(void) ERR_remove_thread_state(NULL); #endif ERR_free_strings(); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + OPENSSL_cleanup(); +#endif return FALSE; }
Hi!
Your patch is being reviewed.
Aki
... which was committed as c164f8afe58c8d83ef2a48aae629c72408dfea01 in master-2.2, terminally breaks the build with LibreSSL. Obviously this wasn't tested or considered ;) *** Warning: Linking the executable test-http-client against the loadable module *** libssl_iostream_openssl.so is not portable! libtool: link: x86_64-pc-linux-gnu-gcc -std=gnu99 -O0 -g -pipe -march=native -mtune=native -Wall -W -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wchar-subscripts -Wformat=2 -Wbad-function-cast -fno-builtin-strftime -Wstrict-aliasing=2 -Wl,-O1 -o .libs/test-http-client test-http-client.o -Wl,--export-dynamic -Wl,--as-needed ./.libs/libhttp.a ../lib-dns/.libs/libdns.a ../lib-ssl-iostream/.libs/libssl_iostream.a ../lib-master/.libs/libmaster.a ../lib-settings/.libs/libsettings.a ../lib-test/.libs/libtest.a ../lib/.libs/liblib.a -ldl ../lib-ssl-iostream/.libs/libssl_iostream_openssl.so -lssl -lcrypto -Wl,-rpath -Wl,/usr/lib64/dovecot ../lib-ssl-iostream/.libs/libssl_iostream_openssl.so: undefined reference to `OPENSSL_cleanup' collect2: error: ld returned 1 exit status make[3]: *** [Makefile:737: test-http-client] Error 1 make[3]: *** Waiting for unfinished jobs.... libtool: link: x86_64-pc-linux-gnu-gcc -std=gnu99 -O0 -g -pipe -march=native -mtune=native -Wall -W -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wchar-subscripts -Wformat=2 -Wbad-function-cast -fno-builtin-strftime -Wstrict-aliasing=2 -Wl,-O1 -o test-http-client-errors test-http-client-errors.o -Wl,--export-dynamic -Wl,--as-needed ./.libs/libhttp.a ../lib-dns/.libs/libdns.a ../lib-ssl-iostream/.libs/libssl_iostream.a ../lib-master/.libs/libmaster.a ../lib-settings/.libs/libsettings.a ../lib-test/.libs/libtest.a ../lib/.libs/liblib.a -ldl make[3]: Leaving directory '/var/tmp/portage/net-mail/dovecot-2.2.26_p20161120/work/dovecot-2.2.26_p20161120/src/lib-http' make[2]: *** [Makefile:493: all-recursive] Error 1 make[2]: Leaving directory '/var/tmp/portage/net-mail/dovecot-2.2.26_p20161120/work/dovecot-2.2.26_p20161120/src' make[1]: *** [Makefile:618: all-recursive] Error 1 make[1]: Leaving directory '/var/tmp/portage/net-mail/dovecot-2.2.26_p20161120/work/dovecot-2.2.26_p20161120' make: *** [Makefile:462: all] Error 2 * ERROR: net-mail/dovecot-2.2.26_p20161120::reub-Local-Overlay failed (compile phase): * emake failed * I am running LibreSSL-2.5.0, so I guess it may not be a supported function yet. Reuben
Hi,
On 22:59 Sun 20 Nov , Reuben Farrelly wrote:
Hi,
This patch:
... which was committed as c164f8afe58c8d83ef2a48aae629c72408dfea01 in master-2.2, terminally breaks the build with LibreSSL. Obviously this wasn't tested or considered ;)
Yes, unfortunately LibreSSL fakes OpenSSL version numbers and reports a
version much bigger than 1.1 while actually providing the API of 1.0.x.
I will submit an additional patch to fix the guard condition there.
Regards, Apollon
participants (4)
-
A. Schulze
-
Aki Tuomi
-
Apollon Oikonomopoulos
-
Reuben Farrelly