summaryrefslogtreecommitdiff
path: root/util/libreboot-utils
diff options
context:
space:
mode:
Diffstat (limited to 'util/libreboot-utils')
-rw-r--r--util/libreboot-utils/include/common.h19
-rw-r--r--util/libreboot-utils/lib/rand.c242
2 files changed, 46 insertions, 215 deletions
diff --git a/util/libreboot-utils/include/common.h b/util/libreboot-utils/include/common.h
index 0bab30de..fb3aa886 100644
--- a/util/libreboot-utils/include/common.h
+++ b/util/libreboot-utils/include/common.h
@@ -13,24 +13,13 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
+#include <errno.h>
/* for linux getrandom
*/
#if defined(__linux__)
-#include <errno.h>
-#if defined(__has_include)
-#if __has_include(<sys/random.h>)
#include <sys/random.h>
-#define HAVE_GETRANDOM 1
-#endif
-#endif
-#if !defined(HAVE_GETRANDOM)
#include <sys/syscall.h>
-#if !defined(SYS_getrandom)
-#define HAVE_GETRANDOM_SYSCALL 1
-#endif
-#endif
-
#endif
#define items(x) (sizeof((x)) / sizeof((x)[0]))
@@ -396,12 +385,6 @@ int dcat(const char *s, size_t n,
unsigned short hextonum(char ch_s);
size_t rlong(void);
-#if defined(__linux__)
-#if defined(HAVE_GETRANDOM) || \
- defined(HAVE_GETRANDOM_SYSCALL)
-int fallback_rand_getrandom(void *buf, size_t len);
-#endif
-#endif
/* Helper functions for command: dump
*/
diff --git a/util/libreboot-utils/lib/rand.c b/util/libreboot-utils/lib/rand.c
index 900c3ed3..ecf07142 100644
--- a/util/libreboot-utils/lib/rand.c
+++ b/util/libreboot-utils/lib/rand.c
@@ -22,6 +22,7 @@
#include <stddef.h>
#include <string.h>
#include <unistd.h>
+#include <stdlib.h>
#include "../include/common.h"
@@ -43,230 +44,77 @@
* theoretically.
*/
+/* for the linux version: we use only the
+ * syscall, because we cannot trust /dev/urandom
+ * to be as robust, and some libc implementations
+ * may default to /dev/urandom under fault conditions.
+ *
+ * for general high reliability, we must abort on
+ * failure. in practise, it will likely never fail.
+ * the arc4random call on bsd never returns error.
+ */
+
size_t
rlong(void)
{
+ size_t rval;
+ int saved_errno = errno;
+
#if (defined(__OpenBSD__) && (OpenBSD) >= 201) || \
defined(__FreeBSD__) || \
defined(__NetBSD__) || defined(__APPLE__)
- int saved_errno = errno;
- size_t rval;
-
arc4random_buf(&rval, sizeof(size_t));
+ goto out;
- errno = saved_errno;
- return rval;
-#else
- static int fd = -1;
- static ssize_t nr = -1;
- static size_t off = 0;
-#if defined (BUFSIZ)
- static char rbuf[BUFSIZ];
-#else
-#ifndef PORTABLE
- static char rbuf[4096];
-#elif ((PORTABLE) > 0)
- static char rbuf[256]; /* scarce memory on old systems */
-#else
- static char rbuf[4096]; /* typical 32-bit BUFSIZ */
-#endif
-#endif
- size_t rval;
- ssize_t new_nr;
-
- int retries = 0;
- int max_retries = 100;
-
- int saved_errno = errno;
-
-#if defined(__linux__)
-#if defined(HAVE_GETRANDOM) || \
- defined(HAVE_GETRANDOM_SYSCALL)
-
- /* linux getrandom()
- *
- * we *can* use arc4random on
- * modern linux, but not on
- * every libc. better use the
- * official linux function
- */
-
- if (fallback_rand_getrandom(&rval, sizeof(rval)) == 0) {
- errno = saved_errno;
- return rval;
- }
-
- /*
- * now fall back to urandom if getrandom failed:
- */
-#endif
-#endif
-
- /* reading from urandom is inherently
- * unreliable on old systems, even if
- * newer systems make it more reliable
- *
- * modern linux/bsd make it safe, but
- * we have to assume that someone is
- * compiling this on linux from 1999
- *
- * this logic therefore applies various
- * tricks to mitigate possible os bugs
- */
-
-retry_urandom_read:
-
- if (++retries > max_retries)
- goto err_rlong;
-
- if (nr < 0 || nr < (ssize_t)sizeof(size_t)) {
-
- if (fd < 0) {
-
- fd = open("/dev/urandom",
- O_RDONLY | O_BINARY | O_NOFOLLOW |
- O_CLOEXEC | O_NOCTTY);
-
-#ifdef USE_OLD_DEV_RANDOM
-#if (USE_OLD_DEV_RANDOM) > 0
- /* WARNING:
- * /dev/random may block
- * forever and does **NOT**
- * guarantee better entropy
- * on old systems
- *
- * only use it if needed
- */
-
- if (fd < 0)
- fd = open("/dev/random",
- O_RDONLY | O_BINARY | O_NOFOLLOW |
- O_CLOEXEC | O_NOCTTY);
-#endif
-#endif
-
- if (fd < 0)
- goto retry_urandom_read;
-
- retries = 0;
- }
-
- new_nr = rw_file_exact(fd, (unsigned char *)rbuf,
- sizeof(rbuf), 0, IO_READ, LOOP_EAGAIN,
- LOOP_EINTR, MAX_ZERO_RW_RETRY, OFF_ERR);
-
- if (new_nr < 0 || new_nr < (ssize_t)sizeof(rbuf))
- goto retry_urandom_read;
-
- /* only reset buffer after successful refill */
- nr = new_nr;
- off = 0;
-
- /* don't re-use same fd, to mitaget
- * fd injection */
- close_no_err(&fd);
- }
-
- fd = -1;
- retries = 0;
-
- memcpy(&rval, rbuf + off, sizeof(size_t));
-
- nr -= (ssize_t)sizeof(size_t);
- off += sizeof(size_t);
-
- errno = saved_errno;
-
- return rval;
-
-err_rlong:
-
- if (errno == saved_errno)
- errno = EIO;
-
- return 0;
-
-#endif
-#else /* FALLBACK_RAND_1989 */
- /* your computer is from a museum
- */
- size_t mix = 0;
- int nr = 0;
- int saved_errno = errno;
-
- /* 100 times, for entropy
- */
- for (nr = 0; nr < 100; nr++)
- mix ^= fallback_rand_1989();
-
- errno = saved_errno;
- return mix;
-#endif
-}
+#elif defined(__linux__)
-#if !(defined(FALLBACK_RAND_1989) && \
- ((FALLBACK_RAND_1989) > 0))
-#if defined(__linux__)
-#if defined(HAVE_GETRANDOM) || \
- defined(HAVE_GETRANDOM_SYSCALL)
-int /* yes, linux is a fallback */
-fallback_rand_getrandom(void *buf, size_t len)
-{
size_t off = 0;
- ssize_t rval = -1;
- int saved_errno = errno;
+ size_t len = sizeof(rval);
- if (!len) {
- errno = EINVAL;
- return -1;
- }
+ ssize_t rc;
- if (buf == NULL) {
- errno = EFAULT;
- return -1;
- }
-
-#if defined(HAVE_GETRANDOM) || \
- defined(HAVE_GETRANDOM_SYSCALL)
+ if (!len)
+ goto err;
while (off < len) {
-#if defined(HAVE_GETRANDOM)
- rval = (ssize_t)getrandom((char *)buf + off, len - off, 0);
-#elif defined(HAVE_GETRANDOM_SYSCALL)
- rval = (ssize_t)syscall(SYS_getrandom,
- (char *)buf + off, len - off, 0);
-#endif
+ rc = (ssize_t)syscall(SYS_getrandom,
+ (char *)&rval + off, len - off, 0);
- if (rval < 0) {
+ if (rc < 0) {
if (errno == EINTR || errno == EAGAIN)
continue;
- errno = EIO;
- return -1; /* unsupported by kernel */
+ goto err; /* possibly unsupported by kernel */
}
- if (rval == 0) {
- errno = EIO;
- return -1;
- }
+ if (rval == 0)
+ goto err;
- off += (size_t)rval;
+ off += (size_t)rc;
}
- errno = saved_errno;
- return 0;
+ goto out;
-#else
- (void)buf;
- (void)len;
+ return rval;
+err:
+ /*
+ * getrandom can return with error, butt arc4random
+ * doesn't. generally, getrandom will be reliably,
+ * but we of course have to maintain parity with
+ * BSD. So a rand failure is to be interpreted as
+ * a major systems failure, and we act accordingly.
+ */
+ err_no_cleanup(1, ECANCELED, "Randomisation failure");
+ exit(1);
- errno = EIO;
- return -1;
-#endif
-}
-#endif
+#else
+#error Unsupported operating system (possibly unsecure randomisation)
#endif
+out:
+ errno = saved_errno;
+ return rval;
+}
#endif