1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
5 #include "efi-loader.h"
7 #include "parse-util.h"
16 static int read_usec(const char *variable
, usec_t
*ret
) {
17 _cleanup_free_
char *j
= NULL
;
24 r
= efi_get_variable_string(variable
, &j
);
28 r
= safe_atou64(j
, &x
);
36 int efi_loader_get_boot_usec(usec_t
*ret_firmware
, usec_t
*ret_loader
) {
46 r
= read_usec(EFI_LOADER_VARIABLE(LoaderTimeInitUSec
), &x
);
48 return log_debug_errno(r
, "Failed to read LoaderTimeInitUSec: %m");
50 r
= read_usec(EFI_LOADER_VARIABLE(LoaderTimeExecUSec
), &y
);
52 return log_debug_errno(r
, "Failed to read LoaderTimeExecUSec: %m");
54 if (y
== 0 || y
< x
|| y
- x
> USEC_PER_HOUR
)
55 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
56 "Bad LoaderTimeInitUSec=%"PRIu64
", LoaderTimeExecUSec=%" PRIu64
"; refusing.",
64 int efi_loader_get_device_part_uuid(sd_id128_t
*ret
) {
65 _cleanup_free_
char *p
= NULL
;
72 r
= efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderDevicePartUUID
), &p
);
76 if (sscanf(p
, SD_ID128_UUID_FORMAT_STR
,
77 &parsed
[0], &parsed
[1], &parsed
[2], &parsed
[3],
78 &parsed
[4], &parsed
[5], &parsed
[6], &parsed
[7],
79 &parsed
[8], &parsed
[9], &parsed
[10], &parsed
[11],
80 &parsed
[12], &parsed
[13], &parsed
[14], &parsed
[15]) != 16)
84 for (unsigned i
= 0; i
< ELEMENTSOF(parsed
); i
++)
85 ret
->bytes
[i
] = parsed
[i
];
90 int efi_loader_get_entries(char ***ret
) {
91 _cleanup_free_ char16_t
*entries
= NULL
;
92 _cleanup_strv_free_
char **l
= NULL
;
101 r
= efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntries
), NULL
, (void**) &entries
, &size
);
105 /* The variable contains a series of individually NUL terminated UTF-16 strings. */
107 for (size_t i
= 0, start
= 0;; i
++) {
108 _cleanup_free_
char *decoded
= NULL
;
111 /* Is this the end of the variable's data? */
112 end
= i
* sizeof(char16_t
) >= size
;
114 /* Are we in the middle of a string? (i.e. not at the end of the variable, nor at a NUL terminator?) If
115 * so, let's go to the next entry. */
116 if (!end
&& entries
[i
] != 0)
119 /* We reached the end of a string, let's decode it into UTF-8 */
120 decoded
= utf16_to_utf8(entries
+ start
, (i
- start
) * sizeof(char16_t
));
124 if (efi_loader_entry_name_valid(decoded
)) {
125 r
= strv_consume(&l
, TAKE_PTR(decoded
));
129 log_debug("Ignoring invalid loader entry '%s'.", decoded
);
131 /* We reached the end of the variable */
135 /* Continue after the NUL byte */
143 int efi_loader_get_features(uint64_t *ret
) {
144 _cleanup_free_
void *v
= NULL
;
150 if (!is_efi_boot()) {
155 r
= efi_get_variable(EFI_LOADER_VARIABLE(LoaderFeatures
), NULL
, &v
, &s
);
157 _cleanup_free_
char *info
= NULL
;
159 /* The new (v240+) LoaderFeatures variable is not supported, let's see if it's systemd-boot at all */
160 r
= efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderInfo
), &info
);
165 /* Variable not set, definitely means not systemd-boot */
167 } else if (first_word(info
, "systemd-boot")) {
169 /* An older systemd-boot version. Let's hardcode the feature set, since it was pretty
170 * static in all its versions. */
172 *ret
= EFI_LOADER_FEATURE_CONFIG_TIMEOUT
|
173 EFI_LOADER_FEATURE_ENTRY_DEFAULT
|
174 EFI_LOADER_FEATURE_ENTRY_ONESHOT
;
179 /* No features supported */
186 if (s
!= sizeof(uint64_t))
187 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
188 "LoaderFeatures EFI variable doesn't have the right size.");
190 memcpy(ret
, v
, sizeof(uint64_t));
194 int efi_stub_get_features(uint64_t *ret
) {
195 _cleanup_free_
void *v
= NULL
;
201 if (!is_efi_boot()) {
206 r
= efi_get_variable(EFI_LOADER_VARIABLE(StubFeatures
), NULL
, &v
, &s
);
208 _cleanup_free_
char *info
= NULL
;
210 /* The new (v252+) StubFeatures variable is not supported, let's see if it's systemd-stub at all */
211 r
= efi_get_variable_string(EFI_LOADER_VARIABLE(StubInfo
), &info
);
216 /* Variable not set, definitely means not systemd-stub */
218 } else if (first_word(info
, "systemd-stub")) {
220 /* An older systemd-stub version. Let's hardcode the feature set, since it was pretty
221 * static in all its versions. */
223 *ret
= EFI_STUB_FEATURE_REPORT_BOOT_PARTITION
;
227 /* No features supported */
234 if (s
!= sizeof(uint64_t))
235 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
236 "StubFeatures EFI variable doesn't have the right size.");
238 memcpy(ret
, v
, sizeof(uint64_t));
242 int efi_measured_uki(int log_level
) {
243 _cleanup_free_
char *pcr_string
= NULL
;
244 static int cached
= -1;
251 /* Checks if we are booted on a kernel with sd-stub which measured the kernel into PCR 11 on a TPM2
252 * chip. Or in other words, if we are running on a TPM enabled UKI. (TPM 1.2 situations are ignored.)
254 * Returns == 0 and > 0 depending on the result of the test. Returns -EREMOTE if we detected a stub
255 * being used, but it measured things into a different PCR than we are configured for in
256 * userspace. (i.e. we expect PCR 11 being used for this by both sd-stub and us) */
258 r
= getenv_bool_secure("SYSTEMD_FORCE_MEASURE"); /* Give user a chance to override the variable test,
259 * for debugging purposes */
263 log_debug_errno(r
, "Failed to parse $SYSTEMD_FORCE_MEASURE, ignoring: %m");
268 r
= efi_get_variable_string(EFI_LOADER_VARIABLE(StubPcrKernelImage
), &pcr_string
);
272 return log_full_errno(log_level
, r
,
273 "Failed to get StubPcrKernelImage EFI variable: %m");
275 r
= safe_atou(pcr_string
, &pcr_nr
);
277 return log_full_errno(log_level
, r
,
278 "Failed to parse StubPcrKernelImage EFI variable: %s", pcr_string
);
279 if (pcr_nr
!= TPM2_PCR_KERNEL_BOOT
)
280 return log_full_errno(log_level
, SYNTHETIC_ERRNO(EREMOTE
),
281 "Kernel stub measured kernel image into PCR %u, which is different than expected %i.",
282 pcr_nr
, TPM2_PCR_KERNEL_BOOT
);
287 int efi_loader_get_config_timeout_one_shot(usec_t
*ret
) {
288 _cleanup_free_
char *v
= NULL
;
289 static struct stat cache_stat
= {};
290 struct stat new_stat
;
297 /* stat() the EFI variable, to see if the mtime changed. If it did, we need to cache again. */
298 if (stat(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot
)), &new_stat
) < 0)
301 if (stat_inode_unmodified(&new_stat
, &cache_stat
)) {
306 r
= efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot
), &v
);
310 r
= safe_atou64(v
, &sec
);
313 if (sec
> USEC_INFINITY
/ USEC_PER_SEC
)
316 cache_stat
= new_stat
;
317 *ret
= cache
= sec
* USEC_PER_SEC
; /* return in μs */
321 int efi_loader_update_entry_one_shot_cache(char **cache
, struct stat
*cache_stat
) {
322 _cleanup_free_
char *v
= NULL
;
323 struct stat new_stat
;
329 /* stat() the EFI variable, to see if the mtime changed. If it did we need to cache again. */
330 if (stat(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderEntryOneShot
)), &new_stat
) < 0)
333 if (stat_inode_unmodified(&new_stat
, cache_stat
))
336 r
= efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryOneShot
), &v
);
340 if (!efi_loader_entry_name_valid(v
))
343 *cache_stat
= new_stat
;
344 free_and_replace(*cache
, v
);
351 bool efi_loader_entry_name_valid(const char *s
) {
352 if (!filename_is_valid(s
)) /* Make sure entry names fit in filenames */
355 return in_charset(s
, ALPHANUMERICAL
"+-_.");