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

systemd / systemd / 15232239991

24 May 2025 08:01PM UTC coverage: 72.053% (-0.02%) from 72.07%
15232239991

push

github

web-flow
docs: add man pages for sd_device_enumerator_[new,ref,unref,unrefp] (#37586)

For #20929.

299160 of 415197 relevant lines covered (72.05%)

703671.29 hits per line

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

56.91
/src/shared/efi-loader.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include "alloc-util.h"
4
#include "efi-api.h"
5
#include "efi-loader.h"
6
#include "efivars.h"
7
#include "env-util.h"
8
#include "log.h"
9
#include "parse-util.h"
10
#include "path-util.h"
11
#include "stat-util.h"
12
#include "string-util.h"
13
#include "strv.h"
14
#include "time-util.h"
15
#include "tpm2-pcr.h"
16
#include "utf8.h"
17

18
#if ENABLE_EFI
19
static int read_usec(const char *variable, usec_t *ret) {
10✔
20
        _cleanup_free_ char *j = NULL;
10✔
21
        uint64_t x = 0;
10✔
22
        int r;
10✔
23

24
        assert(variable);
10✔
25
        assert(ret);
10✔
26

27
        r = efi_get_variable_string(variable, &j);
10✔
28
        if (r < 0)
10✔
29
                return r;
30

31
        r = safe_atou64(j, &x);
×
32
        if (r < 0)
×
33
                return r;
34

35
        *ret = x;
×
36
        return 0;
×
37
}
38

39
static int get_device_part_uuid(const char *variable, sd_id128_t *ret) {
28✔
40
        if (!is_efi_boot())
28✔
41
                return -EOPNOTSUPP;
42

43
        return efi_get_variable_id128(variable, ret);
22✔
44
}
45
#endif
46

47
int efi_loader_get_boot_usec(usec_t *ret_firmware, usec_t *ret_loader) {
24✔
48
#if ENABLE_EFI
49
        uint64_t x, y;
24✔
50
        int r;
24✔
51

52
        assert(ret_firmware);
24✔
53
        assert(ret_loader);
24✔
54

55
        if (!is_efi_boot())
24✔
56
                return -EOPNOTSUPP;
24✔
57

58
        r = read_usec(EFI_LOADER_VARIABLE_STR("LoaderTimeInitUSec"), &x);
10✔
59
        if (r < 0)
10✔
60
                return log_debug_errno(r, "Failed to read LoaderTimeInitUSec: %m");
10✔
61

62
        r = read_usec(EFI_LOADER_VARIABLE_STR("LoaderTimeExecUSec"), &y);
×
63
        if (r < 0)
×
64
                return log_debug_errno(r, "Failed to read LoaderTimeExecUSec: %m");
×
65

66
        if (y == 0 || y < x || y - x > USEC_PER_HOUR)
×
67
                return log_debug_errno(SYNTHETIC_ERRNO(EIO),
×
68
                                       "Bad LoaderTimeInitUSec=%"PRIu64", LoaderTimeExecUSec=%" PRIu64"; refusing.",
69
                                       x, y);
70

71
        *ret_firmware = x;
×
72
        *ret_loader = y;
×
73
        return 0;
×
74
#else
75
        return -EOPNOTSUPP;
76
#endif
77
}
78

79
int efi_loader_get_device_part_uuid(sd_id128_t *ret) {
16✔
80
#if ENABLE_EFI
81
        return get_device_part_uuid(EFI_LOADER_VARIABLE_STR("LoaderDevicePartUUID"), ret);
16✔
82
#else
83
        return -EOPNOTSUPP;
84
#endif
85
}
86

87
int efi_stub_get_device_part_uuid(sd_id128_t *ret) {
12✔
88
#if ENABLE_EFI
89
        return get_device_part_uuid(EFI_LOADER_VARIABLE_STR("StubDevicePartUUID"), ret);
12✔
90
#else
91
        return -EOPNOTSUPP;
92
#endif
93
}
94

95
int efi_loader_get_entries(char ***ret) {
14✔
96
#if ENABLE_EFI
97
        _cleanup_free_ char16_t *entries = NULL;
14✔
98
        _cleanup_strv_free_ char **l = NULL;
14✔
99
        size_t size;
14✔
100
        int r;
14✔
101

102
        assert(ret);
14✔
103

104
        if (!is_efi_boot())
14✔
105
                return -EOPNOTSUPP;
106

107
        r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntries"), NULL, (void**) &entries, &size);
6✔
108
        if (r < 0)
6✔
109
                return r;
110

111
        /* The variable contains a series of individually NUL terminated UTF-16 strings. We gracefully
112
         * consider the final NUL byte optional (i.e. the last string may or may not end in a NUL byte). */
113

114
        for (size_t i = 0, start = 0;; i++) {
720✔
115
                _cleanup_free_ char *decoded = NULL;
24✔
116
                bool end;
726✔
117

118
                /* Is this the end of the variable's data? */
119
                end = i * sizeof(char16_t) >= size;
726✔
120

121
                /* Are we in the middle of a string? (i.e. not at the end of the variable, nor at a NUL terminator?) If
122
                 * so, let's go to the next entry. */
123
                if (!end && entries[i] != 0)
726✔
124
                        continue;
696✔
125

126
                /* Empty string at the end of variable? That's the trailer, we are done (i.e. we have a final
127
                 * NUL terminator). */
128
                if (end && start == i)
30✔
129
                        break;
130

131
                /* We reached the end of a string, let's decode it into UTF-8 */
132
                decoded = utf16_to_utf8(entries + start, (i - start) * sizeof(char16_t));
24✔
133
                if (!decoded)
24✔
134
                        return -ENOMEM;
135

136
                if (efi_loader_entry_name_valid(decoded)) {
24✔
137
                        r = strv_consume(&l, TAKE_PTR(decoded));
24✔
138
                        if (r < 0)
24✔
139
                                return r;
140
                } else
141
                        log_debug("Ignoring invalid loader entry '%s'.", decoded);
×
142

143
                /* Exit the loop if we reached the end of the variable (i.e. we do not have a final NUL
144
                 * terminator) */
145
                if (end)
24✔
146
                        break;
147

148
                /* Continue after the NUL byte */
149
                start = i + 1;
24✔
150
        }
151

152
        *ret = TAKE_PTR(l);
6✔
153
        return 0;
6✔
154
#else
155
        return -EOPNOTSUPP;
156
#endif
157
}
158

159
int efi_loader_get_features(uint64_t *ret) {
6✔
160
#if ENABLE_EFI
161
        _cleanup_free_ void *v = NULL;
6✔
162
        size_t s;
6✔
163
        int r;
6✔
164

165
        assert(ret);
6✔
166

167
        if (!is_efi_boot()) {
6✔
168
                *ret = 0;
×
169
                return 0;
×
170
        }
171

172
        r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderFeatures"), NULL, &v, &s);
6✔
173
        if (r == -ENOENT) {
6✔
174
                _cleanup_free_ char *info = NULL;
×
175

176
                /* The new (v240+) LoaderFeatures variable is not supported, let's see if it's systemd-boot at all */
177
                r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderInfo"), &info);
×
178
                if (r < 0) {
×
179
                        if (r != -ENOENT)
×
180
                                return r;
181

182
                        /* Variable not set, definitely means not systemd-boot */
183

184
                } else if (first_word(info, "systemd-boot")) {
×
185

186
                        /* An older systemd-boot version. Let's hardcode the feature set, since it was pretty
187
                         * static in all its versions. */
188

189
                        *ret = EFI_LOADER_FEATURE_CONFIG_TIMEOUT |
×
190
                                EFI_LOADER_FEATURE_ENTRY_DEFAULT |
191
                                EFI_LOADER_FEATURE_ENTRY_ONESHOT;
192

193
                        return 0;
×
194
                }
195

196
                /* No features supported */
197
                *ret = 0;
×
198
                return 0;
×
199
        }
200
        if (r < 0)
6✔
201
                return r;
202

203
        if (s != sizeof(uint64_t))
6✔
204
                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
×
205
                                       "LoaderFeatures EFI variable doesn't have the right size.");
206

207
        memcpy(ret, v, sizeof(uint64_t));
6✔
208
        return 0;
6✔
209
#else
210
        return -EOPNOTSUPP;
211
#endif
212
}
213

