1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "device-path-util.h"
5 #include "devicetree.h"
9 #include "memory-util-fundamental.h"
10 #include "part-discovery.h"
12 #include "proto/shell-parameters.h"
13 #include "random-seed.h"
15 #include "secure-boot.h"
24 /* magic string to find in the binary image */
25 DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION
" ####");
27 DECLARE_SBAT(SBAT_STUB_SECTION_TEXT
);
29 /* Combine initrds by concatenation in memory */
30 static EFI_STATUS
combine_initrds(
31 const void * const initrds
[], const size_t initrd_sizes
[], size_t n_initrds
,
32 Pages
*ret_initr_pages
, size_t *ret_initrd_size
) {
36 assert(ret_initr_pages
);
37 assert(ret_initrd_size
);
39 for (size_t i
= 0; i
< n_initrds
; i
++) {
43 /* some initrds (the ones from UKI sections) need padding,
44 * pad all to be safe */
45 size_t initrd_size
= ALIGN4(initrd_sizes
[i
]);
46 if (n
> SIZE_MAX
- initrd_size
)
47 return EFI_OUT_OF_RESOURCES
;
52 _cleanup_pages_ Pages pages
= xmalloc_pages(
56 UINT32_MAX
/* Below 4G boundary. */);
57 uint8_t *p
= PHYSICAL_ADDRESS_TO_POINTER(pages
.addr
);
58 for (size_t i
= 0; i
< n_initrds
; i
++) {
64 p
= mempcpy(p
, initrds
[i
], initrd_sizes
[i
]);
66 pad
= ALIGN4(initrd_sizes
[i
]) - initrd_sizes
[i
];
73 assert(PHYSICAL_ADDRESS_TO_POINTER(pages
.addr
+ n
) == p
);
75 *ret_initr_pages
= pages
;
82 static void export_variables(EFI_LOADED_IMAGE_PROTOCOL
*loaded_image
) {
83 static const uint64_t stub_features
=
84 EFI_STUB_FEATURE_REPORT_BOOT_PARTITION
| /* We set LoaderDevicePartUUID */
85 EFI_STUB_FEATURE_PICK_UP_CREDENTIALS
| /* We pick up credentials from the boot partition */
86 EFI_STUB_FEATURE_PICK_UP_SYSEXTS
| /* We pick up system extensions from the boot partition */
87 EFI_STUB_FEATURE_PICK_UP_CONFEXTS
| /* We pick up configuration extensions from the boot partition */
88 EFI_STUB_FEATURE_THREE_PCRS
| /* We can measure kernel image, parameters and sysext */
89 EFI_STUB_FEATURE_RANDOM_SEED
| /* We pass a random seed to the kernel */
90 EFI_STUB_FEATURE_CMDLINE_ADDONS
| /* We pick up .cmdline addons */
91 EFI_STUB_FEATURE_CMDLINE_SMBIOS
| /* We support extending kernel cmdline from SMBIOS Type #11 */
92 EFI_STUB_FEATURE_DEVICETREE_ADDONS
| /* We pick up .dtb addons */
97 /* Export the device path this image is started from, if it's not set yet */
98 if (efivar_get_raw(MAKE_GUID_PTR(LOADER
), u
"LoaderDevicePartUUID", NULL
, NULL
) != EFI_SUCCESS
) {
99 _cleanup_free_ char16_t
*uuid
= disk_get_part_uuid(loaded_image
->DeviceHandle
);
101 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderDevicePartUUID", uuid
, 0);
104 /* If LoaderImageIdentifier is not set, assume the image with this stub was loaded directly from the
105 * UEFI firmware without any boot loader, and hence set the LoaderImageIdentifier ourselves. Note
106 * that some boot chain loaders neither set LoaderImageIdentifier nor make FilePath available to us,
107 * in which case there's simple nothing to set for us. (The UEFI spec doesn't really say who's wrong
108 * here, i.e. whether FilePath may be NULL or not, hence handle this gracefully and check if FilePath
109 * is non-NULL explicitly.) */
110 if (efivar_get_raw(MAKE_GUID_PTR(LOADER
), u
"LoaderImageIdentifier", NULL
, NULL
) != EFI_SUCCESS
&&
111 loaded_image
->FilePath
) {
112 _cleanup_free_ char16_t
*s
= NULL
;
113 if (device_path_to_str(loaded_image
->FilePath
, &s
) == EFI_SUCCESS
)
114 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderImageIdentifier", s
, 0);
117 /* if LoaderFirmwareInfo is not set, let's set it */
118 if (efivar_get_raw(MAKE_GUID_PTR(LOADER
), u
"LoaderFirmwareInfo", NULL
, NULL
) != EFI_SUCCESS
) {
119 _cleanup_free_ char16_t
*s
= NULL
;
120 s
= xasprintf("%ls %u.%02u", ST
->FirmwareVendor
, ST
->FirmwareRevision
>> 16, ST
->FirmwareRevision
& 0xffff);
121 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderFirmwareInfo", s
, 0);
124 /* ditto for LoaderFirmwareType */
125 if (efivar_get_raw(MAKE_GUID_PTR(LOADER
), u
"LoaderFirmwareType", NULL
, NULL
) != EFI_SUCCESS
) {
126 _cleanup_free_ char16_t
*s
= NULL
;
127 s
= xasprintf("UEFI %u.%02u", ST
->Hdr
.Revision
>> 16, ST
->Hdr
.Revision
& 0xffff);
128 efivar_set(MAKE_GUID_PTR(LOADER
), u
"LoaderFirmwareType", s
, 0);
132 /* add StubInfo (this is one is owned by the stub, hence we unconditionally override this with our
134 (void) efivar_set(MAKE_GUID_PTR(LOADER
), u
"StubInfo", u
"systemd-stub " GIT_VERSION
, 0);
136 (void) efivar_set_uint64_le(MAKE_GUID_PTR(LOADER
), u
"StubFeatures", stub_features
, 0);
139 static bool use_load_options(
140 EFI_HANDLE stub_image
,
141 EFI_LOADED_IMAGE_PROTOCOL
*loaded_image
,
146 assert(loaded_image
);
149 /* We only allow custom command lines if we aren't in secure boot or if no cmdline was baked into
151 * We also don't allow it if we are in confidential vms and secureboot is on. */
152 if (secure_boot_enabled() && (have_cmdline
|| is_confidential_vm()))
155 /* We also do a superficial check whether first character of passed command line
156 * is printable character (for compat with some Dell systems which fill in garbage?). */
157 if (loaded_image
->LoadOptionsSize
< sizeof(char16_t
) || ((char16_t
*) loaded_image
->LoadOptions
)[0] <= 0x1F)
160 /* The UEFI shell registers EFI_SHELL_PARAMETERS_PROTOCOL onto images it runs. This lets us know that
161 * LoadOptions starts with the stub binary path which we want to strip off. */
162 EFI_SHELL_PARAMETERS_PROTOCOL
*shell
;
163 if (BS
->HandleProtocol(stub_image
, MAKE_GUID_PTR(EFI_SHELL_PARAMETERS_PROTOCOL
), (void **) &shell
)
165 /* Not running from EFI shell, use entire LoadOptions. Note that LoadOptions is a void*, so
166 * it could be anything! */
167 *ret
= xstrndup16(loaded_image
->LoadOptions
, loaded_image
->LoadOptionsSize
/ sizeof(char16_t
));
168 mangle_stub_cmdline(*ret
);
173 /* No arguments were provided? Then we fall back to built-in cmdline. */
176 /* Assemble the command line ourselves without our stub path. */
177 *ret
= xstrdup16(shell
->Argv
[1]);
178 for (size_t i
= 2; i
< shell
->Argc
; i
++) {
179 _cleanup_free_ char16_t
*old
= *ret
;
180 *ret
= xasprintf("%ls %ls", old
, shell
->Argv
[i
]);
183 mangle_stub_cmdline(*ret
);
187 static EFI_STATUS
load_addons_from_dir(
189 const char16_t
*prefix
,
192 size_t *n_allocated
) {
194 _cleanup_(file_closep
) EFI_FILE
*extra_dir
= NULL
;
195 _cleanup_free_ EFI_FILE_INFO
*dirent
= NULL
;
196 size_t dirent_size
= 0;
205 err
= open_directory(root
, prefix
, &extra_dir
);
206 if (err
== EFI_NOT_FOUND
)
207 /* No extra subdir, that's totally OK */
209 if (err
!= EFI_SUCCESS
)
210 return log_error_status(err
, "Failed to open addons directory '%ls': %m", prefix
);
213 _cleanup_free_ char16_t
*d
= NULL
;
215 err
= readdir(extra_dir
, &dirent
, &dirent_size
);
216 if (err
!= EFI_SUCCESS
)
217 return log_error_status(err
, "Failed to read addons directory of loaded image: %m");
218 if (!dirent
) /* End of directory */
221 if (dirent
->FileName
[0] == '.')
223 if (FLAGS_SET(dirent
->Attribute
, EFI_FILE_DIRECTORY
))
225 if (!is_ascii(dirent
->FileName
))
227 if (strlen16(dirent
->FileName
) > 255) /* Max filename size on Linux */
229 if (!endswith_no_case(dirent
->FileName
, u
".addon.efi"))
232 d
= xstrdup16(dirent
->FileName
);
234 if (*n_items
+ 2 > *n_allocated
) {
235 /* We allocate 16 entries at a time, as a matter of optimization */
236 if (*n_items
> (SIZE_MAX
/ sizeof(uint16_t)) - 16) /* Overflow check, just in case */
239 size_t m
= *n_items
+ 16;
240 *items
= xrealloc(*items
, *n_allocated
* sizeof(uint16_t *), m
* sizeof(uint16_t *));
244 (*items
)[(*n_items
)++] = TAKE_PTR(d
);
245 (*items
)[*n_items
] = NULL
; /* Let's always NUL terminate, to make freeing via strv_free() easy */
251 static void cmdline_append_and_measure_addons(
252 char16_t
*cmdline_global
,
253 char16_t
*cmdline_uki
,
254 char16_t
**cmdline_append
,
255 bool *ret_parameters_measured
) {
257 _cleanup_free_ char16_t
*tmp
= NULL
, *merged
= NULL
;
260 assert(cmdline_append
);
261 assert(ret_parameters_measured
);
263 if (isempty(cmdline_global
) && isempty(cmdline_uki
))
266 merged
= xasprintf("%ls%ls%ls",
267 strempty(cmdline_global
),
268 isempty(cmdline_global
) || isempty(cmdline_uki
) ? u
"" : u
" ",
269 strempty(cmdline_uki
));
271 mangle_stub_cmdline(merged
);
276 (void) tpm_log_load_options(merged
, &m
);
277 *ret_parameters_measured
= m
;
279 tmp
= TAKE_PTR(*cmdline_append
);
280 *cmdline_append
= xasprintf("%ls%ls%ls", strempty(tmp
), isempty(tmp
) ? u
"" : u
" ", merged
);
283 static void dtb_install_addons(
284 struct devicetree_state
*dt_state
,
287 char16_t
**dt_filenames
,
289 bool *ret_parameters_measured
) {
291 int parameters_measured
= -1;
295 assert(n_dts
== 0 || (dt_bases
&& dt_sizes
&& dt_filenames
));
296 assert(ret_parameters_measured
);
298 for (size_t i
= 0; i
< n_dts
; ++i
) {
299 err
= devicetree_install_from_memory(dt_state
, dt_bases
[i
], dt_sizes
[i
]);
300 if (err
!= EFI_SUCCESS
)
301 log_error_status(err
, "Error loading addon devicetree, ignoring: %m");
305 err
= tpm_log_tagged_event(
306 TPM2_PCR_KERNEL_CONFIG
,
307 POINTER_TO_PHYSICAL_ADDRESS(dt_bases
[i
]),
309 DEVICETREE_ADDON_EVENT_TAG_ID
,
312 if (err
!= EFI_SUCCESS
)
313 return (void) log_error_status(
315 "Unable to add measurement of DTB addon #%zu to PCR %i: %m",
317 TPM2_PCR_KERNEL_CONFIG
);
319 parameters_measured
= parameters_measured
< 0 ? m
: (parameters_measured
&& m
);
323 *ret_parameters_measured
= parameters_measured
;
326 static void dt_bases_free(void **dt_bases
, size_t n_dt
) {
327 assert(dt_bases
|| n_dt
== 0);
329 for (size_t i
= 0; i
< n_dt
; ++i
)
335 static void dt_filenames_free(char16_t
**dt_filenames
, size_t n_dt
) {
336 assert(dt_filenames
|| n_dt
== 0);
338 for (size_t i
= 0; i
< n_dt
; ++i
)
339 free(dt_filenames
[i
]);
344 static EFI_STATUS
load_addons(
345 EFI_HANDLE stub_image
,
346 EFI_LOADED_IMAGE_PROTOCOL
*loaded_image
,
347 const char16_t
*prefix
,
349 char16_t
**ret_cmdline
,
350 void ***ret_dt_bases
,
351 size_t **ret_dt_sizes
,
352 char16_t
***ret_dt_filenames
,
355 _cleanup_free_
size_t *dt_sizes
= NULL
;
356 _cleanup_(strv_freep
) char16_t
**items
= NULL
;
357 _cleanup_(file_closep
) EFI_FILE
*root
= NULL
;
358 _cleanup_free_ char16_t
*cmdline
= NULL
;
359 size_t n_items
= 0, n_allocated
= 0, n_dt
= 0;
360 char16_t
**dt_filenames
= NULL
;
361 void **dt_bases
= NULL
;
365 assert(loaded_image
);
367 assert(!!ret_dt_bases
== !!ret_dt_sizes
);
368 assert(!!ret_dt_bases
== !!ret_n_dt
);
369 assert(!!ret_dt_filenames
== !!ret_n_dt
);
371 if (!loaded_image
->DeviceHandle
)
374 CLEANUP_ARRAY(dt_bases
, n_dt
, dt_bases_free
);
375 CLEANUP_ARRAY(dt_filenames
, n_dt
, dt_filenames_free
);
377 err
= open_volume(loaded_image
->DeviceHandle
, &root
);
378 if (err
== EFI_UNSUPPORTED
)
379 /* Error will be unsupported if the bootloader doesn't implement the file system protocol on
380 * its file handles. */
382 if (err
!= EFI_SUCCESS
)
383 return log_error_status(err
, "Unable to open root directory: %m");
385 err
= load_addons_from_dir(root
, prefix
, &items
, &n_items
, &n_allocated
);
386 if (err
!= EFI_SUCCESS
)
390 return EFI_SUCCESS
; /* Empty directory */
392 /* Now, sort the files we found, to make this uniform and stable (and to ensure the TPM measurements
393 * are not dependent on read order) */
394 sort_pointer_array((void**) items
, n_items
, (compare_pointer_func_t
) strcmp16
);
396 for (size_t i
= 0; i
< n_items
; i
++) {
397 size_t addrs
[_UNIFIED_SECTION_MAX
] = {}, szs
[_UNIFIED_SECTION_MAX
] = {};
398 _cleanup_free_ EFI_DEVICE_PATH
*addon_path
= NULL
;
399 _cleanup_(unload_imagep
) EFI_HANDLE addon
= NULL
;
400 EFI_LOADED_IMAGE_PROTOCOL
*loaded_addon
= NULL
;
401 _cleanup_free_ char16_t
*addon_spath
= NULL
;
403 addon_spath
= xasprintf("%ls\\%ls", prefix
, items
[i
]);
404 err
= make_file_device_path(loaded_image
->DeviceHandle
, addon_spath
, &addon_path
);
405 if (err
!= EFI_SUCCESS
)
406 return log_error_status(err
, "Error making device path for %ls: %m", addon_spath
);
408 /* By using shim_load_image, we cover both the case where the PE files are signed with MoK
409 * and with DB, and running with or without shim. */
410 err
= shim_load_image(stub_image
, addon_path
, &addon
);
411 if (err
!= EFI_SUCCESS
) {
412 log_error_status(err
,
413 "Failed to read '%ls' from '%ls', ignoring: %m",
419 err
= BS
->HandleProtocol(addon
,
420 MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL
),
421 (void **) &loaded_addon
);
422 if (err
!= EFI_SUCCESS
)
423 return log_error_status(err
, "Failed to find protocol in %ls: %m", items
[i
]);
425 err
= pe_memory_locate_sections(loaded_addon
->ImageBase
, unified_sections
, addrs
, szs
);
426 if (err
!= EFI_SUCCESS
||
427 (szs
[UNIFIED_SECTION_CMDLINE
] == 0 && szs
[UNIFIED_SECTION_DTB
] == 0)) {
428 if (err
== EFI_SUCCESS
)
430 log_error_status(err
,
431 "Unable to locate embedded .cmdline/.dtb sections in %ls, ignoring: %m",
436 /* We want to enforce that addons are not UKIs, i.e.: they must not embed a kernel. */
437 if (szs
[UNIFIED_SECTION_LINUX
] > 0) {
438 log_error_status(EFI_INVALID_PARAMETER
, "%ls is a UKI, not an addon, ignoring: %m", items
[i
]);
442 /* Also enforce that, in case it is specified, .uname matches as a quick way to allow
443 * enforcing compatibility with a specific UKI only */
444 if (uname
&& szs
[UNIFIED_SECTION_UNAME
] > 0 &&
446 (char *)loaded_addon
->ImageBase
+ addrs
[UNIFIED_SECTION_UNAME
],
447 szs
[UNIFIED_SECTION_UNAME
])) {
448 log_error(".uname mismatch between %ls and UKI, ignoring", items
[i
]);
452 if (ret_cmdline
&& szs
[UNIFIED_SECTION_CMDLINE
] > 0) {
453 _cleanup_free_ char16_t
*tmp
= TAKE_PTR(cmdline
),
454 *extra16
= xstrn8_to_16((char *)loaded_addon
->ImageBase
+ addrs
[UNIFIED_SECTION_CMDLINE
],
455 szs
[UNIFIED_SECTION_CMDLINE
]);
456 cmdline
= xasprintf("%ls%ls%ls", strempty(tmp
), isempty(tmp
) ? u
"" : u
" ", extra16
);
459 if (ret_dt_bases
&& szs
[UNIFIED_SECTION_DTB
] > 0) {
460 dt_sizes
= xrealloc(dt_sizes
,
461 n_dt
* sizeof(size_t),
462 (n_dt
+ 1) * sizeof(size_t));
463 dt_sizes
[n_dt
] = szs
[UNIFIED_SECTION_DTB
];
465 dt_bases
= xrealloc(dt_bases
,
466 n_dt
* sizeof(void *),
467 (n_dt
+ 1) * sizeof(void *));
468 dt_bases
[n_dt
] = xmemdup((uint8_t*)loaded_addon
->ImageBase
+ addrs
[UNIFIED_SECTION_DTB
],
471 dt_filenames
= xrealloc(dt_filenames
,
472 n_dt
* sizeof(char16_t
*),
473 (n_dt
+ 1) * sizeof(char16_t
*));
474 dt_filenames
[n_dt
] = xstrdup16(items
[i
]);
480 if (ret_cmdline
&& !isempty(cmdline
))
481 *ret_cmdline
= TAKE_PTR(cmdline
);
483 if (ret_n_dt
&& n_dt
> 0) {
484 *ret_dt_filenames
= TAKE_PTR(dt_filenames
);
485 *ret_dt_bases
= TAKE_PTR(dt_bases
);
486 *ret_dt_sizes
= TAKE_PTR(dt_sizes
);
493 static EFI_STATUS
run(EFI_HANDLE image
) {
494 _cleanup_free_
void *credential_initrd
= NULL
, *global_credential_initrd
= NULL
, *sysext_initrd
= NULL
, *confext_initrd
= NULL
, *pcrsig_initrd
= NULL
, *pcrpkey_initrd
= NULL
;
495 size_t credential_initrd_size
= 0, global_credential_initrd_size
= 0, sysext_initrd_size
= 0, confext_initrd_size
= 0, pcrsig_initrd_size
= 0, pcrpkey_initrd_size
= 0;
496 void **dt_bases_addons_global
= NULL
, **dt_bases_addons_uki
= NULL
;
497 char16_t
**dt_filenames_addons_global
= NULL
, **dt_filenames_addons_uki
= NULL
;
498 _cleanup_free_
size_t *dt_sizes_addons_global
= NULL
, *dt_sizes_addons_uki
= NULL
;
499 size_t linux_size
, initrd_size
, ucode_size
, dt_size
, n_dts_addons_global
= 0, n_dts_addons_uki
= 0;
500 EFI_PHYSICAL_ADDRESS linux_base
, initrd_base
, ucode_base
, dt_base
;
501 _cleanup_(devicetree_cleanup
) struct devicetree_state dt_state
= {};
502 EFI_LOADED_IMAGE_PROTOCOL
*loaded_image
;
503 size_t addrs
[_UNIFIED_SECTION_MAX
] = {}, szs
[_UNIFIED_SECTION_MAX
] = {};
504 _cleanup_free_ char16_t
*cmdline
= NULL
, *cmdline_addons_global
= NULL
, *cmdline_addons_uki
= NULL
;
505 int sections_measured
= -1, parameters_measured
= -1;
506 _cleanup_free_
char *uname
= NULL
;
507 bool sysext_measured
= false, confext_measured
= false, m
;
508 uint64_t loader_features
= 0;
511 err
= BS
->HandleProtocol(image
, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL
), (void **) &loaded_image
);
512 if (err
!= EFI_SUCCESS
)
513 return log_error_status(err
, "Error getting a LoadedImageProtocol handle: %m");
515 if (loaded_image
->DeviceHandle
&& /* Handle case, where bootloader doesn't support DeviceHandle. */
516 (efivar_get_uint64_le(MAKE_GUID_PTR(LOADER
), u
"LoaderFeatures", &loader_features
) != EFI_SUCCESS
||
517 !FLAGS_SET(loader_features
, EFI_LOADER_FEATURE_RANDOM_SEED
))) {
518 _cleanup_(file_closep
) EFI_FILE
*esp_dir
= NULL
;
520 err
= partition_open(MAKE_GUID_PTR(ESP
), loaded_image
->DeviceHandle
, NULL
, &esp_dir
);
521 if (err
== EFI_SUCCESS
) /* Non-fatal on failure, so that we still boot without it. */
522 (void) process_random_seed(esp_dir
);
525 err
= pe_memory_locate_sections(loaded_image
->ImageBase
, unified_sections
, addrs
, szs
);
526 if (err
!= EFI_SUCCESS
|| szs
[UNIFIED_SECTION_LINUX
] == 0) {
527 if (err
== EFI_SUCCESS
)
529 return log_error_status(err
, "Unable to locate embedded .linux section: %m");
532 CLEANUP_ARRAY(dt_bases_addons_global
, n_dts_addons_global
, dt_bases_free
);
533 CLEANUP_ARRAY(dt_bases_addons_uki
, n_dts_addons_uki
, dt_bases_free
);
534 CLEANUP_ARRAY(dt_filenames_addons_global
, n_dts_addons_global
, dt_filenames_free
);
535 CLEANUP_ARRAY(dt_filenames_addons_uki
, n_dts_addons_uki
, dt_filenames_free
);
537 if (szs
[UNIFIED_SECTION_UNAME
] > 0)
538 uname
= xstrndup8((char *)loaded_image
->ImageBase
+ addrs
[UNIFIED_SECTION_UNAME
],
539 szs
[UNIFIED_SECTION_UNAME
]);
541 /* Now that we have the UKI sections loaded, also load global first and then local (per-UKI)
542 * addons. The data is loaded at once, and then used later. */
548 &cmdline_addons_global
,
549 &dt_bases_addons_global
,
550 &dt_sizes_addons_global
,
551 &dt_filenames_addons_global
,
552 &n_dts_addons_global
);
553 if (err
!= EFI_SUCCESS
)
554 log_error_status(err
, "Error loading global addons, ignoring: %m");
556 /* Some bootloaders always pass NULL in FilePath, so we need to check for it here. */
557 _cleanup_free_ char16_t
*dropin_dir
= get_extra_dir(loaded_image
->FilePath
);
565 &dt_bases_addons_uki
,
566 &dt_sizes_addons_uki
,
567 &dt_filenames_addons_uki
,
569 if (err
!= EFI_SUCCESS
)
570 log_error_status(err
, "Error loading UKI-specific addons, ignoring: %m");
573 /* Measure all "payload" of this PE image into a separate PCR (i.e. where nothing else is written
574 * into so far), so that we have one PCR that we can nicely write policies against because it
575 * contains all static data of this image, and thus can be easily be pre-calculated. */
576 for (UnifiedSection section
= 0; section
< _UNIFIED_SECTION_MAX
; section
++) {
578 if (!unified_section_measure(section
)) /* shall not measure? */
581 if (szs
[section
] == 0) /* not found */
586 /* First measure the name of the section */
587 (void) tpm_log_event_ascii(
588 TPM2_PCR_KERNEL_BOOT
,
589 POINTER_TO_PHYSICAL_ADDRESS(unified_sections
[section
]),
590 strsize8(unified_sections
[section
]), /* including NUL byte */
591 unified_sections
[section
],
594 sections_measured
= sections_measured
< 0 ? m
: (sections_measured
&& m
);
596 /* Then measure the data of the section */
597 (void) tpm_log_event_ascii(
598 TPM2_PCR_KERNEL_BOOT
,
599 POINTER_TO_PHYSICAL_ADDRESS(loaded_image
->ImageBase
) + addrs
[section
],
601 unified_sections
[section
],
604 sections_measured
= sections_measured
< 0 ? m
: (sections_measured
&& m
);
607 /* After we are done, set an EFI variable that tells userspace this was done successfully, and encode
608 * in it which PCR was used. */
609 if (sections_measured
> 0)
610 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER
), u
"StubPcrKernelImage", TPM2_PCR_KERNEL_BOOT
, 0);
612 /* Show splash screen as early as possible */
613 graphics_splash((const uint8_t*) loaded_image
->ImageBase
+ addrs
[UNIFIED_SECTION_SPLASH
], szs
[UNIFIED_SECTION_SPLASH
]);
615 if (use_load_options(image
, loaded_image
, szs
[UNIFIED_SECTION_CMDLINE
] > 0, &cmdline
)) {
616 /* Let's measure the passed kernel command line into the TPM. Note that this possibly
617 * duplicates what we already did in the boot menu, if that was already used. However, since
618 * we want the boot menu to support an EFI binary, and want to this stub to be usable from
619 * any boot menu, let's measure things anyway. */
621 (void) tpm_log_load_options(cmdline
, &m
);
622 parameters_measured
= m
;
623 } else if (szs
[UNIFIED_SECTION_CMDLINE
] > 0) {
624 cmdline
= xstrn8_to_16(
625 (char *) loaded_image
->ImageBase
+ addrs
[UNIFIED_SECTION_CMDLINE
],
626 szs
[UNIFIED_SECTION_CMDLINE
]);
627 mangle_stub_cmdline(cmdline
);
630 /* If we have any extra command line to add via PE addons, load them now and append, and
631 * measure the additions together, after the embedded options, but before the smbios ones,
632 * so that the order is reversed from "most hardcoded" to "most dynamic". The global addons are
633 * loaded first, and the image-specific ones later, for the same reason. */
634 cmdline_append_and_measure_addons(cmdline_addons_global
, cmdline_addons_uki
, &cmdline
, &m
);
635 parameters_measured
= parameters_measured
< 0 ? m
: (parameters_measured
&& m
);
637 /* SMBIOS OEM Strings data is controlled by the host admin and not covered
638 * by the VM attestation, so MUST NOT be trusted when in a confidential VM */
639 if (!is_confidential_vm()) {
640 const char *extra
= smbios_find_oem_string("io.systemd.stub.kernel-cmdline-extra");
642 _cleanup_free_ char16_t
*tmp
= TAKE_PTR(cmdline
), *extra16
= xstr8_to_16(extra
);
643 cmdline
= xasprintf("%ls %ls", tmp
, extra16
);
645 /* SMBIOS strings are measured in PCR1, but we also want to measure them in our specific
646 * PCR12, as firmware-owned PCRs are very difficult to use as they'll contain unpredictable
647 * measurements that are not under control of the machine owner. */
649 (void) tpm_log_load_options(extra16
, &m
);
650 parameters_measured
= parameters_measured
< 0 ? m
: (parameters_measured
&& m
);
654 export_variables(loaded_image
);
656 if (pack_cpio(loaded_image
,
657 /* dropin_dir= */ NULL
,
659 /* exclude_suffix= */ NULL
,
660 ".extra/credentials",
661 /* dir_mode= */ 0500,
662 /* access_mode= */ 0400,
663 /* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG
,
664 u
"Credentials initrd",
666 &credential_initrd_size
,
668 parameters_measured
= parameters_measured
< 0 ? m
: (parameters_measured
&& m
);
670 if (pack_cpio(loaded_image
,
671 u
"\\loader\\credentials",
673 /* exclude_suffix= */ NULL
,
674 ".extra/global_credentials",
675 /* dir_mode= */ 0500,
676 /* access_mode= */ 0400,
677 /* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG
,
678 u
"Global credentials initrd",
679 &global_credential_initrd
,
680 &global_credential_initrd_size
,
682 parameters_measured
= parameters_measured
< 0 ? m
: (parameters_measured
&& m
);
684 if (pack_cpio(loaded_image
,
685 /* dropin_dir= */ NULL
,
686 u
".raw", /* ideally we'd pick up only *.sysext.raw here, but for compat we pick up *.raw instead … */
687 u
".confext.raw", /* … but then exclude *.confext.raw again */
689 /* dir_mode= */ 0555,
690 /* access_mode= */ 0444,
691 /* tpm_pcr= */ TPM2_PCR_SYSEXTS
,
692 u
"System extension initrd",
698 if (pack_cpio(loaded_image
,
699 /* dropin_dir= */ NULL
,
701 /* exclude_suffix= */ NULL
,
703 /* dir_mode= */ 0555,
704 /* access_mode= */ 0444,
705 /* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG
,
706 u
"Configuration extension initrd",
708 &confext_initrd_size
,
710 confext_measured
= m
;
712 dt_size
= szs
[UNIFIED_SECTION_DTB
];
713 dt_base
= dt_size
!= 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image
->ImageBase
) + addrs
[UNIFIED_SECTION_DTB
] : 0;
715 /* First load the base device tree, then fix it up using addons - global first, then per-UKI. */
717 err
= devicetree_install_from_memory(
718 &dt_state
, PHYSICAL_ADDRESS_TO_POINTER(dt_base
), dt_size
);
719 if (err
!= EFI_SUCCESS
)
720 log_error_status(err
, "Error loading embedded devicetree: %m");
723 dtb_install_addons(&dt_state
,
724 dt_bases_addons_global
,
725 dt_sizes_addons_global
,
726 dt_filenames_addons_global
,
729 parameters_measured
= parameters_measured
< 0 ? m
: (parameters_measured
&& m
);
730 dtb_install_addons(&dt_state
,
733 dt_filenames_addons_uki
,
736 parameters_measured
= parameters_measured
< 0 ? m
: (parameters_measured
&& m
);
738 if (parameters_measured
> 0)
739 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER
), u
"StubPcrKernelParameters", TPM2_PCR_KERNEL_CONFIG
, 0);
741 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER
), u
"StubPcrInitRDSysExts", TPM2_PCR_SYSEXTS
, 0);
742 if (confext_measured
)
743 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER
), u
"StubPcrInitRDConfExts", TPM2_PCR_KERNEL_CONFIG
, 0);
745 /* If the PCR signature was embedded in the PE image, then let's wrap it in a cpio and also pass it
746 * to the kernel, so that it can be read from /.extra/tpm2-pcr-signature.json. Note that this section
747 * is not measured, neither as raw section (see above), nor as cpio (here), because it is the
748 * signature of expected PCR values, i.e. its input are PCR measurements, and hence it shouldn't
749 * itself be input for PCR measurements. */
750 if (szs
[UNIFIED_SECTION_PCRSIG
] > 0)
751 (void) pack_cpio_literal(
752 (uint8_t*) loaded_image
->ImageBase
+ addrs
[UNIFIED_SECTION_PCRSIG
],
753 szs
[UNIFIED_SECTION_PCRSIG
],
755 u
"tpm2-pcr-signature.json",
756 /* dir_mode= */ 0555,
757 /* access_mode= */ 0444,
758 /* tpm_pcr= */ UINT32_MAX
,
759 /* tpm_description= */ NULL
,
762 /* ret_measured= */ NULL
);
764 /* If the public key used for the PCR signatures was embedded in the PE image, then let's wrap it in
765 * a cpio and also pass it to the kernel, so that it can be read from
766 * /.extra/tpm2-pcr-public-key.pem. This section is already measure above, hence we won't measure the
768 if (szs
[UNIFIED_SECTION_PCRPKEY
] > 0)
769 (void) pack_cpio_literal(
770 (uint8_t*) loaded_image
->ImageBase
+ addrs
[UNIFIED_SECTION_PCRPKEY
],
771 szs
[UNIFIED_SECTION_PCRPKEY
],
773 u
"tpm2-pcr-public-key.pem",
774 /* dir_mode= */ 0555,
775 /* access_mode= */ 0444,
776 /* tpm_pcr= */ UINT32_MAX
,
777 /* tpm_description= */ NULL
,
779 &pcrpkey_initrd_size
,
780 /* ret_measured= */ NULL
);
782 linux_size
= szs
[UNIFIED_SECTION_LINUX
];
783 linux_base
= POINTER_TO_PHYSICAL_ADDRESS(loaded_image
->ImageBase
) + addrs
[UNIFIED_SECTION_LINUX
];
785 initrd_size
= szs
[UNIFIED_SECTION_INITRD
];
786 initrd_base
= initrd_size
!= 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image
->ImageBase
) + addrs
[UNIFIED_SECTION_INITRD
] : 0;
788 ucode_size
= szs
[UNIFIED_SECTION_UCODE
];
789 ucode_base
= ucode_size
!= 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image
->ImageBase
) + addrs
[UNIFIED_SECTION_UCODE
] : 0;
791 _cleanup_pages_ Pages initrd_pages
= {};
792 if (ucode_base
|| credential_initrd
|| global_credential_initrd
|| sysext_initrd
|| confext_initrd
|| pcrsig_initrd
|| pcrpkey_initrd
) {
793 /* If we have generated initrds dynamically or there is a microcode initrd, combine them with the built-in initrd. */
794 err
= combine_initrds(
795 (const void*const[]) {
796 /* Microcode must always be first as kernel only scans uncompressed cpios
797 * and later initrds might be compressed. */
798 PHYSICAL_ADDRESS_TO_POINTER(ucode_base
),
799 PHYSICAL_ADDRESS_TO_POINTER(initrd_base
),
801 global_credential_initrd
,
810 credential_initrd_size
,
811 global_credential_initrd_size
,
818 &initrd_pages
, &initrd_size
);
819 if (err
!= EFI_SUCCESS
)
822 initrd_base
= initrd_pages
.addr
;
824 /* Given these might be large let's free them explicitly, quickly. */
825 credential_initrd
= mfree(credential_initrd
);
826 global_credential_initrd
= mfree(global_credential_initrd
);
827 sysext_initrd
= mfree(sysext_initrd
);
828 confext_initrd
= mfree(confext_initrd
);
829 pcrsig_initrd
= mfree(pcrsig_initrd
);
830 pcrpkey_initrd
= mfree(pcrpkey_initrd
);
833 err
= linux_exec(image
, cmdline
,
834 PHYSICAL_ADDRESS_TO_POINTER(linux_base
), linux_size
,
835 PHYSICAL_ADDRESS_TO_POINTER(initrd_base
), initrd_size
);
836 graphics_mode(false);
840 DEFINE_EFI_MAIN_FUNCTION(run
, "systemd-stub", /*wait_for_debugger=*/false);