]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/random-util.c
Fix reference to FileDescriptorStoreMax= directive
[thirdparty/systemd.git] / src / basic / random-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
3df3e884 2
11c3a366 3#include <elf.h>
3df3e884 4#include <errno.h>
3df3e884 5#include <fcntl.h>
4dd055f9 6#include <linux/random.h>
11c3a366 7#include <stdbool.h>
dccca82b 8#include <stdint.h>
11c3a366 9#include <stdlib.h>
dccca82b 10#include <string.h>
4dd055f9 11#include <sys/ioctl.h>
11c3a366 12#include <sys/time.h>
11c3a366 13
349cc4a5 14#if HAVE_SYS_AUXV_H
5224c2c7
ZJS
15# include <sys/auxv.h>
16#endif
17
c322f379 18#include "alloc-util.h"
fbccb980 19#include "env-util.h"
e2b55464 20#include "errno-util.h"
3ffd4af2 21#include "fd-util.h"
3e155eba 22#include "fileio.h"
c004493c 23#include "io-util.h"
4d6222b6 24#include "iovec-util.h"
f5947a5e
YW
25#include "missing_random.h"
26#include "missing_syscall.h"
5545f336 27#include "missing_threads.h"
3e155eba 28#include "parse-util.h"
19b761a0 29#include "process-util.h"
3df3e884 30#include "random-util.h"
87cb1ab6 31#include "sha256.h"
3df3e884 32#include "time-util.h"
3df3e884 33
582fc142
LP
34/* This is a "best effort" kind of thing, but has no real security value. So, this should only be used by
35 * random_bytes(), which is not meant for crypto. This could be made better, but we're *not* trying to roll a
36 * userspace prng here, or even have forward secrecy, but rather just do the shortest thing that is at least
37 * better than libc rand(). */
87cb1ab6
JD
38static void fallback_random_bytes(void *p, size_t n) {
39 static thread_local uint64_t fallback_counter = 0;
40 struct {
41 char label[32];
42 uint64_t call_id, block_id;
43 usec_t stamp_mono, stamp_real;
44 pid_t pid, tid;
45 uint8_t auxval[16];
46 } state = {
47 /* Arbitrary domain separation to prevent other usage of AT_RANDOM from clashing. */
48 .label = "systemd fallback random bytes v1",
49 .call_id = fallback_counter++,
50 .stamp_mono = now(CLOCK_MONOTONIC),
51 .stamp_real = now(CLOCK_REALTIME),
19b761a0 52 .pid = getpid_cached(),
582fc142 53 .tid = gettid(),
87cb1ab6 54 };
a0f11d1d 55
87cb1ab6
JD
56#if HAVE_SYS_AUXV_H
57 memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval));
58#endif
3df3e884 59
87cb1ab6
JD
60 while (n > 0) {
61 struct sha256_ctx ctx;
776cf746 62
87cb1ab6
JD
63 sha256_init_ctx(&ctx);
64 sha256_process_bytes(&state, sizeof(state), &ctx);
65 if (n < SHA256_DIGEST_SIZE) {
66 uint8_t partial[SHA256_DIGEST_SIZE];
67 sha256_finish_ctx(&ctx, partial);
68 memcpy(p, partial, n);
69 break;
31234fbe 70 }
87cb1ab6
JD
71 sha256_finish_ctx(&ctx, p);
72 p = (uint8_t *) p + SHA256_DIGEST_SIZE;
73 n -= SHA256_DIGEST_SIZE;
74 ++state.block_id;
31234fbe 75 }
3df3e884
RC
76}
77
87cb1ab6
JD
78void random_bytes(void *p, size_t n) {
79 static bool have_getrandom = true, have_grndinsecure = true;
254d1313 80 _cleanup_close_ int fd = -EBADF;
d5a99b7c 81
87cb1ab6 82 if (n == 0)
3df3e884
RC
83 return;
84
87cb1ab6
JD
85 for (;;) {
86 ssize_t l;
87
88 if (!have_getrandom)
89 break;
90
91 l = getrandom(p, n, have_grndinsecure ? GRND_INSECURE : GRND_NONBLOCK);
92 if (l > 0) {
93 if ((size_t) l == n)
94 return; /* Done reading, success. */
95 p = (uint8_t *) p + l;
96 n -= l;
97 continue; /* Interrupted by a signal; keep going. */
98 } else if (l == 0)
99 break; /* Weird, so fallback to /dev/urandom. */
100 else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
101 have_getrandom = false;
102 break; /* No syscall, so fallback to /dev/urandom. */
103 } else if (errno == EINVAL && have_grndinsecure) {
104 have_grndinsecure = false;
105 continue; /* No GRND_INSECURE; fallback to GRND_NONBLOCK. */
106 } else if (errno == EAGAIN && !have_grndinsecure)
107 break; /* Will block, but no GRND_INSECURE, so fallback to /dev/urandom. */
108
109 break; /* Unexpected, so just give up and fallback to /dev/urandom. */
a0f11d1d 110 }
6a06b1a5 111
87cb1ab6
JD
112 fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
113 if (fd >= 0 && loop_read_exact(fd, p, n, false) == 0)
114 return;
85505064 115
87cb1ab6
JD
116 /* This is a terrible fallback. Oh well. */
117 fallback_random_bytes(p, n);
118}
6a06b1a5 119
87cb1ab6
JD
120int crypto_random_bytes(void *p, size_t n) {
121 static bool have_getrandom = true, seen_initialized = false;
254d1313 122 _cleanup_close_ int fd = -EBADF;
6a06b1a5 123
87cb1ab6
JD
124 if (n == 0)
125 return 0;
6a06b1a5 126
87cb1ab6
JD
127 for (;;) {
128 ssize_t l;
129
130 if (!have_getrandom)
131 break;
132
133 l = getrandom(p, n, 0);
134 if (l > 0) {
135 if ((size_t) l == n)
136 return 0; /* Done reading, success. */
137 p = (uint8_t *) p + l;
138 n -= l;
139 continue; /* Interrupted by a signal; keep going. */
140 } else if (l == 0)
141 return -EIO; /* Weird, should never happen. */
142 else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
143 have_getrandom = false;
144 break; /* No syscall, so fallback to /dev/urandom. */
145 }
146 return -errno;
6a06b1a5 147 }
6a06b1a5 148
87cb1ab6 149 if (!seen_initialized) {
254d1313 150 _cleanup_close_ int ready_fd = -EBADF;
87cb1ab6 151 int r;
3df3e884 152
87cb1ab6
JD
153 ready_fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
154 if (ready_fd < 0)
155 return -errno;
156 r = fd_wait_for_event(ready_fd, POLLIN, USEC_INFINITY);
157 if (r < 0)
158 return r;
159 seen_initialized = true;
160 }
3df3e884 161
87cb1ab6
JD
162 fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
163 if (fd < 0)
164 return -errno;
165 return loop_read_exact(fd, p, n, false);
3df3e884 166}
3e155eba 167
4d6222b6
LP
168int crypto_random_bytes_allocate_iovec(size_t n, struct iovec *ret) {
169 _cleanup_free_ void *p = NULL;
170 int r;
171
172 assert(ret);
173
174 p = malloc(MAX(n, 1U));
175 if (!p)
176 return -ENOMEM;
177
178 r = crypto_random_bytes(p, n);
179 if (r < 0)
180 return r;
181
182 *ret = IOVEC_MAKE(TAKE_PTR(p), n);
183 return 0;
184}
185
3e155eba
LP
186size_t random_pool_size(void) {
187 _cleanup_free_ char *s = NULL;
188 int r;
189
190 /* Read pool size, if possible */
191 r = read_one_line_file("/proc/sys/kernel/random/poolsize", &s);
192 if (r < 0)
193 log_debug_errno(r, "Failed to read pool size from kernel: %m");
194 else {
195 unsigned sz;
196
197 r = safe_atou(s, &sz);
198 if (r < 0)
199 log_debug_errno(r, "Failed to parse pool size: %s", s);
200 else
201 /* poolsize is in bits on 2.6, but we want bytes */
202 return CLAMP(sz / 8, RANDOM_POOL_SIZE_MIN, RANDOM_POOL_SIZE_MAX);
203 }
204
205 /* Use the minimum as default, if we can't retrieve the correct value */
206 return RANDOM_POOL_SIZE_MIN;
207}
4dd055f9
LP
208
209int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
254d1313 210 _cleanup_close_ int opened_fd = -EBADF;
4dd055f9
LP
211 int r;
212
61bd7d1e
LP
213 assert(seed || size == 0);
214
215 if (size == 0)
216 return 0;
217
218 if (fd < 0) {
219 opened_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY);
220 if (opened_fd < 0)
221 return -errno;
222
223 fd = opened_fd;
224 }
4dd055f9
LP
225
226 if (credit) {
227 _cleanup_free_ struct rand_pool_info *info = NULL;
228
229 /* The kernel API only accepts "int" as entropy count (which is in bits), let's avoid any
230 * chance for confusion here. */
231 if (size > INT_MAX / 8)
232 return -EOVERFLOW;
233
234 info = malloc(offsetof(struct rand_pool_info, buf) + size);
235 if (!info)
236 return -ENOMEM;
237
238 info->entropy_count = size * 8;
239 info->buf_size = size;
240 memcpy(info->buf, seed, size);
241
242 if (ioctl(fd, RNDADDENTROPY, info) < 0)
243 return -errno;
244 } else {
e22c60a9 245 r = loop_write(fd, seed, size);
4dd055f9
LP
246 if (r < 0)
247 return r;
248 }
249
61bd7d1e 250 return 1;
4dd055f9 251}
5464c961 252
1a8900e7 253uint64_t random_u64_range(uint64_t m) {
5464c961
LP
254 uint64_t x, remainder;
255
256 /* Generates a random number in the range 0…m-1, unbiased. (Java's algorithm) */
257
258 if (m == 0) /* Let's take m == 0 as special case to return an integer from the full range */
259 return random_u64();
260 if (m == 1)
261 return 0;
262
263 remainder = UINT64_MAX % m;
264
265 do {
266 x = random_u64();
267 } while (x >= UINT64_MAX - remainder);
268
269 return x % m;
270}