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

systemd / systemd / 14505075066

16 Apr 2025 06:24PM UTC coverage: 72.117% (+0.005%) from 72.112%
14505075066

push

github

yuwata
resolve: query the parent zone for DS records

RFC 4035 Section 4.2 requires that missing DS records are queried for in
the parent zone rather than the child zone, the old behaviour could
cause subdomains under home.arpa (RFC 8375) to fail validation.

This commit assumes that QDCOUNT = 1 as per RFC 9619

Fixes https://github.com/systemd/systemd/issues/19496

8 of 8 new or added lines in 2 files covered. (100.0%)

680 existing lines in 33 files now uncovered.

297042 of 411889 relevant lines covered (72.12%)

688478.02 hits per line

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

69.05
/src/bootctl/bootctl-random-seed.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include "alloc-util.h"
4
#include "bootctl.h"
5
#include "bootctl-random-seed.h"
6
#include "bootctl-util.h"
7
#include "efi-api.h"
8
#include "env-util.h"
9
#include "fd-util.h"
10
#include "find-esp.h"
11
#include "fs-util.h"
12
#include "glyph-util.h"
13
#include "io-util.h"
14
#include "mkdir.h"
15
#include "path-util.h"
16
#include "random-util.h"
17
#include "sha256.h"
18
#include "tmpfile-util.h"
19
#include "umask-util.h"
20

21
static int random_seed_verify_permissions(int fd, mode_t expected_type) {
51✔
22
        _cleanup_free_ char *full_path = NULL;
51✔
23
        struct stat st;
51✔
24
        int r;
51✔
25

26
        assert(fd >= 0);
51✔
27

28
        r = fd_get_path(fd, &full_path);
51✔
29
        if (r < 0)
51✔
30
                return log_error_errno(r, "Unable to determine full path of random seed fd: %m");
×
31

32
        if (fstat(fd, &st) < 0)
51✔
33
                return log_error_errno(errno, "Unable to stat %s: %m", full_path);
×
34

35
        if (((st.st_mode ^ expected_type) & S_IFMT) != 0)
51✔
36
                return log_error_errno(SYNTHETIC_ERRNO(EBADF),
×
37
                                       "Unexpected inode type when validating random seed access mode on %s: %m", full_path);
38

39
        if ((st.st_mode & 0007) == 0) /* All world bits are off? Then all is good */
51✔
40
                return 0;
41

42
        if (S_ISREG(expected_type))
10✔
43
                log_error("%s%sRandom seed file '%s' is world accessible, which is a security hole!%s%s",
5✔
44
                          optional_glyph(GLYPH_WARNING_SIGN), optional_glyph(GLYPH_SPACE),
45
                          full_path,
46
                          optional_glyph(GLYPH_SPACE), optional_glyph(GLYPH_WARNING_SIGN));
47
        else
48
                log_error("%s%s Mount point '%s' which backs the random seed file is world accessible, which is a security hole! %s%s",
51✔
49
                          optional_glyph(GLYPH_WARNING_SIGN), optional_glyph(GLYPH_SPACE),
50
                          full_path,
51
                          optional_glyph(GLYPH_SPACE), optional_glyph(GLYPH_WARNING_SIGN));
52

53
        return 1;
54
}
55

