summaryrefslogtreecommitdiff
path: root/random
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2013-12-11 16:59:41 +0100
committerWerner Koch <wk@gnupg.org>2013-12-11 17:01:15 +0100
commitcd548ba2dc777b8b27d8d33182ba733c20222120 (patch)
tree58b2151b8e12bf23958e946554de4fd0ee86ee97 /random
parenteae1e7712e1b687bd77eb37d0eb505fc9d46d93c (diff)
downloadlibgcrypt-cd548ba2dc777b8b27d8d33182ba733c20222120.tar.gz
random: Add a feature to close device file descriptors.
* src/gcrypt.h.in (GCRYCTL_CLOSE_RANDOM_DEVICE): New. * src/global.c (_gcry_vcontrol): Call _gcry_random_close_fds. * random/random.c (_gcry_random_close_fds): New. * random/random-csprng.c (_gcry_rngcsprng_close_fds): New. * random/random-fips.c (_gcry_rngfips_close_fds): New. * random/random-system.c (_gcry_rngsystem_close_fds): New. * random/rndlinux.c (open_device): Add arg retry. (_gcry_rndlinux_gather_random): Add mode to close open fds. * tests/random.c (check_close_random_device): New. (main): Call new test. Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'random')
-rw-r--r--random/rand-internal.h3
-rw-r--r--random/random-csprng.c16
-rw-r--r--random/random-fips.c13
-rw-r--r--random/random-system.c13
-rw-r--r--random/random.c21
-rw-r--r--random/random.h1
-rw-r--r--random/rndlinux.c71
7 files changed, 126 insertions, 12 deletions
diff --git a/random/rand-internal.h b/random/rand-internal.h
index f59a1027..79b23ace 100644
--- a/random/rand-internal.h
+++ b/random/rand-internal.h
@@ -44,6 +44,7 @@ void _gcry_random_progress (const char *what, int printchar,
/*-- random-csprng.c --*/
void _gcry_rngcsprng_initialize (int full);
+void _gcry_rngcsprng_close_fds (void);
void _gcry_rngcsprng_dump_stats (void);
void _gcry_rngcsprng_secure_alloc (void);
void _gcry_rngcsprng_enable_quick_gen (void);
@@ -64,6 +65,7 @@ void _gcry_rngcsprng_fast_poll (void);
/*-- random-fips.c --*/
void _gcry_rngfips_initialize (int full);
+void _gcry_rngfips_close_fds (void);
void _gcry_rngfips_dump_stats (void);
int _gcry_rngfips_is_faked (void);
gcry_error_t _gcry_rngfips_add_bytes (const void *buf, size_t buflen,
@@ -89,6 +91,7 @@ void _gcry_rngfips_deinit_external_test (void *context);
/*-- random-system.c --*/
void _gcry_rngsystem_initialize (int full);
+void _gcry_rngsystem_close_fds (void);
void _gcry_rngsystem_dump_stats (void);
int _gcry_rngsystem_is_faked (void);
gcry_error_t _gcry_rngsystem_add_bytes (const void *buf, size_t buflen,
diff --git a/random/random-csprng.c b/random/random-csprng.c
index 9921c4fd..b6d7f667 100644
--- a/random/random-csprng.c
+++ b/random/random-csprng.c
@@ -154,7 +154,7 @@ static int allow_seed_file_update;
static int secure_alloc;
/* This function pointer is set to the actual entropy gathering
- function during initailization. After initialization it is
+ function during initialization. After initialization it is
guaranteed to point to function. (On systems without a random
gatherer module a dummy function is used).*/
static int (*slow_gather_fnc)(void (*)(const void*, size_t,
@@ -361,6 +361,20 @@ _gcry_rngcsprng_initialize (int full)
}
+/* Try to close the FDs of the random gather module. This is
+ currently only implemented for rndlinux. */
+void
+_gcry_rngcsprng_close_fds (void)
+{
+ lock_pool ();
+#if USE_RNDLINUX
+ _gcry_rndlinux_gather_random (NULL, 0, 0, 0);
+ pool_filled = 0; /* Force re-open on next use. */
+#endif
+ unlock_pool ();
+}
+
+
void
_gcry_rngcsprng_dump_stats (void)
{
diff --git a/random/random-fips.c b/random/random-fips.c
index c8100a21..6ee52f10 100644
--- a/random/random-fips.c
+++ b/random/random-fips.c
@@ -780,6 +780,19 @@ _gcry_rngfips_initialize (int full)
}
+/* Try to close the FDs of the random gather module. This is
+ currently only implemented for rndlinux. */
+void
+_gcry_rngfips_close_fds (void)
+{
+ lock_rng ();
+#if USE_RNDLINUX
+ _gcry_rndlinux_gather_random (NULL, 0, 0, 0);
+#endif
+ unlock_rng ();
+}
+
+
/* Print some statistics about the RNG. */
void
_gcry_rngfips_dump_stats (void)
diff --git a/random/random-system.c b/random/random-system.c
index 0ef9d247..3962ab88 100644
--- a/random/random-system.c
+++ b/random/random-system.c
@@ -193,6 +193,19 @@ _gcry_rngsystem_initialize (int full)
}
+/* Try to close the FDs of the random gather module. This is
+ currently only implemented for rndlinux. */
+void
+_gcry_rngsystem_close_fds (void)
+{
+ lock_rng ();
+#if USE_RNDLINUX
+ _gcry_rndlinux_gather_random (NULL, 0, 0, 0);
+#endif
+ unlock_rng ();
+}
+
+
/* Print some statistics about the RNG. */
void
_gcry_rngsystem_dump_stats (void)
diff --git a/random/random.c b/random/random.c
index 46793013..97018c42 100644
--- a/random/random.c
+++ b/random/random.c
@@ -165,6 +165,27 @@ _gcry_random_initialize (int full)
}
+/* If possible close file descriptors used by the RNG. */
+void
+_gcry_random_close_fds (void)
+{
+ /* Note that we can't do that directly because each random system
+ has its own lock functions which need to be used for accessing
+ the entropy gatherer. */
+
+ if (fips_mode ())
+ _gcry_rngfips_close_fds ();
+ else if (rng_types.standard)
+ _gcry_rngcsprng_close_fds ();
+ else if (rng_types.fips)
+ _gcry_rngfips_close_fds ();
+ else if (rng_types.system)
+ _gcry_rngsystem_close_fds ();
+ else
+ _gcry_rngcsprng_close_fds ();
+}
+
+
/* Return the current RNG type. IGNORE_FIPS_MODE is a flag used to
skip the test for FIPS. This is useful, so that we are able to
return the type of the RNG even before we have setup FIPS mode
diff --git a/random/random.h b/random/random.h
index aae07ab0..2bc8cabc 100644
--- a/random/random.h
+++ b/random/random.h
@@ -28,6 +28,7 @@ void _gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int),
void _gcry_set_preferred_rng_type (int type);
void _gcry_random_initialize (int full);
+void _gcry_random_close_fds (void);
int _gcry_get_rng_type (int ignore_fips_mode);
void _gcry_random_dump_stats(void);
void _gcry_secure_random_alloc(void);
diff --git a/random/rndlinux.c b/random/rndlinux.c
index b304cc9e..21ea8c4b 100644
--- a/random/rndlinux.c
+++ b/random/rndlinux.c
@@ -36,7 +36,7 @@
#include "g10lib.h"
#include "rand-internal.h"
-static int open_device ( const char *name );
+static int open_device (const char *name, int retry);
static int
@@ -54,15 +54,30 @@ set_cloexec_flag (int fd)
/*
- * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists)).
+ * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it
+ * exists)). If RETRY is true, the function does not terminate with
+ * a fatal error but retries until it is able to reopen the device.
*/
static int
-open_device ( const char *name )
+open_device (const char *name, int retry)
{
int fd;
- fd = open ( name, O_RDONLY );
- if ( fd == -1 )
+ if (retry)
+ _gcry_random_progress ("open_dev_random", 'X', 1, 0);
+ again:
+ fd = open (name, O_RDONLY);
+ if (fd == -1 && retry)
+ {
+ struct timeval tv;
+
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ _gcry_random_progress ("wait_dev_random", 'X', 0, (int)tv.tv_sec);
+ select (0, NULL, NULL, NULL, &tv);
+ goto again;
+ }
+ if (fd == -1)
log_fatal ("can't open %s: %s\n", name, strerror(errno) );
if (set_cloexec_flag (fd))
@@ -84,6 +99,10 @@ open_device ( const char *name )
}
+/* Note that the caller needs to make sure that this function is only
+ called by one thread at a time. The function returns 0 on success
+ or true on failure (in which case the caller will signal a fatal
+ error). */
int
_gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
enum random_origins),
@@ -92,6 +111,7 @@ _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
{
static int fd_urandom = -1;
static int fd_random = -1;
+ static unsigned char ever_opened;
int fd;
int n;
byte buffer[768];
@@ -101,6 +121,23 @@ _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
int any_need_entropy = 0;
int delay;
+ if (!add)
+ {
+ /* Special mode to close the descriptors. */
+ if (fd_random != -1)
+ {
+ close (fd_random);
+ fd_random = -1;
+ }
+ if (fd_urandom != -1)
+ {
+ close (fd_urandom);
+ fd_urandom = -1;
+ }
+ return 0;
+ }
+
+
/* First read from a hardware source. However let it account only
for up to 50% of the requested bytes. */
n_hw = _gcry_rndhw_poll_slow (add, origin);
@@ -109,17 +146,29 @@ _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
if (length > 1)
length -= n_hw;
- /* Open the requested device. */
+ /* Open the requested device. The first time a device is to be
+ opened we fail with a fatal error if the device does not exists.
+ In case the device has ever been closed, further open requests
+ will however retry indefinitely. The rationale for this behaviour is
+ that we always require the device to be existent but want a more
+ graceful behaviour if the rarely needed close operation has been
+ used and the device needs to be re-opened later. */
if (level >= 2)
{
- if( fd_random == -1 )
- fd_random = open_device ( NAME_OF_DEV_RANDOM );
+ if (fd_random == -1)
+ {
+ fd_random = open_device (NAME_OF_DEV_RANDOM, (ever_opened & 1));
+ ever_opened |= 1;
+ }
fd = fd_random;
}
else
{
- if( fd_urandom == -1 )
- fd_urandom = open_device ( NAME_OF_DEV_URANDOM );
+ if (fd_urandom == -1)
+ {
+ fd_urandom = open_device (NAME_OF_DEV_URANDOM, (ever_opened & 2));
+ ever_opened |= 2;
+ }
fd = fd_urandom;
}
@@ -164,7 +213,7 @@ _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
log_error ("select() error: %s\n", strerror(errno));
if (!delay)
delay = 1; /* Use 1 second if we encounter an error before
- we have ever blocked. */
+ we have ever blocked. */
continue;
}
}