| RND(9) | Kernel Developer's Manual | RND(9) |
RND,
rnd_attach_source,
rnd_detach_source,
rnd_add_data,
rnd_add_data_intr,
rnd_add_data_sync,
rnd_add_uint32 — functions
to make a device available for entropy collection
#include
<sys/rndsource.h>
typedef struct krndsource krndsource_t;
void
rndsource_setcb(krndsource_t
*rnd_source, void
(*callback)(size_t, void *),
void *cookie);
void
rnd_attach_source(krndsource_t
*rnd_source, char
*devname, uint32_t
source_type, uint32_t
flags);
void
rnd_detach_source(krndsource_t
*rnd_source);
void
rnd_add_data(krndsource_t
*rnd_source, void
*data, uint32_t
len, uint32_t
entropy);
void
rnd_add_data_intr(krndsource_t
*rnd_source, void
*data, uint32_t
len, uint32_t
entropy);
void
rnd_add_data_sync(krndsource_t
*rnd_source, void
*data, uint32_t
len, uint32_t
entropy);
void
rnd_add_uint32(krndsource_t
*rnd_source, uint32_t
datum);
The RND functions enable drivers to
collect samples of physical observations, such as network packet timings or
hardware random number generator outputs, into a kernel entropy pool to
derive key material for
cprng(9) and
rnd(4)
(/dev/random,
/dev/urandom).
Usage model:
RND functions.rndsource_setcb()
if appropriate, e.g. for an on-demand hardware random number
generator.rnd_attach_source().rnd_add_data(),
rnd_add_data_intr(), or
rnd_add_uint32(), or, if in the callback,
rnd_add_data_sync().rnd_detach_source().The following types of random sources are defined:
RND_TYPE_DISKRND_TYPE_ENVRND_TYPE_POWERRND_TYPE_NETRND_TYPE_RNGRND_TYPE_SKEWRND_TYPE_TAPERND_TYPE_TTYRND_TYPE_VMRND_TYPE_UNKNOWNrndsource_setcb(rnd_source,
callback, cookie)rnd_attach_source(), and
the caller must pass RND_FLAG_HASCB to
rnd_attach_source().
The callback is invoked as
callback(nbytes,
cookie);, where nbytes is
the number of bytes requested for the entropy pool, and
cookie is the cookie that was passed to
rndsource_setcb(). The callback normally does
one of two things:
rnd_add_data(),
rnd_add_data_intr(), or
rnd_add_uint32() to add the data to the
pool.rnd_add_data_sync(), not
rnd_add_data(),
rnd_add_data_intr() or
rnd_add_uint32().RND issues calls to each source's
callback in serial — it never issues two
calls to the same source's callback at the same time in two different
threads or on two different CPUs.
The callback may be invoked in thread context or soft
interrupt context, up to SOFTINT_SERIAL, and as
such must follow the rules of soft interrupt handlers in
softint(9) — that
is, the callback must never sleep, except on adaptive
mutex(9) locks at
IPL_SOFTSERIAL. The callback will never be
called in hard interrupt context.
rnd_attach_source(rnd_source,
devname, type,
flags)rndsource_setcb(), the kernel may invoke it at any
time after rnd_attach_source() until
rnd_detach_source(),
so the callback must be ready to be invoked before
calling rnd_attach_source().
The devname is exposed via
rnd(4) and
rndctl(8). The
type must be one of the
RND_TYPE_* constants above. The
flags are the bitwise-or of any of the following
constants:
RND_FLAG_HASCBrndsource_setcb().RND_FLAG_COLLECT_TIMErnd_add_*()
call into the entropy pool. If not set, at most only the data
arguments to rnd_add_*() will be entered.RND_FLAG_COLLECT_VALUErnd_add_*() functions into the pool. If not
set, the data will be ignored; at most the timing of the sample will
be entered.RND_FLAG_DEFAULTRND_FLAG_COLLECT_TIME |
RND_FLAG_COLLECT_VALUE.RND_FLAG_ESTIMATE_TIME,
RND_FLAG_ESTIMATE_VALUErnd_detach_source(rnd_source)rnd_add_*() functions after
rnd_detach_source(). The caller may release the
memory for rnd_source afterward.rnd_add_data(rnd_source,
data, len,
entropy)RND_FLAG_COLLECT_VALUE was
specified for rnd_source, and a timestamp, if
RND_FLAG_COLLECT_TIME was specified.
The argument entropy provides a conservative estimate for the number of bits of entropy in the physical process that generated the data, given all the past samples. Drivers for devices for which this is not known should pass zero; typically only drivers for hardware random number generators pass nonzero values. Hardware random number generator drivers should perform on-line self-tests before advertising nonzero entropy for samples.
rnd_add_data()
must not be used during a callback as set with
rndsource_setcb(); use
rnd_add_data_sync()
instead.
rnd_add_data()
must not be called from thread context with spin locks
held.
For compatibility,
rnd_add_data()
currently
may but
should
not be called from interrupt context, possibly with spin locks
held. However, this may be forbidden in the future; use
rnd_add_data_intr() from interrupt context
instead, if the work can't be usefully deferred to softint or
thread.
rnd_add_data_intr(rnd_source,
data, len,
entropy)rnd_add_data(), but if this fills or would
overflow a sample buffer, schedules a softint to process it and discards
an unspecified subset of the data while counting zero entropy for the
sample.
rnd_add_data_intr()
may be called from any context, including hard interrupt context,
including contexts where spin locks are held, except that it
must not be used during a callback as set with
rndsource_setcb(); use
rnd_add_data_sync()
in that context instead.
rnd_add_data_sync(rnd_source,
data, len,
entropy)rnd_add_data(), but may be used in a callback
as set with rndsource_setcb(). Must always be
called in thread context.rnd_add_uint32(rnd_source,
datum)rnd_add_data_intr(rnd_source,
&datum,
4, 0).
rnd_add_uint32()
may be called from any context, including hard interrupt context,
including contexts where spin locks are held, except that it
must not be used during a callback as set with
rndsource_setcb(); use
rnd_add_data_sync()
in that context instead.
rnd_add_uint32()
is meant for cheaply taking samples from devices that aren't designed to
be hardware random number generators.
These functions are declared in src/sys/sys/rndsource.h and defined in src/sys/kern/kern_entropy.c.
struct xyz_softc {
...
struct krndsource sc_rndsource;
};
static void
xyz_attach(device_t parent, device_t self, void *aux)
{
struct xyz_softc *sc = device_private(self);
...
rndsource_setcb(&sc->sc_rndsource, xyz_get, sc);
rnd_attach_source(&sc->sc_rndsource, device_xname(self),
RND_TYPE_RNG, RND_FLAG_DEFAULT);
}
static int
xyz_detach(device_t self, int flags)
{
...
rnd_detach_source(&sc->sc_rndsource);
...
return 0;
}
static void
xyz_get(size_t nbytes, void *cookie)
{
struct xyz_softc *sc = cookie;
uint32_t v;
unsigned timo = 10;
while (nbytes) {
while (bus_space_read_4(sc->sc_bst, sc->sc_bsh,
XYZ_RNGREADY) == 0) {
if (--timo == 0)
return;
DELAY(10);
}
v = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
XYZ_RNGDATUM);
/* data sheet sez 18 bits entropy in 32-bit sample */
rnd_add_data_sync(&sc->sc_rndsource, &v, sizeof v, 18);
nbytes -= 18/NBBY;
}
}
static void
xyz_intr(void *cookie)
{
struct xyz_softc *sc = cookie;
uint32_t isr;
isr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, XYZ_ISR);
bus_space_write_4(sc->sc_bst, sc->sc_bsh, XYZ_ISR, isr);
rnd_add_uint32(&sc->sc_rndsource, isr);
...
}
The random device was introduced in NetBSD 1.3. It was substantially rewritten in NetBSD 6.0, and again in NetBSD 10.0.
This implementation was written by Taylor R Campbell <riastradh@NetBSD.org>.
| April 25, 2020 | NetBSD 11.0 |