git: 4e5efa1c801f - stable/12 - random(4): Simplify RANDOM_LOADABLE
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 22 Feb 2022 07:28:58 UTC
The branch stable/12 has been updated by obrien: URL: https://cgit.FreeBSD.org/src/commit/?id=4e5efa1c801f8201b77ea40db98f3fcb672d4f7d commit 4e5efa1c801f8201b77ea40db98f3fcb672d4f7d Author: Conrad Meyer <cem@FreeBSD.org> AuthorDate: 2019-12-26 19:32:11 +0000 Commit: David E. O'Brien <obrien@FreeBSD.org> CommitDate: 2022-02-22 06:20:48 +0000 random(4): Simplify RANDOM_LOADABLE Simplify RANDOM_LOADABLE by removing the ability to unload a LOADABLE random(4) implementation. This allows one-time random module selection at boot, by loader(8). Swapping modules on the fly doesn't seem especially useful. This removes the need to hold a lock over the sleepable module calls read_random and read_random_uio. init/deinit have been pulled out of random_algorithm entirely. Algorithms can run their own sysinits to initialize; deinit is removed entirely, as algorithms can not be unloaded. Algorithms should initialize at SI_SUB_RANDOM:SI_ORDER_SECOND. In LOADABLE systems, algorithms install a pointer to their local random_algorithm context in p_random_alg_context at that time. Go ahead and const'ify random_algorithm objects; there is no need to mutate them at runtime. LOADABLE kernel NULL checks are removed from random_harvestq by ordering random_harvestq initialization at SI_SUB_RANDOM:SI_ORDER_THIRD, after algorithm init. Prior to random_harvestq init, hc_harvest_mask is zero and no events are forwarded to algorithms; after random_harvestq init, the relevant pointers will already have been installed. Remove the bulk of random_infra shim wrappers and instead expose the bare function pointers in sys/random.h. In LOADABLE systems, read_random(9) et al are just thin shim macros around invoking the associated function pointer. We do not provide a registration system but instead expect LOADABLE modules to register themselves at SI_SUB_RANDOM:SI_ORDER_SECOND. An example is provided in randomdev.c, as used in the random_fortuna.ko module. (cherry picked from commit 3ee1d5bb9dc2db929b19ca59421d197153dbdc08) --- UPDATING | 4 ++ sys/dev/random/fortuna.c | 27 ++++------ sys/dev/random/other_algorithm.c | 37 ++++--------- sys/dev/random/random_harvestq.c | 25 +-------- sys/dev/random/random_infra.c | 112 ++------------------------------------- sys/dev/random/randomdev.c | 63 +++++++++------------- sys/dev/random/randomdev.h | 22 +++----- sys/sys/random.h | 29 +++++++++- 8 files changed, 90 insertions(+), 229 deletions(-) diff --git a/UPDATING b/UPDATING index de06358e7420..7b02a623823d 100644 --- a/UPDATING +++ b/UPDATING @@ -17,6 +17,10 @@ from older versions of FreeBSD, try WITHOUT_CLANG and WITH_GCC to bootstrap to the tip of head, and then rebuild without this option. The bootstrap process from older version of current across the gcc/clang cutover is a bit fragile. +20220222: + Kernel-loadable random(4) modules are supported again, but are no + longer unloadable. + 20220214: The following knobs have been added related to tradeoffs between safe use of the random device and availability in the absence of diff --git a/sys/dev/random/fortuna.c b/sys/dev/random/fortuna.c index 52e93a594014..71ef7a5e7d84 100644 --- a/sys/dev/random/fortuna.c +++ b/sys/dev/random/fortuna.c @@ -261,15 +261,14 @@ static void random_fortuna_read(uint8_t *, size_t); static bool random_fortuna_seeded(void); static bool random_fortuna_seeded_internal(void); static void random_fortuna_process_event(struct harvest_event *); -static void random_fortuna_init_alg(void *); -static void random_fortuna_deinit_alg(void *); static void random_fortuna_reseed_internal(uint32_t *entropy_data, u_int blockcount); -struct random_algorithm random_alg_context = { +#ifdef RANDOM_LOADABLE +static +#endif +const struct random_algorithm random_alg_context = { .ra_ident = "Fortuna", - .ra_init_alg = random_fortuna_init_alg, - .ra_deinit_alg = random_fortuna_deinit_alg, .ra_pre_read = random_fortuna_pre_read, .ra_read = random_fortuna_read, .ra_seeded = random_fortuna_seeded, @@ -286,6 +285,10 @@ random_fortuna_init_alg(void *unused __unused) struct sysctl_oid *random_fortuna_o; #endif +#ifdef RANDOM_LOADABLE + p_random_alg_context = &random_alg_context; +#endif + RANDOM_RESEED_INIT_LOCK(); /* * Fortuna parameters. Do not adjust these unless you have @@ -330,18 +333,8 @@ random_fortuna_init_alg(void *unused __unused) fortuna_state.fs_counter = UINT128_ZERO; explicit_bzero(&fortuna_state.fs_key, sizeof(fortuna_state.fs_key)); } - -/* ARGSUSED */ -static void -random_fortuna_deinit_alg(void *unused __unused) -{ - - RANDOM_RESEED_DEINIT_LOCK(); - explicit_bzero(&fortuna_state, sizeof(fortuna_state)); -#ifdef _KERNEL - sysctl_ctx_free(&random_clist); -#endif -} +SYSINIT(random_alg, SI_SUB_RANDOM, SI_ORDER_SECOND, random_fortuna_init_alg, + NULL); /*- * FS&K - AddRandomEvent() diff --git a/sys/dev/random/other_algorithm.c b/sys/dev/random/other_algorithm.c index 4ed00c1156ff..b74d2ab6b860 100644 --- a/sys/dev/random/other_algorithm.c +++ b/sys/dev/random/other_algorithm.c @@ -87,8 +87,6 @@ static void random_other_pre_read(void); static void random_other_read(uint8_t *, size_t); static bool random_other_seeded(void); static void random_other_process_event(struct harvest_event *); -static void random_other_init_alg(void *); -static void random_other_deinit_alg(void *); /* * RANDOM_OTHER_NPOOLS is used when reading hardware random @@ -97,10 +95,11 @@ static void random_other_deinit_alg(void *); */ #define RANDOM_OTHER_NPOOLS 1 -struct random_algorithm random_alg_context = { +#ifdef RANDOM_LOADABLE +static +#endif +const struct random_algorithm random_alg_context = { .ra_ident = "other", - .ra_init_alg = random_other_init_alg, - .ra_deinit_alg = random_other_deinit_alg, .ra_pre_read = random_other_pre_read, .ra_read = random_other_read, .ra_seeded = random_other_seeded, @@ -112,34 +111,20 @@ struct random_algorithm random_alg_context = { static mtx_t other_mtx; /* - * void random_other_init_alg(void *unused __unused) - * * Do algorithm-specific initialisation here. */ -void +static void random_other_init_alg(void *unused __unused) { - RANDOM_RESEED_INIT_LOCK(); - /* - * Do set-up work here! - */ -} +#ifdef RANDOM_LOADABLE + p_random_alg_context = &random_alg_context; +#endif -/* - * void random_other_deinit_alg(void *unused __unused) - * - * Do algorithm-specific deinitialisation here. - */ -static void -random_other_deinit_alg(void *unused __unused) -{ - - /* - * Do tear-down work here! - */ - RANDOM_RESEED_DEINIT_LOCK(); + RANDOM_RESEED_INIT_LOCK(); } +SYSINIT(random_alg, SI_SUB_RANDOM, SI_ORDER_SECOND, random_other_init_alg, + NULL); /* * void random_other_pre_read(void) diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c index bb9ec5e4cea0..3f29a5bad979 100644 --- a/sys/dev/random/random_harvestq.c +++ b/sys/dev/random/random_harvestq.c @@ -49,11 +49,6 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/unistd.h> -#if defined(RANDOM_LOADABLE) -#include <sys/lock.h> -#include <sys/sx.h> -#endif - #include <machine/atomic.h> #include <machine/cpu.h> @@ -159,14 +154,7 @@ static struct kproc_desc random_proc_kp = { static __inline void random_harvestq_fast_process_event(struct harvest_event *event) { -#if defined(RANDOM_LOADABLE) - RANDOM_CONFIG_S_LOCK(); - if (p_random_alg_context) -#endif p_random_alg_context->ra_event_processor(event); -#if defined(RANDOM_LOADABLE) - RANDOM_CONFIG_S_UNLOCK(); -#endif explicit_bzero(event, sizeof(*event)); } @@ -227,11 +215,6 @@ random_sources_feed(void) * Step over all of live entropy sources, and feed their output * to the system-wide RNG. */ -#if defined(RANDOM_LOADABLE) - RANDOM_CONFIG_S_LOCK(); - if (p_random_alg_context) { - /* It's an indenting error. Yeah, Yeah. */ -#endif local_read_rate = atomic_readandclear_32(&read_rate); /* Perform at least one read per round */ local_read_rate = MAX(local_read_rate, 1); @@ -271,10 +254,6 @@ random_sources_feed(void) } } explicit_bzero(entropy, sizeof(entropy)); -#if defined(RANDOM_LOADABLE) - } - RANDOM_CONFIG_S_UNLOCK(); -#endif } void @@ -398,7 +377,7 @@ random_harvestq_init(void *unused __unused) RANDOM_HARVEST_INIT_LOCK(); harvest_context.hc_entropy_ring.in = harvest_context.hc_entropy_ring.out = 0; } -SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_init, NULL); +SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_THIRD, random_harvestq_init, NULL); /* * Subroutine to slice up a contiguous chunk of 'entropy' and feed it into the @@ -487,7 +466,7 @@ random_harvestq_deinit(void *unused __unused) while (random_kthread_control >= 0) tsleep(&harvest_context.hc_kthread_proc, 0, "harvqterm", hz/5); } -SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_deinit, NULL); +SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_THIRD, random_harvestq_deinit, NULL); /*- * Entropy harvesting queue routine. diff --git a/sys/dev/random/random_infra.c b/sys/dev/random/random_infra.c index a6090b54c454..0ea0b1065212 100644 --- a/sys/dev/random/random_infra.c +++ b/sys/dev/random/random_infra.c @@ -35,11 +35,6 @@ __FBSDID("$FreeBSD$"); #include <sys/random.h> #include <sys/sysctl.h> -#if defined(RANDOM_LOADABLE) -#include <sys/lock.h> -#include <sys/sx.h> -#endif - #include <dev/random/randomdev.h> /* Set up the sysctl root node for the entropy device */ @@ -102,107 +97,8 @@ SYSCTL_BOOL(_kern_random_initial_seeding, OID_AUTO, MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); #if defined(RANDOM_LOADABLE) -struct random_algorithm *p_random_alg_context = NULL; -#else /* !defined(RANDOM_LOADABLE) */ -struct random_algorithm *p_random_alg_context = &random_alg_context; -#endif /* defined(RANDOM_LOADABLE) */ - -#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); -} - - +const struct random_algorithm *p_random_alg_context; +void (*_read_random)(void *, u_int); +int (*_read_random_uio)(struct uio *, bool); +bool (*_is_random_seeded)(void); #endif /* defined(RANDOM_LOADABLE) */ diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index c9699e7cd251..7136df356990 100644 --- a/sys/dev/random/randomdev.c +++ b/sys/dev/random/randomdev.c @@ -59,17 +59,17 @@ __FBSDID("$FreeBSD$"); #define RANDOM_UNIT 0 +/* + * In loadable random, the core randomdev.c / random(9) routines have static + * visibility and an alternative name to avoid conflicting with the function + * pointers of the real names in the core kernel. random_alg_context_init + * installs pointers to the loadable static names into the core kernel's + * function pointers at SI_SUB_RANDOM:SI_ORDER_SECOND. + */ #if defined(RANDOM_LOADABLE) -#define READ_RANDOM_UIO _read_random_uio -#define READ_RANDOM _read_random -#define IS_RANDOM_SEEDED _is_random_seeded -static int READ_RANDOM_UIO(struct uio *, bool); -static void READ_RANDOM(void *, u_int); -static bool IS_RANDOM_SEEDED(void); -#else -#define READ_RANDOM_UIO read_random_uio -#define READ_RANDOM read_random -#define IS_RANDOM_SEEDED is_random_seeded +static int (read_random_uio)(struct uio *, bool); +static void (read_random)(void *, u_int); +static bool (is_random_seeded)(void); #endif static d_read_t randomdev_read; @@ -89,30 +89,17 @@ static struct cdevsw random_cdevsw = { /* For use with make_dev(9)/destroy_dev(9). */ static struct cdev *random_dev; -static void -random_alg_context_ra_init_alg(void *data) -{ - - p_random_alg_context = &random_alg_context; - p_random_alg_context->ra_init_alg(data); #if defined(RANDOM_LOADABLE) - random_infra_init(READ_RANDOM_UIO, READ_RANDOM, IS_RANDOM_SEEDED); -#endif -} - static void -random_alg_context_ra_deinit_alg(void *data) +random_alg_context_init(void *dummy __unused) { - -#if defined(RANDOM_LOADABLE) - random_infra_uninit(); -#endif - p_random_alg_context->ra_deinit_alg(data); - p_random_alg_context = NULL; + _read_random_uio = (read_random_uio); + _read_random = (read_random); + _is_random_seeded = (is_random_seeded); } - -SYSINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_init_alg, NULL); -SYSUNINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_deinit_alg, NULL); +SYSINIT(random_device, SI_SUB_RANDOM, SI_ORDER_SECOND, random_alg_context_init, + NULL); +#endif static struct selinfo rsel; @@ -124,7 +111,7 @@ static int randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags) { - return (READ_RANDOM_UIO(uio, (flags & O_NONBLOCK) != 0)); + return ((read_random_uio)(uio, (flags & O_NONBLOCK) != 0)); } /* @@ -154,7 +141,7 @@ randomdev_wait_until_seeded(bool interruptible) if (spamcount == 0) printf("random: %s unblock wait\n", __func__); spamcount = (spamcount + 1) % 100; - error = tsleep(&random_alg_context, slpflags, "randseed", + error = tsleep(__DECONST(void*, p_random_alg_context), slpflags, "randseed", hz / 10); if (error == ERESTART || error == EINTR) { KASSERT(interruptible, @@ -170,7 +157,7 @@ randomdev_wait_until_seeded(bool interruptible) } int -READ_RANDOM_UIO(struct uio *uio, bool nonblock) +(read_random_uio)(struct uio *uio, bool nonblock) { /* 16 MiB takes about 0.08 s CPU time on my 2017 AMD Zen CPU */ #define SIGCHK_PERIOD (16 * 1024 * 1024) @@ -238,7 +225,7 @@ READ_RANDOM_UIO(struct uio *uio, bool nonblock) */ if (error == 0 && uio->uio_resid != 0 && total_read % sigchk_period == 0) { - error = tsleep_sbt(&random_alg_context, PCATCH, + error = tsleep_sbt(__DECONST(void*, p_random_alg_context), PCATCH, "randrd", SBT_1NS, 0, C_HARDCLOCK); /* Squash tsleep timeout condition */ if (error == EWOULDBLOCK) @@ -271,7 +258,7 @@ READ_RANDOM_UIO(struct uio *uio, bool nonblock) * 'kern.random.initial_seeding.read_random_bypassed_before_seeding'. */ void -READ_RANDOM(void *random_buf, u_int len) +(read_random)(void *random_buf, u_int len) { KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__)); @@ -305,7 +292,7 @@ READ_RANDOM(void *random_buf, u_int len) } bool -IS_RANDOM_SEEDED(void) +(is_random_seeded)(void) { return (p_random_alg_context->ra_seeded()); } @@ -384,7 +371,7 @@ randomdev_unblock(void) { selwakeuppri(&rsel, PUSER); - wakeup(&random_alg_context); + wakeup(__DECONST(void*, p_random_alg_context)); printf("random: unblocking device.\n"); /* Do random(9) a favour while we are about it. */ (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE); @@ -423,7 +410,7 @@ randomdev_modevent(module_t mod __unused, int type, void *data __unused) make_dev_alias(random_dev, "urandom"); /* compatibility */ break; case MOD_UNLOAD: - destroy_dev(random_dev); + error = EBUSY; break; case MOD_SHUTDOWN: break; diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h index 896b31a5fea2..a5b060c1b376 100644 --- a/sys/dev/random/randomdev.h +++ b/sys/dev/random/randomdev.h @@ -79,15 +79,18 @@ typedef u_int random_source_read_t(void *, u_int); struct random_algorithm { const char *ra_ident; u_int ra_poolcount; - void (*ra_init_alg)(void *); - void (*ra_deinit_alg)(void *); random_alg_pre_read_t *ra_pre_read; random_alg_read_t *ra_read; random_alg_seeded_t *ra_seeded; random_alg_eventprocessor_t *ra_event_processor; }; -extern struct random_algorithm random_alg_context, *p_random_alg_context; +#if defined(RANDOM_LOADABLE) +extern const struct random_algorithm *p_random_alg_context; +#else +extern const struct random_algorithm random_alg_context; +#define p_random_alg_context (&random_alg_context) +#endif #ifdef _KERNEL @@ -105,19 +108,6 @@ struct random_source { void random_source_register(struct random_source *); void random_source_deregister(struct random_source *); -#if defined(RANDOM_LOADABLE) -extern struct sx randomdev_config_lock; -#define RANDOM_CONFIG_INIT_LOCK(x) sx_init(&randomdev_config_lock, "configuration change lock") -#define RANDOM_CONFIG_X_LOCK(x) sx_xlock(&randomdev_config_lock) -#define RANDOM_CONFIG_X_UNLOCK(x) sx_xunlock(&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), void (*)(void *, u_int), - bool (*)(void)); -void random_infra_uninit(void); -#endif - #endif /* _KERNEL */ void randomdev_unblock(void); diff --git a/sys/sys/random.h b/sys/sys/random.h index 9f74674eecd4..9ae0cc061b06 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -37,10 +37,37 @@ struct uio; +/* + * In the loadable random world, there are set of dangling pointers left in the + * core kernel: + * * read_random, read_random_uio, is_random_seeded are function pointers, + * rather than functions. + * * p_random_alg_context is a true pointer in loadable random kernels. + * + * These are initialized at SI_SUB_RANDOM:SI_ORDER_SECOND during boot. The + * read-type pointers are initialized by random_alg_context_init() in + * randomdev.c and p_random_alg_context in the algorithm, e.g., fortuna.c's + * random_fortuna_init_alg(). The nice thing about function pointers is they + * have a similar calling convention to ordinary functions. + * + * (In !loadable, the read_random, etc, routines are just plain functions; + * p_random_alg_context is a macro for the public visibility + * &random_alg_context.) + */ #if defined(DEV_RANDOM) +#if defined(RANDOM_LOADABLE) +extern void (*_read_random)(void *, u_int); +extern int (*_read_random_uio)(struct uio *, bool); +extern bool (*_is_random_seeded)(void); +#define read_random(a, b) (*_read_random)(a, b) +#define read_random_uio(a, b) (*_read_random_uio)(a, b) +#define is_random_seeded() (*_is_random_seeded)() +#else void read_random(void *, u_int); int read_random_uio(struct uio *, bool); bool is_random_seeded(void); +#endif //RANDOM_LOADABLE + #else static __inline int read_random_uio(void *a __unused, u_int b __unused) @@ -56,7 +83,7 @@ is_random_seeded(void) { return (false); } -#endif +#endif //DEV_RANDOM /* * Note: if you add or remove members of random_entropy_source, remember to