Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Side by Side Diff: nss/lib/freebl/unix_rand.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « nss/lib/freebl/tlsprfalg.c ('k') | nss/lib/freebl/win_rand.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include <stdio.h>
6 #include <string.h>
7 #include <signal.h>
8 #include <unistd.h>
9 #include <limits.h>
10 #include <errno.h>
11 #include <stdlib.h>
12 #include <sys/time.h>
13 #include <sys/wait.h>
14 #include <sys/stat.h>
15 #include "secrng.h"
16 #include "secerr.h"
17 #include "prerror.h"
18 #include "prthread.h"
19 #include "prprf.h"
20 #include "prenv.h"
21
22 size_t RNG_FileUpdate(const char *fileName, size_t limit);
23
24 /*
25 * When copying data to the buffer we want the least signicant bytes
26 * from the input since those bits are changing the fastest. The address
27 * of least significant byte depends upon whether we are running on
28 * a big-endian or little-endian machine.
29 *
30 * Does this mean the least signicant bytes are the most significant
31 * to us? :-)
32 */
33
34 static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen)
35 {
36 union endianness {
37 PRInt32 i;
38 char c[4];
39 } u;
40
41 if (srclen <= dstlen) {
42 memcpy(dst, src, srclen);
43 return srclen;
44 }
45 u.i = 0x01020304;
46 if (u.c[0] == 0x01) {
47 /* big-endian case */
48 memcpy(dst, (char*)src + (srclen - dstlen), dstlen);
49 } else {
50 /* little-endian case */
51 memcpy(dst, src, dstlen);
52 }
53 return dstlen;
54 }
55
56 #ifdef SOLARIS
57
58 #include <kstat.h>
59
60 static const PRUint32 entropy_buf_len = 4096; /* buffer up to 4 KB */
61
62 /* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time.
63 * Returns error if RNG_RandomUpdate fails. Also increments *total_fed
64 * by the number of bytes successfully buffered.
65 */
66 static SECStatus BufferEntropy(char* inbuf, PRUint32 inlen,
67 char* entropy_buf, PRUint32* entropy_buffered,
68 PRUint32* total_fed)
69 {
70 PRUint32 tocopy = 0;
71 PRUint32 avail = 0;
72 SECStatus rv = SECSuccess;
73
74 while (inlen) {
75 avail = entropy_buf_len - *entropy_buffered;
76 if (!avail) {
77 /* Buffer is full, time to feed it to the RNG. */
78 rv = RNG_RandomUpdate(entropy_buf, entropy_buf_len);
79 if (SECSuccess != rv) {
80 break;
81 }
82 *entropy_buffered = 0;
83 avail = entropy_buf_len;
84 }
85 tocopy = PR_MIN(avail, inlen);
86 memcpy(entropy_buf + *entropy_buffered, inbuf, tocopy);
87 *entropy_buffered += tocopy;
88 inlen -= tocopy;
89 inbuf += tocopy;
90 *total_fed += tocopy;
91 }
92 return rv;
93 }
94
95 /* Feed kernel statistics structures and ks_data field to the RNG.
96 * Returns status as well as the number of bytes successfully fed to the RNG.
97 */
98 static SECStatus RNG_kstat(PRUint32* fed)
99 {
100 kstat_ctl_t* kc = NULL;
101 kstat_t* ksp = NULL;
102 PRUint32 entropy_buffered = 0;
103 char* entropy_buf = NULL;
104 SECStatus rv = SECSuccess;
105
106 PORT_Assert(fed);
107 if (!fed) {
108 return SECFailure;
109 }
110 *fed = 0;
111
112 kc = kstat_open();
113 PORT_Assert(kc);
114 if (!kc) {
115 return SECFailure;
116 }
117 entropy_buf = (char*) PORT_Alloc(entropy_buf_len);
118 PORT_Assert(entropy_buf);
119 if (entropy_buf) {
120 for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
121 if (-1 == kstat_read(kc, ksp, NULL)) {
122 /* missing data from a single kstat shouldn't be fatal */
123 continue;
124 }
125 rv = BufferEntropy((char*)ksp, sizeof(kstat_t),
126 entropy_buf, &entropy_buffered,
127 fed);
128 if (SECSuccess != rv) {
129 break;
130 }
131
132 if (ksp->ks_data && ksp->ks_data_size>0 && ksp->ks_ndata>0) {
133 rv = BufferEntropy((char*)ksp->ks_data, ksp->ks_data_size,
134 entropy_buf, &entropy_buffered,
135 fed);
136 if (SECSuccess != rv) {
137 break;
138 }
139 }
140 }
141 if (SECSuccess == rv && entropy_buffered) {
142 /* Buffer is not empty, time to feed it to the RNG */
143 rv = RNG_RandomUpdate(entropy_buf, entropy_buffered);
144 }
145 PORT_Free(entropy_buf);
146 } else {
147 rv = SECFailure;
148 }
149 if (kstat_close(kc)) {
150 PORT_Assert(0);
151 rv = SECFailure;
152 }
153 return rv;
154 }
155
156 #endif
157
158 #if defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(FREEBSD) \
159 || defined(NETBSD) || defined(DARWIN) || defined(OPENBSD) \
160 || defined(NTO) || defined(__riscos__)
161 #include <sys/times.h>
162
163 #define getdtablesize() sysconf(_SC_OPEN_MAX)
164
165 static size_t
166 GetHighResClock(void *buf, size_t maxbytes)
167 {
168 int ticks;
169 struct tms buffer;
170
171 ticks=times(&buffer);
172 return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
173 }
174
175 static void
176 GiveSystemInfo(void)
177 {
178 long si;
179
180 /*
181 * Is this really necessary? Why not use rand48 or something?
182 */
183 si = sysconf(_SC_CHILD_MAX);
184 RNG_RandomUpdate(&si, sizeof(si));
185
186 si = sysconf(_SC_STREAM_MAX);
187 RNG_RandomUpdate(&si, sizeof(si));
188
189 si = sysconf(_SC_OPEN_MAX);
190 RNG_RandomUpdate(&si, sizeof(si));
191 }
192 #endif
193
194 #if defined(__sun)
195 #if defined(__svr4) || defined(SVR4)
196 #include <sys/systeminfo.h>
197
198 #define getdtablesize() sysconf(_SC_OPEN_MAX)
199
200 static void
201 GiveSystemInfo(void)
202 {
203 int rv;
204 char buf[2000];
205
206 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
207 if (rv > 0) {
208 RNG_RandomUpdate(buf, rv);
209 }
210 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
211 if (rv > 0) {
212 RNG_RandomUpdate(buf, rv);
213 }
214 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
215 if (rv > 0) {
216 RNG_RandomUpdate(buf, rv);
217 }
218 }
219
220 static size_t
221 GetHighResClock(void *buf, size_t maxbytes)
222 {
223 hrtime_t t;
224 t = gethrtime();
225 if (t) {
226 return CopyLowBits(buf, maxbytes, &t, sizeof(t));
227 }
228 return 0;
229 }
230 #else /* SunOS (Sun, but not SVR4) */
231
232 extern long sysconf(int name);
233
234 static size_t
235 GetHighResClock(void *buf, size_t maxbytes)
236 {
237 return 0;
238 }
239
240 static void
241 GiveSystemInfo(void)
242 {
243 long si;
244
245 /* This is not very good */
246 si = sysconf(_SC_CHILD_MAX);
247 RNG_RandomUpdate(&si, sizeof(si));
248 }
249 #endif
250 #endif /* Sun */
251
252 #if defined(__hpux)
253 #include <sys/unistd.h>
254
255 #define getdtablesize() sysconf(_SC_OPEN_MAX)
256
257 #if defined(__ia64)
258 #include <ia64/sys/inline.h>
259
260 static size_t
261 GetHighResClock(void *buf, size_t maxbytes)
262 {
263 PRUint64 t;
264
265 t = _Asm_mov_from_ar(_AREG44);
266 return CopyLowBits(buf, maxbytes, &t, sizeof(t));
267 }
268 #else
269 static size_t
270 GetHighResClock(void *buf, size_t maxbytes)
271 {
272 extern int ret_cr16();
273 int cr16val;
274
275 cr16val = ret_cr16();
276 return CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val));
277 }
278 #endif
279
280 static void
281 GiveSystemInfo(void)
282 {
283 long si;
284
285 /* This is not very good */
286 si = sysconf(_AES_OS_VERSION);
287 RNG_RandomUpdate(&si, sizeof(si));
288 si = sysconf(_SC_CPU_VERSION);
289 RNG_RandomUpdate(&si, sizeof(si));
290 }
291 #endif /* HPUX */
292
293 #if defined(OSF1)
294 #include <sys/types.h>
295 #include <sys/sysinfo.h>
296 #include <sys/systeminfo.h>
297 #include <c_asm.h>
298
299 static void
300 GiveSystemInfo(void)
301 {
302 char buf[BUFSIZ];
303 int rv;
304 int off = 0;
305
306 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
307 if (rv > 0) {
308 RNG_RandomUpdate(buf, rv);
309 }
310 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
311 if (rv > 0) {
312 RNG_RandomUpdate(buf, rv);
313 }
314 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
315 if (rv > 0) {
316 RNG_RandomUpdate(buf, rv);
317 }
318 }
319
320 /*
321 * Use the "get the cycle counter" instruction on the alpha.
322 * The low 32 bits completely turn over in less than a minute.
323 * The high 32 bits are some non-counter gunk that changes sometimes.
324 */
325 static size_t
326 GetHighResClock(void *buf, size_t maxbytes)
327 {
328 unsigned long t;
329
330 t = asm("rpcc %v0");
331 return CopyLowBits(buf, maxbytes, &t, sizeof(t));
332 }
333
334 #endif /* Alpha */
335
336 #if defined(_IBMR2)
337 static size_t
338 GetHighResClock(void *buf, size_t maxbytes)
339 {
340 return 0;
341 }
342
343 static void
344 GiveSystemInfo(void)
345 {
346 /* XXX haven't found any yet! */
347 }
348 #endif /* IBM R2 */
349
350 #if defined(LINUX)
351 #include <sys/sysinfo.h>
352
353 static size_t
354 GetHighResClock(void *buf, size_t maxbytes)
355 {
356 return 0;
357 }
358
359 static void
360 GiveSystemInfo(void)
361 {
362 #ifndef NO_SYSINFO
363 struct sysinfo si;
364 if (sysinfo(&si) == 0) {
365 RNG_RandomUpdate(&si, sizeof(si));
366 }
367 #endif
368 }
369 #endif /* LINUX */
370
371 #if defined(NCR)
372
373 #include <sys/utsname.h>
374 #include <sys/systeminfo.h>
375
376 #define getdtablesize() sysconf(_SC_OPEN_MAX)
377
378 static size_t
379 GetHighResClock(void *buf, size_t maxbytes)
380 {
381 return 0;
382 }
383
384 static void
385 GiveSystemInfo(void)
386 {
387 int rv;
388 char buf[2000];
389
390 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
391 if (rv > 0) {
392 RNG_RandomUpdate(buf, rv);
393 }
394 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
395 if (rv > 0) {
396 RNG_RandomUpdate(buf, rv);
397 }
398 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
399 if (rv > 0) {
400 RNG_RandomUpdate(buf, rv);
401 }
402 }
403
404 #endif /* NCR */
405
406 #if defined(sgi)
407 #include <fcntl.h>
408 #undef PRIVATE
409 #include <sys/mman.h>
410 #include <sys/syssgi.h>
411 #include <sys/immu.h>
412 #include <sys/systeminfo.h>
413 #include <sys/utsname.h>
414 #include <wait.h>
415
416 static void
417 GiveSystemInfo(void)
418 {
419 int rv;
420 char buf[4096];
421
422 rv = syssgi(SGI_SYSID, &buf[0]);
423 if (rv > 0) {
424 RNG_RandomUpdate(buf, MAXSYSIDSIZE);
425 }
426 #ifdef SGI_RDUBLK
427 rv = syssgi(SGI_RDUBLK, getpid(), &buf[0], sizeof(buf));
428 if (rv > 0) {
429 RNG_RandomUpdate(buf, sizeof(buf));
430 }
431 #endif /* SGI_RDUBLK */
432 rv = syssgi(SGI_INVENT, SGI_INV_READ, buf, sizeof(buf));
433 if (rv > 0) {
434 RNG_RandomUpdate(buf, sizeof(buf));
435 }
436 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
437 if (rv > 0) {
438 RNG_RandomUpdate(buf, rv);
439 }
440 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
441 if (rv > 0) {
442 RNG_RandomUpdate(buf, rv);
443 }
444 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
445 if (rv > 0) {
446 RNG_RandomUpdate(buf, rv);
447 }
448 }
449
450 static size_t GetHighResClock(void *buf, size_t maxbuf)
451 {
452 unsigned phys_addr, raddr, cycleval;
453 static volatile unsigned *iotimer_addr = NULL;
454 static int tries = 0;
455 static int cntr_size;
456 int mfd;
457 long s0[2];
458 struct timeval tv;
459
460 #ifndef SGI_CYCLECNTR_SIZE
461 #define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */
462 #endif
463
464 if (iotimer_addr == NULL) {
465 if (tries++ > 1) {
466 /* Don't keep trying if it didn't work */
467 return 0;
468 }
469
470 /*
471 ** For SGI machines we can use the cycle counter, if it has one,
472 ** to generate some truly random numbers
473 */
474 phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
475 if (phys_addr) {
476 int pgsz = getpagesize();
477 int pgoffmask = pgsz - 1;
478
479 raddr = phys_addr & ~pgoffmask;
480 mfd = open("/dev/mmem", O_RDONLY);
481 if (mfd < 0) {
482 return 0;
483 }
484 iotimer_addr = (unsigned *)
485 mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr);
486 if (iotimer_addr == (void*)-1) {
487 close(mfd);
488 iotimer_addr = NULL;
489 return 0;
490 }
491 iotimer_addr = (unsigned*)
492 ((__psint_t)iotimer_addr | (phys_addr & pgoffmask));
493 /*
494 * The file 'mfd' is purposefully not closed.
495 */
496 cntr_size = syssgi(SGI_CYCLECNTR_SIZE);
497 if (cntr_size < 0) {
498 struct utsname utsinfo;
499
500 /*
501 * We must be executing on a 6.0 or earlier system, since the
502 * SGI_CYCLECNTR_SIZE call is not supported.
503 *
504 * The only pre-6.1 platforms with 64-bit counters are
505 * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
506 */
507 uname(&utsinfo);
508 if (!strncmp(utsinfo.machine, "IP19", 4) ||
509 !strncmp(utsinfo.machine, "IP21", 4))
510 cntr_size = 64;
511 else
512 cntr_size = 32;
513 }
514 cntr_size /= 8; /* Convert from bits to bytes */
515 }
516 }
517
518 s0[0] = *iotimer_addr;
519 if (cntr_size > 4)
520 s0[1] = *(iotimer_addr + 1);
521 memcpy(buf, (char *)&s0[0], cntr_size);
522 return CopyLowBits(buf, maxbuf, &s0, cntr_size);
523 }
524 #endif
525
526 #if defined(sony)
527 #include <sys/systeminfo.h>
528
529 #define getdtablesize() sysconf(_SC_OPEN_MAX)
530
531 static size_t
532 GetHighResClock(void *buf, size_t maxbytes)
533 {
534 return 0;
535 }
536
537 static void
538 GiveSystemInfo(void)
539 {
540 int rv;
541 char buf[2000];
542
543 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
544 if (rv > 0) {
545 RNG_RandomUpdate(buf, rv);
546 }
547 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
548 if (rv > 0) {
549 RNG_RandomUpdate(buf, rv);
550 }
551 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
552 if (rv > 0) {
553 RNG_RandomUpdate(buf, rv);
554 }
555 }
556 #endif /* sony */
557
558 #if defined(sinix)
559 #include <sys/systeminfo.h>
560 #include <sys/times.h>
561
562 int gettimeofday(struct timeval *, struct timezone *);
563 int gethostname(char *, int);
564
565 #define getdtablesize() sysconf(_SC_OPEN_MAX)
566
567 static size_t
568 GetHighResClock(void *buf, size_t maxbytes)
569 {
570 int ticks;
571 struct tms buffer;
572
573 ticks=times(&buffer);
574 return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
575 }
576
577 static void
578 GiveSystemInfo(void)
579 {
580 int rv;
581 char buf[2000];
582
583 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
584 if (rv > 0) {
585 RNG_RandomUpdate(buf, rv);
586 }
587 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
588 if (rv > 0) {
589 RNG_RandomUpdate(buf, rv);
590 }
591 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
592 if (rv > 0) {
593 RNG_RandomUpdate(buf, rv);
594 }
595 }
596 #endif /* sinix */
597
598
599 #ifdef BEOS
600 #include <be/kernel/OS.h>
601
602 static size_t
603 GetHighResClock(void *buf, size_t maxbytes)
604 {
605 bigtime_t bigtime; /* Actually a int64 */
606
607 bigtime = real_time_clock_usecs();
608 return CopyLowBits(buf, maxbytes, &bigtime, sizeof(bigtime));
609 }
610
611 static void
612 GiveSystemInfo(void)
613 {
614 system_info *info = NULL;
615 PRInt32 val;
616 get_system_info(info);
617 if (info) {
618 val = info->boot_time;
619 RNG_RandomUpdate(&val, sizeof(val));
620 val = info->used_pages;
621 RNG_RandomUpdate(&val, sizeof(val));
622 val = info->used_ports;
623 RNG_RandomUpdate(&val, sizeof(val));
624 val = info->used_threads;
625 RNG_RandomUpdate(&val, sizeof(val));
626 val = info->used_teams;
627 RNG_RandomUpdate(&val, sizeof(val));
628 }
629 }
630 #endif /* BEOS */
631
632 #if defined(nec_ews)
633 #include <sys/systeminfo.h>
634
635 #define getdtablesize() sysconf(_SC_OPEN_MAX)
636
637 static size_t
638 GetHighResClock(void *buf, size_t maxbytes)
639 {
640 return 0;
641 }
642
643 static void
644 GiveSystemInfo(void)
645 {
646 int rv;
647 char buf[2000];
648
649 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
650 if (rv > 0) {
651 RNG_RandomUpdate(buf, rv);
652 }
653 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
654 if (rv > 0) {
655 RNG_RandomUpdate(buf, rv);
656 }
657 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
658 if (rv > 0) {
659 RNG_RandomUpdate(buf, rv);
660 }
661 }
662 #endif /* nec_ews */
663
664 size_t RNG_GetNoise(void *buf, size_t maxbytes)
665 {
666 struct timeval tv;
667 int n = 0;
668 int c;
669
670 n = GetHighResClock(buf, maxbytes);
671 maxbytes -= n;
672
673 (void)gettimeofday(&tv, 0);
674 c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec));
675 n += c;
676 maxbytes -= c;
677 c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec));
678 n += c;
679 return n;
680 }
681
682 #define SAFE_POPEN_MAXARGS 10 /* must be at least 2 */
683
684 /*
685 * safe_popen is static to this module and we know what arguments it is
686 * called with. Note that this version only supports a single open child
687 * process at any time.
688 */
689 static pid_t safe_popen_pid;
690 static struct sigaction oldact;
691
692 static FILE *
693 safe_popen(char *cmd)
694 {
695 int p[2], fd, argc;
696 pid_t pid;
697 char *argv[SAFE_POPEN_MAXARGS + 1];
698 FILE *fp;
699 static char blank[] = " \t";
700 static struct sigaction newact;
701
702 if (pipe(p) < 0)
703 return 0;
704
705 fp = fdopen(p[0], "r");
706 if (fp == 0) {
707 close(p[0]);
708 close(p[1]);
709 return 0;
710 }
711
712 /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */
713 newact.sa_handler = SIG_DFL;
714 newact.sa_flags = 0;
715 sigfillset(&newact.sa_mask);
716 sigaction (SIGCHLD, &newact, &oldact);
717
718 pid = fork();
719 switch (pid) {
720 int ndesc;
721
722 case -1:
723 fclose(fp); /* this closes p[0], the fd associated with fp */
724 close(p[1]);
725 sigaction (SIGCHLD, &oldact, NULL);
726 return 0;
727
728 case 0:
729 /* dup write-side of pipe to stderr and stdout */
730 if (p[1] != 1) dup2(p[1], 1);
731 if (p[1] != 2) dup2(p[1], 2);
732
733 /*
734 * close the other file descriptors, except stdin which we
735 * try reassociating with /dev/null, first (bug 174993)
736 */
737 if (!freopen("/dev/null", "r", stdin))
738 close(0);
739 ndesc = getdtablesize();
740 for (fd = PR_MIN(65536, ndesc); --fd > 2; close(fd));
741
742 /* clean up environment in the child process */
743 putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc");
744 putenv("SHELL=/bin/sh");
745 putenv("IFS= \t");
746
747 /*
748 * The caller may have passed us a string that is in text
749 * space. It may be illegal to modify the string
750 */
751 cmd = strdup(cmd);
752 /* format argv */
753 argv[0] = strtok(cmd, blank);
754 argc = 1;
755 while ((argv[argc] = strtok(0, blank)) != 0) {
756 if (++argc == SAFE_POPEN_MAXARGS) {
757 argv[argc] = 0;
758 break;
759 }
760 }
761
762 /* and away we go */
763 execvp(argv[0], argv);
764 exit(127);
765 break;
766
767 default:
768 close(p[1]);
769 break;
770 }
771
772 /* non-zero means there's a cmd running */
773 safe_popen_pid = pid;
774 return fp;
775 }
776
777 static int
778 safe_pclose(FILE *fp)
779 {
780 pid_t pid;
781 int status = -1, rv;
782
783 if ((pid = safe_popen_pid) == 0)
784 return -1;
785 safe_popen_pid = 0;
786
787 fclose(fp);
788
789 /* yield the processor so the child gets some time to exit normally */
790 PR_Sleep(PR_INTERVAL_NO_WAIT);
791
792 /* if the child hasn't exited, kill it -- we're done with its output */
793 while ((rv = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR)
794 ;
795 if (rv == 0) {
796 kill(pid, SIGKILL);
797 while ((rv = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
798 ;
799 }
800
801 /* Reset SIGCHLD signal hander before returning */
802 sigaction(SIGCHLD, &oldact, NULL);
803
804 return status;
805 }
806
807 #ifdef DARWIN
808 #include <TargetConditionals.h>
809 #if !TARGET_OS_IPHONE
810 #include <crt_externs.h>
811 #endif
812 #endif
813
814 /* Fork netstat to collect its output by default. Do not unset this unless
815 * another source of entropy is available
816 */
817 #define DO_NETSTAT 1
818
819 void RNG_SystemInfoForRNG(void)
820 {
821 FILE *fp;
822 char buf[BUFSIZ];
823 size_t bytes;
824 const char * const *cp;
825 char *randfile;
826 #ifdef DARWIN
827 #if TARGET_OS_IPHONE
828 /* iOS does not expose a way to access environ. */
829 char **environ = NULL;
830 #else
831 char **environ = *_NSGetEnviron();
832 #endif
833 #else
834 extern char **environ;
835 #endif
836 #ifdef BEOS
837 static const char * const files[] = {
838 "/boot/var/swap",
839 "/boot/var/log/syslog",
840 "/boot/var/tmp",
841 "/boot/home/config/settings",
842 "/boot/home",
843 0
844 };
845 #else
846 static const char * const files[] = {
847 "/etc/passwd",
848 "/etc/utmp",
849 "/tmp",
850 "/var/tmp",
851 "/usr/tmp",
852 0
853 };
854 #endif
855
856 #if defined(BSDI)
857 static char netstat_ni_cmd[] = "netstat -nis";
858 #else
859 static char netstat_ni_cmd[] = "netstat -ni";
860 #endif
861
862 GiveSystemInfo();
863
864 bytes = RNG_GetNoise(buf, sizeof(buf));
865 RNG_RandomUpdate(buf, bytes);
866
867 /*
868 * Pass the C environment and the addresses of the pointers to the
869 * hash function. This makes the random number function depend on the
870 * execution environment of the user and on the platform the program
871 * is running on.
872 */
873 if (environ != NULL) {
874 cp = (const char * const *) environ;
875 while (*cp) {
876 RNG_RandomUpdate(*cp, strlen(*cp));
877 cp++;
878 }
879 RNG_RandomUpdate(environ, (char*)cp - (char*)environ);
880 }
881
882 /* Give in system information */
883 if (gethostname(buf, sizeof(buf)) == 0) {
884 RNG_RandomUpdate(buf, strlen(buf));
885 }
886 GiveSystemInfo();
887
888 /* grab some data from system's PRNG before any other files. */
889 bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT);
890
891 /* If the user points us to a random file, pass it through the rng */
892 randfile = PR_GetEnvSecure("NSRANDFILE");
893 if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) {
894 char *randCountString = PR_GetEnvSecure("NSRANDCOUNT");
895 int randCount = randCountString ? atoi(randCountString) : 0;
896 if (randCount != 0) {
897 RNG_FileUpdate(randfile, randCount);
898 } else {
899 RNG_FileForRNG(randfile);
900 }
901 }
902
903 /* pass other files through */
904 for (cp = files; *cp; cp++)
905 RNG_FileForRNG(*cp);
906
907 /*
908 * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen
909 * in a pthreads environment. Therefore, we call safe_popen last and on
910 * BSD/OS we do not call safe_popen when we succeeded in getting data
911 * from /dev/urandom.
912 *
913 * Bug 174993: On platforms providing /dev/urandom, don't fork netstat
914 * either, if data has been gathered successfully.
915 */
916
917 #if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \
918 || defined(OPENBSD) || defined(DARWIN) || defined(LINUX) \
919 || defined(HPUX)
920 if (bytes == SYSTEM_RNG_SEED_COUNT)
921 return;
922
923 /*
924 * Modified to abort the process if it failed to read from /dev/urandom.
925 *
926 * See crbug.com/244661 for details.
927 */
928 fprintf(stderr, "[ERROR:%s(%d)] NSS read %zu bytes (expected %d bytes) "
929 "from /dev/urandom. Abort process.\n", __FILE__, __LINE__,
930 bytes, SYSTEM_RNG_SEED_COUNT);
931 fflush(stderr);
932 abort();
933 #endif
934
935 #ifdef SOLARIS
936
937 /*
938 * On Solaris, NSS may be initialized automatically from libldap in
939 * applications that are unaware of the use of NSS. safe_popen forks, and
940 * sometimes creates issues with some applications' pthread_atfork handlers.
941 * We always have /dev/urandom on Solaris 9 and above as an entropy source,
942 * and for Solaris 8 we have the libkstat interface, so we don't need to
943 * fork netstat.
944 */
945
946 #undef DO_NETSTAT
947 if (!bytes) {
948 /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */
949 PRUint32 kstat_bytes = 0;
950 if (SECSuccess != RNG_kstat(&kstat_bytes)) {
951 PORT_Assert(0);
952 }
953 bytes += kstat_bytes;
954 PORT_Assert(bytes);
955 }
956 #endif
957
958 #ifdef DO_NETSTAT
959 fp = safe_popen(netstat_ni_cmd);
960 if (fp != NULL) {
961 while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0)
962 RNG_RandomUpdate(buf, bytes);
963 safe_pclose(fp);
964 }
965 #endif
966
967 }
968
969 #define TOTAL_FILE_LIMIT 1000000 /* one million */
970
971 size_t RNG_FileUpdate(const char *fileName, size_t limit)
972 {
973 FILE * file;
974 int fd;
975 int bytes;
976 size_t fileBytes = 0;
977 struct stat stat_buf;
978 unsigned char buffer[BUFSIZ];
979 static size_t totalFileBytes = 0;
980
981 /* suppress valgrind warnings due to holes in struct stat */
982 memset(&stat_buf, 0, sizeof(stat_buf));
983
984 if (stat((char *)fileName, &stat_buf) < 0)
985 return fileBytes;
986 RNG_RandomUpdate(&stat_buf, sizeof(stat_buf));
987
988 file = fopen(fileName, "r");
989 if (file != NULL) {
990 /* Read from the underlying file descriptor directly to bypass stdio
991 * buffering and avoid reading more bytes than we need from
992 * /dev/urandom. NOTE: we can't use fread with unbuffered I/O because
993 * fread may return EOF in unbuffered I/O mode on Android.
994 *
995 * Moreover, we read into a buffer of size BUFSIZ, so buffered I/O
996 * has no performance advantage. */
997 fd = fileno(file);
998 /* 'file' was just opened, so this should not fail. */
999 PORT_Assert(fd != -1);
1000 while (limit > fileBytes) {
1001 bytes = PR_MIN(sizeof buffer, limit - fileBytes);
1002 bytes = read(fd, buffer, bytes);
1003 if (bytes <= 0)
1004 break;
1005 RNG_RandomUpdate(buffer, bytes);
1006 fileBytes += bytes;
1007 totalFileBytes += bytes;
1008 /* after TOTAL_FILE_LIMIT has been reached, only read in first
1009 ** buffer of data from each subsequent file.
1010 */
1011 if (totalFileBytes > TOTAL_FILE_LIMIT)
1012 break;
1013 }
1014 fclose(file);
1015 }
1016 /*
1017 * Pass yet another snapshot of our highest resolution clock into
1018 * the hash function.
1019 */
1020 bytes = RNG_GetNoise(buffer, sizeof(buffer));
1021 RNG_RandomUpdate(buffer, bytes);
1022 return fileBytes;
1023 }
1024
1025 void RNG_FileForRNG(const char *fileName)
1026 {
1027 RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT);
1028 }
1029
1030 void ReadSingleFile(const char *fileName)
1031 {
1032 FILE * file;
1033 unsigned char buffer[BUFSIZ];
1034
1035 file = fopen(fileName, "rb");
1036 if (file != NULL) {
1037 while (fread(buffer, 1, sizeof(buffer), file) > 0)
1038 ;
1039 fclose(file);
1040 }
1041 }
1042
1043 #define _POSIX_PTHREAD_SEMANTICS
1044 #include <dirent.h>
1045
1046 PRBool
1047 ReadFileOK(char *dir, char *file)
1048 {
1049 struct stat stat_buf;
1050 char filename[PATH_MAX];
1051 int count = snprintf(filename, sizeof filename, "%s/%s",dir, file);
1052
1053 if (count <= 0) {
1054 return PR_FALSE; /* name too long, can't read it anyway */
1055 }
1056
1057 if (stat(filename, &stat_buf) < 0)
1058 return PR_FALSE; /* can't stat, probably can't read it then as well */
1059 return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE;
1060 }
1061
1062 /*
1063 * read one file out of either /etc or the user's home directory.
1064 * fileToRead tells which file to read.
1065 *
1066 * return 1 if it's time to reset the fileToRead (no more files to read).
1067 */
1068 int ReadOneFile(int fileToRead)
1069 {
1070 char *dir = "/etc";
1071 DIR *fd = opendir(dir);
1072 int resetCount = 0;
1073 #ifdef SOLARIS
1074 /* grumble, Solaris does not define struct dirent to be the full length */
1075 typedef union {
1076 unsigned char space[sizeof(struct dirent) + MAXNAMELEN];
1077 struct dirent dir;
1078 } dirent_hack;
1079 dirent_hack entry, firstEntry;
1080
1081 #define entry_dir entry.dir
1082 #else
1083 struct dirent entry, firstEntry;
1084 #define entry_dir entry
1085 #endif
1086
1087 int i, error = -1;
1088
1089 if (fd == NULL) {
1090 dir = PR_GetEnvSecure("HOME");
1091 if (dir) {
1092 fd = opendir(dir);
1093 }
1094 }
1095 if (fd == NULL) {
1096 return 1;
1097 }
1098
1099 for (i=0; i <= fileToRead; i++) {
1100 struct dirent *result = NULL;
1101 do {
1102 error = readdir_r(fd, &entry_dir, &result);
1103 } while (error == 0 && result != NULL &&
1104 !ReadFileOK(dir,&result->d_name[0]));
1105 if (error != 0 || result == NULL) {
1106 resetCount = 1; /* read to the end, start again at the beginning */
1107 if (i != 0) {
1108 /* ran out of entries in the directory, use the first one */
1109 entry = firstEntry;
1110 error = 0;
1111 break;
1112 }
1113 /* if i== 0, there were no readable entries in the directory */
1114 break;
1115 }
1116 if (i==0) {
1117 /* save the first entry in case we run out of entries */
1118 firstEntry = entry;
1119 }
1120 }
1121
1122 if (error == 0) {
1123 char filename[PATH_MAX];
1124 int count = snprintf(filename, sizeof filename,
1125 "%s/%s",dir, &entry_dir.d_name[0]);
1126 if (count >= 1) {
1127 ReadSingleFile(filename);
1128 }
1129 }
1130
1131 closedir(fd);
1132 return resetCount;
1133 }
1134
1135 /*
1136 * do something to try to introduce more noise into the 'GetNoise' call
1137 */
1138 static void rng_systemJitter(void)
1139 {
1140 static int fileToRead = 1;
1141
1142 if (ReadOneFile(fileToRead)) {
1143 fileToRead = 1;
1144 } else {
1145 fileToRead++;
1146 }
1147 }
1148
1149 /*
1150 * Modified to abort the process if it failed to read from /dev/urandom.
1151 *
1152 * See crbug.com/244661 for details.
1153 */
1154 size_t RNG_SystemRNG(void *dest, size_t maxLen)
1155 {
1156 FILE *file;
1157 int fd;
1158 int bytes;
1159 size_t fileBytes = 0;
1160 unsigned char *buffer = dest;
1161
1162 file = fopen("/dev/urandom", "r");
1163 if (file == NULL) {
1164 fprintf(stderr, "[ERROR:%s(%d)] NSS failed to read from /dev/urandom. "
1165 "Abort process.\n", __FILE__, __LINE__);
1166 fflush(stderr);
1167 abort();
1168 }
1169 /* Read from the underlying file descriptor directly to bypass stdio
1170 * buffering and avoid reading more bytes than we need from /dev/urandom.
1171 * NOTE: we can't use fread with unbuffered I/O because fread may return
1172 * EOF in unbuffered I/O mode on Android.
1173 */
1174 fd = fileno(file);
1175 /* 'file' was just opened, so this should not fail. */
1176 PORT_Assert(fd != -1);
1177 while (maxLen > fileBytes) {
1178 bytes = maxLen - fileBytes;
1179 bytes = read(fd, buffer, bytes);
1180 if (bytes <= 0)
1181 break;
1182 fileBytes += bytes;
1183 buffer += bytes;
1184 }
1185 fclose(file);
1186 if (fileBytes != maxLen) {
1187 fprintf(stderr, "[ERROR:%s(%d)] NSS failed to read from /dev/urandom. "
1188 "Abort process.\n", __FILE__, __LINE__);
1189 fflush(stderr);
1190 abort();
1191 }
1192 return fileBytes;
1193 }
OLDNEW
« no previous file with comments | « nss/lib/freebl/tlsprfalg.c ('k') | nss/lib/freebl/win_rand.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698