util/nvmutil: more reliable fallback crypto

we assume the fallback will be rare, so now we
make the mix static and keep xoring it, on the
theory that the number of failures on urandom
will be random, and tthat the fallback may only
apply once or twice in thousands of calls.

the time jitter is adjusted; rather than judge
the difference between two points close to each
other in time, we judge tthe randomness in
difference of time elapsed. this mitigates fast
CPUs being very fast and introducing rounding
errors, and also improves performonce on much
slower CPUs

Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
Leah Rowe
2026-03-16 20:53:46 +00:00
parent a575a47733
commit 251ba82ccb
+44 -49
View File
@@ -373,8 +373,7 @@ void set_mac_byte(unsigned long mac_byte_pos);
void set_mac_nib(unsigned long mac_str_pos, void set_mac_nib(unsigned long mac_str_pos,
unsigned long mac_byte_pos, unsigned long mac_nib_pos); unsigned long mac_byte_pos, unsigned long mac_nib_pos);
unsigned short hextonum(char ch_s); unsigned short hextonum(char ch_s);
unsigned short rhex(void); unsigned long rlong(void);
unsigned short read_urandom(void);
unsigned long entropy_jitter(void); unsigned long entropy_jitter(void);
int x_i_gettimeofday(struct x_st_timeval *tv, void *tz); int x_i_gettimeofday(struct x_st_timeval *tv, void *tz);
void write_mac_part(unsigned long partnum); void write_mac_part(unsigned long partnum);
@@ -1364,30 +1363,25 @@ hextonum(char ch_s)
return ch - 'a' + 10; return ch - 'a' + 10;
if (ch == '?' || ch == 'x') if (ch == '?' || ch == 'x')
return rhex(); /* random character */ return rlong() & 0xf;
return 16; /* invalid character */ return 16; /* invalid character */
} }
unsigned short unsigned long
rhex(void) rlong(void)
{ {
struct x_st_timeval tv; struct x_st_timeval tv;
unsigned long mix; static unsigned long mix = 0;
static unsigned long counter = 0; static unsigned long counter = 0;
unsigned short r;
/* Read /dev/urandom static int fd = -1;
* if possible */ unsigned long rval = 0;
r = read_urandom(); long nr = -1;
if (r < 16)
return r;
/* Fallback */
x_i_gettimeofday(&tv, NULL); x_i_gettimeofday(&tv, NULL);
mix = (unsigned long)tv.tv_sec mix ^= (unsigned long)tv.tv_sec
^ (unsigned long)tv.tv_usec ^ (unsigned long)tv.tv_usec
^ (unsigned long)getpid() ^ (unsigned long)getpid()
^ (unsigned long)&mix ^ (unsigned long)&mix
@@ -1402,45 +1396,45 @@ rhex(void)
mix ^= (unsigned long)&tv; mix ^= (unsigned long)&tv;
mix ^= (unsigned long)&counter; mix ^= (unsigned long)&counter;
return (unsigned short)(mix & 0xf); /*
} * Now, we won't use this mix
* immediately. We'll try to
unsigned short * read urandom first, which is
read_urandom(void) * likely safer, and pass that,
{ * falling back to the mixture
static int fd = -1; * if urandom fails.
static long n = -1; *
* Since urandom is likely
static unsigned char r[256]; * reliable, the number of
* times it will fail is
if (fd < 0) { * likely extremely random,
* thus, building more than
fd = open("/dev/urandom", O_RDONLY | O_NONBLOCK); * sufficient entropy by the
#ifndef NVMUTIL_UNVEIL * time we do eventually use
if (fd < 0) /* older openbsd */ * the fallback code
fd = open("/dev/arandom", O_RDONLY | O_NONBLOCK); */
#endif
if (fd < 0) /* super old unix (could block) */
fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (fd < 0) if (fd < 0)
return 16; fd = open("/dev/urandom", O_RDONLY | O_BINARY | O_NONBLOCK);
}
if (n < 0) { #if !(defined(__OpenBSD__) && defined(OpenBSD)) || \
(defined(__OpenBSD__) && defined(OpenBSD) && \
OpenBSD < 604)
if (fd < 0) /* old openbsd */
fd = open("/dev/arandom", O_RDONLY | O_BINARY | O_NONBLOCK);
#endif
n = rw_file_exact(fd, r, 256, 0, IO_READ, if (fd < 0)
LOOP_EAGAIN, LOOP_EINTR, 2, OFF_ERR); fd = open("/dev/random", O_RDONLY | O_BINARY | O_NONBLOCK);
if (n == 0) nr = rw_file_exact(fd, (unsigned char *)&rval,
n = -1; sizeof(unsigned long), 0, IO_READ, LOOP_EAGAIN,
if (n < 0) LOOP_EINTR, MAX_ZERO_RW_RETRY, OFF_ERR);
return 16;
--n; if (nr == sizeof(unsigned long))
} return rval;
return r[n--] & 0xf; return mix;
} }
unsigned long unsigned long
@@ -1451,8 +1445,9 @@ entropy_jitter(void)
long mix_diff; long mix_diff;
int i; int i;
for (i = 0; i < 8; i++) {
x_i_gettimeofday(&a, NULL); x_i_gettimeofday(&a, NULL);
for (i = 0; i < 8; i++) {
getpid(); getpid();
x_i_gettimeofday(&b, NULL); x_i_gettimeofday(&b, NULL);
@@ -3043,7 +3038,7 @@ x_i_mkstemp(char *template)
for (i = 0; i < 100; i++) { for (i = 0; i < 100; i++) {
for (j = 0; j < 6; j++) for (j = 0; j < 6; j++)
p[j] = ch[rhex() & 31]; p[j] = ch[rlong() & 31];
fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600); fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600);