diff -up openssl-1.1.1c/crypto/fips/fips.c.fork-safety openssl-1.1.1c/crypto/fips/fips.c --- openssl-1.1.1c/crypto/fips/fips.c.fork-safety 2019-11-20 11:36:22.343506961 +0100 +++ openssl-1.1.1c/crypto/fips/fips.c 2019-11-21 17:44:32.920776849 +0100 @@ -472,7 +472,7 @@ int FIPS_module_mode_set(int onoff) fips_set_mode(onoff); /* force RNG reseed with entropy from getrandom() on next call */ - rand_fork(); + rand_force_reseed(); ret = 1; goto end; diff -up openssl-1.1.1c/crypto/include/internal/rand_int.h.fork-safety openssl-1.1.1c/crypto/include/internal/rand_int.h --- openssl-1.1.1c/crypto/include/internal/rand_int.h.fork-safety 2019-11-20 11:36:22.382506277 +0100 +++ openssl-1.1.1c/crypto/include/internal/rand_int.h 2019-11-21 17:45:42.102456672 +0100 @@ -24,9 +24,9 @@ typedef struct rand_pool_st RAND_POOL; void rand_cleanup_int(void); +void rand_force_reseed(void); void rand_drbg_cleanup_int(void); void drbg_delete_thread_state(void); -void rand_fork(void); /* Hardware-based seeding functions. */ size_t rand_acquire_entropy_from_tsc(RAND_POOL *pool); diff -up openssl-1.1.1c/crypto/init.c.fork-safety openssl-1.1.1c/crypto/init.c --- openssl-1.1.1c/crypto/init.c.fork-safety 2019-05-28 15:12:21.000000000 +0200 +++ openssl-1.1.1c/crypto/init.c 2019-11-21 17:34:13.478597398 +0100 @@ -847,6 +847,5 @@ void OPENSSL_fork_parent(void) void OPENSSL_fork_child(void) { - rand_fork(); } #endif diff -up openssl-1.1.1c/crypto/rand/drbg_lib.c.fork-safety openssl-1.1.1c/crypto/rand/drbg_lib.c --- openssl-1.1.1c/crypto/rand/drbg_lib.c.fork-safety 2019-11-20 11:36:22.383506260 +0100 +++ openssl-1.1.1c/crypto/rand/drbg_lib.c 2019-11-21 17:46:37.583397431 +0100 @@ -197,7 +197,7 @@ static RAND_DRBG *rand_drbg_new(int secu } drbg->secure = secure && CRYPTO_secure_allocated(drbg); - drbg->fork_count = rand_fork_count; + drbg->fork_id = openssl_get_fork_id(); drbg->parent = parent; if (parent == NULL) { @@ -583,6 +583,7 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, int prediction_resistance, const unsigned char *adin, size_t adinlen) { + int fork_id; int reseed_required = 0; if (drbg->state != DRBG_READY) { @@ -608,8 +609,10 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, return 0; } - if (drbg->fork_count != rand_fork_count) { - drbg->fork_count = rand_fork_count; + fork_id = openssl_get_fork_id(); + + if (drbg->fork_id != fork_id) { + drbg->fork_id = fork_id; reseed_required = 1; } @@ -1011,6 +1014,20 @@ size_t rand_drbg_seedlen(RAND_DRBG *drbg return min_entropy > min_entropylen ? min_entropy : min_entropylen; } +void rand_force_reseed(void) +{ + RAND_DRBG *drbg; + + drbg = RAND_DRBG_get0_master(); + drbg->fork_id = 0; + + drbg = RAND_DRBG_get0_private(); + drbg->fork_id = 0; + + drbg = RAND_DRBG_get0_public(); + drbg->fork_id = 0; +} + /* Implements the default OpenSSL RAND_add() method */ static int drbg_add(const void *buf, int num, double randomness) { diff -up openssl-1.1.1c/crypto/rand/rand_lcl.h.fork-safety openssl-1.1.1c/crypto/rand/rand_lcl.h --- openssl-1.1.1c/crypto/rand/rand_lcl.h.fork-safety 2019-11-20 11:36:22.383506260 +0100 +++ openssl-1.1.1c/crypto/rand/rand_lcl.h 2019-11-21 17:34:13.485597265 +0100 @@ -176,12 +176,12 @@ struct rand_drbg_st { int secure; /* 1: allocated on the secure heap, 0: otherwise */ int type; /* the nid of the underlying algorithm */ /* - * Stores the value of the rand_fork_count global as of when we last - * reseeded. The DRBG reseeds automatically whenever drbg->fork_count != - * rand_fork_count. Used to provide fork-safety and reseed this DRBG in - * the child process. + * Stores the return value of openssl_get_fork_id() as of when we last + * reseeded. The DRBG reseeds automatically whenever drbg->fork_id != + * openssl_get_fork_id(). Used to provide fork-safety and reseed this + * DRBG in the child process. */ - int fork_count; + int fork_id; unsigned short flags; /* various external flags */ /* @@ -273,19 +273,6 @@ struct rand_drbg_st { /* The global RAND method, and the global buffer and DRBG instance. */ extern RAND_METHOD rand_meth; -/* - * A "generation count" of forks. Incremented in the child process after a - * fork. Since rand_fork_count is increment-only, and only ever written to in - * the child process of the fork, which is guaranteed to be single-threaded, no - * locking is needed for normal (read) accesses; the rest of pthread fork - * processing is assumed to introduce the necessary memory barriers. Sibling - * children of a given parent will produce duplicate values, but this is not - * problematic because the reseeding process pulls input from the system CSPRNG - * and/or other global sources, so the siblings will end up generating - * different output streams. - */ -extern int rand_fork_count; - /* DRBG helpers */ int rand_drbg_restart(RAND_DRBG *drbg, const unsigned char *buffer, size_t len, size_t entropy); diff -up openssl-1.1.1c/crypto/rand/rand_lib.c.fork-safety openssl-1.1.1c/crypto/rand/rand_lib.c --- openssl-1.1.1c/crypto/rand/rand_lib.c.fork-safety 2019-11-20 11:36:22.374506418 +0100 +++ openssl-1.1.1c/crypto/rand/rand_lib.c 2019-11-21 17:34:13.487597227 +0100 @@ -30,8 +30,6 @@ static CRYPTO_RWLOCK *rand_meth_lock; static const RAND_METHOD *default_RAND_meth; static CRYPTO_ONCE rand_init = CRYPTO_ONCE_STATIC_INIT; -int rand_fork_count; - static CRYPTO_RWLOCK *rand_nonce_lock; static int rand_nonce_count; @@ -303,11 +301,6 @@ void rand_drbg_cleanup_additional_data(R rand_pool_reattach(pool, out); } -void rand_fork(void) -{ - rand_fork_count++; -} - DEFINE_RUN_ONCE_STATIC(do_rand_init) { #ifndef OPENSSL_NO_ENGINE diff -up openssl-1.1.1c/crypto/threads_none.c.fork-safety openssl-1.1.1c/crypto/threads_none.c --- openssl-1.1.1c/crypto/threads_none.c.fork-safety 2019-05-28 15:12:21.000000000 +0200 +++ openssl-1.1.1c/crypto/threads_none.c 2019-11-21 17:34:13.489597189 +0100 @@ -12,6 +12,11 @@ #if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG) +# if defined(OPENSSL_SYS_UNIX) +# include +# include +# endif + CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void) { CRYPTO_RWLOCK *lock; @@ -133,4 +138,12 @@ int openssl_init_fork_handlers(void) return 0; } +int openssl_get_fork_id(void) +{ +# if defined(OPENSSL_SYS_UNIX) + return getpid(); +# else + return 0; +# endif +} #endif diff -up openssl-1.1.1c/crypto/threads_pthread.c.fork-safety openssl-1.1.1c/crypto/threads_pthread.c --- openssl-1.1.1c/crypto/threads_pthread.c.fork-safety 2019-05-28 15:12:21.000000000 +0200 +++ openssl-1.1.1c/crypto/threads_pthread.c 2019-11-21 17:34:13.492597131 +0100 @@ -12,6 +12,11 @@ #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && !defined(OPENSSL_SYS_WINDOWS) +# if defined(OPENSSL_SYS_UNIX) +# include +# include +#endif + # ifdef PTHREAD_RWLOCK_INITIALIZER # define USE_RWLOCK # endif @@ -193,4 +198,9 @@ int openssl_init_fork_handlers(void) # endif return 0; } + +int openssl_get_fork_id(void) +{ + return getpid(); +} #endif diff -up openssl-1.1.1c/crypto/threads_win.c.fork-safety openssl-1.1.1c/crypto/threads_win.c --- openssl-1.1.1c/crypto/threads_win.c.fork-safety 2019-05-28 15:12:21.000000000 +0200 +++ openssl-1.1.1c/crypto/threads_win.c 2019-11-21 17:34:13.495597074 +0100 @@ -164,4 +164,8 @@ int openssl_init_fork_handlers(void) return 0; } +int openssl_get_fork_id(void) +{ + return 0; +} #endif diff -up openssl-1.1.1c/include/internal/cryptlib.h.fork-safety openssl-1.1.1c/include/internal/cryptlib.h --- openssl-1.1.1c/include/internal/cryptlib.h.fork-safety 2019-05-28 15:12:21.000000000 +0200 +++ openssl-1.1.1c/include/internal/cryptlib.h 2019-11-21 17:34:13.497597036 +0100 @@ -80,6 +80,7 @@ extern unsigned int OPENSSL_ia32cap_P[]; void OPENSSL_showfatal(const char *fmta, ...); void crypto_cleanup_all_ex_data_int(void); int openssl_init_fork_handlers(void); +int openssl_get_fork_id(void); char *ossl_safe_getenv(const char *name); diff -up openssl-1.1.1c/test/drbgtest.c.fork-safety openssl-1.1.1c/test/drbgtest.c --- openssl-1.1.1c/test/drbgtest.c.fork-safety 2019-11-20 11:36:22.384506242 +0100 +++ openssl-1.1.1c/test/drbgtest.c 2019-11-21 17:34:13.499596998 +0100 @@ -22,6 +22,13 @@ # include #endif + +#if defined(OPENSSL_SYS_UNIX) +# include +# include +# include +#endif + #include "testutil.h" #include "drbgtest.h" @@ -696,6 +703,40 @@ static int test_drbg_reseed(int expect_s return 1; } + +#if defined(OPENSSL_SYS_UNIX) +/* + * Test whether master, public and private DRBG are reseeded after + * forking the process. + */ +static int test_drbg_reseed_after_fork(RAND_DRBG *master, + RAND_DRBG *public, + RAND_DRBG *private) +{ + pid_t pid; + int status=0; + + pid = fork(); + if (!TEST_int_ge(pid, 0)) + return 0; + + if (pid > 0) { + /* I'm the parent; wait for the child and check its exit code */ + return TEST_int_eq(waitpid(pid, &status, 0), pid) && TEST_int_eq(status, 0); + } + + /* I'm the child; check whether all three DRBGs reseed. */ + if (!TEST_true(test_drbg_reseed(1, master, public, private, 1, 1, 1, 0))) + status = 1; + + /* Remove hooks */ + unhook_drbg(master); + unhook_drbg(public); + unhook_drbg(private); + exit(status); +} +#endif + /* * Test whether the default rand_method (RAND_OpenSSL()) is * setup correctly, in particular whether reseeding works @@ -786,6 +827,10 @@ static int test_rand_drbg_reseed(void) goto error; reset_drbg_hook_ctx(); +#if defined(OPENSSL_SYS_UNIX) + if (!TEST_true(test_drbg_reseed_after_fork(master, public, private))) + goto error; +#endif /* fill 'randomness' buffer with some arbitrary data */ memset(rand_add_buf, 'r', sizeof(rand_add_buf));