random(4): Add is_random_seeded(9) KPI

The imagined use is for early boot consumers of random to be able to make
decisions based on whether random is available yet or not.  One such
consumer seems to be __stack_chk_init(), which runs immediately after random
is initialized.  A follow-up patch will attempt to address that.

Reported by:	many
Reviewed by:	delphij (except man page)
Approved by:	secteam(delphij)
Differential Revision:	https://reviews.freebsd.org/D19926
This commit is contained in:
Conrad Meyer 2019-04-16 17:12:17 +00:00
parent 2866548c8a
commit f3d2512db6
8 changed files with 59 additions and 5 deletions

View File

@ -31,6 +31,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
disable the most expensive debugging functionality run disable the most expensive debugging functionality run
"ln -s 'abort:false,junk:false' /etc/malloc.conf".) "ln -s 'abort:false,junk:false' /etc/malloc.conf".)
20190416:
The loadable random module KPI has changed; the random_infra_init()
routine now requires a 3rd function pointer for a bool (*)(void)
method that returns true if the random device is seeded (and
therefore unblocked).
20190404: 20190404:
r345895 reverts r320698. This implies that an nfsuserd(8) daemon r345895 reverts r320698. This implies that an nfsuserd(8) daemon
built from head sources between r320757 (July 6, 2017) and built from head sources between r320757 (July 6, 2017) and

View File

@ -1668,6 +1668,7 @@ MLINKS+=psignal.9 gsignal.9 \
psignal.9 tdsignal.9 psignal.9 tdsignal.9
MLINKS+=random.9 arc4rand.9 \ MLINKS+=random.9 arc4rand.9 \
random.9 arc4random.9 \ random.9 arc4random.9 \
random.9 is_random_seeded.9 \
random.9 read_random.9 \ random.9 read_random.9 \
random.9 read_random_uio.9 \ random.9 read_random_uio.9 \
random.9 srandom.9 random.9 srandom.9

View File

@ -26,13 +26,14 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" " .\" "
.Dd April 15, 2019 .Dd April 16, 2019
.Dt RANDOM 9 .Dt RANDOM 9
.Os .Os
.Sh NAME .Sh NAME
.Nm arc4rand , .Nm arc4rand ,
.Nm arc4random , .Nm arc4random ,
.Nm arc4random_buf , .Nm arc4random_buf ,
.Nm is_random_seeded ,
.Nm random , .Nm random ,
.Nm read_random , .Nm read_random ,
.Nm read_random_uio , .Nm read_random_uio ,
@ -48,6 +49,8 @@
.Fn arc4rand "void *ptr" "u_int length" "int reseed" .Fn arc4rand "void *ptr" "u_int length" "int reseed"
.Pp .Pp
.In sys/random.h .In sys/random.h
.Ft bool
.Fn is_random_seeded "void"
.Ft void .Ft void
.Fn read_random "void *buffer" "int count" .Fn read_random "void *buffer" "int count"
.Ft int .Ft int
@ -108,6 +111,13 @@ instead, use the
family of functions. family of functions.
.Pp .Pp
The The
.Fn is_random_seeded
function can be used to check in advance if
.Fn read_random
will block.
(If random is seeded, it will not block.)
.Pp
The
.Fn read_random_uio .Fn read_random_uio
function behaves identically to function behaves identically to
.Xr read 2 .Xr read 2

View File

@ -63,12 +63,20 @@ null_read_random(void *dummy __unused, u_int dummy2 __unused)
panic("%s: no random module is loaded", __func__); panic("%s: no random module is loaded", __func__);
} }
static bool
null_is_random_seeded(void)
{
return (false);
}
struct random_readers { struct random_readers {
int (*read_random_uio)(struct uio *, bool); int (*read_random_uio)(struct uio *, bool);
void (*read_random)(void *, u_int); void (*read_random)(void *, u_int);
bool (*is_random_seeded)(void);
} random_reader_context = { } random_reader_context = {
(int (*)(struct uio *, bool))nullop, (int (*)(struct uio *, bool))nullop,
null_read_random, null_read_random,
null_is_random_seeded,
}; };
struct sx randomdev_config_lock; struct sx randomdev_config_lock;
@ -82,12 +90,15 @@ random_infra_sysinit(void *dummy __unused)
SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysinit, NULL); SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysinit, NULL);
void void
random_infra_init(int (*p_random_read_uio)(struct uio *, bool), void (*p_random_read)(void *, u_int)) random_infra_init(int (*p_random_read_uio)(struct uio *, bool),
void (*p_random_read)(void *, u_int),
bool (*p_is_random_seeded)(void))
{ {
RANDOM_CONFIG_X_LOCK(); RANDOM_CONFIG_X_LOCK();
random_reader_context.read_random_uio = p_random_read_uio; random_reader_context.read_random_uio = p_random_read_uio;
random_reader_context.read_random = p_random_read; random_reader_context.read_random = p_random_read;
random_reader_context.is_random_seeded = p_is_random_seeded;
RANDOM_CONFIG_X_UNLOCK(); RANDOM_CONFIG_X_UNLOCK();
} }
@ -98,6 +109,7 @@ random_infra_uninit(void)
RANDOM_CONFIG_X_LOCK(); RANDOM_CONFIG_X_LOCK();
random_reader_context.read_random_uio = (int (*)(struct uio *, bool))nullop; random_reader_context.read_random_uio = (int (*)(struct uio *, bool))nullop;
random_reader_context.read_random = null_read_random; random_reader_context.read_random = null_read_random;
random_reader_context.is_random_seeded = null_is_random_seeded;
RANDOM_CONFIG_X_UNLOCK(); RANDOM_CONFIG_X_UNLOCK();
} }
@ -129,4 +141,13 @@ read_random(void *buf, u_int len)
RANDOM_CONFIG_S_UNLOCK(); RANDOM_CONFIG_S_UNLOCK();
} }
bool
is_random_seeded(void)
{
RANDOM_CONFIG_S_LOCK();
random_reader_context.is_random_seeded();
RANDOM_CONFIG_S_UNLOCK();
}
#endif /* defined(RANDOM_LOADABLE) */ #endif /* defined(RANDOM_LOADABLE) */