56
static int set_system_token(void) {
23✔
57
        uint8_t buffer[RANDOM_EFI_SEED_SIZE];
23✔
58
        size_t token_size;
23✔
59
        int r;
23✔
60

61
        if (!touch_variables())
23✔
62
                return 0;
23✔
63

64
        r = getenv_bool("SYSTEMD_WRITE_SYSTEM_TOKEN");
7✔
65
        if (r < 0) {
7✔
66
                if (r != -ENXIO)
7✔
UNCOV
67
                        log_warning_errno(r, "Failed to parse $SYSTEMD_WRITE_SYSTEM_TOKEN, ignoring.");
×
UNCOV
68
        } else if (r == 0) {
×
UNCOV
69
                log_notice("Not writing system token, because $SYSTEMD_WRITE_SYSTEM_TOKEN is set to false.");
×
UNCOV
70
                return 0;
×
71
        }
72

73
        r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderSystemToken"), NULL, NULL, &token_size);
7✔
74
        if (r == -ENODATA)
7✔
UNCOV
75
                log_debug_errno(r, "LoaderSystemToken EFI variable is invalid (too short?), replacing.");
×
76
        else if (r < 0) {
7✔
77
                if (r != -ENOENT)
4✔
78
                        return log_error_errno(r, "Failed to test system token validity: %m");
×
79
        } else {
80
                if (token_size >= sizeof(buffer)) {
3✔
81
                        /* Let's avoid writes if we can, and initialize this only once. */
82
                        log_debug("System token already written, not updating.");
3✔
83
                        return 0;
3✔
84
                }
85

86
                log_debug("Existing system token size (%zu) does not match our expectations (%zu), replacing.", token_size, sizeof(buffer));
×
87
        }
88

89
        r = crypto_random_bytes(buffer, sizeof(buffer));
4✔
90
        if (r < 0)
4✔
UNCOV
91
                return log_error_errno(r, "Failed to acquire random seed: %m");
×
92

93
        /* Let's write this variable with an umask in effect, so that unprivileged users can't see the token
94
         * and possibly get identification information or too much insight into the kernel's entropy pool
95
         * state. */
96
        WITH_UMASK(0077) {
8✔
97
                r = efi_set_variable(EFI_LOADER_VARIABLE_STR("LoaderSystemToken"), buffer, sizeof(buffer));
4✔
98
                if (r < 0) {
4✔
UNCOV
99
                        if (!arg_graceful)
×
UNCOV
100
                                return log_error_errno(r, "Failed to write 'LoaderSystemToken' EFI variable: %m");
×
101

102
                        if (r == -EINVAL)
×
UNCOV
103
                                log_notice_errno(r, "Unable to write 'LoaderSystemToken' EFI variable (firmware problem?), ignoring: %m");
×
104
                        else
UNCOV
105
                                log_notice_errno(r, "Unable to write 'LoaderSystemToken' EFI variable, ignoring: %m");
×
106
                } else
107
                        log_info("Successfully initialized system token in EFI variable with %zu bytes.", sizeof(buffer));
4✔
108
        }
109

110
        return 0;
4✔
111
}
112

