aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/random
diff options
context:
space:
mode:
authorConrad Meyer <cem@FreeBSD.org>2019-04-15 18:40:36 +0000
committerConrad Meyer <cem@FreeBSD.org>2019-04-15 18:40:36 +0000
commit13774e82285e8d5eb3afeff63760725f747f8581 (patch)
tree4e63f007ef63568f5bed09510f908fbcaa77f22c /sys/dev/random
parent16fba2f38a8258ea656bba74d52e55436464e66b (diff)
Notes
Diffstat (limited to 'sys/dev/random')
-rw-r--r--sys/dev/random/fortuna.c16
-rw-r--r--sys/dev/random/random_harvestq.c5
-rw-r--r--sys/dev/random/random_infra.c20
-rw-r--r--sys/dev/random/randomdev.c113
-rw-r--r--sys/dev/random/randomdev.h2
5 files changed, 98 insertions, 58 deletions
diff --git a/sys/dev/random/fortuna.c b/sys/dev/random/fortuna.c
index e8a407525138..a6cfccaa3a1a 100644
--- a/sys/dev/random/fortuna.c
+++ b/sys/dev/random/fortuna.c
@@ -451,16 +451,22 @@ random_fortuna_read(uint8_t *buf, u_int bytecount)
RANDOM_RESEED_UNLOCK();
}
+#ifdef _KERNEL
+static bool block_seeded_status = false;
+SYSCTL_BOOL(_kern_random, OID_AUTO, block_seeded_status, CTLFLAG_RWTUN,
+ &block_seeded_status, 0,
+ "If non-zero, pretend Fortuna is in an unseeded state. By setting "
+ "this as a tunable, boot can be tested as if the random device is "
+ "unavailable.");
+#endif
+
bool
random_fortuna_seeded(void)
{
#ifdef _KERNEL
- /* When set, act as if we are not seeded. */
- KFAIL_POINT_CODE(DEBUG_FP, random_fortuna_seeded, {
- if (RETURN_VALUE != 0)
- fortuna_state.fs_counter = UINT128_ZERO;
- });
+ if (block_seeded_status)
+ return (false);
#endif
return (!uint128_is_zero(fortuna_state.fs_counter));
diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c
index 3f5ecc7ddea3..d31a6a89a8b7 100644
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -421,11 +421,6 @@ random_harvestq_prime(void *unused __unused)
if (keyfile != NULL) {
data = preload_fetch_addr(keyfile);
size = preload_fetch_size(keyfile);
- /* skip the first bit of the stash so others like arc4 can also have some. */
- if (size > RANDOM_CACHED_SKIP_START) {
- data += RANDOM_CACHED_SKIP_START;
- size -= RANDOM_CACHED_SKIP_START;
- }
/* Trim the size. If the admin has a file with a funny size, we lose some. Tough. */
size -= (size % sizeof(event.he_entropy));
if (data != NULL && size != 0) {
diff --git a/sys/dev/random/random_infra.c b/sys/dev/random/random_infra.c
index d31b84b24582..324c40dcecd4 100644
--- a/sys/dev/random/random_infra.c
+++ b/sys/dev/random/random_infra.c
@@ -57,12 +57,18 @@ struct random_algorithm *p_random_alg_context = &random_alg_context;
#if defined(RANDOM_LOADABLE)
+static void
+null_read_random(void *dummy __unused, u_int dummy2 __unused)
+{
+ panic("%s: no random module is loaded", __func__);
+}
+
struct random_readers {
int (*read_random_uio)(struct uio *, bool);
- u_int (*read_random)(void *, u_int);
+ void (*read_random)(void *, u_int);
} random_reader_context = {
(int (*)(struct uio *, bool))nullop,
- (u_int (*)(void *, u_int))nullop,
+ null_read_random,
};
struct sx randomdev_config_lock;
@@ -76,7 +82,7 @@ random_infra_sysinit(void *dummy __unused)
SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysinit, NULL);
void
-random_infra_init(int (*p_random_read_uio)(struct uio *, bool), u_int (*p_random_read)(void *, u_int))
+random_infra_init(int (*p_random_read_uio)(struct uio *, bool), void (*p_random_read)(void *, u_int))
{
RANDOM_CONFIG_X_LOCK();
@@ -91,7 +97,7 @@ random_infra_uninit(void)
RANDOM_CONFIG_X_LOCK();
random_reader_context.read_random_uio = (int (*)(struct uio *, bool))nullop;
- random_reader_context.read_random = (u_int (*)(void *, u_int))nullop;
+ random_reader_context.read_random = null_read_random;
RANDOM_CONFIG_X_UNLOCK();
}
@@ -114,15 +120,13 @@ read_random_uio(struct uio *uio, bool nonblock)
return (retval);
}
-u_int
+void
read_random(void *buf, u_int len)
{
- u_int retval;
RANDOM_CONFIG_S_LOCK();
- retval = random_reader_context.read_random(buf, len);
+ random_reader_context.read_random(buf, len);
RANDOM_CONFIG_S_UNLOCK();
- return (retval);
}
#endif /* defined(RANDOM_LOADABLE) */
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c
index 94bd2f1a4147..19a73b28151a 100644
--- a/sys/dev/random/randomdev.c
+++ b/sys/dev/random/randomdev.c
@@ -63,7 +63,7 @@ __FBSDID("$FreeBSD$");
#define READ_RANDOM_UIO _read_random_uio
#define READ_RANDOM _read_random
static int READ_RANDOM_UIO(struct uio *, bool);
-static u_int READ_RANDOM(void *, u_int);
+static void READ_RANDOM(void *, u_int);
#else
#define READ_RANDOM_UIO read_random_uio
#define READ_RANDOM read_random
@@ -124,11 +124,53 @@ randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags)
return (READ_RANDOM_UIO(uio, (flags & O_NONBLOCK) != 0));
}
+/*
+ * If the random device is not seeded, blocks until it is seeded.
+ *
+ * Returns zero when the random device is seeded.
+ *
+ * If the 'interruptible' parameter is true, and the device is unseeded, this
+ * routine may be interrupted. If interrupted, it will return either ERESTART
+ * or EINTR.
+ */
+#define SEEDWAIT_INTERRUPTIBLE true
+#define SEEDWAIT_UNINTERRUPTIBLE false
+static int
+randomdev_wait_until_seeded(bool interruptible)
+{
+ int error, spamcount, slpflags;
+
+ slpflags = interruptible ? PCATCH : 0;
+
+ error = 0;
+ spamcount = 0;
+ while (!p_random_alg_context->ra_seeded()) {
+ /* keep tapping away at the pre-read until we seed/unblock. */
+ p_random_alg_context->ra_pre_read();
+ /* Only bother the console every 10 seconds or so */
+ if (spamcount == 0)
+ printf("random: %s unblock wait\n", __func__);
+ spamcount = (spamcount + 1) % 100;
+ error = tsleep(&random_alg_context, slpflags, "randseed",
+ hz / 10);
+ if (error == ERESTART || error == EINTR) {
+ KASSERT(interruptible,
+ ("unexpected wake of non-interruptible sleep"));
+ break;
+ }
+ /* Squash tsleep timeout condition */
+ if (error == EWOULDBLOCK)
+ error = 0;
+ KASSERT(error == 0, ("unexpected tsleep error %d", error));
+ }
+ return (error);
+}
+
int
READ_RANDOM_UIO(struct uio *uio, bool nonblock)
{
uint8_t *random_buf;
- int error, spamcount;
+ int error;
ssize_t read_len, total_read, c;
/* 16 MiB takes about 0.08 s CPU time on my 2017 AMD Zen CPU */
#define SIGCHK_PERIOD (16 * 1024 * 1024)
@@ -140,26 +182,13 @@ READ_RANDOM_UIO(struct uio *uio, bool nonblock)
random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
p_random_alg_context->ra_pre_read();
error = 0;
- spamcount = 0;
/* (Un)Blocking logic */
- while (!p_random_alg_context->ra_seeded()) {
- if (nonblock) {
+ if (!p_random_alg_context->ra_seeded()) {
+ if (nonblock)
error = EWOULDBLOCK;
- break;
- }
- /* keep tapping away at the pre-read until we seed/unblock. */
- p_random_alg_context->ra_pre_read();
- /* Only bother the console every 10 seconds or so */
- if (spamcount == 0)
- printf("random: %s unblock wait\n", __func__);
- spamcount = (spamcount + 1)%100;
- error = tsleep(&random_alg_context, PCATCH, "randseed", hz/10);
- if (error == ERESTART || error == EINTR)
- break;
- /* Squash tsleep timeout condition */
- if (error == EWOULDBLOCK)
- error = 0;
- KASSERT(error == 0, ("unexpected tsleep error %d", error));
+ else
+ error = randomdev_wait_until_seeded(
+ SEEDWAIT_INTERRUPTIBLE);
}
if (error == 0) {
read_rate_increment((uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t));
@@ -210,30 +239,36 @@ READ_RANDOM_UIO(struct uio *uio, bool nonblock)
* It cannot assumed that random_buf is a multiple of
* RANDOM_BLOCKSIZE bytes.
*/
-u_int
+void
READ_RANDOM(void *random_buf, u_int len)
{
- u_int read_len;
- uint8_t local_buf[len + RANDOM_BLOCKSIZE];
+ u_int read_directly_len;
KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__));
p_random_alg_context->ra_pre_read();
- /* (Un)Blocking logic; if not seeded, return nothing. */
- if (p_random_alg_context->ra_seeded()) {
- read_rate_increment((len + sizeof(uint32_t))/sizeof(uint32_t));
- if (len > 0) {
- /*
- * Belt-and-braces.
- * Round up the read length to a crypto block size multiple,
- * which is what the underlying generator is expecting.
- */
- read_len = roundup(len, RANDOM_BLOCKSIZE);
- p_random_alg_context->ra_read(local_buf, read_len);
- memcpy(random_buf, local_buf, len);
- }
- } else
- len = 0;
- return (len);
+ /* (Un)Blocking logic */
+ if (!p_random_alg_context->ra_seeded())
+ (void)randomdev_wait_until_seeded(SEEDWAIT_UNINTERRUPTIBLE);
+ read_rate_increment(roundup2(len, sizeof(uint32_t)));
+ if (len == 0)
+ return;
+ /*
+ * The underlying generator expects multiples of
+ * RANDOM_BLOCKSIZE.
+ */
+ read_directly_len = rounddown(len, RANDOM_BLOCKSIZE);
+ if (read_directly_len > 0)
+ p_random_alg_context->ra_read(random_buf, read_directly_len);
+ if (read_directly_len < len) {
+ uint8_t remainder_buf[RANDOM_BLOCKSIZE];
+
+ p_random_alg_context->ra_read(remainder_buf,
+ sizeof(remainder_buf));
+ memcpy((char *)random_buf + read_directly_len, remainder_buf,
+ len - read_directly_len);
+
+ explicit_bzero(remainder_buf, sizeof(remainder_buf));
+ }
}
static __inline void
diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h
index 0f3b359d1f1f..41300f237aaf 100644
--- a/sys/dev/random/randomdev.h
+++ b/sys/dev/random/randomdev.h
@@ -118,7 +118,7 @@ extern struct sx randomdev_config_lock;
#define RANDOM_CONFIG_S_LOCK(x) sx_slock(&randomdev_config_lock)
#define RANDOM_CONFIG_S_UNLOCK(x) sx_sunlock(&randomdev_config_lock)
#define RANDOM_CONFIG_DEINIT_LOCK(x) sx_destroy(&randomdev_config_lock)
-void random_infra_init(int (*)(struct uio *, bool), u_int (*)(void *, u_int));
+void random_infra_init(int (*)(struct uio *, bool), void (*)(void *, u_int));
void random_infra_uninit(void);
#endif