214
int efi_stub_get_features(uint64_t *ret) {
12✔
215
#if ENABLE_EFI
216
        _cleanup_free_ void *v = NULL;
12✔
217
        size_t s;
12✔
218
        int r;
12✔
219

220
        assert(ret);
12✔
221

222
        if (!is_efi_boot()) {
12✔
223
                *ret = 0;
×
224
                return 0;
×
225
        }
226

227
        r = efi_get_variable(EFI_LOADER_VARIABLE_STR("StubFeatures"), NULL, &v, &s);
12✔
228
        if (r == -ENOENT) {
12✔
229
                _cleanup_free_ char *info = NULL;
×
230

231
                /* The new (v252+) StubFeatures variable is not supported, let's see if it's systemd-stub at all */
232
                r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("StubInfo"), &info);
×
233
                if (r < 0) {
×
234
                        if (r != -ENOENT)
×
235
                                return r;
236

237
                        /* Variable not set, definitely means not systemd-stub */
238

239
                } else if (first_word(info, "systemd-stub")) {
×
240

241
                        /* An older systemd-stub version. Let's hardcode the feature set, since it was pretty
242
                         * static in all its versions. */
243

244
                        *ret = EFI_STUB_FEATURE_REPORT_BOOT_PARTITION;
×
245
                        return 0;
×
246
                }
247

248
                /* No features supported */
249
                *ret = 0;
×
250
                return 0;
×
251
        }
