diff options
author | pjd <pjd@FreeBSD.org> | 2012-07-04 19:51:25 +0000 |
---|---|---|
committer | pjd <pjd@FreeBSD.org> | 2012-07-04 19:51:25 +0000 |
commit | 8cbf06904c76a2c9ed6b6e796cc669bb7b92e090 (patch) | |
tree | d0dad201d7d17d8750958079b6795c4eed40e39a | |
parent | 860961ab47e87d7fdd9b6940ef70346e37f33708 (diff) | |
download | FreeBSD-src-8cbf06904c76a2c9ed6b6e796cc669bb7b92e090.zip FreeBSD-src-8cbf06904c76a2c9ed6b6e796cc669bb7b92e090.tar.gz |
Prefer sysctl to open/read/close for obtaining random data.
This method is more sandbox-friendly and also should be faster as only
one syscall is needed instead of three.
In case of an error fall back to the old method.
Reviewed by: simon, gleb
MFC after: 2 weeks
-rw-r--r-- | lib/libc/gen/arc4random.c | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/lib/libc/gen/arc4random.c b/lib/libc/gen/arc4random.c index a2b235f..46059ab 100644 --- a/lib/libc/gen/arc4random.c +++ b/lib/libc/gen/arc4random.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include <unistd.h> #include <sys/types.h> #include <sys/param.h> +#include <sys/sysctl.h> #include <sys/time.h> #include <pthread.h> @@ -78,6 +79,9 @@ static struct arc4_stream rs; static pid_t arc4_stir_pid; static int arc4_count; +extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, + void *newp, size_t newlen); + static inline u_int8_t arc4_getbyte(void); static void arc4_stir(void); @@ -109,6 +113,28 @@ arc4_addrandom(u_char *dat, int datlen) rs.j = rs.i; } +static size_t +arc4_sysctl(u_char *buf, size_t size) +{ + int mib[2]; + size_t len, done; + + mib[0] = CTL_KERN; + mib[1] = KERN_ARND; + done = 0; + + do { + len = size; + if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1) + return (done); + done += len; + buf += len; + size -= len; + } while (size > 0); + + return (done); +} + static void arc4_stir(void) { @@ -123,12 +149,16 @@ arc4_stir(void) arc4_init(); rs_initialized = 1; } - fd = _open(RANDOMDEV, O_RDONLY, 0); done = 0; - if (fd >= 0) { - if (_read(fd, &rdat, KEYSIZE) == KEYSIZE) - done = 1; - (void)_close(fd); + if (arc4_sysctl((u_char *)&rdat, KEYSIZE) == KEYSIZE) + done = 1; + if (!done) { + fd = _open(RANDOMDEV, O_RDONLY, 0); + if (fd >= 0) { + if (_read(fd, &rdat, KEYSIZE) == KEYSIZE) + done = 1; + (void)_close(fd); + } } if (!done) { (void)gettimeofday(&rdat.tv, NULL); |