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

systemd / systemd / 24642716378

18 Apr 2026 10:29PM UTC coverage: 70.661% (-1.2%) from 71.872%
24642716378

push

github

web-flow
iovec-wrapper: fix memleak, rename functions for consistency, and introduce several helper functions (#41689)

227 of 237 new or added lines in 4 files covered. (95.78%)

3483 existing lines in 82 files now uncovered.

76021 of 107585 relevant lines covered (70.66%)

4993286.11 hits per line

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

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

3
#include <elf.h>
4
#include <fcntl.h>
5
#include <linux/random.h>
6
#include <string.h>
7
#include <sys/auxv.h>
8
#include <sys/ioctl.h>
9
#include <sys/random.h>
10
#include <threads.h>
11
#include <unistd.h>
12

13
#include "alloc-util.h"
14
#include "fd-util.h"
15
#include "fileio.h"
16
#include "io-util.h"
17
#include "iovec-util.h"
18
#include "log.h"
19
#include "parse-util.h"
20
#include "pidfd-util.h"
21
#include "process-util.h"
22
#include "random-util.h"
23
#include "sha256.h"
24
#include "time-util.h"
25

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

48
        memcpy(state.label, "systemd fallback random bytes v1", sizeof(state.label));
×
49
        memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval));
×
50
        (void) pidfd_get_inode_id_self_cached(&state.pidfdid);
×
51

52
        while (n > 0) {
×
53
                struct sha256_ctx ctx;
×
54

55
                sha256_init_ctx(&ctx);
×
56
                sha256_process_bytes(&state, sizeof(state), &ctx);
×
57
                if (n < SHA256_DIGEST_SIZE) {
×
58
                        uint8_t partial[SHA256_DIGEST_SIZE];
×
59
                        sha256_finish_ctx(&ctx, partial);
×
60
                        memcpy(p, partial, n);
×
61
                        break;
×
62
                }
63
                sha256_finish_ctx(&ctx, p);
×
64
                p = (uint8_t *) p + SHA256_DIGEST_SIZE;
×
65
                n -= SHA256_DIGEST_SIZE;
×
66
                ++state.block_id;
×
67
        }
68
}
×
69

70
void random_bytes(void *p, size_t n) {
5,523,247✔
71
        assert(p || n == 0);
5,523,247✔
72

73
        if (n == 0)
5,523,247✔
74
                return;
75

76
        for (;;) {
5,523,247✔
77
                ssize_t l;
5,523,247✔
78

79
                l = getrandom(p, n, GRND_INSECURE);
5,523,247✔
80
                if (l <= 0)
5,523,247✔
81
                        break; /* Unexpected error. Give up and fallback to /dev/urandom. */
82

83
                if ((size_t) l == n)
5,523,247✔
84
                        return; /* Done reading, success. */
85

86
                p = (uint8_t *) p + l;
×
87
                n -= l;
×
88
                /* Interrupted by a signal; keep going. */
89
        }
90

91
        _cleanup_close_ int fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
5,523,247✔
92
        if (fd >= 0 && loop_read_exact(fd, p, n, false) >= 0)
×
93
                return;
×
94

95
        /* This is a terrible fallback. Oh well. */
96
        fallback_random_bytes(p, n);
×
97
}
98

UNCOV
99
int random_bytes_allocate_iovec(size_t n, struct iovec *ret) {
×
UNCOV
100
        assert(ret);
×
101

UNCOV
102
        void *p = malloc(MAX(n, 1U));
×
UNCOV
103
        if (!p)
×
UNCOV
104
                return -ENOMEM;
×
105

UNCOV
106
        random_bytes(p, n);
×
107

UNCOV
108
        *ret = IOVEC_MAKE(TAKE_PTR(p), n);
×
UNCOV
109
        return 0;
×
110
}
111

112
int crypto_random_bytes(void *p, size_t n) {
141✔
113
        assert(p || n == 0);
141✔
114

115
        if (n == 0)
141✔
116
                return 0;
117

118
        for (;;) {
141✔
119
                ssize_t l;
141✔
120

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

127
                if ((size_t) l == n)
141✔
128
                        return 0; /* Done reading, success. */
129

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

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

140
        assert(ret);
59✔
141

142
        p = malloc(MAX(n, 1U));
59✔
143
        if (!p)
59✔
144
                return -ENOMEM;
145

146
        r = crypto_random_bytes(p, n);
59✔
147
        if (r < 0)
59✔
148
                return r;
149

150
        *ret = IOVEC_MAKE(TAKE_PTR(p), n);
59✔
151
        return 0;
59✔
152
}
153

154
size_t random_pool_size(void) {
142✔
155
        _cleanup_free_ char *s = NULL;
142✔
156
        int r;
142✔
157

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

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

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

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

181
        assert(seed || size == 0);
79✔
182

183
        if (size == 0)
79✔
184
                return 0;
185

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

191
                fd = opened_fd;
192
        }
193

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

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

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

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

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

218
        return 1;
219
}
220

221
uint64_t random_u64_range(uint64_t m) {
2,820,239✔
222
        uint64_t x, remainder;
2,820,239✔
223

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

226
        if (m == 0) /* Let's take m == 0 as special case to return an integer from the full range */
2,820,239✔
UNCOV
227
                return random_u64();
×
228
        if (m == 1)
2,820,239✔
229
                return 0;
230

231
        remainder = UINT64_MAX % m;
2,720,239✔
232

233
        do {
2,720,242✔
234
                x = random_u64();
2,720,242✔
235
        } while (x >= UINT64_MAX - remainder);
2,720,242✔
236

237
        return x % m;
2,720,239✔
238
}
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