[RFC PATCH 0/2] Propagating reseed notifications to user space

Babis Chalios
2023-08-23T09:17:26Z

User space often implements PRNGs that use /dev/random as entropy
source. We can not expect that this randomness sources stay completely
unknown forever. For various reasons, the originating PRNG seed may
become known at which point the PRNG becomes insecure for further random
number generation. Events that can lead to that are for example fast
computers reversing the PRNG function using a number of inputs or
Virtual Machine clones which carry seed values into their clones.

During LPC 2022 Jason, Alex, Michael and me brainstormed on how to
atomically expose a notification to user space that it should reseed.
Atomicity is key for the VM clone case. This patchset implements a
potential path to do so.

This patchset introduces an epoch value as the means of communicating to
the guest the need to reseed. The epoch is a 32bit value with the
following form:

RNG epoch
*-------------*---------------------*
| notifier id | epoch counter value |
*-------------*---------------------*
8 bits 24 bits

Changes in this value signal moments in time that PRNGs need to be
re-seeded. As a result, the intended use of the epoch from user space
PRNGs is to cache the epoch value every time they reseed using kernel
entropy, then control that its value hasn't changed before giving out
random numbers. If the value has changed the PRNG needs to reseed before
producing any more random bits.

The API for getting hold of this value is offered through
/dev/(u)random. We introduce a new ioctl for these devices, which
creates an anonymous file descriptor. User processes can call the
ioctl() to get the anon fd and then mmap it to a single page. That page
contains the value of the epoch at offset 0.

Naturally, random.c is the component that maintains the RNG epoch.
During initialization it allocates a single global page which holds the
epoch value. Moreover, it exposes an API to kernel subsystems
(notifiers) which can report events that require PRNG reseeding.
Notifiers register with random.c and receive an 8-bit notifier id (up to
256 subscribers should be enough) and a pointer to the epoch. Notifying,
then, is equivalent to writing in the epoch address a new epoch value.

Notifiers write epoch values that include the notifier ID on the higher
8 bits and increasing counter values on the 24 remaining bits. This
guarantees that two notifiers cannot ever write the same epoch value,
since notificator IDs are unique.

The first patch of this series implements the epoch mechanism. It adds
the logic in the random.c to maintain the epoch page and expose the
user space facing API. It also adds the internal API that allows kernel
systems to register as notifiers.

Based on this API, we can implement notifiers. As example notifier, this
patch set only contains a virtio-rng backend. If we agree on this path
forward, the natural next notifier would be an in-kernel timer with a
user settable frequency that allows the kernel to notify all its user
space applications to reseed regularly.

Michael sent out a proposal for an extension to virtio-rng [1] which we
can use to turn virtio-rng devices to RNG epoch notifiers. Briefly, the
proposal defines the concept of "entropy leaks", i.e. events in time
that cause entropy to decrease, such as VM snapshots. A virtio-rng
driver can program the device to perform a number of operations on guest
memory when entropy leaks happen. The proposal defines two possible
operations:

* "fill-on-leak": Fill a buffer with random bytes
* "copy-on-leak": Copy a source buffer in a destination buffer

The second patch implements the entropy leak reporting feature of
virtio-rng and registers virtio-rng devices as epoch notifiers with
random.c. It ensures that one copy-on-leak operation is always in-flight
to increase the epoch value when a VM snapshot occurs. The intention is
that the VMM will perform these operations before resuming vCPUs, so
that user space processes will observe the changes in the epoch value
atomically. Additionally, it always keeps a fill-on-leak command in the
queue, so that we can get some fresh entropy when VM snapshots occur.

This is an RFC, so that we can discuss whether the proposed ABI works.
Also, I'd like to hear people's opinion on the internal registration
API, 8/24 split etc. If we decide that this approach works, I 'm happy
to add documentation for it, with examples on how user space can make
use of it.

[1] https://lore.kernel.org/virtio-dev/20221121162756.350032-1-mst@redhat.com/

Babis Chalios (2):
random: emit reseed notifications for PRNGs
virtio-rng: implement entropy leak feature

drivers/char/hw_random/virtio-rng.c | 189 +++++++++++++++++++++++++++-
drivers/char/random.c | 147 ++++++++++++++++++++++
include/linux/random.h | 28 +++++
include/uapi/linux/random.h | 11 ++
include/uapi/linux/virtio_rng.h | 3 +
5 files changed, 373 insertions(+), 5 deletions(-)

--
2.40.1