1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #if defined(__i386__) || defined(__x86_64__)
4 #include <cpuid.h>
5 #endif
6 
7 #include <elf.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <linux/random.h>
11 #include <pthread.h>
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/ioctl.h>
17 #include <sys/time.h>
18 
19 #if HAVE_SYS_AUXV_H
20 #  include <sys/auxv.h>
21 #endif
22 
23 #include "alloc-util.h"
24 #include "env-util.h"
25 #include "errno-util.h"
26 #include "fd-util.h"
27 #include "fileio.h"
28 #include "io-util.h"
29 #include "missing_random.h"
30 #include "missing_syscall.h"
31 #include "parse-util.h"
32 #include "random-util.h"
33 #include "siphash24.h"
34 #include "time-util.h"
35 
36 static bool srand_called = false;
37 
genuine_random_bytes(void * p,size_t n,RandomFlags flags)38 int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
39         static int have_syscall = -1;
40         _cleanup_close_ int fd = -1;
41 
42         /* Gathers some high-quality randomness from the kernel. This call won't block, unless the RANDOM_BLOCK
43          * flag is set. If it doesn't block, it will still always return some data from the kernel, regardless
44          * of whether the random pool is fully initialized or not. When creating cryptographic key material you
45          * should always use RANDOM_BLOCK. */
46 
47         if (n == 0)
48                 return 0;
49 
50         /* Use the getrandom() syscall unless we know we don't have it. */
51         if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
52                 for (;;) {
53                         ssize_t l = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_INSECURE);
54 
55                         if (l > 0) {
56                                 have_syscall = true;
57 
58                                 if ((size_t) l == n)
59                                         return 0; /* Yay, success! */
60 
61                                 /* We didn't get enough data, so try again */
62                                 assert((size_t) l < n);
63                                 p = (uint8_t*) p + l;
64                                 n -= l;
65                                 continue;
66 
67                         } else if (l == 0) {
68                                 have_syscall = true;
69                                 return -EIO;
70 
71                         } else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
72                                 /* We lack the syscall, continue with reading from /dev/urandom. */
73                                 have_syscall = false;
74                                 break;
75 
76                         } else if (errno == EINVAL) {
77                                 /* If we previously passed GRND_INSECURE, and this flag isn't known, then
78                                  * we're likely running an old kernel which has getrandom() but not
79                                  * GRND_INSECURE. In this case, fall back to /dev/urandom. */
80                                 if (!FLAGS_SET(flags, RANDOM_BLOCK))
81                                         break;
82 
83                                 return -errno;
84                         } else
85                                 return -errno;
86                 }
87         }
88 
89         fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
90         if (fd < 0)
91                 return errno == ENOENT ? -ENOSYS : -errno;
92 
93         return loop_read_exact(fd, p, n, true);
94 }
95 
clear_srand_initialization(void)96 static void clear_srand_initialization(void) {
97         srand_called = false;
98 }
99 
initialize_srand(void)100 void initialize_srand(void) {
101         static bool pthread_atfork_registered = false;
102         unsigned x;
103 
104         if (srand_called)
105                 return;
106 
107 #if HAVE_SYS_AUXV_H
108         /* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed
109          * the pseudo-random generator. It's better than nothing... But let's first hash it to make it harder
110          * to recover the original value by watching any pseudo-random bits we generate. After all the
111          * AT_RANDOM data might be used by other stuff too (in particular: ASLR), and we probably shouldn't
112          * leak the seed for that. */
113 
114         const void *auxv = ULONG_TO_PTR(getauxval(AT_RANDOM));
115         if (auxv) {
116                 static const uint8_t auxval_hash_key[16] = {
117                         0x92, 0x6e, 0xfe, 0x1b, 0xcf, 0x00, 0x52, 0x9c, 0xcc, 0x42, 0xcf, 0xdc, 0x94, 0x1f, 0x81, 0x0f
118                 };
119 
120                 x = (unsigned) siphash24(auxv, 16, auxval_hash_key);
121         } else
122 #endif
123                 x = 0;
124 
125         x ^= (unsigned) now(CLOCK_REALTIME);
126         x ^= (unsigned) gettid();
127 
128         srand(x);
129         srand_called = true;
130 
131         if (!pthread_atfork_registered) {
132                 (void) pthread_atfork(NULL, NULL, clear_srand_initialization);
133                 pthread_atfork_registered = true;
134         }
135 }
136 
137 /* INT_MAX gives us only 31 bits, so use 24 out of that. */
138 #if RAND_MAX >= INT_MAX
139 assert_cc(RAND_MAX >= 16777215);
140 #  define RAND_STEP 3
141 #else
142 /* SHORT_INT_MAX or lower gives at most 15 bits, we just use 8 out of that. */
143 assert_cc(RAND_MAX >= 255);
144 #  define RAND_STEP 1
145 #endif
146 
pseudo_random_bytes(void * p,size_t n)147 void pseudo_random_bytes(void *p, size_t n) {
148         uint8_t *q;
149 
150         /* This returns pseudo-random data using libc's rand() function. You probably never want to call this
151          * directly, because why would you use this if you can get better stuff cheaply? Use random_bytes()
152          * instead, see below: it will fall back to this function if there's nothing better to get, but only
153          * then. */
154 
155         initialize_srand();
156 
157         for (q = p; q < (uint8_t*) p + n; q += RAND_STEP) {
158                 unsigned rr;
159 
160                 rr = (unsigned) rand();
161 
162 #if RAND_STEP >= 3
163                 if ((size_t) (q - (uint8_t*) p + 2) < n)
164                         q[2] = rr >> 16;
165 #endif
166 #if RAND_STEP >= 2
167                 if ((size_t) (q - (uint8_t*) p + 1) < n)
168                         q[1] = rr >> 8;
169 #endif
170                 q[0] = rr;
171         }
172 }
173 
random_bytes(void * p,size_t n)174 void random_bytes(void *p, size_t n) {
175 
176         /* This returns high quality randomness if we can get it cheaply. If we can't because for some reason
177          * it is not available we'll try some crappy fallbacks.
178          *
179          * What this function will do:
180          *
181          *         • Use getrandom(GRND_INSECURE) or /dev/urandom, to return high-quality random values if
182          *           they are cheaply available, or less high-quality random values if they are not.
183          *
184          *         • This function will return pseudo-random data, generated via libc rand() if nothing
185          *           better is available.
186          *
187          *         • This function will work fine in early boot
188          *
189          *         • This function will always succeed
190          *
191          * What this function won't do:
192          *
193          *         • This function will never fail: it will give you randomness no matter what. It might not
194          *           be high quality, but it will return some, possibly generated via libc's rand() call.
195          *
196          *         • This function will never block: if the only way to get good randomness is a blocking,
197          *           synchronous getrandom() we'll instead provide you with pseudo-random data.
198          *
199          * This function is hence great for things like seeding hash tables, generating random numeric UNIX
200          * user IDs (that are checked for collisions before use) and such.
201          *
202          * This function is hence not useful for generating UUIDs or cryptographic key material.
203          */
204 
205         if (genuine_random_bytes(p, n, 0) >= 0)
206                 return;
207 
208         /* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */
209         pseudo_random_bytes(p, n);
210 }
211 
random_pool_size(void)212 size_t random_pool_size(void) {
213         _cleanup_free_ char *s = NULL;
214         int r;
215 
216         /* Read pool size, if possible */
217         r = read_one_line_file("/proc/sys/kernel/random/poolsize", &s);
218         if (r < 0)
219                 log_debug_errno(r, "Failed to read pool size from kernel: %m");
220         else {
221                 unsigned sz;
222 
223                 r = safe_atou(s, &sz);
224                 if (r < 0)
225                         log_debug_errno(r, "Failed to parse pool size: %s", s);
226                 else
227                         /* poolsize is in bits on 2.6, but we want bytes */
228                         return CLAMP(sz / 8, RANDOM_POOL_SIZE_MIN, RANDOM_POOL_SIZE_MAX);
229         }
230 
231         /* Use the minimum as default, if we can't retrieve the correct value */
232         return RANDOM_POOL_SIZE_MIN;
233 }
234 
random_write_entropy(int fd,const void * seed,size_t size,bool credit)235 int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
236         _cleanup_close_ int opened_fd = -1;
237         int r;
238 
239         assert(seed || size == 0);
240 
241         if (size == 0)
242                 return 0;
243 
244         if (fd < 0) {
245                 opened_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY);
246                 if (opened_fd < 0)
247                         return -errno;
248 
249                 fd = opened_fd;
250         }
251 
252         if (credit) {
253                 _cleanup_free_ struct rand_pool_info *info = NULL;
254 
255                 /* The kernel API only accepts "int" as entropy count (which is in bits), let's avoid any
256                  * chance for confusion here. */
257                 if (size > INT_MAX / 8)
258                         return -EOVERFLOW;
259 
260                 info = malloc(offsetof(struct rand_pool_info, buf) + size);
261                 if (!info)
262                         return -ENOMEM;
263 
264                 info->entropy_count = size * 8;
265                 info->buf_size = size;
266                 memcpy(info->buf, seed, size);
267 
268                 if (ioctl(fd, RNDADDENTROPY, info) < 0)
269                         return -errno;
270         } else {
271                 r = loop_write(fd, seed, size, false);
272                 if (r < 0)
273                         return r;
274         }
275 
276         return 1;
277 }
278 
random_u64_range(uint64_t m)279 uint64_t random_u64_range(uint64_t m) {
280         uint64_t x, remainder;
281 
282         /* Generates a random number in the range 0…m-1, unbiased. (Java's algorithm) */
283 
284         if (m == 0) /* Let's take m == 0 as special case to return an integer from the full range */
285                 return random_u64();
286         if (m == 1)
287                 return 0;
288 
289         remainder = UINT64_MAX % m;
290 
291         do {
292                 x = random_u64();
293         } while (x >= UINT64_MAX - remainder);
294 
295         return x % m;
296 }
297