• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 14554080340

19 Apr 2025 11:46AM UTC coverage: 72.101% (-0.03%) from 72.13%
14554080340

push

github

web-flow
Add two new paragraphs to coding style about header files (#37188)

296880 of 411754 relevant lines covered (72.1%)

687547.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.05
/src/basic/random-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <elf.h>
4
#include <errno.h>
5
#include <fcntl.h>
6
#include <linux/random.h>
7
#include <stdbool.h>
8
#include <stdint.h>
9
#include <stdlib.h>
10
#include <string.h>
11
#include <sys/auxv.h>
12
#include <sys/ioctl.h>
13
#include <sys/time.h>
14
#include <threads.h>
15

16
#include "alloc-util.h"
17
#include "env-util.h"
18
#include "errno-util.h"
19
#include "fd-util.h"
20
#include "fileio.h"
21
#include "io-util.h"
22
#include "iovec-util.h"
23
#include "log.h"
24
#include "missing_random.h"
25
#include "missing_syscall.h"
26
#include "parse-util.h"
27
#include "pidfd-util.h"
28
#include "process-util.h"
29
#include "random-util.h"
30
#include "sha256.h"
31
#include "time-util.h"
32

33
/* This is a "best effort" kind of thing, but has no real security value. So, this should only be used by
34
 * random_bytes(), which is not meant for crypto. This could be made better, but we're *not* trying to roll a
35
 * userspace prng here, or even have forward secrecy, but rather just do the shortest thing that is at least
36
 * better than libc rand(). */
37
static void fallback_random_bytes(void *p, size_t n) {
×
38
        static thread_local uint64_t fallback_counter = 0;
×
39
        struct {
×
40
                char label[32];
41
                uint64_t call_id, block_id;
42
                usec_t stamp_mono, stamp_real;
43
                pid_t pid, tid;
44
                uint64_t pidfdid;
45
                uint8_t auxval[16];
46
        } state = {
×
47
                /* Arbitrary domain separation to prevent other usage of AT_RANDOM from clashing. */
48
                .call_id = fallback_counter++,
×
49
                .stamp_mono = now(CLOCK_MONOTONIC),
×
50
                .stamp_real = now(CLOCK_REALTIME),
×
51
                .pid = getpid_cached(),
×
52
                .tid = gettid(),
×
53
        };
54

55
        memcpy(state.label, "systemd fallback random bytes v1", sizeof(state.label));
×
56
        memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval));
×
57
        (void) pidfd_get_inode_id_self_cached(&state.pidfdid);
×
58

59
        while (n > 0) {
×
60
                struct sha256_ctx ctx;
×
61

62
                sha256_init_ctx(&ctx);
×
63
                sha256_process_bytes(&state, sizeof(state), &ctx);
×
64
                if (n < SHA256_DIGEST_SIZE) {
×
65
                        uint8_t partial[SHA256_DIGEST_SIZE];
×
66
                        sha256_finish_ctx(&ctx, partial);
×
67
                        memcpy(p, partial, n);
×
68
                        break;
×
69
                }
70
                sha256_finish_ctx(&ctx, p);
×
71
                p = (uint8_t *) p + SHA256_DIGEST_SIZE;
×
72
                n -= SHA256_DIGEST_SIZE;
×
73
                ++state.block_id;
×
74
        }
75
}
×
76

77
void random_bytes(void *p, size_t n) {
5,191,273✔
78
        static bool have_grndinsecure = true;
5,191,273✔
79

80
        assert(p || n == 0);
5,191,273✔
81

82
        if (n == 0)
5,191,273✔
83
                return;
84

85
        for (;;) {
5,191,273✔
86
                ssize_t l;
5,191,273✔
87

88
                l = getrandom(p, n, have_grndinsecure ? GRND_INSECURE : GRND_NONBLOCK);
5,191,273✔
89
                if (l < 0 && errno == EINVAL && have_grndinsecure) {
5,191,273✔
90
                        /* No GRND_INSECURE; fallback to GRND_NONBLOCK. */
91
                        have_grndinsecure = false;
×
92
                        continue;
×
93
                }
94
                if (l <= 0)
5,191,273✔
95
                        break; /* Will block (with GRND_NONBLOCK), or unexpected error. Give up and fallback
96
                                  to /dev/urandom. */
97

98
                if ((size_t) l == n)
5,191,273✔
99
                        return; /* Done reading, success. */
100

101
                p = (uint8_t *) p + l;
×
102
                n -= l;
×
103
                /* Interrupted by a signal; keep going. */
104
        }
105

106
        _cleanup_close_ int fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
5,191,273✔
107
        if (fd >= 0 && loop_read_exact(fd, p, n, false) >= 0)
×
108
                return;
×
109

110
        /* This is a terrible fallback. Oh well. */
111
        fallback_random_bytes(p, n);
×
112
}
113

