Navigation Menu

Skip to content

Commit

Permalink
Bug 1346735 - drop netstat from unix_rand; add new urandom only entro…
Browse files Browse the repository at this point in the history
…py source, r=mt,ttaubert

Differential Revision: https://nss-review.dev.mozaws.net/D45

--HG--
extra : rebase_source : 043c91ac1b4d2ba04dbc6cb2a955552687e6d1dd
  • Loading branch information
franziskuskiefer committed Jan 18, 2017
1 parent f9fec7e commit e048621
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 172 deletions.
1 change: 1 addition & 0 deletions coreconf/config.gypi
Expand Up @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions lib/freebl/freebl_base.gypi
Expand Up @@ -177,6 +177,11 @@
'CT_VERIF',
],
}],
[ 'only_dev_random==1', {
'defines': [
'SEED_ONLY_DEV_URANDOM',
]
}],
[ 'OS=="mac"', {
'conditions': [
[ 'target_arch=="ia32"', {
Expand Down
4 changes: 3 additions & 1 deletion lib/freebl/sysrand.c
Expand Up @@ -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
Expand Down
171 changes: 0 additions & 171 deletions lib/freebl/unix_rand.c
Expand Up @@ -682,150 +682,16 @@ 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
#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;
Expand Down Expand Up @@ -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));
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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 */
Expand Down
50 changes: 50 additions & 0 deletions 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;
}

0 comments on commit e048621

Please sign in to comment.