]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/stub.c
Merge pull request #28919 from fbuihuu/custom-config-file-install-path
[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 "part-discovery.h"
10 #include "pe.h"
11 #include "proto/shell-parameters.h"
12 #include "random-seed.h"
13 #include "sbat.h"
14 #include "secure-boot.h"
15 #include "shim.h"
16 #include "splash.h"
17 #include "tpm2-pcr.h"
18 #include "uki.h"
19 #include "util.h"
20 #include "version.h"
21 #include "vmm.h"
22
23 /* magic string to find in the binary image */
24 _used_ _section_(".sdmagic") static const char magic[] = "#### LoaderInfo: systemd-stub " GIT_VERSION " ####";
25
26 DECLARE_SBAT(SBAT_STUB_SECTION_TEXT);
27
28 static EFI_STATUS combine_initrd(
29 EFI_PHYSICAL_ADDRESS initrd_base, size_t initrd_size,
30 const void * const extra_initrds[], const size_t extra_initrd_sizes[], size_t n_extra_initrds,
31 Pages *ret_initr_pages, size_t *ret_initrd_size) {
32
33 size_t n;
34
35 assert(ret_initr_pages);
36 assert(ret_initrd_size);
37
38 /* Combines four initrds into one, by simple concatenation in memory */
39
40 n = ALIGN4(initrd_size); /* main initrd might not be padded yet */
41
42 for (size_t i = 0; i < n_extra_initrds; i++) {
43 if (!extra_initrds[i])
44 continue;
45
46 if (n > SIZE_MAX - extra_initrd_sizes[i])
47 return EFI_OUT_OF_RESOURCES;
48
49 n += extra_initrd_sizes[i];
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 if (initrd_base != 0) {
59 size_t pad;
60
61 /* Order matters, the real initrd must come first, since it might include microcode updates
62 * which the kernel only looks for in the first cpio archive */
63 p = mempcpy(p, PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
64
65 pad = ALIGN4(initrd_size) - initrd_size;
66 if (pad > 0) {
67 memset(p, 0, pad);
68 p += pad;
69 }
70 }
71
72 for (size_t i = 0; i < n_extra_initrds; i++) {
73 if (!extra_initrds[i])
74 continue;
75
76 p = mempcpy(p, extra_initrds[i], extra_initrd_sizes[i]);
77 }
78
79 assert(PHYSICAL_ADDRESS_TO_POINTER(pages.addr + n) == p);
80
81 *ret_initr_pages = pages;
82 *ret_initrd_size = n;
83 pages.n_pages = 0;
84
85 return EFI_SUCCESS;
86 }
87
88 static void export_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
89 static const uint64_t stub_features =
90 EFI_STUB_FEATURE_REPORT_BOOT_PARTITION | /* We set LoaderDevicePartUUID */
91 EFI_STUB_FEATURE_PICK_UP_CREDENTIALS | /* We pick up credentials from the boot partition */
92 EFI_STUB_FEATURE_PICK_UP_SYSEXTS | /* We pick up system extensions from the boot partition */
93 EFI_STUB_FEATURE_THREE_PCRS | /* We can measure kernel image, parameters and sysext */
94 EFI_STUB_FEATURE_RANDOM_SEED | /* We pass a random seed to the kernel */
95 EFI_STUB_FEATURE_CMDLINE_ADDONS | /* We pick up .cmdline addons */
96 EFI_STUB_FEATURE_CMDLINE_SMBIOS | /* We support extending kernel cmdline from SMBIOS Type #11 */
97 0;
98
99 assert(loaded_image);
100
101 /* Export the device path this image is started from, if it's not set yet */
102 if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", NULL, NULL) != EFI_SUCCESS) {
103 _cleanup_free_ char16_t *uuid = disk_get_part_uuid(loaded_image->DeviceHandle);
104 if (uuid)
105 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderDevicePartUUID", uuid, 0);
106 }
107
108 /* If LoaderImageIdentifier is not set, assume the image with this stub was loaded directly from the
109 * UEFI firmware without any boot loader, and hence set the LoaderImageIdentifier ourselves. Note
110 * that some boot chain loaders neither set LoaderImageIdentifier nor make FilePath available to us,
111 * in which case there's simple nothing to set for us. (The UEFI spec doesn't really say who's wrong
112 * here, i.e. whether FilePath may be NULL or not, hence handle this gracefully and check if FilePath
113 * is non-NULL explicitly.) */
114 if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderImageIdentifier", NULL, NULL) != EFI_SUCCESS &&
115 loaded_image->FilePath) {
116 _cleanup_free_ char16_t *s = NULL;
117 if (device_path_to_str(loaded_image->FilePath, &s) == EFI_SUCCESS)
118 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderImageIdentifier", s, 0);
119 }
120
121 /* if LoaderFirmwareInfo is not set, let's set it */
122 if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareInfo", NULL, NULL) != EFI_SUCCESS) {
123 _cleanup_free_ char16_t *s = NULL;
124 s = xasprintf("%ls %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
125 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareInfo", s, 0);
126 }
127
128 /* ditto for LoaderFirmwareType */
129 if (efivar_get_raw(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareType", NULL, NULL) != EFI_SUCCESS) {
130 _cleanup_free_ char16_t *s = NULL;
131 s = xasprintf("UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
132 efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderFirmwareType", s, 0);
133 }
134
135
136 /* add StubInfo (this is one is owned by the stub, hence we unconditionally override this with our
137 * own data) */
138 (void) efivar_set(MAKE_GUID_PTR(LOADER), u"StubInfo", u"systemd-stub " GIT_VERSION, 0);
139
140 (void) efivar_set_uint64_le(MAKE_GUID_PTR(LOADER), u"StubFeatures", stub_features, 0);
141 }
142
143 static bool use_load_options(
144 EFI_HANDLE stub_image,
145 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
146 bool have_cmdline,
147 char16_t **ret) {
148
149 assert(stub_image);
150 assert(loaded_image);
151 assert(ret);
152
153 /* We only allow custom command lines if we aren't in secure boot or if no cmdline was baked into
154 * the stub image.
155 * We also don't allow it if we are in confidential vms and secureboot is on. */
156 if (secure_boot_enabled() && (have_cmdline || is_confidential_vm()))
157 return false;
158
159 /* We also do a superficial check whether first character of passed command line
160 * is printable character (for compat with some Dell systems which fill in garbage?). */
161 if (loaded_image->LoadOptionsSize < sizeof(char16_t) || ((char16_t *) loaded_image->LoadOptions)[0] <= 0x1F)
162 return false;
163
164 /* The UEFI shell registers EFI_SHELL_PARAMETERS_PROTOCOL onto images it runs. This lets us know that
165 * LoadOptions starts with the stub binary path which we want to strip off. */
166 EFI_SHELL_PARAMETERS_PROTOCOL *shell;
167 if (BS->HandleProtocol(stub_image, MAKE_GUID_PTR(EFI_SHELL_PARAMETERS_PROTOCOL), (void **) &shell)
168 != EFI_SUCCESS) {
169 /* Not running from EFI shell, use entire LoadOptions. Note that LoadOptions is a void*, so
170 * it could be anything! */
171 *ret = xstrndup16(loaded_image->LoadOptions, loaded_image->LoadOptionsSize / sizeof(char16_t));
172 mangle_stub_cmdline(*ret);
173 return true;
174 }
175
176 if (shell->Argc < 2)
177 /* No arguments were provided? Then we fall back to built-in cmdline. */
178 return false;
179
180 /* Assemble the command line ourselves without our stub path. */
181 *ret = xstrdup16(shell->Argv[1]);
182 for (size_t i = 2; i < shell->Argc; i++) {
183 _cleanup_free_ char16_t *old = *ret;
184 *ret = xasprintf("%ls %ls", old, shell->Argv[i]);
185 }
186
187 mangle_stub_cmdline(*ret);
188 return true;
189 }
190
191 static EFI_STATUS load_addons_from_dir(
192 EFI_FILE *root,
193 const char16_t *prefix,
194 char16_t ***items,
195 size_t *n_items,
196 size_t *n_allocated) {
197
198 _cleanup_(file_closep) EFI_FILE *extra_dir = NULL;
199 _cleanup_free_ EFI_FILE_INFO *dirent = NULL;
200 size_t dirent_size = 0;
201 EFI_STATUS err;
202
203 assert(root);
204 assert(prefix);
205 assert(items);
206 assert(n_items);
207 assert(n_allocated);
208
209 err = open_directory(root, prefix, &extra_dir);
210 if (err == EFI_NOT_FOUND)
211 /* No extra subdir, that's totally OK */
212 return EFI_SUCCESS;
213 if (err != EFI_SUCCESS)
214 return log_error_status(err, "Failed to open addons directory '%ls': %m", prefix);
215
216 for (;;) {
217 _cleanup_free_ char16_t *d = NULL;
218
219 err = readdir(extra_dir, &dirent, &dirent_size);
220 if (err != EFI_SUCCESS)
221 return log_error_status(err, "Failed to read addons directory of loaded image: %m");
222 if (!dirent) /* End of directory */
223 break;
224
225 if (dirent->FileName[0] == '.')
226 continue;
227 if (FLAGS_SET(dirent->Attribute, EFI_FILE_DIRECTORY))
228 continue;
229 if (!is_ascii(dirent->FileName))
230 continue;
231 if (strlen16(dirent->FileName) > 255) /* Max filename size on Linux */
232 continue;
233 if (!endswith_no_case(dirent->FileName, u".addon.efi"))
234 continue;
235
236 d = xstrdup16(dirent->FileName);
237
238 if (*n_items + 2 > *n_allocated) {
239 /* We allocate 16 entries at a time, as a matter of optimization */
240 if (*n_items > (SIZE_MAX / sizeof(uint16_t)) - 16) /* Overflow check, just in case */
241 return log_oom();
242
243 size_t m = *n_items + 16;
244 *items = xrealloc(*items, *n_allocated * sizeof(uint16_t *), m * sizeof(uint16_t *));
245 *n_allocated = m;
246 }
247
248 (*items)[(*n_items)++] = TAKE_PTR(d);
249 (*items)[*n_items] = NULL; /* Let's always NUL terminate, to make freeing via strv_free() easy */
250 }
251
252 return EFI_SUCCESS;
253
254 }
255
256 static EFI_STATUS cmdline_append_and_measure_addons(
257 EFI_HANDLE stub_image,
258 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
259 const char16_t *prefix,
260 const char *uname,
261 bool *ret_parameters_measured,
262 char16_t **cmdline_append) {
263
264 _cleanup_(strv_freep) char16_t **items = NULL;
265 _cleanup_(file_closep) EFI_FILE *root = NULL;
266 _cleanup_free_ char16_t *buffer = NULL;
267 size_t n_items = 0, n_allocated = 0;
268 EFI_STATUS err;
269
270 assert(stub_image);
271 assert(loaded_image);
272 assert(prefix);
273 assert(ret_parameters_measured);
274 assert(cmdline_append);
275
276 if (!loaded_image->DeviceHandle)
277 return EFI_SUCCESS;
278
279 err = open_volume(loaded_image->DeviceHandle, &root);
280 if (err == EFI_UNSUPPORTED)
281 /* Error will be unsupported if the bootloader doesn't implement the file system protocol on
282 * its file handles. */
283 return EFI_SUCCESS;
284 if (err != EFI_SUCCESS)
285 return log_error_status(err, "Unable to open root directory: %m");
286
287 err = load_addons_from_dir(root, prefix, &items, &n_items, &n_allocated);
288 if (err != EFI_SUCCESS)
289 return err;
290
291 if (n_items == 0)
292 return EFI_SUCCESS; /* Empty directory */
293
294 /* Now, sort the files we found, to make this uniform and stable (and to ensure the TPM measurements
295 * are not dependent on read order) */
296 sort_pointer_array((void**) items, n_items, (compare_pointer_func_t) strcmp16);
297
298 for (size_t i = 0; i < n_items; i++) {
299 size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
300 _cleanup_free_ EFI_DEVICE_PATH *addon_path = NULL;
301 _cleanup_(unload_imagep) EFI_HANDLE addon = NULL;
302 EFI_LOADED_IMAGE_PROTOCOL *loaded_addon = NULL;
303 _cleanup_free_ char16_t *addon_spath = NULL;
304
305 addon_spath = xasprintf("%ls\\%ls", prefix, items[i]);
306 err = make_file_device_path(loaded_image->DeviceHandle, addon_spath, &addon_path);
307 if (err != EFI_SUCCESS)
308 return log_error_status(err, "Error making device path for %ls: %m", addon_spath);
309
310 /* By using shim_load_image, we cover both the case where the PE files are signed with MoK
311 * and with DB, and running with or without shim. */
312 err = shim_load_image(stub_image, addon_path, &addon);
313 if (err != EFI_SUCCESS) {
314 log_error_status(err,
315 "Failed to read '%ls' from '%ls', ignoring: %m",
316 items[i],
317 addon_spath);
318 continue;
319 }
320
321 err = BS->HandleProtocol(addon,
322 MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL),
323 (void **) &loaded_addon);
324 if (err != EFI_SUCCESS)
325 return log_error_status(err, "Failed to find protocol in %ls: %m", items[i]);
326
327 err = pe_memory_locate_sections(loaded_addon->ImageBase, unified_sections, addrs, szs);
328 if (err != EFI_SUCCESS || szs[UNIFIED_SECTION_CMDLINE] == 0) {
329 if (err == EFI_SUCCESS)
330 err = EFI_NOT_FOUND;
331 log_error_status(err,
332 "Unable to locate embedded .cmdline section in %ls, ignoring: %m",
333 items[i]);
334 continue;
335 }
336
337 /* We want to enforce that addons are not UKIs, i.e.: they must not embed a kernel. */
338 if (szs[UNIFIED_SECTION_LINUX] > 0) {
339 log_error_status(EFI_INVALID_PARAMETER, "%ls is a UKI, not an addon, ignoring: %m", items[i]);
340 continue;
341 }
342
343 /* Also enforce that, in case it is specified, .uname matches as a quick way to allow
344 * enforcing compatibility with a specific UKI only */
345 if (uname && szs[UNIFIED_SECTION_UNAME] > 0 &&
346 !strneq8(uname,
347 (char *)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_UNAME],
348 szs[UNIFIED_SECTION_UNAME])) {
349 log_error(".uname mismatch between %ls and UKI, ignoring", items[i]);
350 continue;
351 }
352
353 _cleanup_free_ char16_t *tmp = TAKE_PTR(buffer),
354 *extra16 = xstrn8_to_16((char *)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_CMDLINE],
355 szs[UNIFIED_SECTION_CMDLINE]);
356 buffer = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", extra16);
357 }
358
359 mangle_stub_cmdline(buffer);
360
361 if (!isempty(buffer)) {
362 _cleanup_free_ char16_t *tmp = TAKE_PTR(*cmdline_append);
363 bool m = false;
364
365 (void) tpm_log_load_options(buffer, &m);
366 *ret_parameters_measured = m;
367
368 *cmdline_append = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", buffer);
369 }
370
371 return EFI_SUCCESS;
372 }
373
374 static EFI_STATUS run(EFI_HANDLE image) {
375 _cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL;
376 size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
377 size_t linux_size, initrd_size, dt_size;
378 EFI_PHYSICAL_ADDRESS linux_base, initrd_base, dt_base;
379 _cleanup_(devicetree_cleanup) struct devicetree_state dt_state = {};
380 EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
381 size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
382 _cleanup_free_ char16_t *cmdline = NULL;
383 int sections_measured = -1, parameters_measured = -1;
384 _cleanup_free_ char *uname = NULL;
385 bool sysext_measured = false, m;
386 uint64_t loader_features = 0;
387 EFI_STATUS err;
388
389 err = BS->HandleProtocol(image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &loaded_image);
390 if (err != EFI_SUCCESS)
391 return log_error_status(err, "Error getting a LoadedImageProtocol handle: %m");
392
393 if (efivar_get_uint64_le(MAKE_GUID_PTR(LOADER), u"LoaderFeatures", &loader_features) != EFI_SUCCESS ||
394 !FLAGS_SET(loader_features, EFI_LOADER_FEATURE_RANDOM_SEED)) {
395 _cleanup_(file_closep) EFI_FILE *esp_dir = NULL;
396
397 err = partition_open(MAKE_GUID_PTR(ESP), loaded_image->DeviceHandle, NULL, &esp_dir);
398 if (err == EFI_SUCCESS) /* Non-fatal on failure, so that we still boot without it. */
399 (void) process_random_seed(esp_dir);
400 }
401
402 err = pe_memory_locate_sections(loaded_image->ImageBase, unified_sections, addrs, szs);
403 if (err != EFI_SUCCESS || szs[UNIFIED_SECTION_LINUX] == 0) {
404 if (err == EFI_SUCCESS)
405 err = EFI_NOT_FOUND;
406 return log_error_status(err, "Unable to locate embedded .linux section: %m");
407 }
408
409 /* Measure all "payload" of this PE image into a separate PCR (i.e. where nothing else is written
410 * into so far), so that we have one PCR that we can nicely write policies against because it
411 * contains all static data of this image, and thus can be easily be pre-calculated. */
412 for (UnifiedSection section = 0; section < _UNIFIED_SECTION_MAX; section++) {
413
414 if (!unified_section_measure(section)) /* shall not measure? */
415 continue;
416
417 if (szs[section] == 0) /* not found */
418 continue;
419
420 m = false;
421
422 /* First measure the name of the section */
423 (void) tpm_log_event_ascii(
424 TPM2_PCR_KERNEL_BOOT,
425 POINTER_TO_PHYSICAL_ADDRESS(unified_sections[section]),
426 strsize8(unified_sections[section]), /* including NUL byte */
427 unified_sections[section],
428 &m);
429
430 sections_measured = sections_measured < 0 ? m : (sections_measured && m);
431
432 /* Then measure the data of the section */
433 (void) tpm_log_event_ascii(
434 TPM2_PCR_KERNEL_BOOT,
435 POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[section],
436 szs[section],
437 unified_sections[section],
438 &m);
439
440 sections_measured = sections_measured < 0 ? m : (sections_measured && m);
441 }
442
443 /* After we are done, set an EFI variable that tells userspace this was done successfully, and encode
444 * in it which PCR was used. */
445 if (sections_measured > 0)
446 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrKernelImage", TPM2_PCR_KERNEL_BOOT, 0);
447
448 /* Show splash screen as early as possible */
449 graphics_splash((const uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_SPLASH], szs[UNIFIED_SECTION_SPLASH]);
450
451 if (szs[UNIFIED_SECTION_UNAME] > 0)
452 uname = xstrndup8((char *)loaded_image->ImageBase + addrs[UNIFIED_SECTION_UNAME],
453 szs[UNIFIED_SECTION_UNAME]);
454
455 if (use_load_options(image, loaded_image, szs[UNIFIED_SECTION_CMDLINE] > 0, &cmdline)) {
456 /* Let's measure the passed kernel command line into the TPM. Note that this possibly
457 * duplicates what we already did in the boot menu, if that was already used. However, since
458 * we want the boot menu to support an EFI binary, and want to this stub to be usable from
459 * any boot menu, let's measure things anyway. */
460 m = false;
461 (void) tpm_log_load_options(cmdline, &m);
462 parameters_measured = m;
463 } else if (szs[UNIFIED_SECTION_CMDLINE] > 0) {
464 cmdline = xstrn8_to_16(
465 (char *) loaded_image->ImageBase + addrs[UNIFIED_SECTION_CMDLINE],
466 szs[UNIFIED_SECTION_CMDLINE]);
467 mangle_stub_cmdline(cmdline);
468 }
469
470 /* If we have any extra command line to add via PE addons, load them now and append, and
471 * measure the additions separately, after the embedded options, but before the smbios ones,
472 * so that the order is reversed from "most hardcoded" to "most dynamic". The global addons are
473 * loaded first, and the image-specific ones later, for the same reason. */
474 err = cmdline_append_and_measure_addons(
475 image,
476 loaded_image,
477 u"\\loader\\addons",
478 uname,
479 &m,
480 &cmdline);
481 if (err != EFI_SUCCESS)
482 log_error_status(err, "Error loading global addons, ignoring: %m");
483 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
484
485 _cleanup_free_ char16_t *dropin_dir = get_extra_dir(loaded_image->FilePath);
486 err = cmdline_append_and_measure_addons(
487 image,
488 loaded_image,
489 dropin_dir,
490 uname,
491 &m,
492 &cmdline);
493 if (err != EFI_SUCCESS)
494 log_error_status(err, "Error loading UKI-specific addons, ignoring: %m");
495 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
496
497 /* SMBIOS OEM Strings data is controlled by the host admin and not covered
498 * by the VM attestation, so MUST NOT be trusted when in a confidential VM */
499 if (!is_confidential_vm()) {
500 const char *extra = smbios_find_oem_string("io.systemd.stub.kernel-cmdline-extra");
501 if (extra) {
502 _cleanup_free_ char16_t *tmp = TAKE_PTR(cmdline), *extra16 = xstr8_to_16(extra);
503 cmdline = xasprintf("%ls %ls", tmp, extra16);
504
505 /* SMBIOS strings are measured in PCR1, but we also want to measure them in our specific
506 * PCR12, as firmware-owned PCRs are very difficult to use as they'll contain unpredictable
507 * measurements that are not under control of the machine owner. */
508 m = false;
509 (void) tpm_log_load_options(extra16, &m);
510 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
511 }
512 }
513
514 export_variables(loaded_image);
515
516 if (pack_cpio(loaded_image,
517 NULL,
518 u".cred",
519 ".extra/credentials",
520 /* dir_mode= */ 0500,
521 /* access_mode= */ 0400,
522 /* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
523 u"Credentials initrd",
524 &credential_initrd,
525 &credential_initrd_size,
526 &m) == EFI_SUCCESS)
527 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
528
529 if (pack_cpio(loaded_image,
530 u"\\loader\\credentials",
531 u".cred",
532 ".extra/global_credentials",
533 /* dir_mode= */ 0500,
534 /* access_mode= */ 0400,
535 /* tpm_pcr= */ TPM2_PCR_KERNEL_CONFIG,
536 u"Global credentials initrd",
537 &global_credential_initrd,
538 &global_credential_initrd_size,
539 &m) == EFI_SUCCESS)
540 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
541
542 if (pack_cpio(loaded_image,
543 NULL,
544 u".raw",
545 ".extra/sysext",
546 /* dir_mode= */ 0555,
547 /* access_mode= */ 0444,
548 /* tpm_pcr= */ TPM2_PCR_SYSEXTS,
549 u"System extension initrd",
550 &sysext_initrd,
551 &sysext_initrd_size,
552 &m) == EFI_SUCCESS)
553 sysext_measured = m;
554
555 if (parameters_measured > 0)
556 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrKernelParameters", TPM2_PCR_KERNEL_CONFIG, 0);
557 if (sysext_measured)
558 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrInitRDSysExts", TPM2_PCR_SYSEXTS, 0);
559
560 /* If the PCR signature was embedded in the PE image, then let's wrap it in a cpio and also pass it
561 * to the kernel, so that it can be read from /.extra/tpm2-pcr-signature.json. Note that this section
562 * is not measured, neither as raw section (see above), nor as cpio (here), because it is the
563 * signature of expected PCR values, i.e. its input are PCR measurements, and hence it shouldn't
564 * itself be input for PCR measurements. */
565 if (szs[UNIFIED_SECTION_PCRSIG] > 0)
566 (void) pack_cpio_literal(
567 (uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_PCRSIG],
568 szs[UNIFIED_SECTION_PCRSIG],
569 ".extra",
570 u"tpm2-pcr-signature.json",
571 /* dir_mode= */ 0555,
572 /* access_mode= */ 0444,
573 /* tpm_pcr= */ UINT32_MAX,
574 /* tpm_description= */ NULL,
575 &pcrsig_initrd,
576 &pcrsig_initrd_size,
577 /* ret_measured= */ NULL);
578
579 /* If the public key used for the PCR signatures was embedded in the PE image, then let's wrap it in
580 * a cpio and also pass it to the kernel, so that it can be read from
581 * /.extra/tpm2-pcr-public-key.pem. This section is already measure above, hence we won't measure the
582 * cpio. */
583 if (szs[UNIFIED_SECTION_PCRPKEY] > 0)
584 (void) pack_cpio_literal(
585 (uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_PCRPKEY],
586 szs[UNIFIED_SECTION_PCRPKEY],
587 ".extra",
588 u"tpm2-pcr-public-key.pem",
589 /* dir_mode= */ 0555,
590 /* access_mode= */ 0444,
591 /* tpm_pcr= */ UINT32_MAX,
592 /* tpm_description= */ NULL,
593 &pcrpkey_initrd,
594 &pcrpkey_initrd_size,
595 /* ret_measured= */ NULL);
596
597 linux_size = szs[UNIFIED_SECTION_LINUX];
598 linux_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_LINUX];
599
600 initrd_size = szs[UNIFIED_SECTION_INITRD];
601 initrd_base = initrd_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_INITRD] : 0;
602
603 dt_size = szs[UNIFIED_SECTION_DTB];
604 dt_base = dt_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_DTB] : 0;
605
606 _cleanup_pages_ Pages initrd_pages = {};
607 if (credential_initrd || global_credential_initrd || sysext_initrd || pcrsig_initrd || pcrpkey_initrd) {
608 /* If we have generated initrds dynamically, let's combine them with the built-in initrd. */
609 err = combine_initrd(
610 initrd_base, initrd_size,
611 (const void*const[]) {
612 credential_initrd,
613 global_credential_initrd,
614 sysext_initrd,
615 pcrsig_initrd,
616 pcrpkey_initrd,
617 },
618 (const size_t[]) {
619 credential_initrd_size,
620 global_credential_initrd_size,
621 sysext_initrd_size,
622 pcrsig_initrd_size,
623 pcrpkey_initrd_size,
624 },
625 5,
626 &initrd_pages, &initrd_size);
627 if (err != EFI_SUCCESS)
628 return err;
629
630 initrd_base = initrd_pages.addr;
631
632 /* Given these might be large let's free them explicitly, quickly. */
633 credential_initrd = mfree(credential_initrd);
634 global_credential_initrd = mfree(global_credential_initrd);
635 sysext_initrd = mfree(sysext_initrd);
636 pcrsig_initrd = mfree(pcrsig_initrd);
637 pcrpkey_initrd = mfree(pcrpkey_initrd);
638 }
639
640 if (dt_size > 0) {
641 err = devicetree_install_from_memory(
642 &dt_state, PHYSICAL_ADDRESS_TO_POINTER(dt_base), dt_size);
643 if (err != EFI_SUCCESS)
644 log_error_status(err, "Error loading embedded devicetree: %m");
645 }
646
647 err = linux_exec(image, cmdline,
648 PHYSICAL_ADDRESS_TO_POINTER(linux_base), linux_size,
649 PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
650 graphics_mode(false);
651 return err;
652 }
653
654 DEFINE_EFI_MAIN_FUNCTION(run, "systemd-stub", /*wait_for_debugger=*/false);