diff options
| author | Leah Rowe <leah@libreboot.org> | 2026-03-19 18:34:28 +0000 |
|---|---|---|
| committer | Leah Rowe <leah@libreboot.org> | 2026-03-19 18:34:28 +0000 |
| commit | f8b07dba2932714507f7ead6b8464ba3157d84bd (patch) | |
| tree | 3e16546c3827d7a18f5b14ec28217161eb0f01f2 | |
| parent | 7c66a788bdfc8136a603eec6d805b75cc382b239 (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.h | 25 | ||||
| -rw-r--r-- | util/nvmutil/lib/num.c | 83 |
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) { |
