summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwtchang%redhat.com <devnull@localhost>2006-09-23 19:36:15 +0000
committerwtchang%redhat.com <devnull@localhost>2006-09-23 19:36:15 +0000
commitff66387b94d0ff1258f6c81ac7f806f6bf650203 (patch)
tree1f244f14e65dacd308847d22dec73fd9934bc50a
parent83e71942a779c69718efe25da88f99bc1e7146f8 (diff)
downloadnss-hg-ff66387b94d0ff1258f6c81ac7f806f6bf650203.tar.gz
Bug 352754: Backported the fix for bug 182758 to the MOZILLA_1_8_BRANCH.
a=mtschrep for Mozilla 1.8 RC2. Modified files: config.mk unix_rand.c
-rw-r--r--security/nss/lib/freebl/config.mk4
-rw-r--r--security/nss/lib/freebl/unix_rand.c133
2 files changed, 137 insertions, 0 deletions
diff --git a/security/nss/lib/freebl/config.mk b/security/nss/lib/freebl/config.mk
index ecbc9373f..cef7dad9c 100644
--- a/security/nss/lib/freebl/config.mk
+++ b/security/nss/lib/freebl/config.mk
@@ -75,6 +75,10 @@ PROGRAM =
EXTRA_LIBS += $(DIST)/lib/$(LIB_PREFIX)secutil.$(LIB_SUFFIX)
+ifeq ($(OS_TARGET), SunOS)
+OS_LIBS += -lkstat
+endif
+
ifeq (,$(filter-out WIN%,$(OS_TARGET)))
# don't want the 32 in the shared library name
diff --git a/security/nss/lib/freebl/unix_rand.c b/security/nss/lib/freebl/unix_rand.c
index 6a4c283bb..a3afe5da9 100644
--- a/security/nss/lib/freebl/unix_rand.c
+++ b/security/nss/lib/freebl/unix_rand.c
@@ -80,6 +80,108 @@ static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen)
return dstlen;
}
+#ifdef SOLARIS
+
+#include <kstat.h>
+
+static const PRUint32 entropy_buf_len = 4096; /* buffer up to 4 KB */
+
+/* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time.
+ * Returns error if RNG_RandomUpdate fails. Also increments *total_fed
+ * by the number of bytes successfully buffered.
+ */
+static SECStatus BufferEntropy(char* inbuf, PRUint32 inlen,
+ char* entropy_buf, PRUint32* entropy_buffered,
+ PRUint32* total_fed)
+{
+ PRUint32 tocopy = 0;
+ PRUint32 avail = 0;
+ SECStatus rv = SECSuccess;
+
+ while (inlen) {
+ avail = entropy_buf_len - *entropy_buffered;
+ if (!avail) {
+ /* Buffer is full, time to feed it to the RNG. */
+ rv = RNG_RandomUpdate(entropy_buf, entropy_buf_len);
+ if (SECSuccess != rv) {
+ break;
+ }
+ *entropy_buffered = 0;
+ avail = entropy_buf_len;
+ }
+ tocopy = PR_MIN(avail, inlen);
+ memcpy(entropy_buf + *entropy_buffered, inbuf, tocopy);
+ *entropy_buffered += tocopy;
+ inlen -= tocopy;
+ inbuf += tocopy;
+ *total_fed += tocopy;
+ }
+ return rv;
+}
+
+/* Feed kernel statistics structures and ks_data field to the RNG.
+ * Returns status as well as the number of bytes successfully fed to the RNG.
+ */
+static SECStatus RNG_kstat(PRUint32* fed)
+{
+ kstat_ctl_t* kc = NULL;
+ kstat_t* ksp = NULL;
+ PRUint32 entropy_buffered = 0;
+ char* entropy_buf = NULL;
+ SECStatus rv = SECSuccess;
+
+ PORT_Assert(fed);
+ if (!fed) {
+ return SECFailure;
+ }
+ *fed = 0;
+
+ kc = kstat_open();
+ PORT_Assert(kc);
+ if (!kc) {
+ return SECFailure;
+ }
+ entropy_buf = (char*) PORT_Alloc(entropy_buf_len);
+ PORT_Assert(entropy_buf);
+ if (entropy_buf) {
+ for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
+ if (-1 == kstat_read(kc, ksp, NULL)) {
+ /* missing data from a single kstat shouldn't be fatal */
+ continue;
+ }
+ rv = BufferEntropy((char*)ksp, sizeof(kstat_t),
+ entropy_buf, &entropy_buffered,
+ fed);
+ if (SECSuccess != rv) {
+ break;
+ }
+
+ if (ksp->ks_data && ksp->ks_data_size>0 && ksp->ks_ndata>0) {
+ rv = BufferEntropy((char*)ksp->ks_data, ksp->ks_data_size,
+ entropy_buf, &entropy_buffered,
+ fed);
+ if (SECSuccess != rv) {
+ break;
+ }
+ }
+ }
+ if (SECSuccess == rv && entropy_buffered) {
+ /* Buffer is not empty, time to feed it to the RNG */
+ rv = RNG_RandomUpdate(entropy_buf, entropy_buffered);
+ }
+ PORT_Free(entropy_buf);
+ } else {
+ rv = SECFailure;
+ }
+ if (kstat_close(kc)) {
+ PORT_Assert(0);
+ rv = SECFailure;
+ }
+ return rv;
+}
+
+#endif
+
#if defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(FREEBSD) \
|| defined(NETBSD) || defined(NTO) || defined(DARWIN) || defined(OPENBSD)
#include <sys/times.h>
@@ -774,6 +876,11 @@ safe_pclose(FILE *fp)
#include <crt_externs.h>
#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;
@@ -872,6 +979,29 @@ for the small amount of entropy it provides.
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_PS
fp = safe_popen(ps_cmd);
if (fp != NULL) {
@@ -880,12 +1010,15 @@ for the small amount of entropy it provides.
safe_pclose(fp);
}
#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
}
#else