Changeset View
Standalone View
sys/dev/random/random_infra.c
Show All 29 Lines | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/random.h> | #include <sys/random.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#if defined(RANDOM_LOADABLE) | |||||
#include <sys/lock.h> | |||||
#include <sys/sx.h> | |||||
#endif | |||||
#include <dev/random/randomdev.h> | #include <dev/random/randomdev.h> | ||||
/* Set up the sysctl root node for the entropy device */ | /* Set up the sysctl root node for the entropy device */ | ||||
SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, | SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, | ||||
"Cryptographically Secure Random Number Generator"); | "Cryptographically Secure Random Number Generator"); | ||||
SYSCTL_NODE(_kern_random, OID_AUTO, initial_seeding, CTLFLAG_RW, 0, | SYSCTL_NODE(_kern_random, OID_AUTO, initial_seeding, CTLFLAG_RW, 0, | ||||
"Initial seeding control and information"); | "Initial seeding control and information"); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
SYSCTL_BOOL(_kern_random_initial_seeding, OID_AUTO, | SYSCTL_BOOL(_kern_random_initial_seeding, OID_AUTO, | ||||
disable_bypass_warnings, CTLFLAG_RDTUN, | disable_bypass_warnings, CTLFLAG_RDTUN, | ||||
&random_bypass_disable_warnings, 0, "If non-zero, do not log a warning " | &random_bypass_disable_warnings, 0, "If non-zero, do not log a warning " | ||||
"if the 'bypass_before_seeding' knob is enabled and a request is " | "if the 'bypass_before_seeding' knob is enabled and a request is " | ||||
"submitted prior to initial seeding."); | "submitted prior to initial seeding."); | ||||
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); | MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); | ||||
#if defined(RANDOM_LOADABLE) | #if defined(RANDOM_LOADABLE) | ||||
struct random_algorithm *p_random_alg_context = NULL; | const struct random_algorithm *p_random_alg_context; | ||||
cem: This change makes 3-4 assumptions:
1. Pointer-sized and natively aligned stores are atomic on… | |||||
Not Done Inline ActionsWhen I did the last load of major code updates in this area, there was a LOT of pushback, some of it idealistic (the people who wanted every choice to be made by the owner/operator, at least by high principle), and some of it from the folks who wanted/needed *small* systems with most components unloadable if not deletable. Most of those objections seem to have quietened down now. I'd be *delighted* to see the RANDOM_LOADABLE facility gone. Keep the KLD ability, please - it's nice to be able to test e.g. the NIST algorithms. markm: When I did the last load of major code updates in this area, there was a LOT of pushback, some… | |||||
Done Inline ActionsOn second thought, this unrelated change may break userspace load (arc4random will be fine, but there are many direct read_random callers and I have not audited all of them for is_random_seeded checks). So I will drop it from a subsequent revisions of this diff. cem: On second thought, this unrelated change may break userspace load (arc4random will be fine, but… | |||||
#else /* !defined(RANDOM_LOADABLE) */ | void (*_read_random)(void *, u_int); | ||||
struct random_algorithm *p_random_alg_context = &random_alg_context; | int (*_read_random_uio)(struct uio *, bool); | ||||
#endif /* defined(RANDOM_LOADABLE) */ | bool (*_is_random_seeded)(void); | ||||
#if defined(RANDOM_LOADABLE) | |||||
static void | |||||
null_read_random(void *dummy __unused, u_int dummy2 __unused) | |||||
{ | |||||
panic("%s: no random module is loaded", __func__); | |||||
} | |||||
static bool | |||||
null_is_random_seeded(void) | |||||
{ | |||||
return (false); | |||||
} | |||||
struct random_readers { | |||||
int (*read_random_uio)(struct uio *, bool); | |||||
void (*read_random)(void *, u_int); | |||||
bool (*is_random_seeded)(void); | |||||
} random_reader_context = { | |||||
(int (*)(struct uio *, bool))nullop, | |||||
null_read_random, | |||||
null_is_random_seeded, | |||||
}; | |||||
struct sx randomdev_config_lock; | |||||
static void | |||||
random_infra_sysinit(void *dummy __unused) | |||||
{ | |||||
RANDOM_CONFIG_INIT_LOCK(); | |||||
} | |||||
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), | |||||
void (*p_random_read)(void *, u_int), | |||||
bool (*p_is_random_seeded)(void)) | |||||
{ | |||||
RANDOM_CONFIG_X_LOCK(); | |||||
random_reader_context.read_random_uio = p_random_read_uio; | |||||
random_reader_context.read_random = p_random_read; | |||||
random_reader_context.is_random_seeded = p_is_random_seeded; | |||||
RANDOM_CONFIG_X_UNLOCK(); | |||||
} | |||||
void | |||||
random_infra_uninit(void) | |||||
{ | |||||
RANDOM_CONFIG_X_LOCK(); | |||||
random_reader_context.read_random_uio = (int (*)(struct uio *, bool))nullop; | |||||
random_reader_context.read_random = null_read_random; | |||||
random_reader_context.is_random_seeded = null_is_random_seeded; | |||||
RANDOM_CONFIG_X_UNLOCK(); | |||||
} | |||||
static void | |||||
random_infra_sysuninit(void *dummy __unused) | |||||
{ | |||||
RANDOM_CONFIG_DEINIT_LOCK(); | |||||
} | |||||
SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_FIRST, random_infra_sysuninit, NULL); | |||||
int | |||||
read_random_uio(struct uio *uio, bool nonblock) | |||||
{ | |||||
int retval; | |||||
RANDOM_CONFIG_S_LOCK(); | |||||
retval = random_reader_context.read_random_uio(uio, nonblock); | |||||
RANDOM_CONFIG_S_UNLOCK(); | |||||
return (retval); | |||||
} | |||||
void | |||||
read_random(void *buf, u_int len) | |||||
{ | |||||
RANDOM_CONFIG_S_LOCK(); | |||||
random_reader_context.read_random(buf, len); | |||||
RANDOM_CONFIG_S_UNLOCK(); | |||||
} | |||||
bool | |||||
is_random_seeded(void) | |||||
{ | |||||
bool result; | |||||
RANDOM_CONFIG_S_LOCK(); | |||||
result = random_reader_context.is_random_seeded(); | |||||
RANDOM_CONFIG_S_UNLOCK(); | |||||
return (result); | |||||
} | |||||
#endif /* defined(RANDOM_LOADABLE) */ | #endif /* defined(RANDOM_LOADABLE) */ |
This change makes 3-4 assumptions:
Are 1-2 true, or should we instead use the atomic_store_rel / atomic_load_acq wrappers? Maybe that would show intent better even if the assumption is true.
My 4th assumption is this: that we care about being able to load a random.ko from kldload in userspace (for example, because the architecture does not use loader(8), or some other reason). If we don't need to be able to kldload from userspace, we could simplify this a *ton* by removing all the wrappers and having the loadable random provide the read_random_foo and is_random_seeded symbols directly. That would remove all of the assumptions above, and still remove the need for any configuration lock.
Thoughts?
I don't know what the consumers of random_loadable actually want from the interface. I'd prefer to just remove support entirely and let downstreams hack their proprietary random modules into their own downstream source trees in a way that meets their needs. Does anyone else consider that an option?