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
--- a/coreconf/config.gypi
+++ b/coreconf/config.gypi
@@ -103,16 +103,17 @@
'fuzz%': 0,
'fuzz_tls%': 0,
'fuzz_oss%': 0,
'sign_libs%': 1,
'use_pprof%': 0,
'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.
# This is mostly for linking to libraries.
'variables': {
'mapfile%': '',
'test_build%': 0,
'debug_optimization_level%': '0',
--- a/lib/freebl/freebl_base.gypi
+++ b/lib/freebl/freebl_base.gypi
@@ -172,16 +172,21 @@
'UNSAFE_FUZZER_MODE',
],
}],
[ 'ct_verif==1', {
'defines': [
'CT_VERIF',
],
}],
+ [ 'only_dev_random==1', {
+ 'defines': [
+ 'SEED_ONLY_DEV_URANDOM',
+ ]
+ }],
[ 'OS=="mac"', {
'conditions': [
[ 'target_arch=="ia32"', {
'sources': [
'mpi/mpi_sse2.s',
],
'defines': [
'MP_USE_UINT_DIGIT',
--- a/lib/freebl/sysrand.c
+++ b/lib/freebl/sysrand.c
@@ -3,14 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#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
#include "win_rand.c"
#endif
--- a/lib/freebl/unix_rand.c
+++ b/lib/freebl/unix_rand.c
@@ -677,160 +677,26 @@ RNG_GetNoise(void *buf, size_t maxbytes)
c = CopyLowBits((char *)buf + n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec));
n += c;
maxbytes -= c;
c = CopyLowBits((char *)buf + n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec));
n += c;
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
#include <crt_externs.h>
#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;
char *randfile;
#ifdef DARWIN
#if TARGET_OS_IPHONE
/* iOS does not expose a way to access environ. */
char **environ = NULL;
@@ -855,22 +721,16 @@ RNG_SystemInfoForRNG(void)
"/etc/utmp",
"/tmp",
"/var/tmp",
"/usr/tmp",
0
};
#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));
RNG_RandomUpdate(buf, bytes);
/*
* Pass the C environment and the addresses of the pointers to the
* hash function. This makes the random number function depend on the
@@ -885,17 +745,16 @@ RNG_SystemInfoForRNG(void)
}
RNG_RandomUpdate(environ, (char *)cp - (char *)environ);
}
/* Give in system information */
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);
if (!bytes) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
}
/* If the user points us to a random file, pass it through the rng */
@@ -909,62 +768,32 @@ RNG_SystemInfoForRNG(void)
RNG_FileForRNG(randfile);
}
}
/* pass other files through */
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;
if (SECSuccess != RNG_kstat(&kstat_bytes)) {
PORT_Assert(0);
}
bytes += kstat_bytes;
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 */
size_t
RNG_FileUpdate(const char *fileName, size_t limit)
{
FILE *file;
new file mode 100644
--- /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;
+}