252
        if (r < 0)
12✔
253
                return r;
254

255
        if (s != sizeof(uint64_t))
12✔
256
                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
×
257
                                       "StubFeatures EFI variable doesn't have the right size.");
258

259
        memcpy(ret, v, sizeof(uint64_t));
12✔
260
        return 0;
12✔
261
#else
262
        return -EOPNOTSUPP;
263
#endif
264
}
265

266
int efi_measured_uki(int log_level) {
308✔
267
#if ENABLE_EFI
268
        _cleanup_free_ char *pcr_string = NULL;
308✔
269
        static int cached = -1;
308✔
270
        unsigned pcr_nr;
308✔
271
        int r;
308✔
272

273
        if (cached >= 0)
308✔
274
                return cached;
275

276
        /* Checks if we are booted on a kernel with sd-stub which measured the kernel into PCR 11 on a TPM2
277
         * chip. Or in other words, if we are running on a TPM enabled UKI. (TPM 1.2 situations are ignored.)
278
         *
279
         * Returns == 0 and > 0 depending on the result of the test. Returns -EREMOTE if we detected a stub
280
         * being used, but it measured things into a different PCR than we are configured for in
281
         * userspace. (i.e. we expect PCR 11 being used for this by both sd-stub and us) */
282

283
        r = secure_getenv_bool("SYSTEMD_FORCE_MEASURE"); /* Give user a chance to override the variable test,
99✔
284
                                                          * for debugging purposes */
285
        if (r >= 0)
99✔
286
                return (cached = r);
17✔
287
        if (r != -ENXIO)
82✔
288
                log_debug_errno(r, "Failed to parse $SYSTEMD_FORCE_MEASURE, ignoring: %m");
×
289

290
        if (!efi_has_tpm2())
82✔
291
                return (cached = 0);
23✔
292

293
        r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("StubPcrKernelImage"), &pcr_string);
59✔
294
        if (r == -ENOENT)
59✔
295
                return (cached = 0);
×
296
        if (r < 0)
59✔
297
                return log_full_errno(log_level, r,
×
298
                                      "Failed to get StubPcrKernelImage EFI variable: %m");
299

300
        r = safe_atou(pcr_string, &pcr_nr);
59✔
301
        if (r < 0)
