154359Sroberto/*- 254359Sroberto * SPDX-License-Identifier: BSD-2-Clause 354359Sroberto * 4285612Sdelphij * Copyright (c) 2018 Conrad Meyer <cem@FreeBSD.org> 554359Sroberto * All rights reserved. 654359Sroberto * 754359Sroberto * Redistribution and use in source and binary forms, with or without 8330141Sdelphij * modification, are permitted provided that the following conditions 9330141Sdelphij * are met: 1054359Sroberto * 1. Redistributions of source code must retain the above copyright 1182498Sroberto * notice, this list of conditions and the following disclaimer. 1254359Sroberto * 2. Redistributions in binary form must reproduce the above copyright 13294569Sdelphij * notice, this list of conditions and the following disclaimer in the 1454359Sroberto * documentation and/or other materials provided with the distribution. 15285612Sdelphij * 16285612Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17285612Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18285612Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1954359Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2054359Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21285612Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2254359Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2354359Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2454359Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2554359Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2654359Sroberto * SUCH DAMAGE. 2754359Sroberto */ 28285612Sdelphij 2954359Sroberto#include <sys/param.h> 3054359Sroberto#include <sys/errno.h> 3154359Sroberto#include <sys/limits.h> 3254359Sroberto#include <sys/proc.h> 3354359Sroberto#include <sys/random.h> 3454359Sroberto#include <sys/sysproto.h> 3554359Sroberto#include <sys/systm.h> 3654359Sroberto#include <sys/uio.h> 3754359Sroberto 3854359Sroberto#define GRND_VALIDFLAGS (GRND_NONBLOCK | GRND_RANDOM | GRND_INSECURE) 3954359Sroberto 40285612Sdelphij/* 4154359Sroberto * read_random_uio(9) returns EWOULDBLOCK if a nonblocking request would block, 4254359Sroberto * but the Linux API name is EAGAIN. On FreeBSD, they have the same numeric 4354359Sroberto * value for now. 4454359Sroberto */ 4554359SrobertoCTASSERT(EWOULDBLOCK == EAGAIN); 4654359Sroberto 4754359Srobertostatic int 48285612Sdelphijkern_getrandom(struct thread *td, void *user_buf, size_t buflen, 4954359Sroberto unsigned int flags) 5054359Sroberto{ 5154359Sroberto struct uio auio; 5254359Sroberto struct iovec aiov; 5354359Sroberto int error; 5454359Sroberto 55285612Sdelphij if ((flags & ~GRND_VALIDFLAGS) != 0) 5654359Sroberto return (EINVAL); 5754359Sroberto if (buflen > IOSIZE_MAX) 58285612Sdelphij return (EINVAL); 5954359Sroberto 60285612Sdelphij /* 6154359Sroberto * Linux compatibility: We have two choices for handling Linux's 6254359Sroberto * GRND_INSECURE. 6354359Sroberto * 6454359Sroberto * 1. We could ignore it completely (like GRND_RANDOM). However, this 6554359Sroberto * might produce the surprising result of GRND_INSECURE requests 6654359Sroberto * blocking, when the Linux API does not block. 67289997Sglebius * 68289997Sglebius * 2. Alternatively, we could treat GRND_INSECURE requests as requests 69289997Sglebius * for GRND_NONBLOCK. Here, the surprising result for Linux programs 70289997Sglebius * is that invocations with unseeded random(4) will produce EAGAIN, 71289997Sglebius * rather than garbage. 72289997Sglebius * 73289997Sglebius * Honoring the flag in the way Linux does seems fraught. If we 74289997Sglebius * actually use the output of a random(4) implementation prior to 75289997Sglebius * seeding, we leak some entropy about the initial seed to attackers. 76289997Sglebius * This seems unacceptable -- it defeats the purpose of blocking on 77289997Sglebius * initial seeding. 78289997Sglebius * 79289997Sglebius * Secondary to that concern, before seeding we may have arbitrarily 80289997Sglebius * little entropy collected; producing output from zero or a handful of 81289997Sglebius * entropy bits does not seem particularly useful to userspace. 82293650Sglebius * 83293650Sglebius * If userspace can accept garbage, insecure non-random bytes, they can 84289997Sglebius * create their own insecure garbage with srandom(time(NULL)) or 85293650Sglebius * similar. Asking the kernel to produce it from the secure 86289997Sglebius * getrandom(2) API seems inane. 87293650Sglebius * 88293650Sglebius * We elect to emulate GRND_INSECURE as an alternative spelling of 89293650Sglebius * GRND_NONBLOCK (2). 90294569Sdelphij */ 91293650Sglebius if ((flags & GRND_INSECURE) != 0) 92293650Sglebius flags |= GRND_NONBLOCK; 93293650Sglebius 94293650Sglebius if (buflen == 0) { 95293650Sglebius td->td_retval[0] = 0; 96293650Sglebius return (0); 97289997Sglebius } 98289997Sglebius 99293650Sglebius aiov.iov_base = user_buf; 100289997Sglebius aiov.iov_len = buflen; 101289997Sglebius auio.uio_iov = &aiov; 102289997Sglebius auio.uio_iovcnt = 1; 103289997Sglebius auio.uio_offset = 0; 104298699Sdelphij auio.uio_resid = buflen; 105289997Sglebius auio.uio_segflg = UIO_USERSPACE; 106289997Sglebius auio.uio_rw = UIO_READ; 107289997Sglebius auio.uio_td = td; 108289997Sglebius 109289997Sglebius error = read_random_uio(&auio, (flags & GRND_NONBLOCK) != 0); 110289997Sglebius if (error == 0) 111298699Sdelphij td->td_retval[0] = buflen - auio.uio_resid; 112298699Sdelphij return (error); 113298699Sdelphij} 114298699Sdelphij 115298699Sdelphij#ifndef _SYS_SYSPROTO_H_ 116298699Sdelphijstruct getrandom_args { 117298699Sdelphij void *buf; 118298699Sdelphij size_t buflen; 119298699Sdelphij unsigned int flags; 120298699Sdelphij}; 121298699Sdelphij#endif 122298699Sdelphij 123298699Sdelphijint 124298699Sdelphijsys_getrandom(struct thread *td, struct getrandom_args *uap) 125298699Sdelphij{ 126298699Sdelphij return (kern_getrandom(td, uap->buf, uap->buflen, uap->flags)); 127298699Sdelphij} 128298699Sdelphij