tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

unix_rand.c (19856B)


      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 <sys/types.h>
     16 #include <dirent.h>
     17 #include "secrng.h"
     18 #include "secerr.h"
     19 #include "prerror.h"
     20 #include "prthread.h"
     21 #include "prprf.h"
     22 #include "prenv.h"
     23 
     24 size_t RNG_FileUpdate(const char *fileName, size_t limit);
     25 
     26 /*
     27 * When copying data to the buffer we want the least signicant bytes
     28 * from the input since those bits are changing the fastest. The address
     29 * of least significant byte depends upon whether we are running on
     30 * a big-endian or little-endian machine.
     31 *
     32 * Does this mean the least signicant bytes are the most significant
     33 * to us? :-)
     34 */
     35 
     36 static size_t
     37 CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen)
     38 {
     39    union endianness {
     40        PRInt32 i;
     41        char c[4];
     42    } u;
     43 
     44    if (srclen <= dstlen) {
     45        memcpy(dst, src, srclen);
     46        return srclen;
     47    }
     48    u.i = 0x01020304;
     49    if (u.c[0] == 0x01) {
     50        /* big-endian case */
     51        memcpy(dst, (char *)src + (srclen - dstlen), dstlen);
     52    } else {
     53        /* little-endian case */
     54        memcpy(dst, src, dstlen);
     55    }
     56    return dstlen;
     57 }
     58 
     59 #ifdef SOLARIS
     60 
     61 #include <kstat.h>
     62 
     63 static const PRUint32 entropy_buf_len = 4096; /* buffer up to 4 KB */
     64 
     65 /* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time.
     66 * Returns error if RNG_RandomUpdate fails. Also increments *total_fed
     67 * by the number of bytes successfully buffered.
     68 */
     69 static SECStatus
     70 BufferEntropy(char *inbuf, PRUint32 inlen,
     71              char *entropy_buf, PRUint32 *entropy_buffered,
     72              PRUint32 *total_fed)
     73 {
     74    PRUint32 tocopy = 0;
     75    PRUint32 avail = 0;
     76    SECStatus rv = SECSuccess;
     77 
     78    while (inlen) {
     79        avail = entropy_buf_len - *entropy_buffered;
     80        if (!avail) {
     81            /* Buffer is full, time to feed it to the RNG. */
     82            rv = RNG_RandomUpdate(entropy_buf, entropy_buf_len);
     83            if (SECSuccess != rv) {
     84                break;
     85            }
     86            *entropy_buffered = 0;
     87            avail = entropy_buf_len;
     88        }
     89        tocopy = PR_MIN(avail, inlen);
     90        memcpy(entropy_buf + *entropy_buffered, inbuf, tocopy);
     91        *entropy_buffered += tocopy;
     92        inlen -= tocopy;
     93        inbuf += tocopy;
     94        *total_fed += tocopy;
     95    }
     96    return rv;
     97 }
     98 
     99 /* Feed kernel statistics structures and ks_data field to the RNG.
    100 * Returns status as well as the number of bytes successfully fed to the RNG.
    101 */
    102 static SECStatus
    103 RNG_kstat(PRUint32 *fed)
    104 {
    105    kstat_ctl_t *kc = NULL;
    106    kstat_t *ksp = NULL;
    107    PRUint32 entropy_buffered = 0;
    108    char *entropy_buf = NULL;
    109    SECStatus rv = SECSuccess;
    110 
    111    PORT_Assert(fed);
    112    if (!fed) {
    113        return SECFailure;
    114    }
    115    *fed = 0;
    116 
    117    kc = kstat_open();
    118    PORT_Assert(kc);
    119    if (!kc) {
    120        return SECFailure;
    121    }
    122    entropy_buf = (char *)PORT_Alloc(entropy_buf_len);
    123    PORT_Assert(entropy_buf);
    124    if (entropy_buf) {
    125        for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
    126            if (-1 == kstat_read(kc, ksp, NULL)) {
    127                /* missing data from a single kstat shouldn't be fatal */
    128                continue;
    129            }
    130            rv = BufferEntropy((char *)ksp, sizeof(kstat_t),
    131                               entropy_buf, &entropy_buffered,
    132                               fed);
    133            if (SECSuccess != rv) {
    134                break;
    135            }
    136 
    137            if (ksp->ks_data && ksp->ks_data_size > 0 && ksp->ks_ndata > 0) {
    138                rv = BufferEntropy((char *)ksp->ks_data, ksp->ks_data_size,
    139                                   entropy_buf, &entropy_buffered,
    140                                   fed);
    141                if (SECSuccess != rv) {
    142                    break;
    143                }
    144            }
    145        }
    146        if (SECSuccess == rv && entropy_buffered) {
    147            /* Buffer is not empty, time to feed it to the RNG */
    148            rv = RNG_RandomUpdate(entropy_buf, entropy_buffered);
    149        }
    150        PORT_Free(entropy_buf);
    151    } else {
    152        rv = SECFailure;
    153    }
    154    if (kstat_close(kc)) {
    155        PORT_Assert(0);
    156        rv = SECFailure;
    157    }
    158    return rv;
    159 }
    160 
    161 #endif
    162 
    163 #if defined(FREEBSD) || defined(NETBSD) || defined(DARWIN) || defined(OPENBSD) || defined(NTO) || defined(__riscos__) || defined(__GNU__) || defined(__FreeBSD_kernel__) || defined(__NetBSD_kernel__)
    164 #include <sys/times.h>
    165 
    166 static size_t
    167 GetHighResClock(void *buf, size_t maxbytes)
    168 {
    169    int ticks;
    170    struct tms buffer;
    171 
    172    ticks = times(&buffer);
    173    return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
    174 }
    175 
    176 static void
    177 GiveSystemInfo(void)
    178 {
    179    long si;
    180 
    181    /*
    182     * Is this really necessary?  Why not use rand48 or something?
    183     */
    184    si = sysconf(_SC_CHILD_MAX);
    185    RNG_RandomUpdate(&si, sizeof(si));
    186 
    187    si = sysconf(_SC_STREAM_MAX);
    188    RNG_RandomUpdate(&si, sizeof(si));
    189 
    190    si = sysconf(_SC_OPEN_MAX);
    191    RNG_RandomUpdate(&si, sizeof(si));
    192 }
    193 #endif
    194 
    195 #if defined(__sun)
    196 #if defined(__svr4) || defined(SVR4)
    197 #include <sys/systeminfo.h>
    198 
    199 static void
    200 GiveSystemInfo(void)
    201 {
    202    int rv;
    203    char buf[2000];
    204 
    205    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
    206    if (rv > 0) {
    207        RNG_RandomUpdate(buf, rv);
    208    }
    209    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
    210    if (rv > 0) {
    211        RNG_RandomUpdate(buf, rv);
    212    }
    213    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
    214    if (rv > 0) {
    215        RNG_RandomUpdate(buf, rv);
    216    }
    217 }
    218 
    219 static size_t
    220 GetHighResClock(void *buf, size_t maxbytes)
    221 {
    222    hrtime_t t;
    223    t = gethrtime();
    224    if (t) {
    225        return CopyLowBits(buf, maxbytes, &t, sizeof(t));
    226    }
    227    return 0;
    228 }
    229 #else /* SunOS (Sun, but not SVR4) */
    230 
    231 extern long sysconf(int name);
    232 
    233 static size_t
    234 GetHighResClock(void *buf, size_t maxbytes)
    235 {
    236    return 0;
    237 }
    238 
    239 static void
    240 GiveSystemInfo(void)
    241 {
    242    long si;
    243 
    244    /* This is not very good */
    245    si = sysconf(_SC_CHILD_MAX);
    246    RNG_RandomUpdate(&si, sizeof(si));
    247 }
    248 #endif
    249 #endif /* Sun */
    250 
    251 #if defined(__hpux)
    252 #include <sys/unistd.h>
    253 
    254 #if defined(__ia64)
    255 #include <ia64/sys/inline.h>
    256 
    257 static size_t
    258 GetHighResClock(void *buf, size_t maxbytes)
    259 {
    260    PRUint64 t;
    261 
    262    t = _Asm_mov_from_ar(_AREG44);
    263    return CopyLowBits(buf, maxbytes, &t, sizeof(t));
    264 }
    265 #else
    266 static size_t
    267 GetHighResClock(void *buf, size_t maxbytes)
    268 {
    269    extern int ret_cr16();
    270    int cr16val;
    271 
    272    cr16val = ret_cr16();
    273    return CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val));
    274 }
    275 #endif
    276 
    277 static void
    278 GiveSystemInfo(void)
    279 {
    280    long si;
    281 
    282    /* This is not very good */
    283    si = sysconf(_AES_OS_VERSION);
    284    RNG_RandomUpdate(&si, sizeof(si));
    285    si = sysconf(_SC_CPU_VERSION);
    286    RNG_RandomUpdate(&si, sizeof(si));
    287 }
    288 #endif /* HPUX */
    289 
    290 #if defined(_IBMR2)
    291 static size_t
    292 GetHighResClock(void *buf, size_t maxbytes)
    293 {
    294    return 0;
    295 }
    296 
    297 static void
    298 GiveSystemInfo(void)
    299 {
    300    /* XXX haven't found any yet! */
    301 }
    302 #endif /* IBM R2 */
    303 
    304 #if defined(LINUX)
    305 #include <sys/sysinfo.h>
    306 
    307 static size_t
    308 GetHighResClock(void *buf, size_t maxbytes)
    309 {
    310    return 0;
    311 }
    312 
    313 static void
    314 GiveSystemInfo(void)
    315 {
    316 #ifndef NO_SYSINFO
    317    struct sysinfo si;
    318    if (sysinfo(&si) == 0) {
    319        RNG_RandomUpdate(&si, sizeof(si));
    320    }
    321 #endif
    322 }
    323 #endif /* LINUX */
    324 
    325 #if defined(NCR)
    326 
    327 #include <sys/utsname.h>
    328 #include <sys/systeminfo.h>
    329 
    330 static size_t
    331 GetHighResClock(void *buf, size_t maxbytes)
    332 {
    333    return 0;
    334 }
    335 
    336 static void
    337 GiveSystemInfo(void)
    338 {
    339    int rv;
    340    char buf[2000];
    341 
    342    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
    343    if (rv > 0) {
    344        RNG_RandomUpdate(buf, rv);
    345    }
    346    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
    347    if (rv > 0) {
    348        RNG_RandomUpdate(buf, rv);
    349    }
    350    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
    351    if (rv > 0) {
    352        RNG_RandomUpdate(buf, rv);
    353    }
    354 }
    355 
    356 #endif /* NCR */
    357 
    358 #if defined(sgi)
    359 #include <fcntl.h>
    360 #undef PRIVATE
    361 #include <sys/mman.h>
    362 #include <sys/syssgi.h>
    363 #include <sys/immu.h>
    364 #include <sys/systeminfo.h>
    365 #include <sys/utsname.h>
    366 #include <wait.h>
    367 
    368 static void
    369 GiveSystemInfo(void)
    370 {
    371    int rv;
    372    char buf[4096];
    373 
    374    rv = syssgi(SGI_SYSID, &buf[0]);
    375    if (rv > 0) {
    376        RNG_RandomUpdate(buf, MAXSYSIDSIZE);
    377    }
    378 #ifdef SGI_RDUBLK
    379    rv = syssgi(SGI_RDUBLK, getpid(), &buf[0], sizeof(buf));
    380    if (rv > 0) {
    381        RNG_RandomUpdate(buf, sizeof(buf));
    382    }
    383 #endif /* SGI_RDUBLK */
    384    rv = syssgi(SGI_INVENT, SGI_INV_READ, buf, sizeof(buf));
    385    if (rv > 0) {
    386        RNG_RandomUpdate(buf, sizeof(buf));
    387    }
    388    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
    389    if (rv > 0) {
    390        RNG_RandomUpdate(buf, rv);
    391    }
    392    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
    393    if (rv > 0) {
    394        RNG_RandomUpdate(buf, rv);
    395    }
    396    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
    397    if (rv > 0) {
    398        RNG_RandomUpdate(buf, rv);
    399    }
    400 }
    401 
    402 static size_t
    403 GetHighResClock(void *buf, size_t maxbuf)
    404 {
    405    unsigned phys_addr, raddr, cycleval;
    406    static volatile unsigned *iotimer_addr = NULL;
    407    static int tries = 0;
    408    static int cntr_size;
    409    int mfd;
    410    long s0[2];
    411    struct timeval tv;
    412 
    413 #ifndef SGI_CYCLECNTR_SIZE
    414 #define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */
    415 #endif
    416 
    417    if (iotimer_addr == NULL) {
    418        if (tries++ > 1) {
    419            /* Don't keep trying if it didn't work */
    420            return 0;
    421        }
    422 
    423        /*
    424        ** For SGI machines we can use the cycle counter, if it has one,
    425        ** to generate some truly random numbers
    426        */
    427        phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
    428        if (phys_addr) {
    429            int pgsz = getpagesize();
    430            int pgoffmask = pgsz - 1;
    431 
    432            raddr = phys_addr & ~pgoffmask;
    433            mfd = open("/dev/mmem", O_RDONLY);
    434            if (mfd < 0) {
    435                return 0;
    436            }
    437            iotimer_addr = (unsigned *)
    438                mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr);
    439            if (iotimer_addr == (void *)-1) {
    440                close(mfd);
    441                iotimer_addr = NULL;
    442                return 0;
    443            }
    444            iotimer_addr = (unsigned *)((__psint_t)iotimer_addr | (phys_addr & pgoffmask));
    445            /*
    446             * The file 'mfd' is purposefully not closed.
    447             */
    448            cntr_size = syssgi(SGI_CYCLECNTR_SIZE);
    449            if (cntr_size < 0) {
    450                struct utsname utsinfo;
    451 
    452                /*
    453                 * We must be executing on a 6.0 or earlier system, since the
    454                 * SGI_CYCLECNTR_SIZE call is not supported.
    455                 *
    456                 * The only pre-6.1 platforms with 64-bit counters are
    457                 * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
    458                 */
    459                uname(&utsinfo);
    460                if (!strncmp(utsinfo.machine, "IP19", 4) ||
    461                    !strncmp(utsinfo.machine, "IP21", 4))
    462                    cntr_size = 64;
    463                else
    464                    cntr_size = 32;
    465            }
    466            cntr_size /= 8; /* Convert from bits to bytes */
    467        }
    468    }
    469 
    470    s0[0] = *iotimer_addr;
    471    if (cntr_size > 4)
    472        s0[1] = *(iotimer_addr + 1);
    473    memcpy(buf, (char *)&s0[0], cntr_size);
    474    return CopyLowBits(buf, maxbuf, &s0, cntr_size);
    475 }
    476 #endif
    477 
    478 #if defined(sony)
    479 #include <sys/systeminfo.h>
    480 
    481 static size_t
    482 GetHighResClock(void *buf, size_t maxbytes)
    483 {
    484    return 0;
    485 }
    486 
    487 static void
    488 GiveSystemInfo(void)
    489 {
    490    int rv;
    491    char buf[2000];
    492 
    493    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
    494    if (rv > 0) {
    495        RNG_RandomUpdate(buf, rv);
    496    }
    497    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
    498    if (rv > 0) {
    499        RNG_RandomUpdate(buf, rv);
    500    }
    501    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
    502    if (rv > 0) {
    503        RNG_RandomUpdate(buf, rv);
    504    }
    505 }
    506 #endif /* sony */
    507 
    508 #if defined(sinix)
    509 #include <sys/systeminfo.h>
    510 #include <sys/times.h>
    511 
    512 int gettimeofday(struct timeval *, struct timezone *);
    513 int gethostname(char *, int);
    514 
    515 static size_t
    516 GetHighResClock(void *buf, size_t maxbytes)
    517 {
    518    int ticks;
    519    struct tms buffer;
    520 
    521    ticks = times(&buffer);
    522    return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
    523 }
    524 
    525 static void
    526 GiveSystemInfo(void)
    527 {
    528    int rv;
    529    char buf[2000];
    530 
    531    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
    532    if (rv > 0) {
    533        RNG_RandomUpdate(buf, rv);
    534    }
    535    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
    536    if (rv > 0) {
    537        RNG_RandomUpdate(buf, rv);
    538    }
    539    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
    540    if (rv > 0) {
    541        RNG_RandomUpdate(buf, rv);
    542    }
    543 }
    544 #endif /* sinix */
    545 
    546 #if defined(nec_ews)
    547 #include <sys/systeminfo.h>
    548 
    549 static size_t
    550 GetHighResClock(void *buf, size_t maxbytes)
    551 {
    552    return 0;
    553 }
    554 
    555 static void
    556 GiveSystemInfo(void)
    557 {
    558    int rv;
    559    char buf[2000];
    560 
    561    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
    562    if (rv > 0) {
    563        RNG_RandomUpdate(buf, rv);
    564    }
    565    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
    566    if (rv > 0) {
    567        RNG_RandomUpdate(buf, rv);
    568    }
    569    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
    570    if (rv > 0) {
    571        RNG_RandomUpdate(buf, rv);
    572    }
    573 }
    574 #endif /* nec_ews */
    575 
    576 size_t
    577 RNG_GetNoise(void *buf, size_t maxbytes)
    578 {
    579    struct timeval tv;
    580    int n = 0;
    581    int c;
    582 
    583    n = GetHighResClock(buf, maxbytes);
    584    maxbytes -= n;
    585 
    586    (void)gettimeofday(&tv, 0);
    587    c = CopyLowBits((char *)buf + n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec));
    588    n += c;
    589    maxbytes -= c;
    590    c = CopyLowBits((char *)buf + n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec));
    591    n += c;
    592    return n;
    593 }
    594 
    595 #ifdef DARWIN
    596 #include <TargetConditionals.h>
    597 #if !TARGET_OS_IPHONE
    598 #include <crt_externs.h>
    599 #endif
    600 #endif
    601 
    602 void
    603 RNG_SystemInfoForRNG(void)
    604 {
    605    char buf[BUFSIZ];
    606    size_t bytes;
    607    const char *const *cp;
    608    char *randfile;
    609 #ifdef DARWIN
    610 #if TARGET_OS_IPHONE
    611    /* iOS does not expose a way to access environ. */
    612    char **environ = NULL;
    613 #else
    614    char **environ = *_NSGetEnviron();
    615 #endif
    616 #else
    617    extern char **environ;
    618 #endif
    619    static const char *const files[] = {
    620        "/etc/passwd",
    621        "/etc/utmp",
    622        "/tmp",
    623        "/var/tmp",
    624        "/usr/tmp",
    625        0
    626    };
    627 
    628    GiveSystemInfo();
    629 
    630    bytes = RNG_GetNoise(buf, sizeof(buf));
    631    RNG_RandomUpdate(buf, bytes);
    632 
    633    /*
    634     * Pass the C environment and the addresses of the pointers to the
    635     * hash function. This makes the random number function depend on the
    636     * execution environment of the user and on the platform the program
    637     * is running on.
    638     */
    639    if (environ != NULL) {
    640        cp = (const char *const *)environ;
    641        while (*cp) {
    642            RNG_RandomUpdate(*cp, strlen(*cp));
    643            cp++;
    644        }
    645        RNG_RandomUpdate(environ, (char *)cp - (char *)environ);
    646    }
    647 
    648    /* Give in system information */
    649    if (gethostname(buf, sizeof(buf)) == 0) {
    650        RNG_RandomUpdate(buf, strlen(buf));
    651    }
    652 
    653    /* grab some data from system's PRNG before any other files. */
    654    bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT);
    655    if (!bytes) {
    656        PORT_SetError(SEC_ERROR_NEED_RANDOM);
    657    }
    658 
    659    /* If the user points us to a random file, pass it through the rng */
    660    randfile = PR_GetEnvSecure("NSRANDFILE");
    661    if ((randfile != NULL) && (randfile[0] != '\0')) {
    662        char *randCountString = PR_GetEnvSecure("NSRANDCOUNT");
    663        int randCount = randCountString ? atoi(randCountString) : 0;
    664        if (randCount != 0) {
    665            RNG_FileUpdate(randfile, randCount);
    666        } else {
    667            RNG_FileForRNG(randfile);
    668        }
    669    }
    670 
    671    /* pass other files through */
    672    for (cp = files; *cp; cp++)
    673        RNG_FileForRNG(*cp);
    674 
    675 #if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(DARWIN) || defined(LINUX) || defined(HPUX)
    676    if (bytes)
    677        return;
    678 #endif
    679 
    680 #ifdef SOLARIS
    681    if (!bytes) {
    682        /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */
    683        PRUint32 kstat_bytes = 0;
    684        if (SECSuccess != RNG_kstat(&kstat_bytes)) {
    685            PORT_Assert(0);
    686        }
    687        bytes += kstat_bytes;
    688        PORT_Assert(bytes);
    689    }
    690 #endif
    691 }
    692 
    693 #define TOTAL_FILE_LIMIT 1000000 /* one million */
    694 
    695 size_t
    696 RNG_FileUpdate(const char *fileName, size_t limit)
    697 {
    698    FILE *file;
    699    int fd;
    700    int bytes;
    701    size_t fileBytes = 0;
    702    struct stat stat_buf;
    703    unsigned char buffer[BUFSIZ];
    704    static size_t totalFileBytes = 0;
    705 
    706    /* suppress valgrind warnings due to holes in struct stat */
    707    memset(&stat_buf, 0, sizeof(stat_buf));
    708 
    709    if (stat((char *)fileName, &stat_buf) < 0)
    710        return fileBytes;
    711    RNG_RandomUpdate(&stat_buf, sizeof(stat_buf));
    712 
    713    file = fopen(fileName, "r");
    714    if (file != NULL) {
    715        /* Read from the underlying file descriptor directly to bypass stdio
    716         * buffering and avoid reading more bytes than we need from
    717         * /dev/urandom. NOTE: we can't use fread with unbuffered I/O because
    718         * fread may return EOF in unbuffered I/O mode on Android.
    719         *
    720         * Moreover, we read into a buffer of size BUFSIZ, so buffered I/O
    721         * has no performance advantage. */
    722        fd = fileno(file);
    723        /* 'file' was just opened, so this should not fail. */
    724        PORT_Assert(fd != -1);
    725        while (limit > fileBytes && fd != -1) {
    726            bytes = PR_MIN(sizeof buffer, limit - fileBytes);
    727            bytes = read(fd, buffer, bytes);
    728            if (bytes <= 0)
    729                break;
    730            RNG_RandomUpdate(buffer, bytes);
    731            fileBytes += bytes;
    732            totalFileBytes += bytes;
    733            /* after TOTAL_FILE_LIMIT has been reached, only read in first
    734            ** buffer of data from each subsequent file.
    735            */
    736            if (totalFileBytes > TOTAL_FILE_LIMIT)
    737                break;
    738        }
    739        fclose(file);
    740    }
    741    /*
    742     * Pass yet another snapshot of our highest resolution clock into
    743     * the hash function.
    744     */
    745    bytes = RNG_GetNoise(buffer, sizeof(buffer));
    746    RNG_RandomUpdate(buffer, bytes);
    747    return fileBytes;
    748 }
    749 
    750 void
    751 RNG_FileForRNG(const char *fileName)
    752 {
    753    RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT);
    754 }
    755 
    756 #define _POSIX_PTHREAD_SEMANTICS
    757 #include <dirent.h>
    758 
    759 PRBool
    760 ReadFileOK(char *dir, char *file)
    761 {
    762    struct stat stat_buf;
    763    char filename[PATH_MAX];
    764    int count = snprintf(filename, sizeof filename, "%s/%s", dir, file);
    765 
    766    if (count <= 0) {
    767        return PR_FALSE; /* name too long, can't read it anyway */
    768    }
    769 
    770    if (stat(filename, &stat_buf) < 0)
    771        return PR_FALSE; /* can't stat, probably can't read it then as well */
    772    return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE;
    773 }
    774 
    775 size_t
    776 RNG_SystemRNG(void *dest, size_t maxLen)
    777 {
    778    FILE *file;
    779    int fd;
    780    int bytes;
    781    size_t fileBytes = 0;
    782    unsigned char *buffer = dest;
    783 
    784    file = fopen("/dev/urandom", "r");
    785    if (file == NULL) {
    786        PORT_SetError(SEC_ERROR_NEED_RANDOM);
    787        return 0;
    788    }
    789    /* Read from the underlying file descriptor directly to bypass stdio
    790     * buffering and avoid reading more bytes than we need from /dev/urandom.
    791     * NOTE: we can't use fread with unbuffered I/O because fread may return
    792     * EOF in unbuffered I/O mode on Android.
    793     */
    794    fd = fileno(file);
    795    /* 'file' was just opened, so this should not fail. */
    796    PORT_Assert(fd != -1);
    797    while (maxLen > fileBytes && fd != -1) {
    798        bytes = maxLen - fileBytes;
    799        bytes = read(fd, buffer, bytes);
    800        if (bytes <= 0)
    801            break;
    802        fileBytes += bytes;
    803        buffer += bytes;
    804    }
    805    fclose(file);
    806    if (fileBytes != maxLen) {
    807        PORT_SetError(SEC_ERROR_NEED_RANDOM); /* system RNG failed */
    808        fileBytes = 0;
    809    }
    810    return fileBytes;
    811 }