diff options
| author | Paul Eggert | 2016-01-17 12:12:08 -0800 |
|---|---|---|
| committer | Paul Eggert | 2016-01-17 12:13:49 -0800 |
| commit | 05e8148a24ebe51fbe758dd16265e8fb81f85953 (patch) | |
| tree | 447c9fa28f9b8b3e8380f4f1c039b6cf76ce5750 /src | |
| parent | a0d5b7ae3bb014bb0b1c205d123c597df0e76411 (diff) | |
| download | emacs-05e8148a24ebe51fbe758dd16265e8fb81f85953.tar.gz emacs-05e8148a24ebe51fbe758dd16265e8fb81f85953.zip | |
Prefer GnuTLS when acquiring random seed
This attempts to improve on the fix for Bug#22202.
* configure.ac (HAVE_DEV_URANDOM): Remove.
Check /dev/urandom existence at run time, not at build time,
since the device could exist in the former but not the latter.
* src/sysdep.c [HAVE_GNUTLS]: Include gnutls/gnutls.h.
(gnutls_rnd) [GNUTLS_VERSION_NUMBER < 0x020c00]: New fallback macro.
(random_seed): New typedef.
(set_random_seed): New static function.
(seed_random): Use them.
(init_random): Use random_seed instead of uintmax_t, so as to
not consume more entropy than needed. Prefer gnutls_rnd if it
works; this avoids a redundant open of /dev/urandom on
GNU/Linux with modern GnuTLS.
Diffstat (limited to 'src')
| -rw-r--r-- | src/sysdep.c | 85 |
1 files changed, 43 insertions, 42 deletions
diff --git a/src/sysdep.c b/src/sysdep.c index 1fa422947ed..635443cfe66 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -99,6 +99,15 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 99 | #include "process.h" | 99 | #include "process.h" |
| 100 | #include "cm.h" | 100 | #include "cm.h" |
| 101 | 101 | ||
| 102 | #ifdef HAVE_GNUTLS | ||
| 103 | # include <gnutls/gnutls.h> | ||
| 104 | #endif | ||
| 105 | #if 0x020c00 <= GNUTLS_VERSION_NUMBER | ||
| 106 | # include <gnutls/crypto.h> | ||
| 107 | #else | ||
| 108 | # define gnutls_rnd(level, data, len) (-1) | ||
| 109 | #endif | ||
| 110 | |||
| 102 | #ifdef WINDOWSNT | 111 | #ifdef WINDOWSNT |
| 103 | #include <direct.h> | 112 | #include <direct.h> |
| 104 | /* In process.h which conflicts with the local copy. */ | 113 | /* In process.h which conflicts with the local copy. */ |
| @@ -2068,63 +2077,55 @@ init_signals (bool dumping) | |||
| 2068 | # endif /* !HAVE_RANDOM */ | 2077 | # endif /* !HAVE_RANDOM */ |
| 2069 | #endif /* !RAND_BITS */ | 2078 | #endif /* !RAND_BITS */ |
| 2070 | 2079 | ||
| 2080 | #ifdef HAVE_RANDOM | ||
| 2081 | typedef unsigned int random_seed; | ||
| 2082 | static void set_random_seed (random_seed arg) { srandom (arg); } | ||
| 2083 | #elif defined HAVE_LRAND48 | ||
| 2084 | /* Although srand48 uses a long seed, this is unsigned long to avoid | ||
| 2085 | undefined behavior on signed integer overflow in init_random. */ | ||
| 2086 | typedef unsigned long int random_seed; | ||
| 2087 | static void set_random_seed (random_seed arg) { srand48 (arg); } | ||
| 2088 | #else | ||
| 2089 | typedef unsigned int random_seed; | ||
| 2090 | static void set_random_seed (random_seed arg) { srand (arg); } | ||
| 2091 | #endif | ||
| 2092 | |||
| 2071 | void | 2093 | void |
| 2072 | seed_random (void *seed, ptrdiff_t seed_size) | 2094 | seed_random (void *seed, ptrdiff_t seed_size) |
| 2073 | { | 2095 | { |
| 2074 | #if defined HAVE_RANDOM || ! defined HAVE_LRAND48 | 2096 | random_seed arg = 0; |
| 2075 | unsigned int arg = 0; | ||
| 2076 | #else | ||
| 2077 | long int arg = 0; | ||
| 2078 | #endif | ||
| 2079 | unsigned char *argp = (unsigned char *) &arg; | 2097 | unsigned char *argp = (unsigned char *) &arg; |
| 2080 | unsigned char *seedp = seed; | 2098 | unsigned char *seedp = seed; |
| 2081 | ptrdiff_t i; | 2099 | for (ptrdiff_t i = 0; i < seed_size; i++) |
| 2082 | for (i = 0; i < seed_size; i++) | ||
| 2083 | argp[i % sizeof arg] ^= seedp[i]; | 2100 | argp[i % sizeof arg] ^= seedp[i]; |
| 2084 | #ifdef HAVE_RANDOM | 2101 | set_random_seed (arg); |
| 2085 | srandom (arg); | ||
| 2086 | #else | ||
| 2087 | # ifdef HAVE_LRAND48 | ||
| 2088 | srand48 (arg); | ||
| 2089 | # else | ||
| 2090 | srand (arg); | ||
| 2091 | # endif | ||
| 2092 | #endif | ||
| 2093 | } | 2102 | } |
| 2094 | 2103 | ||
| 2095 | void | 2104 | void |
| 2096 | init_random (void) | 2105 | init_random (void) |
| 2097 | { | 2106 | { |
| 2098 | uintmax_t v; | 2107 | random_seed v; |
| 2099 | struct timespec t; | 2108 | if (gnutls_rnd (GNUTLS_RND_NONCE, &v, sizeof v) != 0) |
| 2100 | bool success = false; | ||
| 2101 | |||
| 2102 | #if HAVE_DEV_URANDOM | ||
| 2103 | FILE *fp = fopen ("/dev/urandom", "rb"); | ||
| 2104 | |||
| 2105 | if (fp) | ||
| 2106 | { | 2109 | { |
| 2107 | int i; | 2110 | bool success = false; |
| 2108 | 2111 | #ifndef WINDOWSNT | |
| 2109 | for (i = 0, v = 0; i < sizeof (uintmax_t); i++) | 2112 | int fd = emacs_open ("/dev/urandom", O_RDONLY | O_BINARY, 0); |
| 2113 | if (0 <= fd) | ||
| 2110 | { | 2114 | { |
| 2111 | v <<= 8; | 2115 | success = emacs_read (fd, &v, sizeof v) == sizeof v; |
| 2112 | v |= fgetc (fp); | 2116 | emacs_close (fd); |
| 2117 | } | ||
| 2118 | #else | ||
| 2119 | success = w32_init_random (&v, sizeof v) == 0; | ||
| 2120 | #endif | ||
| 2121 | if (! success) | ||
| 2122 | { | ||
| 2123 | /* Fall back to current time value + PID. */ | ||
| 2124 | struct timespec t = current_timespec (); | ||
| 2125 | v = getpid () ^ t.tv_sec ^ t.tv_nsec; | ||
| 2113 | } | 2126 | } |
| 2114 | fclose (fp); | ||
| 2115 | success = true; | ||
| 2116 | } | ||
| 2117 | #elif defined WINDOWSNT | ||
| 2118 | if (w32_init_random (&v, sizeof v) == 0) | ||
| 2119 | success = true; | ||
| 2120 | #endif /* HAVE_DEV_URANDOM || WINDOWSNT */ | ||
| 2121 | if (!success) | ||
| 2122 | { | ||
| 2123 | /* Fall back to current time value + PID. */ | ||
| 2124 | t = current_timespec (); | ||
| 2125 | v = getpid () ^ t.tv_sec ^ t.tv_nsec; | ||
| 2126 | } | 2127 | } |
| 2127 | seed_random (&v, sizeof v); | 2128 | set_random_seed (v); |
| 2128 | } | 2129 | } |
| 2129 | 2130 | ||
| 2130 | /* | 2131 | /* |