summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2026-03-19 18:34:28 +0000
committerLeah Rowe <leah@libreboot.org>2026-03-19 18:34:28 +0000
commitf8b07dba2932714507f7ead6b8464ba3157d84bd (patch)
tree3e16546c3827d7a18f5b14ec28217161eb0f01f2
parent7c66a788bdfc8136a603eec6d805b75cc382b239 (diff)
util/nvmutil: rand: use getrandom on newer linux
we still fall back to the old /dev/urandom read on older linux, via runtime detection (ENOSYS). getrandom is better, because it guarantees entropy via blocking, and works even when /dev/urandom is unavailable. it has the same practical benefit as arc4random, which i use on bsd. linux can have arc4random, but not every linux libc has it, so it's better to use getrandom on linux. older linux will fall back to /dev/urandom Signed-off-by: Leah Rowe <leah@libreboot.org>
-rw-r--r--util/nvmutil/include/common.h25
-rw-r--r--util/nvmutil/lib/num.c83
2 files changed, 105 insertions, 3 deletions
diff --git a/util/nvmutil/include/common.h b/util/nvmutil/include/common.h
index 36218d25..0a3beeac 100644
--- a/util/nvmutil/include/common.h
+++ b/util/nvmutil/include/common.h
@@ -9,6 +9,25 @@
#include <sys/stat.h>
#include <limits.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]))
/* system prototypes
@@ -318,6 +337,12 @@ void set_mac_nib(unsigned long mac_str_pos,
unsigned long mac_byte_pos, unsigned long mac_nib_pos);
unsigned short hextonum(char ch_s);
unsigned long rlong(void);
+#if defined(__linux__)
+#if defined(HAVE_GETRANDOM) || \
+ defined(HAVE_GETRANDOM_SYSCALL)
+int fallback_rand_getrandom(void *buf, size_t len);
+#endif
+#endif
void write_mac_part(unsigned long partnum);
/* Helper functions for command: dump
diff --git a/util/nvmutil/lib/num.c b/util/nvmutil/lib/num.c
index 48c8dee1..91b85e5b 100644
--- a/util/nvmutil/lib/num.c
+++ b/util/nvmutil/lib/num.c
@@ -75,6 +75,37 @@ rlong(void)
unsigned long rval;
long new_nr;
+ int retries = 0;
+ int max_retries = 100;
+
+#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
+ *
+ * similar benefits to arc4random
+ * e.g. works in chroot, blocks
+ * until it has enough entropy,
+ * and works even when /dev/urandom
+ * is available (doesn't use it);
+ * it's generally more reliable
+ */
+
+ if (fallback_rand_getrandom(&rval, sizeof(rval)) == 0)
+ 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
@@ -87,9 +118,6 @@ rlong(void)
* tricks to mitigate possible os bugs
*/
- int retries = 0;
- int max_retries = 100;
-
retry_urandom_read:
if (++retries > max_retries)
@@ -104,6 +132,10 @@ retry_urandom_read:
O_CLOEXEC);
#ifdef __OpenBSD__
+/* TODO: dead code
+ openbsd 2.1 had arc4random.
+ arandam was introduced **later**
+ */
if (fd < 0) /* old openbsd */
fd = open("/dev/arandom",
O_RDONLY | O_BINARY | O_NOFOLLOW |
@@ -178,6 +210,51 @@ rlong_next:
#endif
}
+#if defined(__linux__)
+#if defined(HAVE_GETRANDOM) || \
+ defined(HAVE_GETRANDOM_SYSCALL)
+int
+fallback_rand_getrandom(void *buf, size_t len)
+{
+ ssize_t rval = -1;
+
+ /* keep strict compiler
+ * happy if unused
+ */
+ (void)rval;
+ (void)buf;
+ (void)len;
+
+#if defined(HAVE_GETRANDOM)
+ do {
+ rval = getrandom(buf, len, 0);
+ } while (rval < 0 && errno == EINTR);
+
+#elif defined(HAVE_GETRANDOM_SYSCALL)
+ do {
+ rval = syscall(SYS_getrandom, buf, len, 0);
+ } while (ret < 0 && errno == EINTR);
+
+#else
+ return -1;
+#endif
+
+#if defined(HAVE_GETRANDOM) || \
+ defined(HAVE_GETRANDOM_SYSCALL)
+
+ if (rval == (ssize_t)len) {
+ return 0;
+ }
+
+ if (rval < 0 && errno == ENOSYS)
+ return -1; /* not supported by kernel */
+
+ return -1;
+#endif
+}
+#endif
+#endif
+
void
check_bin(unsigned long a, const char *a_name)
{