59✔
302
                return log_full_errno(log_level, r,
×
303
                                      "Failed to parse StubPcrKernelImage EFI variable: %s", pcr_string);
304
        if (pcr_nr != TPM2_PCR_KERNEL_BOOT)
59✔
305
                return log_full_errno(log_level, SYNTHETIC_ERRNO(EREMOTE),
×
306
                                      "Kernel stub measured kernel image into PCR %u, which is different than expected %i.",
307
                                      pcr_nr, TPM2_PCR_KERNEL_BOOT);
308

309
        return (cached = 1);
59✔
310
#else
311
        return log_full_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP), "Compiled without support for EFI");
312
#endif
313
}
314

315
int efi_loader_get_config_timeout_one_shot(usec_t *ret) {
×
316
#if ENABLE_EFI
317
        _cleanup_free_ char *v = NULL;
×
318
        static struct stat cache_stat = {};
×
319
        struct stat new_stat;
×
320
        static usec_t cache;
×
321
        uint64_t sec;
×
322
        int r;
×
323

324
        assert(ret);
×
325

326
        /* stat() the EFI variable, to see if the mtime changed. If it did, we need to cache again. */
327
        if (stat(EFIVAR_PATH(EFI_LOADER_VARIABLE_STR("LoaderConfigTimeoutOneShot")), &new_stat) < 0)
×
328
                return -errno;
×
329

330
        if (stat_inode_unmodified(&new_stat, &cache_stat)) {
×
331
                *ret = cache;
×
332
                return 0;
×
333
        }
334

335
        r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderConfigTimeoutOneShot"), &v);
×
336
        if (r < 0)
×
337
                return r;
338

339
        r = safe_atou64(v, &sec);
×
340
        if (r < 0)
×
341
                return r;
342
        if (sec > USEC_INFINITY / USEC_PER_SEC)
×
343
                return -ERANGE;
344

345
        cache_stat = new_stat;
×
346
        *ret = cache = sec * USEC_PER_SEC; /* return in μs */
×
347
        return 0;
×
348
#else
349
        return -EOPNOTSUPP;
350
#endif
351
}
352

353
int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat) {
×
354
#if ENABLE_EFI
355
        _cleanup_free_ char *v = NULL;
×
356
        struct stat new_stat;
×
357
        int r;
×
358

359
        assert(cache);
×
360
        assert(cache_stat);
×
361

362
        /* stat() the EFI variable, to see if the mtime changed. If it did we need to cache again. */
363
        if (stat(EFIVAR_PATH(EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot")), &new_stat) < 0)
×
364
                return -errno;
×
365

366
        if (stat_inode_unmodified(&new_stat, cache_stat))
×
367
                return 0;
368

369
        r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot"), &v);
×
370
        if (r < 0)
×
371
                return r;
372

373
        if (!efi_loader_entry_name_valid(v))
×
374
                return -EINVAL;
375

376
        *cache_stat = new_stat;
×
377
        free_and_replace(*cache, v);
×
378

379
        return 0;
×
380
#else
381
        return -EOPNOTSUPP;
382
#endif
383
}
384

385
int efi_get_variable_id128(const char *variable, sd_id128_t *ret) {
22✔
386
#if ENABLE_EFI
387
        int r;
22✔
388

389
        assert(variable);
22✔
390

391
        /* This is placed here (rather than in basic/efivars.c) because code in basic/ is not allowed to link
392
         * against libsystemd.so */
393

394
        _cleanup_free_ char *p = NULL;
22✔
395
        r = efi_get_variable_string(variable, &p);
22✔
396
        if (r < 0)
22✔
397
                return r;
398

399
        return sd_id128_from_string(p, ret);
22✔
400
#else
401
        return -EOPNOTSUPP;
402
#endif
403
}
404

405
bool efi_loader_entry_name_valid(const char *s) {
74✔
406
        if (!filename_is_valid(s)) /* Make sure entry names fit in filenames */
74✔
407
                return false;
408

409
        return in_charset(s, ALPHANUMERICAL "+-_.@");
74✔
410
}
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