]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/gen/getentropy.c
gnu/dts: Update our copy of arm dts from Linux 4.16
[FreeBSD/FreeBSD.git] / lib / libc / gen / getentropy.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2018 Conrad Meyer <cem@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/random.h>
34
35 #include <errno.h>
36 #include <stdlib.h>
37
38 #include "libc_private.h"
39
40 /*
41  * If a newer libc is accidentally installed on an older kernel, provide high
42  * quality random data anyway.  The sysctl interface is not as fast and does
43  * not block by itself, but is provided by even very old kernels.
44  */
45 static int
46 getentropy_fallback(void *buf, size_t buflen)
47 {
48         /*
49          * oldp (buf) == NULL has a special meaning for sysctl that results in
50          * no EFAULT.  For compatibility with the kernel getrandom(2), detect
51          * this case and return the appropriate error.
52          */
53         if (buf == NULL && buflen > 0) {
54                 errno = EFAULT;
55                 return (-1);
56         }
57         if (__arc4_sysctl(buf, buflen) != buflen) {
58                 if (errno == EFAULT)
59                         return (-1);
60                 /*
61                  * This cannot happen.  _arc4_sysctl() spins until the random
62                  * device is seeded and then repeatedly reads until the full
63                  * request is satisfied.  The only way for this to return a zero
64                  * byte or short read is if sysctl(2) on the kern.arandom MIB
65                  * fails.  In this case, exceping the user-provided-a-bogus-
66                  * buffer EFAULT, give up (like for arc4random(3)'s arc4_stir).
67                  */
68                 abort();
69         }
70         return (0);
71 }
72
73 int
74 getentropy(void *buf, size_t buflen)
75 {
76         ssize_t rd;
77
78         if (buflen > 256) {
79                 errno = EIO;
80                 return (-1);
81         }
82
83         while (buflen > 0) {
84                 rd = getrandom(buf, buflen, 0);
85                 if (rd == -1) {
86                         if (errno == EINTR)
87                                 continue;
88                         else if (errno == ENOSYS)
89                                 return (getentropy_fallback(buf, buflen));
90                         else
91                                 return (-1);
92                 }
93
94                 /* This cannot happen. */
95                 if (rd == 0)
96                         abort();
97
98                 buf = (char *)buf + rd;
99                 buflen -= rd;
100         }
101
102         return (0);
103 }