// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2022-2024 Jason A. Donenfeld <[email protected]>. All Rights Reserved. */ #include <linux/array_size.h> #include <linux/minmax.h> #include <vdso/datapage.h> #include <vdso/getrandom.h> #include <vdso/unaligned.h> #include <asm/vdso/getrandom.h> #include <uapi/linux/mman.h> #include <uapi/linux/random.h> #undef PAGE_SIZE #undef PAGE_MASK #define PAGE_SIZE … #define PAGE_MASK … #define MEMCPY_AND_ZERO_SRC(type, dst, src, len) … static void memcpy_and_zero_src(void *dst, void *src, size_t len) { … } /** * __cvdso_getrandom_data - Generic vDSO implementation of getrandom() syscall. * @rng_info: Describes state of kernel RNG, memory shared with kernel. * @buffer: Destination buffer to fill with random bytes. * @len: Size of @buffer in bytes. * @flags: Zero or more GRND_* flags. * @opaque_state: Pointer to an opaque state area. * @opaque_len: Length of opaque state area. * * This implements a "fast key erasure" RNG using ChaCha20, in the same way that the kernel's * getrandom() syscall does. It periodically reseeds its key from the kernel's RNG, at the same * schedule that the kernel's RNG is reseeded. If the kernel's RNG is not ready, then this always * calls into the syscall. * * If @buffer, @len, and @flags are 0, and @opaque_len is ~0UL, then @opaque_state is populated * with a struct vgetrandom_opaque_params and the function returns 0; if it does not return 0, * this function should not be used. * * @opaque_state *must* be allocated by calling mmap(2) using the mmap_prot and mmap_flags fields * from the struct vgetrandom_opaque_params, and states must not straddle pages. Unless external * locking is used, one state must be allocated per thread, as it is not safe to call this function * concurrently with the same @opaque_state. However, it is safe to call this using the same * @opaque_state that is shared between main code and signal handling code, within the same thread. * * Returns: The number of random bytes written to @buffer, or a negative value indicating an error. */ static __always_inline ssize_t __cvdso_getrandom_data(const struct vdso_rng_data *rng_info, void *buffer, size_t len, unsigned int flags, void *opaque_state, size_t opaque_len) { … } static __always_inline ssize_t __cvdso_getrandom(void *buffer, size_t len, unsigned int flags, void *opaque_state, size_t opaque_len) { … }