summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2026-03-25 10:34:37 +0000
committerLeah Rowe <leah@libreboot.org>2026-03-25 10:34:37 +0000
commitf7f1856969df44c47deca559a1b77b82d4f42cb3 (patch)
tree80493845ccec6d0265898d05153a2df7aab0c6c4
parente1ff02f323b747d49a6c20c5d3d89702fd1677ba (diff)
libreboot-utils: move rand to own file
Signed-off-by: Leah Rowe <leah@libreboot.org>
-rw-r--r--util/libreboot-utils/Makefile9
-rw-r--r--util/libreboot-utils/lib/num.c316
-rw-r--r--util/libreboot-utils/lib/rand.c351
3 files changed, 359 insertions, 317 deletions
diff --git a/util/libreboot-utils/Makefile b/util/libreboot-utils/Makefile
index f741d3f5..692ebf0f 100644
--- a/util/libreboot-utils/Makefile
+++ b/util/libreboot-utils/Makefile
@@ -37,14 +37,16 @@ OBJS_NVMUTIL = \
obj/lib/io.o \
obj/lib/checksum.o \
obj/lib/word.o \
- obj/lib/mkhtemp.o
+ obj/lib/mkhtemp.o \
+ obj/lib/rand.o
OBJS_MKHTEMP = \
obj/mkhtemp.o \
obj/lib/file.o \
obj/lib/string.o \
obj/lib/num.o \
- obj/lib/mkhtemp.o
+ obj/lib/mkhtemp.o \
+ obj/lib/rand.o
# default mode
CFLAGS_MODE = $(PORTABLE)
@@ -106,6 +108,9 @@ obj/lib/word.o: lib/word.c
obj/lib/mkhtemp.o: lib/mkhtemp.c
$(CC_MODE) $(CFLAGS_MODE) -c lib/mkhtemp.c -o obj/lib/mkhtemp.o
+obj/lib/rand.o: lib/rand.c
+ $(CC_MODE) $(CFLAGS_MODE) -c lib/rand.c -o obj/lib/rand.o
+
# install
install: $(PROG) $(PROGMKH)
diff --git a/util/libreboot-utils/lib/num.c b/util/libreboot-utils/lib/num.c
index 0b76e257..c02b6722 100644
--- a/util/libreboot-utils/lib/num.c
+++ b/util/libreboot-utils/lib/num.c
@@ -2,6 +2,7 @@
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
*
* Numerical functions.
+ * NOTE: randomness was moved to rand.c
*/
/*
@@ -117,321 +118,6 @@ err_hextonum:
/* caller just checks >15. */
}
-/* Random numbers
- */
-
-/* when calling this: save errno
- * first, then set errno to zero.
- * on error, this function will
- * set errno and possibly return
- *
- * rlong also preserves errno
- * and leaves it unchanged on
- * success, so if you do it
- * right, you can detect error.
- * this is because it uses
- * /dev/urandom which can err.
- * ditto getrandom (EINTR),
- * theoretically.
- */
-
-size_t
-rlong(void)
-{
-#if !(defined(FALLBACK_RAND_1989) && \
- ((FALLBACK_RAND_1989) > 0))
-#if (defined(__OpenBSD__) && (OpenBSD) >= 201) || \
- defined(__FreeBSD__) || \
- defined(__NetBSD__) || defined(__APPLE__)
-
- int saved_errno = errno;
- size_t rval;
-
- arc4random_buf(&rval, sizeof(size_t));
-
- 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
-}
-
-#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;
-
- if (!len) {
- errno = EINVAL;
- return -1;
- }
-
- if (buf == NULL) {
- errno = EFAULT;
- return -1;
- }
-
-#if defined(HAVE_GETRANDOM) || \
- defined(HAVE_GETRANDOM_SYSCALL)
-
- 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
-
- if (rval < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
-
- errno = EIO;
- return -1; /* unsupported by kernel */
- }
-
- if (rval == 0) {
- errno = EIO;
- return -1;
- }
-
- off += (size_t)rval;
- }
-
- errno = saved_errno;
- return 0;
-
-#else
- (void)buf;
- (void)len;
-
- errno = EIO;
- return -1;
-#endif
-}
-#endif
-#endif
-#else
-size_t
-fallback_rand_1989(void)
-{
- static size_t mix = 0;
- static size_t counter = 0;
-
- struct timeval tv;
-
- /* nobody should use this
- * (not crypto-safe)
- */
-
- gettimeofday(&tv, NULL);
-
- mix ^= (size_t)tv.tv_sec
- ^ (size_t)tv.tv_usec
- ^ (size_t)getpid()
- ^ (size_t)&mix
- ^ counter++
- ^ entropy_jitter();
-
- /*
- * Stack addresses can vary between
- * calls, thus increasing entropy.
- */
- mix ^= (size_t)&mix;
- mix ^= (size_t)&tv;
- mix ^= (size_t)&counter;
-
- return mix;
-}
-
-size_t
-entropy_jitter(void)
-{
- size_t mix;
-
- struct timeval a, b;
- ssize_t mix_diff;
-
- int c;
-
- mix = 0;
-
- gettimeofday(&a, NULL);
-
- for (c = 0; c < 32; c++) {
-
- getpid();
- gettimeofday(&b, NULL);
-
- /*
- * prevent negative numbers to prevent overflow,
- * which would bias rand to large numbers
- */
- mix_diff = (ssize_t)(b.tv_usec - a.tv_usec);
- if (mix_diff < 0)
- mix_diff = -mix_diff;
-
- mix ^= (size_t)(mix_diff);
-
- mix ^= (size_t)&mix;
-
- }
-
- return mix;
-}
-#endif
-
void
check_bin(size_t a, const char *a_name)
{
diff --git a/util/libreboot-utils/lib/rand.c b/util/libreboot-utils/lib/rand.c
new file mode 100644
index 00000000..c84664fa
--- /dev/null
+++ b/util/libreboot-utils/lib/rand.c
@@ -0,0 +1,351 @@
+/* SPDX-License-Identifier: MIT
+ * Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
+ *
+ * Random number generation
+ */
+
+#ifndef RAND_H
+#define RAND_H
+
+#ifdef __OpenBSD__
+#include <sys/param.h>
+#endif
+#include <sys/types.h>
+#if defined(FALLBACK_RAND_1989) && \
+ (FALLBACK_RAND_1989) > 0
+#include <sys/time.h>
+#endif
+
+#include <errno.h>
+#if !((defined(__OpenBSD__) && (OpenBSD) >= 201) || \
+ defined(__FreeBSD__) || \
+ defined(__NetBSD__) || defined(__APPLE__))
+#include <fcntl.h> /* if not arc4random: /dev/urandom */
+#endif
+#include <limits.h>
+#include <stddef.h>
+#include <string.h>
+#if defined(FALLBACK_RAND_1989) && \
+ (FALLBACK_RAND_1989) > 0
+#include <time.h>
+#endif
+#include <unistd.h>
+
+#include "../include/common.h"
+
+/* Random numbers
+ */
+
+/* when calling this: save errno
+ * first, then set errno to zero.
+ * on error, this function will
+ * set errno and possibly return
+ *
+ * rlong also preserves errno
+ * and leaves it unchanged on
+ * success, so if you do it
+ * right, you can detect error.
+ * this is because it uses
+ * /dev/urandom which can err.
+ * ditto getrandom (EINTR),
+ * theoretically.
+ */
+
+size_t
+rlong(void)
+{
+#if !(defined(FALLBACK_RAND_1989) && \
+ ((FALLBACK_RAND_1989) > 0))
+#if (defined(__OpenBSD__) && (OpenBSD) >= 201) || \
+ defined(__FreeBSD__) || \
+ defined(__NetBSD__) || defined(__APPLE__)
+
+ int saved_errno = errno;
+ size_t rval;
+
+ arc4random_buf(&rval, sizeof(size_t));
+
+ 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
+}
+
+#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;
+
+ if (!len) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (buf == NULL) {
+ errno = EFAULT;
+ return -1;
+ }
+
+#if defined(HAVE_GETRANDOM) || \
+ defined(HAVE_GETRANDOM_SYSCALL)
+
+ 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
+
+ if (rval < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+
+ errno = EIO;
+ return -1; /* unsupported by kernel */
+ }
+
+ if (rval == 0) {
+ errno = EIO;
+ return -1;
+ }
+
+ off += (size_t)rval;
+ }
+
+ errno = saved_errno;
+ return 0;
+
+#else
+ (void)buf;
+ (void)len;
+
+ errno = EIO;
+ return -1;
+#endif
+}
+#endif
+#endif
+#else
+size_t
+fallback_rand_1989(void)
+{
+ static size_t mix = 0;
+ static size_t counter = 0;
+
+ struct timeval tv;
+
+ /* nobody should use this
+ * (not crypto-safe)
+ */
+
+ gettimeofday(&tv, NULL);
+
+ mix ^= (size_t)tv.tv_sec
+ ^ (size_t)tv.tv_usec
+ ^ (size_t)getpid()
+ ^ (size_t)&mix
+ ^ counter++
+ ^ entropy_jitter();
+
+ /*
+ * Stack addresses can vary between
+ * calls, thus increasing entropy.
+ */
+ mix ^= (size_t)&mix;
+ mix ^= (size_t)&tv;
+ mix ^= (size_t)&counter;
+
+ return mix;
+}
+
+size_t
+entropy_jitter(void)
+{
+ size_t mix;
+
+ struct timeval a, b;
+ ssize_t mix_diff;
+
+ int c;
+
+ mix = 0;
+
+ gettimeofday(&a, NULL);
+
+ for (c = 0; c < 32; c++) {
+
+ getpid();
+ gettimeofday(&b, NULL);
+
+ /*
+ * prevent negative numbers to prevent overflow,
+ * which would bias rand to large numbers
+ */
+ mix_diff = (ssize_t)(b.tv_usec - a.tv_usec);
+ if (mix_diff < 0)
+ mix_diff = -mix_diff;
+
+ mix ^= (size_t)(mix_diff);
+
+ mix ^= (size_t)&mix;
+
+ }
+
+ return mix;
+}
+#endif
+
+#endif