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
* read urandom first, which is
* likely safer, and pass that,
* falling back to the mixture
* if urandom fails.
*
* Since urandom is likely
* reliable, the number of
* times it will fail is
* likely extremely random,
* thus, building more than
* sufficient entropy by the
* time we do eventually use
* the fallback code
*/
unsigned short if (fd < 0)
read_urandom(void) fd = open("/dev/urandom", O_RDONLY | O_BINARY | O_NONBLOCK);
{
static int fd = -1;
static long n = -1;
static unsigned char r[256]; #if !(defined(__OpenBSD__) && defined(OpenBSD)) || \
(defined(__OpenBSD__) && defined(OpenBSD) && \
if (fd < 0) { OpenBSD < 604)
if (fd < 0) /* old openbsd */
fd = open("/dev/urandom", O_RDONLY | O_NONBLOCK); fd = open("/dev/arandom", O_RDONLY | O_BINARY | O_NONBLOCK);
#ifndef NVMUTIL_UNVEIL
if (fd < 0) /* older openbsd */
fd = open("/dev/arandom", O_RDONLY | O_NONBLOCK);
#endif #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/random", O_RDONLY | O_BINARY | O_NONBLOCK);
}
if (n < 0) { nr = rw_file_exact(fd, (unsigned char *)&rval,
sizeof(unsigned long), 0, IO_READ, LOOP_EAGAIN,
LOOP_EINTR, MAX_ZERO_RW_RETRY, OFF_ERR);
n = rw_file_exact(fd, r, 256, 0, IO_READ, if (nr == sizeof(unsigned long))
LOOP_EAGAIN, LOOP_EINTR, 2, OFF_ERR); return rval;
if (n == 0) return mix;
n = -1;
if (n < 0)
return 16;
--n;
}
return r[n--] & 0xf;
} }
unsigned long unsigned long
@@ -1451,8 +1445,9 @@ entropy_jitter(void)
long mix_diff; long mix_diff;
int i; int i;
x_i_gettimeofday(&a, NULL);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
x_i_gettimeofday(&a, NULL);
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);