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];
|
(sizeof(unsigned int) >= 4) ? 1 : -1];
|
||||||
typedef char static_assert_unsigned_long_is_4[
|
typedef char static_assert_unsigned_long_is_4[
|
||||||
(sizeof(unsigned long) >= 4) ? 1 : -1];
|
(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_int_ge_32[(sizeof(int) >= 4) ? 1 : -1];
|
||||||
typedef char static_assert_twos_complement[
|
typedef char static_assert_twos_complement[
|
||||||
((-1 & 3) == 3) ? 1 : -1
|
((-1 & 3) == 3) ? 1 : -1
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "../include/common.h"
|
#include "../include/common.h"
|
||||||
@@ -57,36 +58,123 @@ rlong(void)
|
|||||||
|
|
||||||
return rval;
|
return rval;
|
||||||
#else
|
#else
|
||||||
int fd;
|
static int fd = -1;
|
||||||
|
static long nr = -1;
|
||||||
long nr;
|
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;
|
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__
|
#ifdef __OpenBSD__
|
||||||
if (fd < 0) /* old 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
|
#endif
|
||||||
|
|
||||||
if (fd < 0)
|
#ifdef PORTABLE_RAND_DEV
|
||||||
fd = open("/dev/random", O_RDONLY | O_BINARY);
|
#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)
|
if (fd < 0)
|
||||||
err(errno, "can't open random device");
|
fd = open("/dev/random",
|
||||||
|
O_RDONLY | O_BINARY | O_NOFOLLOW |
|
||||||
|
O_CLOEXEC);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
nr = rw_file_exact(fd, (unsigned char *)&rval,
|
if (fd < 0)
|
||||||
sizeof(unsigned long), 0, IO_READ, LOOP_EAGAIN,
|
goto retry_urandom_read;
|
||||||
LOOP_EINTR, MAX_ZERO_RW_RETRY, OFF_ERR);
|
|
||||||
|
|
||||||
if (close_on_eintr(fd) < 0)
|
retries = 0;
|
||||||
err(errno, "Can't close randomness fd");
|
}
|
||||||
|
|
||||||
if (nr != sizeof(unsigned long))
|
new_nr = rw_file_exact(fd, (unsigned char *)rbuf,
|
||||||
err(errno, "Incomplete read from random device");
|
sizeof(rbuf), 0, IO_READ, LOOP_EAGAIN,
|
||||||
|
LOOP_EINTR, MAX_ZERO_RW_RETRY, OFF_ERR);
|
||||||
|
|
||||||
|
if (new_nr < 0 || new_nr < (long)sizeof(rbuf))
|
||||||
|
goto retry_urandom_read;
|
||||||
|
|
||||||
|
/* 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;
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user