113
int install_random_seed(const char *esp) {
23✔
114
        _cleanup_close_ int esp_fd = -EBADF, loader_dir_fd = -EBADF, fd = -EBADF;
46✔
115
        _cleanup_free_ char *tmp = NULL;
23✔
116
        uint8_t buffer[RANDOM_EFI_SEED_SIZE];
23✔
117
        struct sha256_ctx hash_state;
23✔
118
        bool refreshed, warned = false;
23✔
119
        int r;
23✔
120

121
        assert(esp);
23✔
122

123
        assert_cc(RANDOM_EFI_SEED_SIZE == SHA256_DIGEST_SIZE);
23✔
124

125
        esp_fd = open(esp, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
23✔
126
        if (esp_fd < 0)
23✔
UNCOV
127
                return log_error_errno(errno, "Failed to open ESP directory '%s': %m", esp);
×
128

129
        (void) random_seed_verify_permissions(esp_fd, S_IFDIR);
23✔
130

131
        loader_dir_fd = open_mkdir_at(esp_fd, "loader", O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOFOLLOW, 0775);
23✔
132
        if (loader_dir_fd < 0)
23✔
UNCOV
133
                return log_error_errno(loader_dir_fd, "Failed to open loader directory '%s/loader': %m", esp);
×
134

135
        r = crypto_random_bytes(buffer, sizeof(buffer));
23✔
136
        if (r < 0)
23✔
UNCOV
137
                return log_error_errno(r, "Failed to acquire random seed: %m");
×
138

139
        sha256_init_ctx(&hash_state);
23✔
140
        sha256_process_bytes_and_size(buffer, sizeof(buffer), &hash_state);
23✔
141

142
        fd = openat(loader_dir_fd, "random-seed", O_NOFOLLOW|O_CLOEXEC|O_RDONLY|O_NOCTTY);
23✔
143
        if (fd < 0) {
23✔
144
                if (errno != ENOENT)
17✔
UNCOV
145
                        return log_error_errno(errno, "Failed to open old random seed file: %m");
×
146

147
                sha256_process_bytes(&(const ssize_t) { 0 }, sizeof(ssize_t), &hash_state);
17✔
148
                refreshed = false;
17✔
149
        } else {
150
                ssize_t n;
6✔
151

152
                warned = random_seed_verify_permissions(fd, S_IFREG) > 0;
6✔
153

154
                /* Hash the old seed in so that we never regress in entropy. */
155

156
                n = read(fd, buffer, sizeof(buffer));
6✔
157
                if (n < 0)
6✔
UNCOV
158
                        return log_error_errno(errno, "Failed to read old random seed file: %m");
×
159

160
                sha256_process_bytes_and_size(buffer, n, &hash_state);
6✔
161

162
                fd = safe_close(fd);
6✔
163
                refreshed = n > 0;
6✔
164
        }
165

166
        sha256_finish_ctx(&hash_state, buffer);
23✔
167

168
        if (tempfn_random("random-seed", "bootctl", &tmp) < 0)
23✔
169
                return log_oom();
×
170

171
        fd = openat(loader_dir_fd, tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600);
23✔
172
        if (fd < 0)
23✔
UNCOV
173
                return log_error_errno(fd, "Failed to open random seed file for writing: %m");
×
174

175
        if (!warned) /* only warn once per seed file */
23✔
176
                (void) random_seed_verify_permissions(fd, S_IFREG);
22✔
177

178
        r = loop_write(fd, buffer, sizeof(buffer));
23✔
179
        if (r < 0) {
23✔
180
                log_error_errno(r, "Failed to write random seed file: %m");
×
UNCOV
181
                goto fail;
×
182
        }
183

184
        if (fsync(fd) < 0 || fsync(loader_dir_fd) < 0) {
23✔
UNCOV
185
                r = log_error_errno(errno, "Failed to sync random seed file: %m");
×
UNCOV
186
                goto fail;
×
187
        }
188

189
        if (renameat(loader_dir_fd, tmp, loader_dir_fd, "random-seed") < 0) {
23✔
UNCOV
190
                r = log_error_errno(errno, "Failed to move random seed file into place: %m");
×
191
                goto fail;
×
192
        }
193

194
        tmp = mfree(tmp);
23✔
195

196
        if (syncfs(fd) < 0)
23✔
197
                return log_error_errno(errno, "Failed to sync ESP file system: %m");
×
198

199
        log_info("Random seed file %s/loader/random-seed successfully %s (%zu bytes).", esp, refreshed ? "refreshed" : "written", sizeof(buffer));
40✔
200

201
        return set_system_token();
23✔
202

UNCOV
203
fail:
×
UNCOV
204
        assert(tmp);
×
UNCOV
205
        (void) unlinkat(loader_dir_fd, tmp, 0);
×
206

UNCOV
207
        return r;
×
208
}
209

210
int verb_random_seed(int argc, char *argv[], void *userdata) {
10✔
211
        int r;
10✔
212

213
        r = find_esp_and_warn(arg_root, arg_esp_path, false, &arg_esp_path, NULL, NULL, NULL, NULL, NULL);
10✔
214
        if (r == -ENOKEY) {
10✔
215
                /* find_esp_and_warn() doesn't warn about ENOKEY, so let's do that on our own */
216
                if (!arg_graceful)
×
UNCOV
217
                        return log_error_errno(r, "Unable to find ESP.");
×
218

UNCOV
219
                log_notice("No ESP found, not initializing random seed.");
×
UNCOV
220
                return 0;
×
221
        }
222
        if (r < 0)
10✔
223
                return r;
224

225
        r = install_random_seed(arg_esp_path);
10✔
226
        if (r < 0)
10✔
227
                return r;
×
228

229
        return 0;
230
}
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