]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/stub.c
units: add Before=shutdown.target to systemd-networkd-persistent-storage.service
[thirdparty/systemd.git] / src / boot / efi / stub.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "cpio.h"
4 #include "device-path-util.h"
5 #include "devicetree.h"
6 #include "graphics.h"
7 #include "linux.h"
8 #include "measure.h"
9 #include "memory-util-fundamental.h"
10 #include "part-discovery.h"
11 #include "pe.h"
12 #include "proto/shell-parameters.h"
13 #include "random-seed.h"
14 #include "sbat.h"
15 #include "secure-boot.h"
16 #include "shim.h"
17 #include "splash.h"
18 #include "tpm2-pcr.h"
19 #include "uki.h"
20 #include "util.h"
21 #include "version.h"
22 #include "vmm.h"
23
24 /* magic string to find in the binary image */
25 DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION " ####");
26
27 DECLARE_SBAT(SBAT_STUB_SECTION_TEXT);
28
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) {
33
34 size_t n = 0;
35
36 assert(ret_initr_pages);
37 assert(ret_initrd_size);
38
39 for (size_t i = 0; i < n_initrds; i++) {
40 if (!initrds[i])
41 continue;
42
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;
48
49 n += initrd_size;
50 }
51
52 _cleanup_pages_ Pages pages = xmalloc_pages(
53 AllocateMaxAddress,
54 EfiLoaderData,
55 EFI_SIZE_TO_PAGES(n),
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++) {
59 if (!initrds[i])
60 continue;
61
62 size_t pad;
63
64 p = mempcpy(p, initrds[i], initrd_sizes[i]);
65
66 pad = ALIGN4(initrd_sizes[i]) - initrd_sizes[i];
67 if (pad > 0) {
68 memzero(p, pad);
69 p += pad;
70 }
71 }
72
73 assert(PHYSICAL_ADDRESS_TO_POINTER(pages.addr + n) == p);
74
75 *ret_initr_pages = pages;
76 *ret_initrd_size = n;
77 pages.n_pages = 0;
78
79 return EFI_SUCCESS;
80 }
81
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 */
93 0;
94
95 assert(loaded_image);
96
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);
100 if (uuid)
101 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", uuid, 0);
102 }
103
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);
115 }
116
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);
122 }
123
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);
129 }
130
131
132 /* add StubInfo (this is one is owned by the stub, hence we unconditionally override this with our
133 * own data) */
134 (void) efivar_set(MAKE_GUID_PTR(LOADER), u"StubInfo", u"systemd-stub " GIT_VERSION, 0);
135
136 (void) efivar_set_uint64_le(MAKE_GUID_PTR(LOADER), u"StubFeatures", stub_features, 0);
137 }
138
139 static bool use_load_options(
140 EFI_HANDLE stub_image,
141 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
142 bool have_cmdline,
143 char16_t **ret) {
144
145 assert(stub_image);
146 assert(loaded_image);
147 assert(ret);
148
149 /* We only allow custom command lines if we aren't in secure boot or if no cmdline was baked into
150 * the stub image.
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()))
153 return false;
154
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)
158 return false;
159
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)
164 != EFI_SUCCESS) {
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);
169 return true;
170 }
171
172 if (shell->Argc < 2)
173 /* No arguments were provided? Then we fall back to built-in cmdline. */
174 return false;
175
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]);
181 }
182
183 mangle_stub_cmdline(*ret);
184 return true;
185 }
186
187 static EFI_STATUS load_addons_from_dir(
188 EFI_FILE *root,
189 const char16_t *prefix,
190 char16_t ***items,
191 size_t *n_items,
192 size_t *n_allocated) {
193
194 _cleanup_(file_closep) EFI_FILE *extra_dir = NULL;
195 _cleanup_free_ EFI_FILE_INFO *dirent = NULL;
196 size_t dirent_size = 0;
197 EFI_STATUS err;
198
199 assert(root);
200 assert(prefix);
201 assert(items);
202 assert(n_items);
203 assert(n_allocated);
204
205 err = open_directory(root, prefix, &extra_dir);
206 if (err == EFI_NOT_FOUND)
207 /* No extra subdir, that's totally OK */
208 return EFI_SUCCESS;
209 if (err != EFI_SUCCESS)
210 return log_error_status(err, "Failed to open addons directory '%ls': %m", prefix);
211
212 for (;;) {
213 _cleanup_free_ char16_t *d = NULL;
214
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 */
219 break;
220
221 if (dirent->FileName[0] == '.')
222 continue;
223 if (FLAGS_SET(dirent->Attribute, EFI_FILE_DIRECTORY))
224 continue;
225 if (!is_ascii(dirent->FileName))
226 continue;
227 if (strlen16(dirent->FileName) > 255) /* Max filename size on Linux */
228 continue;
229 if (!endswith_no_case(dirent->FileName, u".addon.efi"))
230 continue;
231
232 d = xstrdup16(dirent->FileName);
233
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 */
237 return log_oom();
238
239 size_t m = *n_items + 16;
240 *items = xrealloc(*items, *n_allocated * sizeof(uint16_t *), m * sizeof(uint16_t *));
241 *n_allocated = m;
242 }
243
244 (*items)[(*n_items)++] = TAKE_PTR(d);
245 (*items)[*n_items] = NULL; /* Let's always NUL terminate, to make freeing via strv_free() easy */
246 }
247
248 return EFI_SUCCESS;
249 }
250
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) {
256
257 _cleanup_free_ char16_t *tmp = NULL, *merged = NULL;
258 bool m = false;
259
260 assert(cmdline_append);
261 assert(ret_parameters_measured);
262
263 if (isempty(cmdline_global) && isempty(cmdline_uki))
264 return;
265
266 merged = xasprintf("%ls%ls%ls",
267 strempty(cmdline_global),
268 isempty(cmdline_global) || isempty(cmdline_uki) ? u"" : u" ",
269 strempty(cmdline_uki));
270
271 mangle_stub_cmdline(merged);
272
273 if (isempty(merged))
274 return;
275
276 (void) tpm_log_load_options(merged, &m);
277 *ret_parameters_measured = m;
278
279 tmp = TAKE_PTR(*cmdline_append);
280 *cmdline_append = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", merged);
281 }
282
283 static void dtb_install_addons(
284 struct devicetree_state *dt_state,
285 void **dt_bases,
286 size_t *dt_sizes,
287 char16_t **dt_filenames,
288 size_t n_dts,
289 bool *ret_parameters_measured) {
290
291 int parameters_measured = -1;
292 EFI_STATUS err;
293
294 assert(dt_state);
295 assert(n_dts == 0 || (dt_bases && dt_sizes && dt_filenames));
296 assert(ret_parameters_measured);
297
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");
302 else {
303 bool m = false;
304
305 err = tpm_log_tagged_event(
306 TPM2_PCR_KERNEL_CONFIG,
307 POINTER_TO_PHYSICAL_ADDRESS(dt_bases[i]),
308 dt_sizes[i],
309 DEVICETREE_ADDON_EVENT_TAG_ID,
310 dt_filenames[i],
311 &m);
312 if (err != EFI_SUCCESS)
313 return (void) log_error_status(
314 err,
315 "Unable to add measurement of DTB addon #%zu to PCR %i: %m",
316 i,
317 TPM2_PCR_KERNEL_CONFIG);
318
319 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
320 }
321 }
322
323 *ret_parameters_measured = parameters_measured;
324 }
325
326 static void dt_bases_free(void **dt_bases, size_t n_dt) {
327 assert(dt_bases || n_dt == 0);
328
329 for (size_t i = 0; i < n_dt; ++i)
330 free(dt_bases[i]);
331
332 free(dt_bases);
333 }
334
335 static void dt_filenames_free(char16_t **dt_filenames, size_t n_dt) {
336 assert(dt_filenames || n_dt == 0);
337
338 for (size_t i = 0; i < n_dt; ++i)
339 free(dt_filenames[i]);
340
341 free(dt_filenames);
342 }
343
344 static EFI_STATUS load_addons(
345 EFI_HANDLE stub_image,
346 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
347 const char16_t *prefix,
348 const char *uname,
349 char16_t **ret_cmdline,
350 void ***ret_dt_bases,
351 size_t **ret_dt_sizes,
352 char16_t ***ret_dt_filenames,
353 size_t *ret_n_dt) {
354
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;
362 EFI_STATUS err;
363
364 assert(stub_image);
365 assert(loaded_image);
366 assert(prefix);
367 assert(!!ret_dt_bases == !!ret_dt_sizes);
368 assert(!!ret_dt_bases == !!ret_n_dt);
369 assert(!!ret_dt_filenames == !!ret_n_dt);
370
371 if (!loaded_image->DeviceHandle)
372 return EFI_SUCCESS;
373
374 CLEANUP_ARRAY(dt_bases, n_dt, dt_bases_free);
375 CLEANUP_ARRAY(dt_filenames, n_dt, dt_filenames_free);
376
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. */
381 return EFI_SUCCESS;
382 if (err != EFI_SUCCESS)
383 return log_error_status(err, "Unable to open root directory: %m");
384
385 err = load_addons_from_dir(root, prefix, &items, &n_items, &n_allocated);
386 if (err != EFI_SUCCESS)
387 return err;
388
389 if (n_items == 0)
390 return EFI_SUCCESS; /* Empty directory */
391
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);
395
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;
402
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);
407
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",
414 items[i],
415 addon_spath);
416 continue;
417 }
418
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]);
424
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)
429 err = EFI_NOT_FOUND;
430 log_error_status(err,
431 "Unable to locate embedded .cmdline/.dtb sections in %ls, ignoring: %m",
432 items[i]);
433 continue;
434 }
435
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]);
439 continue;
440 }
441
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 &&
445 !strneq8(uname,
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]);
449 continue;
450 }
451
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);
457 }
458
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];
464
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],
469 dt_sizes[n_dt]);
470
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]);
475
476 ++n_dt;
477 }
478 }
479
480 if (ret_cmdline && !isempty(cmdline))
481 *ret_cmdline = TAKE_PTR(cmdline);
482
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);
487 *ret_n_dt = n_dt;
488 }
489
490 return EFI_SUCCESS;
491 }
492
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;
509 EFI_STATUS err;
510
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");
514
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;
519
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);
523 }
524
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)
528 err = EFI_NOT_FOUND;
529 return log_error_status(err, "Unable to locate embedded .linux section: %m");
530 }
531
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);
536
537 if (szs[UNIFIED_SECTION_UNAME] > 0)
538 uname = xstrndup8((char *)loaded_image->ImageBase + addrs[UNIFIED_SECTION_UNAME],
539 szs[UNIFIED_SECTION_UNAME]);
540
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. */
543 err = load_addons(
544 image,
545 loaded_image,
546 u"\\loader\\addons",
547 uname,
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");
555
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);
558 if (dropin_dir) {
559 err = load_addons(
560 image,
561 loaded_image,
562 dropin_dir,
563 uname,
564 &cmdline_addons_uki,
565 &dt_bases_addons_uki,
566 &dt_sizes_addons_uki,
567 &dt_filenames_addons_uki,
568 &n_dts_addons_uki);
569 if (err != EFI_SUCCESS)
570 log_error_status(err, "Error loading UKI-specific addons, ignoring: %m");
571 }
572
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++) {
577
578 if (!unified_section_measure(section)) /* shall not measure? */
579 continue;
580
581 if (szs[section] == 0) /* not found */
582 continue;
583
584 m = false;
585
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],
592 &m);
593
594 sections_measured = sections_measured < 0 ? m : (sections_measured && m);
595
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],
600 szs[section],
601 unified_sections[section],
602 &m);
603
604 sections_measured = sections_measured < 0 ? m : (sections_measured && m);
605 }
606
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);
611
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]);
614
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. */
620 m = false;
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);
628 }
629
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);
636
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");
641 if (extra) {
642 _cleanup_free_ char16_t *tmp = TAKE_PTR(cmdline), *extra16 = xstr8_to_16(extra);
643 cmdline = xasprintf("%ls %ls", tmp, extra16);
644
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. */
648 m = false;
649 (void) tpm_log_load_options(extra16, &m);
650 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
651 }
652 }
653
654 export_variables(loaded_image);
655
656 if (pack_cpio(loaded_image,
657 /* dropin_dir= */ NULL,
658 u".cred",
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",
665 &credential_initrd,
666 &credential_initrd_size,
667 &m) == EFI_SUCCESS)
668 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
669
670 if (pack_cpio(loaded_image,
671 u"\\loader\\credentials",
672 u".cred",
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,
681 &m) == EFI_SUCCESS)
682 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
683
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 */
688 ".extra/sysext",
689 /* dir_mode= */ 0555,
690 /* access_mode= */ 0444,
691 /* tpm_pcr= */ TPM2_PCR_SYSEXTS,
692 u"System extension initrd",
693 &sysext_initrd,
694 &sysext_initrd_size,
695 &m) == EFI_SUCCESS)
696 sysext_measured = m;
697
698 if (pack_cpio(loaded_image,
699 /* dropin_dir= */ NULL,
700 u".confext.raw",
701 /* exclude_suffix= */ NULL,
702 ".extra/confext",
703 /* dir_mode= */ 0555,
704 /* access_mode= */ 0444,
705 /* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
706 u"Configuration extension initrd",
707 &confext_initrd,
708 &confext_initrd_size,
709 &m) == EFI_SUCCESS)
710 confext_measured = m;
711
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;
714
715 /* First load the base device tree, then fix it up using addons - global first, then per-UKI. */
716 if (dt_size > 0) {
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");
721 }
722
723 dtb_install_addons(&dt_state,
724 dt_bases_addons_global,
725 dt_sizes_addons_global,
726 dt_filenames_addons_global,
727 n_dts_addons_global,
728 &m);
729 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
730 dtb_install_addons(&dt_state,
731 dt_bases_addons_uki,
732 dt_sizes_addons_uki,
733 dt_filenames_addons_uki,
734 n_dts_addons_uki,
735 &m);
736 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
737
738 if (parameters_measured > 0)
739 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrKernelParameters", TPM2_PCR_KERNEL_CONFIG, 0);
740 if (sysext_measured)
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);
744
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],
754 ".extra",
755 u"tpm2-pcr-signature.json",
756 /* dir_mode= */ 0555,
757 /* access_mode= */ 0444,
758 /* tpm_pcr= */ UINT32_MAX,
759 /* tpm_description= */ NULL,
760 &pcrsig_initrd,
761 &pcrsig_initrd_size,
762 /* ret_measured= */ NULL);
763
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
767 * cpio. */
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],
772 ".extra",
773 u"tpm2-pcr-public-key.pem",
774 /* dir_mode= */ 0555,
775 /* access_mode= */ 0444,
776 /* tpm_pcr= */ UINT32_MAX,
777 /* tpm_description= */ NULL,
778 &pcrpkey_initrd,
779 &pcrpkey_initrd_size,
780 /* ret_measured= */ NULL);
781
782 linux_size = szs[UNIFIED_SECTION_LINUX];
783 linux_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_LINUX];
784
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;
787
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;
790
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),
800 credential_initrd,
801 global_credential_initrd,
802 sysext_initrd,
803 confext_initrd,
804 pcrsig_initrd,
805 pcrpkey_initrd,
806 },
807 (const size_t[]) {
808 ucode_size,
809 initrd_size,
810 credential_initrd_size,
811 global_credential_initrd_size,
812 sysext_initrd_size,
813 confext_initrd_size,
814 pcrsig_initrd_size,
815 pcrpkey_initrd_size,
816 },
817 8,
818 &initrd_pages, &initrd_size);
819 if (err != EFI_SUCCESS)
820 return err;
821
822 initrd_base = initrd_pages.addr;
823
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);
831 }
832
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);
837 return err;
838 }
839
840 DEFINE_EFI_MAIN_FUNCTION(run, "systemd-stub", /*wait_for_debugger=*/false);