114
int crypto_random_bytes(void *p, size_t n) {
140✔
115
        assert(p || n == 0);
140✔
116

117
        if (n == 0)
140✔
118
                return 0;
119

120
        for (;;) {
140✔
121
                ssize_t l;
140✔
122

123
                l = getrandom(p, n, 0);
140✔
124
                if (l < 0)
140✔
125
                        return -errno;
×
126
                if (l == 0)
140✔
127
                        return -EIO; /* Weird, should never happen. */
128

129
                if ((size_t) l == n)
140✔
130
                        return 0; /* Done reading, success. */
131

132
                p = (uint8_t *) p + l;
×
133
                n -= l;
×
134
                /* Interrupted by a signal; keep going. */
135
        }
136
}
137

138
int crypto_random_bytes_allocate_iovec(size_t n, struct iovec *ret) {
56✔
139
        _cleanup_free_ void *p = NULL;
56✔
140
        int r;
56✔
141

142
        assert(ret);
56✔
143

144
        p = malloc(MAX(n, 1U));
56✔
145
        if (!p)
56✔
146
                return -ENOMEM;
147

148
        r = crypto_random_bytes(p, n);
56✔
149
        if (r < 0)
56✔
150
                return r;
151

152
        *ret = IOVEC_MAKE(TAKE_PTR(p), n);
56✔
153
        return 0;
56✔
154
}
155

156
size_t random_pool_size(void) {
130✔
157
        _cleanup_free_ char *s = NULL;
130✔
158
        int r;
130✔
159

160
        /* Read pool size, if possible */
161
        r = read_one_line_file("/proc/sys/kernel/random/poolsize", &s);
130✔
162
        if (r < 0)
130✔
163
                log_debug_errno(r, "Failed to read pool size from kernel: %m");
130✔
164
        else {
165
                unsigned sz;
130✔
166

167
                r = safe_atou(s, &sz);
130✔
168
                if (r < 0)
130✔
169
                        log_debug_errno(r, "Failed to parse pool size: %s", s);
×
170
                else
171
                        /* poolsize is in bits on 2.6, but we want bytes */
172
                        return CLAMP(sz / 8, RANDOM_POOL_SIZE_MIN, RANDOM_POOL_SIZE_MAX);
130✔
173
        }
174

175
        /* Use the minimum as default, if we can't retrieve the correct value */
176
        return RANDOM_POOL_SIZE_MIN;
177
}
178

179
int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
73✔
180
        _cleanup_close_ int opened_fd = -EBADF;
73✔
181
        int r;
73✔
182

183
        assert(seed || size == 0);
73✔
184

185
        if (size == 0)
73✔
186
                return 0;
187

188
        if (fd < 0) {
73✔
189
                opened_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY);
10✔
190
                if (opened_fd < 0)
10✔
191
                        return -errno;
×
192

193
                fd = opened_fd;
194
        }
195

196
        if (credit) {
73✔
197
                _cleanup_free_ struct rand_pool_info *info = NULL;
×
198

199
                /* The kernel API only accepts "int" as entropy count (which is in bits), let's avoid any
200
                 * chance for confusion here. */
201
                if (size > INT_MAX / 8)
×
202
                        return -EOVERFLOW;
203

204
                info = malloc(offsetof(struct rand_pool_info, buf) + size);
×
205
                if (!info)
×
206
                        return -ENOMEM;
207

208
                info->entropy_count = size * 8;
×
209
                info->buf_size = size;
×
210
                memcpy(info->buf, seed, size);
×
211

212
                if (ioctl(fd, RNDADDENTROPY, info) < 0)
×
213
                        return -errno;
×
214
        } else {
215
                r = loop_write(fd, seed, size);
73✔
216
                if (r < 0)
73✔
217
                        return r;
×
218
        }
219

220
        return 1;
221
}
222

223
uint64_t random_u64_range(uint64_t m) {
2,815,369✔
224
        uint64_t x, remainder;
2,815,369✔
225

226
        /* Generates a random number in the range 0…m-1, unbiased. (Java's algorithm) */
227

228
        if (m == 0) /* Let's take m == 0 as special case to return an integer from the full range */
2,815,369✔
229
                return random_u64();
×
230
        if (m == 1)
2,815,369✔
231
                return 0;
232

233
        remainder = UINT64_MAX % m;
2,715,369✔
234

235
        do {
2,715,370✔
236
                x = random_u64();
2,715,370✔
237
        } while (x >= UINT64_MAX - remainder);
2,715,370✔
238

239
        return x % m;
2,715,369✔
240
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc