From 2915fe19a6676374c335d8c50eaaa4c940cf47d6 Mon Sep 17 00:00:00 2001 From: Rich Salz Date: Thu, 22 Jun 2017 14:00:06 -0400 Subject: [PATCH] Add fork handlers, based on pthread_atfork Only for Unix platforms Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/3754) --- crypto/include/internal/cryptlib.h | 1 + crypto/init.c | 29 +++++++++++++++ crypto/threads_none.c | 5 +++ crypto/threads_pthread.c | 10 ++++++ crypto/threads_win.c | 5 +++ doc/man3/OPENSSL_fork_prepare.pod | 58 ++++++++++++++++++++++++++++++ doc/man3/OPENSSL_init_crypto.pod | 5 +++ include/openssl/crypto.h | 8 ++++- util/libcrypto.num | 3 ++ 9 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 doc/man3/OPENSSL_fork_prepare.pod diff --git a/crypto/include/internal/cryptlib.h b/crypto/include/internal/cryptlib.h index f3ec9b67b8..d2ab720d34 100644 --- a/crypto/include/internal/cryptlib.h +++ b/crypto/include/internal/cryptlib.h @@ -66,6 +66,7 @@ extern unsigned int OPENSSL_ia32cap_P[]; void OPENSSL_showfatal(const char *fmta, ...); extern int OPENSSL_NONPIC_relocated; void crypto_cleanup_all_ex_data_int(void); +int openssl_init_fork_handlers(void); int openssl_strerror_r(int errnum, char *buf, size_t buflen); # if !defined(OPENSSL_NO_STDIO) diff --git a/crypto/init.c b/crypto/init.c index e159a3dd0c..bc961718da 100644 --- a/crypto/init.c +++ b/crypto/init.c @@ -552,6 +552,10 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) && !RUN_ONCE(&add_all_digests, ossl_init_add_all_digests)) return 0; + if ((opts & OPENSSL_INIT_NO_ATFORK) == 0 + && !openssl_init_fork_handlers()) + return 0; + if ((opts & OPENSSL_INIT_NO_LOAD_CONFIG) && !RUN_ONCE(&config, ossl_init_no_config)) return 0; @@ -677,3 +681,28 @@ int OPENSSL_atexit(void (*handler)(void)) return 1; } + +#ifdef OPENSSL_SYS_UNIX +/* + * The following three functions are for OpenSSL developers. This is + * where we set/reset state across fork (called via pthread_atfork when + * it exists, or manually by the application when it doesn't). + * + * WARNING! If you put code in either OPENSSL_fork_parent or + * OPENSSL_fork_child, you MUST MAKE SURE that they are async-signal- + * safe. See this link, for example: + * http://man7.org/linux/man-pages/man7/signal-safety.7.html + */ + +void OPENSSL_fork_prepare(void) +{ +} + +void OPENSSL_fork_parent(void) +{ +} + +void OPENSSL_fork_child(void) +{ +} +#endif diff --git a/crypto/threads_none.c b/crypto/threads_none.c index 72bf25b0d5..39aadd0e98 100644 --- a/crypto/threads_none.c +++ b/crypto/threads_none.c @@ -121,4 +121,9 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock) return 1; } +int openssl_init_fork_handlers(void) +{ + return 0; +} + #endif diff --git a/crypto/threads_pthread.c b/crypto/threads_pthread.c index 151013e470..f7c792123b 100644 --- a/crypto/threads_pthread.c +++ b/crypto/threads_pthread.c @@ -8,6 +8,7 @@ */ #include +#include #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && !defined(OPENSSL_SYS_WINDOWS) @@ -168,4 +169,13 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock) return 1; } +int openssl_init_fork_handlers(void) +{ +# ifdef OPENSSL_SYS_UNIX + if (pthread_atfork(OPENSSL_fork_prepare, + OPENSSL_fork_parent, OPENSSL_fork_child) == 0) + return 1; +# endif + return 0; +} #endif diff --git a/crypto/threads_win.c b/crypto/threads_win.c index 4e0de908ee..512e19f5f3 100644 --- a/crypto/threads_win.c +++ b/crypto/threads_win.c @@ -133,4 +133,9 @@ int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock) return 1; } +int openssl_init_fork_handlers(void) +{ + return 0; +} + #endif diff --git a/doc/man3/OPENSSL_fork_prepare.pod b/doc/man3/OPENSSL_fork_prepare.pod new file mode 100644 index 0000000000..4d05096c8d --- /dev/null +++ b/doc/man3/OPENSSL_fork_prepare.pod @@ -0,0 +1,58 @@ +=pod + +=head1 NAME + +OPENSSL_fork_prepare, +OPENSSL_fork_parent, +OPENSSL_fork_child +- OpenSSL fork handlers + +=head1 SYNOPSIS + + #include + + void OPENSSL_fork_prepare(void); + void OPENSSL_fork_parent(void); + void OPENSSL_fork_child(void); + +=head1 DESCRIPTION + +OpenSSL has state that should be reset when a process forks. For example, +the entropy pool used to generate random numbers (and therefore encryption +keys) should not be shared across multiple programs. +The OPENSSL_fork_prepare(), OPENSSL_fork_parent(), and OPENSSL_fork_child() +functions are used to reset this internal state. + +Platforms without fork(2) will probably not need to use these functions. +Platforms with fork(2) but without pthreads_atfork(3) will probably need +to call them manually, as described in the following paragraph. Platforms +such as Linux that have both functions will normally not need to call these +functions as the OpenSSL library will do so automatically. + +L will register these funtions with the appropriate +hander, unless the B flag is used. For those +applications, these functions can be called directly. They should be used +according to the calling sequence described by the pthreads_atfork(3) +documentation, which is summarized here. OPENSSL_fork_prepare() should +be called before a fork() is done. After the fork() returns, the parent +process should call OPENSSL_fork_parent() and the child process should +call OPENSSL_fork_child(). + +=head1 SEE ALSO + +L + +=head1 HISTORY + +These functions were added in OpenSSL 1.1.1. + +=head1 COPYRIGHT + +Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the OpenSSL license (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/doc/man3/OPENSSL_init_crypto.pod b/doc/man3/OPENSSL_init_crypto.pod index fcc617ea4b..1ee7705b2b 100644 --- a/doc/man3/OPENSSL_init_crypto.pod +++ b/doc/man3/OPENSSL_init_crypto.pod @@ -150,6 +150,11 @@ With this option the library will automatically load and initialise all the built in engines listed above with the exception of the openssl and dasync engines. This not a default option. +=item OPENSSL_INIT_NO_ATFORK + +With this option the library will not register its fork handlers. +See OPENSSL_fork_prepare(3) for details. + =back Multiple options may be combined together in a single call to diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h index 5c7d1139d6..06ca40eba9 100644 --- a/include/openssl/crypto.h +++ b/include/openssl/crypto.h @@ -332,6 +332,11 @@ int FIPS_mode(void); int FIPS_mode_set(int r); void OPENSSL_init(void); +# ifdef OPENSSL_SYS_UNIX +void OPENSSL_fork_prepare(void); +void OPENSSL_fork_parent(void); +void OPENSSL_fork_child(void); +# endif struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result); int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec); @@ -364,7 +369,8 @@ int CRYPTO_memcmp(const void * in_a, const void * in_b, size_t len); # define OPENSSL_INIT_ENGINE_CAPI 0x00002000L # define OPENSSL_INIT_ENGINE_PADLOCK 0x00004000L # define OPENSSL_INIT_ENGINE_AFALG 0x00008000L -/* OPENSSL_INIT flag 0x00010000 reserved for internal use */ +# define OPENSSL_INIT_reserved_internal 0x00010000L +# define OPENSSL_INIT_NO_ATFORK 0x00020000L /* OPENSSL_INIT flag range 0xfff00000 reserved for OPENSSL_init_ssl() */ /* Max OPENSSL_INIT flag value is 0x80000000 */ diff --git a/util/libcrypto.num b/util/libcrypto.num index d734461a9b..c861878fb1 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4342,3 +4342,6 @@ OSSL_STORE_INFO_set0_NAME_description 4284 1_1_1 EXIST::FUNCTION: OSSL_STORE_INFO_get1_NAME_description 4285 1_1_1 EXIST::FUNCTION: OSSL_STORE_do_all_loaders 4286 1_1_1 EXIST::FUNCTION: OSSL_STORE_LOADER_get0_engine 4287 1_1_1 EXIST::FUNCTION: +OPENSSL_fork_prepare 4288 1_1_1 EXIST:UNIX:FUNCTION: +OPENSSL_fork_parent 4289 1_1_1 EXIST:UNIX:FUNCTION: +OPENSSL_fork_child 4290 1_1_1 EXIST:UNIX:FUNCTION: -- 2.25.1