static int makeprng(void) { /* can't create in cprng_init(), too early */ sysctl_prng = cprng_strong_create("sysctl", IPL_NONE, CPRNG_INIT_ANY|CPRNG_REKEY_ANY); return 0; }
/* * Fetch a per-CPU CPRNG, or create and save one if necessary. */ static struct cprng_strong * rnd_percpu_cprng(void) { struct cprng_strong **cprngp, *cprng, *tmp = NULL; /* Fast path: if there already is a CPRNG for this CPU, use it. */ cprngp = percpu_getref(percpu_urandom_cprng); cprng = *cprngp; if (__predict_true(cprng != NULL)) goto out; percpu_putref(percpu_urandom_cprng); /* * Slow path: create a CPRNG named by this CPU. * * XXX The CPU of the name may be different from the CPU to * which it is assigned, because we need to choose a name and * allocate a cprng while preemption is enabled. This could be * fixed by changing the cprng_strong API (e.g., by adding a * cprng_strong_setname or by separating allocation from * initialization), but it's not clear that's worth the * trouble. */ char name[32]; (void)snprintf(name, sizeof(name), "urandom%u", cpu_index(curcpu())); tmp = cprng_strong_create(name, IPL_NONE, (CPRNG_INIT_ANY | CPRNG_REKEY_ANY)); /* Try again, but we may have been preempted and lost a race. */ cprngp = percpu_getref(percpu_urandom_cprng); cprng = *cprngp; if (__predict_false(cprng != NULL)) goto out; /* Commit the CPRNG we just created. */ cprng = tmp; tmp = NULL; *cprngp = cprng; out: percpu_putref(percpu_urandom_cprng); if (tmp != NULL) cprng_strong_destroy(tmp); KASSERT(cprng != NULL); return cprng; }
/* * Fetch a /dev/u?random context's CPRNG, or create and save one if * necessary. */ static struct cprng_strong * rnd_ctx_cprng(struct rnd_ctx *ctx) { struct cprng_strong *cprng, *tmp = NULL; /* Fast path: if someone has already allocated a CPRNG, use it. */ cprng = ctx->rc_cprng; if (__predict_true(cprng != NULL)) { /* Make sure the CPU hasn't prefetched cprng's guts. */ membar_consumer(); goto out; } /* Slow path: create a CPRNG. Allocate before taking locks. */ char name[64]; struct lwp *const l = curlwp; (void)snprintf(name, sizeof(name), "%d %"PRIu64" %u", (int)l->l_proc->p_pid, l->l_ncsw, l->l_cpticks); const int flags = (ctx->rc_hard? (CPRNG_USE_CV | CPRNG_HARD) : (CPRNG_INIT_ANY | CPRNG_REKEY_ANY)); tmp = cprng_strong_create(name, IPL_NONE, flags); /* Publish cprng's guts before the pointer to them. */ membar_producer(); /* Attempt to publish tmp, unless someone beat us. */ cprng = atomic_cas_ptr(&ctx->rc_cprng, NULL, tmp); if (__predict_false(cprng != NULL)) { /* Make sure the CPU hasn't prefetched cprng's guts. */ membar_consumer(); goto out; } /* Published. Commit tmp. */ cprng = tmp; tmp = NULL; out: if (tmp != NULL) cprng_strong_destroy(tmp); KASSERT(cprng != NULL); return cprng; }