summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2014-07-29 10:22:43 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2014-07-29 12:55:54 +0200
commitec83c49234a81531ad123e831df2c49a1ac6ebe5 (patch)
tree65749fabbf355d785552805be67828330b99745a /lib
parent7a76e94f7c4d1facc8e04dc6158f1dbfd6265a0e (diff)
downloadgnutls-ec83c49234a81531ad123e831df2c49a1ac6ebe5.tar.gz
Use pthread_atfork() and variants to detect fork
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/atfork.c105
-rw-r--r--lib/atfork.h76
-rw-r--r--lib/gnutls_global.c9
-rw-r--r--lib/nettle/rnd-fips.c17
-rw-r--r--lib/nettle/rnd.c36
-rw-r--r--lib/pkcs11.c29
7 files changed, 212 insertions, 62 deletions
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;
}