mirror of
https://codeberg.org/libreboot/lbmk.git
synced 2026-03-25 13:29:03 +02:00
util/nvmutil: buffered urandom reads
also generally tidied the code and made it more robust e.g. retries Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
@@ -438,6 +438,8 @@ typedef char static_assert_unsigned_int_is_4[
|
||||
(sizeof(unsigned int) >= 4) ? 1 : -1];
|
||||
typedef char static_assert_unsigned_long_is_4[
|
||||
(sizeof(unsigned long) >= 4) ? 1 : -1];
|
||||
typedef char static_assert_long_ulong[
|
||||
(sizeof(unsigned long) == sizeof(long)) ? 1 : -1];
|
||||
typedef char static_assert_int_ge_32[(sizeof(int) >= 4) ? 1 : -1];
|
||||
typedef char static_assert_twos_complement[
|
||||
((-1 & 3) == 3) ? 1 : -1
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../include/common.h"
|
||||
@@ -57,36 +58,123 @@ rlong(void)
|
||||
|
||||
return rval;
|
||||
#else
|
||||
int fd;
|
||||
|
||||
long nr;
|
||||
|
||||
static int fd = -1;
|
||||
static long nr = -1;
|
||||
static unsigned long 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
|
||||
unsigned long rval;
|
||||
long new_nr;
|
||||
|
||||
fd = open("/dev/urandom", O_RDONLY | O_BINARY);
|
||||
/* 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
|
||||
*/
|
||||
|
||||
int retries = 0;
|
||||
int max_retries = 100;
|
||||
|
||||
retry_urandom_read:
|
||||
|
||||
if (++retries > max_retries)
|
||||
goto rlong_next;
|
||||
|
||||
if (nr < 0 || nr < (long)sizeof(unsigned long)) {
|
||||
|
||||
if (fd < 0) {
|
||||
|
||||
fd = open("/dev/urandom",
|
||||
O_RDONLY | O_BINARY | O_NOFOLLOW |
|
||||
O_CLOEXEC);
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
if (fd < 0) /* old openbsd */
|
||||
fd = open("/dev/arandom", O_RDONLY | O_BINARY);
|
||||
fd = open("/dev/arandom",
|
||||
O_RDONLY | O_BINARY | O_NOFOLLOW |
|
||||
O_CLOEXEC);
|
||||
#endif
|
||||
|
||||
#ifdef PORTABLE_RAND_DEV
|
||||
#if (PORTABLE_RAND_DEV) > 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);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (fd < 0)
|
||||
fd = open("/dev/random", O_RDONLY | O_BINARY);
|
||||
goto retry_urandom_read;
|
||||
|
||||
if (fd < 0)
|
||||
err(errno, "can't open random device");
|
||||
retries = 0;
|
||||
}
|
||||
|
||||
nr = rw_file_exact(fd, (unsigned char *)&rval,
|
||||
sizeof(unsigned long), 0, IO_READ, LOOP_EAGAIN,
|
||||
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 (close_on_eintr(fd) < 0)
|
||||
err(errno, "Can't close randomness fd");
|
||||
if (new_nr < 0 || new_nr < (long)sizeof(rbuf))
|
||||
goto retry_urandom_read;
|
||||
|
||||
if (nr != sizeof(unsigned long))
|
||||
err(errno, "Incomplete read from random device");
|
||||
/* only reset buffer after successful refill */
|
||||
nr = new_nr;
|
||||
off = 0;
|
||||
|
||||
/* to mitigate file descriptor
|
||||
* injection, we do not re-use
|
||||
* the same descriptor each time
|
||||
*/
|
||||
(void) close_on_eintr(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
fd = -1;
|
||||
retries = 0;
|
||||
|
||||
memcpy(&rval, rbuf + off, sizeof(unsigned long));
|
||||
|
||||
nr -= (long)sizeof(unsigned long);
|
||||
off += sizeof(unsigned long);
|
||||
|
||||
return rval;
|
||||
|
||||
rlong_next:
|
||||
|
||||
fd = -1;
|
||||
off = 0;
|
||||
nr = -1;
|
||||
|
||||
/* TODO: will re-add timer-based fallback here #if defined(PORTABLE) */
|
||||
|
||||
err(EIO, "Can't read from /dev/[ua]random");
|
||||
return 0;
|
||||
|
||||
/* add portable timers here */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user