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