View File

@ -62,11 +62,14 @@ __FBSDID("$FreeBSD$");
#if defined(RANDOM_LOADABLE) #if defined(RANDOM_LOADABLE)
#define READ_RANDOM_UIO _read_random_uio #define READ_RANDOM_UIO _read_random_uio
#define READ_RANDOM _read_random #define READ_RANDOM _read_random
#define IS_RANDOM_SEEDED _is_random_seeded
static int READ_RANDOM_UIO(struct uio *, bool); static int READ_RANDOM_UIO(struct uio *, bool);
static void READ_RANDOM(void *, u_int); static void READ_RANDOM(void *, u_int);
static bool IS_RANDOM_SEEDED(void);
#else #else
#define READ_RANDOM_UIO read_random_uio #define READ_RANDOM_UIO read_random_uio
#define READ_RANDOM read_random #define READ_RANDOM read_random
#define IS_RANDOM_SEEDED is_random_seeded
#endif #endif
static d_read_t randomdev_read; static d_read_t randomdev_read;
@ -93,7 +96,7 @@ random_alg_context_ra_init_alg(void *data)
p_random_alg_context = &random_alg_context; p_random_alg_context = &random_alg_context;
p_random_alg_context->ra_init_alg(data); p_random_alg_context->ra_init_alg(data);
#if defined(RANDOM_LOADABLE) #if defined(RANDOM_LOADABLE)
random_infra_init(READ_RANDOM_UIO, READ_RANDOM); random_infra_init(READ_RANDOM_UIO, READ_RANDOM, IS_RANDOM_SEEDED);
#endif #endif
} }
@ -271,6 +274,12 @@ READ_RANDOM(void *random_buf, u_int len)
} }
} }
bool
IS_RANDOM_SEEDED(void)
{
return (p_random_alg_context->ra_seeded());
}
static __inline void static __inline void
randomdev_accumulate(uint8_t *buf, u_int count) randomdev_accumulate(uint8_t *buf, u_int count)
{ {

View File

@ -118,7 +118,8 @@ extern struct sx randomdev_config_lock;
#define RANDOM_CONFIG_S_LOCK(x) sx_slock(&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_S_UNLOCK(x) sx_sunlock(&randomdev_config_lock)
#define RANDOM_CONFIG_DEINIT_LOCK(x) sx_destroy(&randomdev_config_lock) #define RANDOM_CONFIG_DEINIT_LOCK(x) sx_destroy(&randomdev_config_lock)
void random_infra_init(int (*)(struct uio *, bool), void (*)(void *, u_int)); void random_infra_init(int (*)(struct uio *, bool), void (*)(void *, u_int),
bool (*)(void));
void random_infra_uninit(void); void random_infra_uninit(void);
#endif #endif

View File

@ -60,7 +60,7 @@
* in the range 5 to 9. * in the range 5 to 9.
*/ */
#undef __FreeBSD_version #undef __FreeBSD_version
#define __FreeBSD_version 1300018 /* Master, propagated to newvers */ #define __FreeBSD_version 1300019 /* Master, propagated to newvers */
/* /*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,

View File

@ -40,6 +40,7 @@ struct uio;
#if defined(DEV_RANDOM) #if defined(DEV_RANDOM)
void read_random(void *, u_int); void read_random(void *, u_int);
int read_random_uio(struct uio *, bool); int read_random_uio(struct uio *, bool);
bool is_random_seeded(void);
#else #else
static __inline int static __inline int
read_random_uio(void *a __unused, u_int b __unused) read_random_uio(void *a __unused, u_int b __unused)
@ -50,6 +51,11 @@ static __inline void
read_random(void *a __unused, u_int b __unused) read_random(void *a __unused, u_int b __unused)
{ {
} }
static __inline bool
is_random_seeded(void)
{
return (false);
}
#endif #endif
/* /*