RND(9)

RND(9) | Kernel Developer's Manual | RND(9)

# NAME

`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

# SYNOPSIS

`#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);

# DESCRIPTION

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:

1. Allocate and zero a struct krndsource object before using the `RND` functions.
2. Optionally, set a callback with `rndsource_setcb`() if appropriate, e.g. for an on-demand hardware random number generator.
3. Attach the random source with `rnd_attach_source`().
4. Enter data with `rnd_add_data`(), `rnd_add_data_intr`(), or `rnd_add_uint32`(), or, if in the callback, `rnd_add_data_sync`().
5. When the driver is done, detach it with `rnd_detach_source`().

The following types of random sources are defined:

`RND_TYPE_DISK`
  Disk devices, typically sampling seek timings.
`RND_TYPE_ENV`
  Environmental sensors.
`RND_TYPE_POWER`
  Power sensors and timing of power-related events.
`RND_TYPE_NET`
  Network interfaces, typically sampling packet timings. By default, sample from network interfaces are ignored, for hysterical raisins.
`RND_TYPE_RNG`
  Hardware random number generators.
`RND_TYPE_SKEW`
  Skew between clocks.
`RND_TYPE_TAPE`
  Tape devices, typically sampling I/O timings.
`RND_TYPE_TTY`
  Tty devices, typically sampling interrupt timings.
`RND_TYPE_VM`
  Virtual memory fault timings.
`RND_TYPE_UNKNOWN`
  Unknown sources, or sources not otherwise classified.

# FUNCTIONS

`rndsource_setcb`(rnd_source, callback, cookie)
  Sets a callback to be invoked when the entropy pool is hungry to draw data from this source on demand. Optional; if used, must be used before `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:

  - Sends a request to a hardware device for entropy and returns. The hardware will later return data asynchronously by an interrupt, and the callback will use `rnd_add_data`(), `rnd_add_data_intr`(), or `rnd_add_uint32`() to add the data to the pool.
  - Synchronously gathers entropy from hardware — for example, by a CPU instruction like Intel RDSEED. In this case, in order to add data to the pool before returning, the callback must use `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)
  Makes rnd_source available for entropy collection. Must be called before the source struct pointed to by rnd_source is used in any of the following functions. If a callback was specified with `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_HASCB`
    The random source has a callback, which must have been set with `rndsource_setcb`().
  `RND_FLAG_COLLECT_TIME`
    Enter the timing of each `rnd_add_*`() call into the entropy pool. If not set, at most only the data arguments to `rnd_add_*`() will be entered.
  `RND_FLAG_COLLECT_VALUE`
    Enter the data arguments passed to the `rnd_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_DEFAULT`
    Equivalent to `RND_FLAG_COLLECT_TIME` | `RND_FLAG_COLLECT_VALUE`.
  `RND_FLAG_ESTIMATE_TIME`, `RND_FLAG_ESTIMATE_VALUE`
    Legacy options no longer used.
`rnd_detach_source`(rnd_source)
  Disconnects rnd_source from entropy collection. The kernel will cease to invoke the callback, if any, and the caller must not use rnd_source with any of the `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)
  Enters len bytes at data into the entropy pool, if `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)
  Tries to enter len bytes at data into the entropy pool like `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)
  Like `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)
  Equivalent to `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.

# FILES

These functions are declared in src/sys/sys/rndsource.h and defined in src/sys/kern/kern_entropy.c.

# EXAMPLES

    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);
    	...
    }

# SEE ALSO

rnd(4), rndctl(8), cprng(9)

# HISTORY

The random device was introduced in NetBSD 1.3. It was substantially rewritten in NetBSD 6.0, and again in NetBSD 10.0.

# AUTHORS

This implementation was written by Taylor R Campbell <riastradh@NetBSD.org>.

April 25, 2020 | NetBSD 11.0