|
@ -1,4 +1,4 @@ |
|
|
/* $OpenBSD: getentropy_solaris.c,v 1.1 2014/07/08 10:45:35 beck Exp $ */ |
|
|
|
|
|
|
|
|
/* $OpenBSD: getentropy_solaris.c,v 1.2 2014/07/12 13:19:44 beck Exp $ */ |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> |
|
|
* Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> |
|
@ -66,7 +66,8 @@ int getentropy(void *buf, size_t len); |
|
|
|
|
|
|
|
|
extern int main(int, char *argv[]); |
|
|
extern int main(int, char *argv[]); |
|
|
static int gotdata(char *buf, size_t len); |
|
|
static int gotdata(char *buf, size_t len); |
|
|
static int getentropy_urandom(void *buf, size_t len); |
|
|
|
|
|
|
|
|
static int getentropy_urandom(void *buf, size_t len, const char *path, |
|
|
|
|
|
int devfscheck); |
|
|
static int getentropy_fallback(void *buf, size_t len); |
|
|
static int getentropy_fallback(void *buf, size_t len); |
|
|
|
|
|
|
|
|
int |
|
|
int |
|
@ -80,20 +81,39 @@ getentropy(void *buf, size_t len) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* Try to get entropy with /dev/urandom |
|
|
|
|
|
|
|
|
* Try to get entropy with /dev/urandom... |
|
|
|
|
|
* |
|
|
|
|
|
* Solaris provides /dev/urandom as a symbolic link to |
|
|
|
|
|
* /devices/pseudo/random@0:urandom which is provided by |
|
|
|
|
|
* a devfs filesystem. Best practice is to use O_NOFOLLOW, |
|
|
|
|
|
* so we must try the unpublished name directly. |
|
|
|
|
|
* |
|
|
|
|
|
* This can fail if the process is inside a chroot which lacks |
|
|
|
|
|
* the devfs mount, or if file descriptors are exhausted. |
|
|
|
|
|
*/ |
|
|
|
|
|
ret = getentropy_urandom(buf, len, |
|
|
|
|
|
"/devices/pseudo/random@0:urandom", 1); |
|
|
|
|
|
if (ret != -1) |
|
|
|
|
|
return (ret); |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
* Unfortunately, chroot spaces on Solaris are sometimes setup |
|
|
|
|
|
* with direct device node of the well-known /dev/urandom name |
|
|
|
|
|
* (perhaps to avoid dragging all of devfs into the space). |
|
|
* |
|
|
* |
|
|
* This can fail if the process is inside a chroot or if file |
|
|
* This can fail if the process is inside a chroot or if file |
|
|
* descriptors are exhausted. |
|
|
* descriptors are exhausted. |
|
|
*/ |
|
|
*/ |
|
|
ret = getentropy_urandom(buf, len); |
|
|
|
|
|
|
|
|
ret = getentropy_urandom(buf, len, "/dev/urandom", 0); |
|
|
if (ret != -1) |
|
|
if (ret != -1) |
|
|
return (ret); |
|
|
return (ret); |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* Entropy collection via /dev/urandom and sysctl have failed. |
|
|
|
|
|
|
|
|
* Entropy collection via /dev/urandom has failed. |
|
|
* |
|
|
* |
|
|
* No other API exists for collecting entropy, and we have |
|
|
* No other API exists for collecting entropy, and we have |
|
|
* no failsafe way to get it on Solaris that is not sensitive |
|
|
|
|
|
* to resource exhaustion. |
|
|
|
|
|
|
|
|
* no failsafe way to get it on Solaris that is not sensitive |
|
|
|
|
|
* to resource exhaustion. |
|
|
* |
|
|
* |
|
|
* We have very few options: |
|
|
* We have very few options: |
|
|
* - Even syslog_r is unsafe to call at this low level, so |
|
|
* - Even syslog_r is unsafe to call at this low level, so |
|
@ -141,7 +161,7 @@ gotdata(char *buf, size_t len) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static int |
|
|
static int |
|
|
getentropy_urandom(void *buf, size_t len) |
|
|
|
|
|
|
|
|
getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck) |
|
|
{ |
|
|
{ |
|
|
struct stat st; |
|
|
struct stat st; |
|
|
size_t i; |
|
|
size_t i; |
|
@ -150,19 +170,14 @@ getentropy_urandom(void *buf, size_t len) |
|
|
|
|
|
|
|
|
start: |
|
|
start: |
|
|
|
|
|
|
|
|
flags = O_RDONLY; |
|
|
|
|
|
|
|
|
flags = O_RDONLY; |
|
|
#ifdef O_NOFOLLOW |
|
|
#ifdef O_NOFOLLOW |
|
|
flags |= O_NOFOLLOW; |
|
|
|
|
|
|
|
|
flags |= O_NOFOLLOW; |
|
|
#endif |
|
|
#endif |
|
|
#ifdef O_CLOEXEC |
|
|
#ifdef O_CLOEXEC |
|
|
flags |= O_CLOEXEC; |
|
|
|
|
|
|
|
|
flags |= O_CLOEXEC; |
|
|
#endif |
|
|
#endif |
|
|
/* |
|
|
|
|
|
* Solaris provides /dev/urandom as a symbolic link. |
|
|
|
|
|
* /devices/pseudo/random@0:urandom should be the |
|
|
|
|
|
* real device path, and we do want O_NOFOLLOW. |
|
|
|
|
|
*/ |
|
|
|
|
|
fd = open("/devices/pseudo/random@0:urandom", flags, 0); |
|
|
|
|
|
|
|
|
fd = open(path, flags, 0); |
|
|
if (fd == -1) { |
|
|
if (fd == -1) { |
|
|
if (errno == EINTR) |
|
|
if (errno == EINTR) |
|
|
goto start; |
|
|
goto start; |
|
@ -173,7 +188,8 @@ start: |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
/* Lightly verify that the device node looks sane */ |
|
|
/* Lightly verify that the device node looks sane */ |
|
|
if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) { |
|
|
|
|
|
|
|
|
if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode) || |
|
|
|
|
|
(devfscheck && (strcmp(st.st_fstype, "devfs") != 0))) { |
|
|
close(fd); |
|
|
close(fd); |
|
|
goto nodevrandom; |
|
|
goto nodevrandom; |
|
|
} |
|
|
} |
|
|