summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranziskus Kiefer <franziskuskiefer@gmail.com>2017-01-18 11:30:03 +0100
committerFranziskus Kiefer <franziskuskiefer@gmail.com>2017-01-18 11:30:03 +0100
commit913ed91b7ac9e61d319a834d43de9f8bf2519f55 (patch)
tree69a8c3f103358ba8531198448979609a1469d0bf
parenteac2d8d58c22fbc58ffc168ac84e7e60bb2d18e2 (diff)
downloadnss-hg-913ed91b7ac9e61d319a834d43de9f8bf2519f55.tar.gz
Bug 1346735 - drop netstat from unix_rand; add new urandom only entropy source, r=mt,ttaubert
Differential Revision: https://nss-review.dev.mozaws.net/D45
-rw-r--r--coreconf/config.gypi1
-rw-r--r--lib/freebl/freebl_base.gypi5
-rw-r--r--lib/freebl/sysrand.c4
-rw-r--r--lib/freebl/unix_rand.c171
-rw-r--r--lib/freebl/unix_urandom.c50
5 files changed, 59 insertions, 172 deletions
diff --git a/coreconf/config.gypi b/coreconf/config.gypi
index f338dd2a0..6b15be0d7 100644
--- a/coreconf/config.gypi
+++ b/coreconf/config.gypi
@@ -108,6 +108,7 @@
'ct_verif%': 0,
'nss_public_dist_dir%': '<(nss_dist_dir)/public',
'nss_private_dist_dir%': '<(nss_dist_dir)/private',
+ 'only_dev_random%': 1,
},
'target_defaults': {
# Settings specific to targets should go here.
diff --git a/lib/freebl/freebl_base.gypi b/lib/freebl/freebl_base.gypi
index 7570eec88..d154e11e1 100644
--- a/lib/freebl/freebl_base.gypi
+++ b/lib/freebl/freebl_base.gypi
@@ -177,6 +177,11 @@
'CT_VERIF',
],
}],
+ [ 'only_dev_random==1', {
+ 'defines': [
+ 'SEED_ONLY_DEV_URANDOM',
+ ]
+ }],
[ 'OS=="mac"', {
'conditions': [
[ 'target_arch=="ia32"', {
diff --git a/lib/freebl/sysrand.c b/lib/freebl/sysrand.c
index 1b6cbdfcd..763f6af11 100644
--- a/lib/freebl/sysrand.c
+++ b/lib/freebl/sysrand.c
@@ -8,7 +8,9 @@
#include "seccomon.h"
-#if defined(XP_UNIX) || defined(XP_BEOS)
+#if (defined(XP_UNIX) || defined(XP_BEOS)) && defined(SEED_ONLY_DEV_URANDOM)
+#include "unix_urandom.c"
+#elif defined(XP_UNIX) || defined(XP_BEOS)
#include "unix_rand.c"
#endif
#ifdef XP_WIN
diff --git a/lib/freebl/unix_rand.c b/lib/freebl/unix_rand.c
index 775e117ac..20c76ec66 100644
--- a/lib/freebl/unix_rand.c
+++ b/lib/freebl/unix_rand.c
@@ -682,134 +682,6 @@ RNG_GetNoise(void *buf, size_t maxbytes)
return n;
}
-#define SAFE_POPEN_MAXARGS 10 /* must be at least 2 */
-
-/*
- * safe_popen is static to this module and we know what arguments it is
- * called with. Note that this version only supports a single open child
- * process at any time.
- */
-static pid_t safe_popen_pid;
-static struct sigaction oldact;
-
-static FILE *
-safe_popen(char *cmd)
-{
- int p[2], fd, argc;
- pid_t pid;
- char *argv[SAFE_POPEN_MAXARGS + 1];
- FILE *fp;
- static char blank[] = " \t";
- static struct sigaction newact;
-
- if (pipe(p) < 0)
- return 0;
-
- fp = fdopen(p[0], "r");
- if (fp == 0) {
- close(p[0]);
- close(p[1]);
- return 0;
- }
-
- /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */
- newact.sa_handler = SIG_DFL;
- newact.sa_flags = 0;
- sigfillset(&newact.sa_mask);
- sigaction(SIGCHLD, &newact, &oldact);
-
- pid = fork();
- switch (pid) {
- int ndesc;
-
- case -1:
- fclose(fp); /* this closes p[0], the fd associated with fp */
- close(p[1]);
- sigaction(SIGCHLD, &oldact, NULL);
- return 0;
-
- case 0:
- /* dup write-side of pipe to stderr and stdout */
- if (p[1] != 1)
- dup2(p[1], 1);
- if (p[1] != 2)
- dup2(p[1], 2);
-
- /*
- * close the other file descriptors, except stdin which we
- * try reassociating with /dev/null, first (bug 174993)
- */
- if (!freopen("/dev/null", "r", stdin))
- close(0);
- ndesc = getdtablesize();
- for (fd = PR_MIN(65536, ndesc); --fd > 2; close(fd))
- ;
-
- /* clean up environment in the child process */
- putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc");
- putenv("SHELL=/bin/sh");
- putenv("IFS= \t");
-
- /*
- * The caller may have passed us a string that is in text
- * space. It may be illegal to modify the string
- */
- cmd = strdup(cmd);
- /* format argv */
- argv[0] = strtok(cmd, blank);
- argc = 1;
- while ((argv[argc] = strtok(0, blank)) != 0) {
- if (++argc == SAFE_POPEN_MAXARGS) {
- argv[argc] = 0;
- break;
- }
- }
-
- /* and away we go */
- execvp(argv[0], argv);
- exit(127);
- break;
-
- default:
- close(p[1]);
- break;
- }
-
- /* non-zero means there's a cmd running */
- safe_popen_pid = pid;
- return fp;
-}
-
-static int
-safe_pclose(FILE *fp)
-{
- pid_t pid;
- int status = -1, rv;
-
- if ((pid = safe_popen_pid) == 0)
- return -1;
- safe_popen_pid = 0;
-
- fclose(fp);
-
- /* yield the processor so the child gets some time to exit normally */
- PR_Sleep(PR_INTERVAL_NO_WAIT);
-
- /* if the child hasn't exited, kill it -- we're done with its output */
- while ((rv = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR)
- ;
- if (rv == 0) {
- kill(pid, SIGKILL);
- while ((rv = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
- ;
- }
-
- /* Reset SIGCHLD signal hander before returning */
- sigaction(SIGCHLD, &oldact, NULL);
-
- return status;
-}
-
#ifdef DARWIN
#include <TargetConditionals.h>
#if !TARGET_OS_IPHONE
@@ -817,15 +689,9 @@ safe_pclose(FILE *fp)
#endif
#endif
-/* Fork netstat to collect its output by default. Do not unset this unless
- * another source of entropy is available
- */
-#define DO_NETSTAT 1
-
void
RNG_SystemInfoForRNG(void)
{
- FILE *fp;
char buf[BUFSIZ];
size_t bytes;
const char *const *cp;
@@ -860,12 +726,6 @@ RNG_SystemInfoForRNG(void)
};
#endif
-#if defined(BSDI)
- static char netstat_ni_cmd[] = "netstat -nis";
-#else
- static char netstat_ni_cmd[] = "netstat -ni";
-#endif
-
GiveSystemInfo();
bytes = RNG_GetNoise(buf, sizeof(buf));
@@ -890,7 +750,6 @@ RNG_SystemInfoForRNG(void)
if (gethostname(buf, sizeof(buf)) == 0) {
RNG_RandomUpdate(buf, strlen(buf));
}
- GiveSystemInfo();
/* grab some data from system's PRNG before any other files. */
bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT);
@@ -914,33 +773,12 @@ RNG_SystemInfoForRNG(void)
for (cp = files; *cp; cp++)
RNG_FileForRNG(*cp);
-/*
- * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen
- * in a pthreads environment. Therefore, we call safe_popen last and on
- * BSD/OS we do not call safe_popen when we succeeded in getting data
- * from /dev/urandom.
- *
- * Bug 174993: On platforms providing /dev/urandom, don't fork netstat
- * either, if data has been gathered successfully.
- */
-
#if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(DARWIN) || defined(LINUX) || defined(HPUX)
if (bytes)
return;
#endif
#ifdef SOLARIS
-
-/*
- * On Solaris, NSS may be initialized automatically from libldap in
- * applications that are unaware of the use of NSS. safe_popen forks, and
- * sometimes creates issues with some applications' pthread_atfork handlers.
- * We always have /dev/urandom on Solaris 9 and above as an entropy source,
- * and for Solaris 8 we have the libkstat interface, so we don't need to
- * fork netstat.
- */
-
-#undef DO_NETSTAT
if (!bytes) {
/* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */
PRUint32 kstat_bytes = 0;
@@ -951,15 +789,6 @@ RNG_SystemInfoForRNG(void)
PORT_Assert(bytes);
}
#endif
-
-#ifdef DO_NETSTAT
- fp = safe_popen(netstat_ni_cmd);
- if (fp != NULL) {
- while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0)
- RNG_RandomUpdate(buf, bytes);
- safe_pclose(fp);
- }
-#endif
}
#define TOTAL_FILE_LIMIT 1000000 /* one million */
diff --git a/lib/freebl/unix_urandom.c b/lib/freebl/unix_urandom.c
new file mode 100644
index 000000000..25e6ad91c
--- /dev/null
+++ b/lib/freebl/unix_urandom.c
@@ -0,0 +1,50 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include "secerr.h"
+#include "secrng.h"
+#include "prprf.h"
+
+void
+RNG_SystemInfoForRNG(void)
+{
+ PRUint8 bytes[SYSTEM_RNG_SEED_COUNT];
+ size_t numBytes = RNG_SystemRNG(bytes, SYSTEM_RNG_SEED_COUNT);
+ if (!numBytes) {
+ /* error is set */
+ return;
+ }
+ RNG_RandomUpdate(bytes, numBytes);
+}
+
+size_t
+RNG_SystemRNG(void *dest, size_t maxLen)
+{
+ int fd;
+ int bytes;
+ size_t fileBytes = 0;
+ unsigned char *buffer = dest;
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0) {
+ PORT_SetError(SEC_ERROR_NEED_RANDOM);
+ return 0;
+ }
+ while (fileBytes < maxLen) {
+ bytes = read(fd, buffer, maxLen - fileBytes);
+ if (bytes <= 0) {
+ break;
+ }
+ fileBytes += bytes;
+ buffer += bytes;
+ }
+ (void)close(fd);
+ if (fileBytes != maxLen) {
+ PORT_SetError(SEC_ERROR_NEED_RANDOM);
+ return 0;
+ }
+ return fileBytes;
+}