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