diff options
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/atfork.c | 105 | ||||
-rw-r--r-- | lib/atfork.h | 76 | ||||
-rw-r--r-- | lib/gnutls_global.c | 9 | ||||
-rw-r--r-- | lib/nettle/rnd-fips.c | 17 | ||||
-rw-r--r-- | lib/nettle/rnd.c | 36 | ||||
-rw-r--r-- | lib/pkcs11.c | 29 |
8 files changed, 214 insertions, 62 deletions
diff --git a/configure.ac b/configure.ac index af38fa5e29..eef6c9fefc 100644 --- a/configure.ac +++ b/configure.ac @@ -149,6 +149,8 @@ dnl Check clock_gettime and pthread_mutex_lock in libc (avoid linking to other l AC_CHECK_FUNCS([fork inet_ntop inet_pton getrusage getpwuid_r nanosleep daemon getpid clock_gettime iconv localtime vasprintf],,) AM_CONDITIONAL(HAVE_FORK, test "$ac_cv_func_fork" != "no") +AC_CHECK_FUNCS([pthread_atfork __register_atfork],,) + AC_LIB_HAVE_LINKFLAGS(rt,, [#include <time.h> #include <signal.h> ], [timer_create (0,0,0);]) diff --git a/lib/Makefile.am b/lib/Makefile.am index 52b0588dcc..9d3cf338f8 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -82,7 +82,7 @@ COBJECTS = gnutls_range.c gnutls_record.c \ random.c crypto-api.c gnutls_privkey.c gnutls_pcert.c \ gnutls_pubkey.c locks.c gnutls_dtls.c system_override.c \ crypto-backend.c verify-tofu.c pin.c tpm.c fips.c \ - safe-memset.c inet_pton.c + safe-memset.c inet_pton.c atfork.c atfork.h if ENABLE_SELF_CHECKS COBJECTS += crypto-selftests.c crypto-selftests-pk.c diff --git a/lib/atfork.c b/lib/atfork.c new file mode 100644 index 0000000000..c1303d5534 --- /dev/null +++ b/lib/atfork.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2010-2012 Free Software Foundation, Inc. + * Copyright (C) 2014 Red Hat + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#include <config.h> +#include <gnutls_int.h> +#include <gnutls_errors.h> + +#include <sys/socket.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <atfork.h> + +#ifndef _WIN32 + +# if defined(HAVE___REGISTER_ATFORK) || defined(HAVE_PTHREAD_ATFORK) +# define HAVE_ATFORK +# endif + +/* The maximum number of users of the API */ +# define MAX_VALS 6 + +static unsigned int * fvals[MAX_VALS]; +static unsigned int fvals_size = 0; + +# ifdef HAVE_ATFORK +static void fork_handler(void) +{ + unsigned i; + for (i=0;i<fvals_size;i++) + *fvals[i] = 1; +} +# endif + +static void set_val_on_fork(unsigned int *val, unsigned int def) +{ +fprintf(stderr, "fvals: %d\n", fvals_size); + if (fvals_size >= MAX_VALS) + abort(); /* internal error */ + *val = def; + fvals[fvals_size++] = val; +} + +void _gnutls_fork_set_val(unsigned int *val) +{ +# ifdef HAVE_ATFORK + set_val_on_fork(val, 0); +# else + set_val_on_fork(val, getpid()); +# endif +} + +# if defined(HAVE_PTHREAD_ATFORK) + +# include <pthread.h> + +int _gnutls_register_fork_handler(void) +{ + if (pthread_atfork(NULL, NULL, fork_handler) != 0) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + return 0; +} + +# elif defined(HAVE___REGISTER_ATFORK) +extern int __register_atfork(void (*)(void), void(*)(void), void (*)(void), void *); +extern void *__dso_handle; + +int _gnutls_register_fork_handler(void) +{ + if (__register_atfork(NULL, NULL, fork_handler, __dso_handle) != 0) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + return 0; +} + +# else + +/* we have to detect fork manually */ +int _gnutls_register_fork_handler(void) +{ + return 0; +} + +# endif + +#endif /* !_WIN32 */ diff --git a/lib/atfork.h b/lib/atfork.h new file mode 100644 index 0000000000..cf299ab636 --- /dev/null +++ b/lib/atfork.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2014 Red Hat + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef ATFORK_H +#define ATFORK_H + +#include <config.h> +#include <gnutls_int.h> + +#ifndef _WIN32 + +/* API */ +int _gnutls_register_fork_handler(void); /* global init */ + +/* Each user of the API that needs to be notified registers + * a pointer to an int */ +void _gnutls_fork_set_val(unsigned int *val); + +/* + * Each user, calls this function with the integer registered + * to check whether a fork is detected + * + * unsigned _gnutls_fork_detected(unsigned int *v); + */ + +# if defined(HAVE___REGISTER_ATFORK) || defined(HAVE_PTHREAD_ATFORK) +inline static +unsigned _gnutls_fork_detected(unsigned int *v) +{ + if (*v != 0) { + *v = 0; + return 1; + } + return 0; +} +# else +# include <unistd.h> + +inline static +unsigned _gnutls_fork_detected(unsigned int *v) +{ + if (getpid() != (pid_t)*v) { + *v = getpid(); + return 1; + } + return 0; +} + +# endif + +#else /* _WIN32 */ +# define _gnutls_fork_set_val() 0 +# define _gnutls_register_fork_handler() 0 +# define _gnutls_fork_detected(x) 0 +#endif + +#endif diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c index 5c832d0328..ae676a2f84 100644 --- a/lib/gnutls_global.c +++ b/lib/gnutls_global.c @@ -33,6 +33,7 @@ #include <accelerated/cryptodev.h> #include <accelerated/accelerated.h> #include <fips.h> +#include <atfork.h> #include "gettext.h" @@ -290,6 +291,14 @@ int gnutls_global_init(void) goto out; } +#ifndef _WIN32 + ret = _gnutls_register_fork_handler(); + if (ret < 0) { + gnutls_assert(); + goto out; + } +#endif + _gnutls_register_accel_crypto(); _gnutls_cryptodev_init(); diff --git a/lib/nettle/rnd-fips.c b/lib/nettle/rnd-fips.c index e4b5629746..e7c20ea5c8 100644 --- a/lib/nettle/rnd-fips.c +++ b/lib/nettle/rnd-fips.c @@ -30,6 +30,7 @@ #include <nettle/aes.h> #include <nettle/memxor.h> #include <locks.h> +#include <atfork.h> #include <rnd-common.h> /* This provides a random generator for gnutls. It uses @@ -47,9 +48,7 @@ struct fips_ctx { struct drbg_aes_ctx nonce_context; struct drbg_aes_ctx normal_context; struct drbg_aes_ctx strong_context; -#ifdef HAVE_GETPID - pid_t pid; -#endif + unsigned int dfork; }; static int _rngfips_ctx_reinit(struct fips_ctx *fctx); @@ -61,10 +60,7 @@ static int get_random(struct drbg_aes_ctx *ctx, struct fips_ctx *fctx, int ret; if (ctx->reseed_counter > DRBG_AES_RESEED_TIME -#ifdef HAVE_GETPID - || fctx->pid != getpid() -#endif - ) { + || _gnutls_fork_detected(&fctx->dfork) != 0) { ret = _rngfips_ctx_reinit(fctx); if (ret < 0) @@ -134,9 +130,7 @@ static int _rngfips_ctx_init(struct fips_ctx *fctx) if (ret < 0) return gnutls_assert_val(ret); -#ifdef HAVE_GETPID - fctx->pid = getpid(); -#endif + _gnutls_fork_set_val(&fctx->dfork); return 0; } @@ -159,9 +153,6 @@ static int _rngfips_ctx_reinit(struct fips_ctx *fctx) if (ret < 0) return gnutls_assert_val(ret); -#ifdef HAVE_GETPID - fctx->pid = getpid(); -#endif return 0; } diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c index e8b0f40506..6d192fe4ad 100644 --- a/lib/nettle/rnd.c +++ b/lib/nettle/rnd.c @@ -33,10 +33,9 @@ #include <gnutls_num.h> #include <nettle/yarrow.h> #include <nettle/salsa20.h> -#ifdef HAVE_GETPID -#include <unistd.h> /* getpid */ -#endif #include <rnd-common.h> +#include <system.h> +#include <atfork.h> #include <errno.h> #define SOURCES 2 @@ -54,9 +53,7 @@ struct nonce_ctx_st { struct salsa20_ctx ctx; unsigned int counter; void *mutex; -#ifdef HAVE_GETPID - pid_t pid; /* detect fork() */ -#endif + unsigned int dfork; }; struct rnd_ctx_st { @@ -66,9 +63,7 @@ struct rnd_ctx_st { time_t trivia_previous_time; time_t trivia_time_count; void *mutex; -#ifdef HAVE_GETPID - pid_t pid; /* detect fork() */ -#endif + unsigned dfork; /* detect fork() */ }; static struct rnd_ctx_st rnd_ctx; @@ -121,10 +116,6 @@ static int do_device_source(struct rnd_ctx_st *ctx, int init, struct event_st *e int ret; if (init) { -#ifdef HAVE_GETPID - ctx->pid = event->pid; -#endif - memcpy(&ctx->device_last_read, &event->now, sizeof(ctx->device_last_read)); @@ -182,6 +173,8 @@ static int nonce_rng_init(struct nonce_ctx_st *ctx, unsigned init) * from the old key */ salsa20r12_crypt(&ctx->ctx, sizeof(buffer), buffer, buffer); } else { + _gnutls_fork_set_val(&ctx->dfork); + /* when initializing read the IV from the system randomness source */ ret = _rnd_get_system_entropy(iv, sizeof(iv)); if (ret < 0) @@ -194,9 +187,6 @@ static int nonce_rng_init(struct nonce_ctx_st *ctx, unsigned init) zeroize_key(buffer, sizeof(buffer)); ctx->counter = 0; -#ifdef HAVE_GETPID - ctx->pid = getpid(); -#endif return 0; } @@ -233,6 +223,8 @@ static int wrap_nettle_rnd_init(void **ctx) _rnd_get_event(&event); + _gnutls_fork_set_val(&rnd_ctx.dfork); + ret = do_device_source(&rnd_ctx, 1, &event); if (ret < 0) { gnutls_assert(); @@ -259,9 +251,6 @@ static int wrap_nettle_rnd_nonce(void *_ctx, void *data, size_t datasize) { int ret, reseed = 0; -#ifdef HAVE_GETPID - pid_t tpid = getpid(); -#endif /* we don't really need memset here, but otherwise we * get filled with valgrind warnings */ @@ -269,11 +258,9 @@ wrap_nettle_rnd_nonce(void *_ctx, void *data, size_t datasize) RND_LOCK(&nonce_ctx); -#ifdef HAVE_GETPID - if (tpid != nonce_ctx.pid) { /* fork() detected */ + if (_gnutls_fork_detected(&nonce_ctx.dfork)) { reseed = 1; } -#endif if (reseed != 0 || nonce_ctx.counter > NONCE_RESEED_BYTES) { /* reseed nonce */ @@ -309,13 +296,10 @@ wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize) RND_LOCK(&rnd_ctx); -#ifdef HAVE_GETPID - if (event.pid != rnd_ctx.pid) { /* fork() detected */ + if (_gnutls_fork_detected(&rnd_ctx.dfork)) { /* fork() detected */ memset(&rnd_ctx.device_last_read, 0, sizeof(rnd_ctx.device_last_read)); - rnd_ctx.pid = event.pid; reseed = 1; } -#endif /* reseed main */ ret = do_trivia_source(&rnd_ctx, 0, &event); diff --git a/lib/pkcs11.c b/lib/pkcs11.c index b49ef5bef0..386d17877f 100644 --- a/lib/pkcs11.c +++ b/lib/pkcs11.c @@ -36,9 +36,7 @@ #include <pkcs11_int.h> #include <p11-kit/p11-kit.h> #include <p11-kit/pin.h> -#ifdef HAVE_GETPID -# include <unistd.h> -#endif +#include <atfork.h> #define MAX_PROVIDERS 16 @@ -101,9 +99,7 @@ struct find_cert_st { static struct gnutls_pkcs11_provider_st providers[MAX_PROVIDERS]; static unsigned int active_providers = 0; static unsigned int providers_initialized = 0; -#ifdef HAVE_GETPID -static pid_t init_pid = -1; -#endif +static unsigned int dfork = 0; gnutls_pkcs11_token_callback_t _gnutls_token_func; void *_gnutls_token_data; @@ -256,30 +252,20 @@ int _gnutls_pkcs11_check_init(void) if (ret != 0) return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR); -#ifdef HAVE_GETPID - if (init_pid == 0) - init_pid = getpid(); -#endif - if (providers_initialized != 0) { ret = 0; -#ifdef HAVE_GETPID - if (init_pid != getpid()) { + + if (_gnutls_fork_detected(&dfork)) { /* if we are initialized but a fork is detected */ ret = gnutls_pkcs11_reinit(); if (ret == 0) ret = 1; } -#endif gnutls_mutex_unlock(&_gnutls_pkcs11_mutex); return ret; } -#ifdef HAVE_GETPID - init_pid = getpid(); -#endif - providers_initialized = 1; _gnutls_debug_log("Initializing PKCS #11 modules\n"); ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO, NULL); @@ -600,6 +586,8 @@ gnutls_pkcs11_init(unsigned int flags, const char *deprecated_config_file) } init++; + _gnutls_fork_set_val(&dfork); + p11_kit_pin_register_callback(P11_KIT_PIN_FALLBACK, p11_kit_pin_file_callback, NULL, NULL); @@ -639,7 +627,7 @@ int gnutls_pkcs11_reinit(void) ck_rv_t rv; /* make sure that we don't call more than once after a fork */ - if (init_pid == getpid()) + if (_gnutls_fork_detected(&dfork) == 0) return 0; for (i = 0; i < active_providers; i++) { @@ -657,9 +645,6 @@ int gnutls_pkcs11_reinit(void) } } } -#ifdef HAVE_GETPID - init_pid = getpid(); -#endif return 0; } |