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

systemd / systemd / 12877533250

20 Jan 2025 11:16PM UTC coverage: 0.117%. Remained the same
12877533250

push

github

web-flow
pidfd: cache our own pidfd inode id, and use it at various places (#36060)

This is split out of and preparation for #35224, but makes a ton of
sense on its own

0 of 95 new or added lines in 10 files covered. (0.0%)

4667 existing lines in 34 files now uncovered.

478 of 408040 relevant lines covered (0.12%)

1.45 hits per line

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

0.0
/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

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

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

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

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

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

76
void random_bytes(void *p, size_t n) {
×
77
        static bool have_grndinsecure = true;
×
78

79
        assert(p || n == 0);
×
80

81
        if (n == 0)
×
82
                return;
83

84
        for (;;) {
×
85
                ssize_t l;
×
86

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

97
                if ((size_t) l == n)
×
98
                        return; /* Done reading, success. */
99

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

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

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

113
int crypto_random_bytes(void *p, size_t n) {
×
114
        assert(p || n == 0);
×
115

116
        if (n == 0)
×
117
                return 0;
118

119
        for (;;) {
×
120
                ssize_t l;
×
121

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

128
                if ((size_t) l == n)
×
129
                        return 0; /* Done reading, success. */
130

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

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

141
        assert(ret);
×
142

143
        p = malloc(MAX(n, 1U));
×
144
        if (!p)
×
145
                return -ENOMEM;
146

147
        r = crypto_random_bytes(p, n);
×
148
        if (r < 0)
×
149
                return r;
150

151
        *ret = IOVEC_MAKE(TAKE_PTR(p), n);
×
152
        return 0;
×
153
}
154

155
size_t random_pool_size(void) {
×
156
        _cleanup_free_ char *s = NULL;
×
157
        int r;
×
158

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

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

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

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

182
        assert(seed || size == 0);
×
183

184
        if (size == 0)
×
185
                return 0;
186

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

192
                fd = opened_fd;
193
        }
194

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

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

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

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

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

219
        return 1;
220
}
221

222
uint64_t random_u64_range(uint64_t m) {
×
223
        uint64_t x, remainder;
×
224

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

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

232
        remainder = UINT64_MAX % m;
×
233

234
        do {
×
235
                x = random_u64();
×
236
        } while (x >= UINT64_MAX - remainder);
×
237

238
        return x % m;
×
239
}
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