]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/boot/efi/stub.c
systemd-stub: ignore EFI shell unauthenticated kernel command line if we are in confi...
[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
fab0eeb7
EGE
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()))
b17f3b3d
JJ
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;
19f08504 163 if (BS->HandleProtocol(stub_image, MAKE_GUID_PTR(EFI_SHELL_PARAMETERS_PROTOCOL), (void **) &shell)
b17f3b3d
JJ
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;
2f3c3b0b 180 *ret = xasprintf("%ls %ls", old, shell->Argv[i]);
b17f3b3d
JJ
181 }
182
183 mangle_stub_cmdline(*ret);
184 return true;
185}
186
05c9f9c2
LB
187static 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
252static EFI_STATUS cmdline_append_and_measure_addons(
253 EFI_HANDLE stub_image,
254 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
255 const char16_t *prefix,
256 const char *uname,
257 bool *ret_parameters_measured,
258 char16_t **cmdline_append) {
259
260 _cleanup_(strv_freep) char16_t **items = NULL;
261 _cleanup_(file_closep) EFI_FILE *root = NULL;
262 _cleanup_free_ char16_t *buffer = NULL;
263 size_t n_items = 0, n_allocated = 0;
264 EFI_STATUS err;
265
266 assert(stub_image);
267 assert(loaded_image);
268 assert(prefix);
269 assert(ret_parameters_measured);
270 assert(cmdline_append);
271
272 if (!loaded_image->DeviceHandle)
273 return EFI_SUCCESS;
274
275 err = open_volume(loaded_image->DeviceHandle, &root);
276 if (err == EFI_UNSUPPORTED)
277 /* Error will be unsupported if the bootloader doesn't implement the file system protocol on
278 * its file handles. */
279 return EFI_SUCCESS;
280 if (err != EFI_SUCCESS)
281 return log_error_status(err, "Unable to open root directory: %m");
282
283 err = load_addons_from_dir(root, prefix, &items, &n_items, &n_allocated);
284 if (err != EFI_SUCCESS)
285 return err;
286
287 if (n_items == 0)
288 return EFI_SUCCESS; /* Empty directory */
289
290 /* Now, sort the files we found, to make this uniform and stable (and to ensure the TPM measurements
291 * are not dependent on read order) */
292 sort_pointer_array((void**) items, n_items, (compare_pointer_func_t) strcmp16);
293
294 for (size_t i = 0; i < n_items; i++) {
295 size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
296 _cleanup_free_ EFI_DEVICE_PATH *addon_path = NULL;
297 _cleanup_(unload_imagep) EFI_HANDLE addon = NULL;
298 EFI_LOADED_IMAGE_PROTOCOL *loaded_addon = NULL;
299 _cleanup_free_ char16_t *addon_spath = NULL;
300
301 addon_spath = xasprintf("%ls\\%ls", prefix, items[i]);
302 err = make_file_device_path(loaded_image->DeviceHandle, addon_spath, &addon_path);
303 if (err != EFI_SUCCESS)
304 return log_error_status(err, "Error making device path for %ls: %m", addon_spath);
305
306 /* By using shim_load_image, we cover both the case where the PE files are signed with MoK
307 * and with DB, and running with or without shim. */
308 err = shim_load_image(stub_image, addon_path, &addon);
309 if (err != EFI_SUCCESS) {
310 log_error_status(err,
311 "Failed to read '%ls' from '%ls', ignoring: %m",
312 items[i],
313 addon_spath);
314 continue;
315 }
316
317 err = BS->HandleProtocol(addon,
318 MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL),
319 (void **) &loaded_addon);
320 if (err != EFI_SUCCESS)
321 return log_error_status(err, "Failed to find protocol in %ls: %m", items[i]);
322
323 err = pe_memory_locate_sections(loaded_addon->ImageBase, unified_sections, addrs, szs);
324 if (err != EFI_SUCCESS || szs[UNIFIED_SECTION_CMDLINE] == 0) {
325 if (err == EFI_SUCCESS)
326 err = EFI_NOT_FOUND;
327 log_error_status(err,
328 "Unable to locate embedded .cmdline section in %ls, ignoring: %m",
329 items[i]);
330 continue;
331 }
332
333 /* We want to enforce that addons are not UKIs, i.e.: they must not embed a kernel. */
334 if (szs[UNIFIED_SECTION_LINUX] > 0) {
335 log_error_status(EFI_INVALID_PARAMETER, "%ls is a UKI, not an addon, ignoring: %m", items[i]);
336 continue;
337 }
338
339 /* Also enforce that, in case it is specified, .uname matches as a quick way to allow
340 * enforcing compatibility with a specific UKI only */
341 if (uname && szs[UNIFIED_SECTION_UNAME] > 0 &&
342 !strneq8(uname,
343 (char *)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_UNAME],
344 szs[UNIFIED_SECTION_UNAME])) {
345 log_error(".uname mismatch between %ls and UKI, ignoring", items[i]);
346 continue;
347 }
348
349 _cleanup_free_ char16_t *tmp = TAKE_PTR(buffer),
350 *extra16 = xstrn8_to_16((char *)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_CMDLINE],
351 szs[UNIFIED_SECTION_CMDLINE]);
352 buffer = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", extra16);
353 }
354
355 mangle_stub_cmdline(buffer);
356
357 if (!isempty(buffer)) {
358 _cleanup_free_ char16_t *tmp = TAKE_PTR(*cmdline_append);
359 bool m = false;
360
361 (void) tpm_log_load_options(buffer, &m);
362 *ret_parameters_measured = m;
363
364 *cmdline_append = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", buffer);
365 }
366
367 return EFI_SUCCESS;
368}
369
31a131bb 370static EFI_STATUS run(EFI_HANDLE image) {
23002b45 371 _cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL;
927ebebe
JJ
372 size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
373 size_t linux_size, initrd_size, dt_size;
33bc9b75
MR
374 EFI_PHYSICAL_ADDRESS linux_base, initrd_base, dt_base;
375 _cleanup_(devicetree_cleanup) struct devicetree_state dt_state = {};
b30a43df 376 EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
927ebebe
JJ
377 size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
378 _cleanup_free_ char16_t *cmdline = NULL;
72c97c19 379 int sections_measured = -1, parameters_measured = -1;
05c9f9c2 380 _cleanup_free_ char *uname = NULL;
de7ad6d4 381 bool sysext_measured = false, m;
0a1d8ac7 382 uint64_t loader_features = 0;
0fa2cac4
KS
383 EFI_STATUS err;
384
b4eb2de7 385 err = BS->HandleProtocol(image, MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL), (void **) &loaded_image);
2a5e4fe4 386 if (err != EFI_SUCCESS)
c2c62035 387 return log_error_status(err, "Error getting a LoadedImageProtocol handle: %m");
0fa2cac4 388
19f08504 389 if (efivar_get_uint64_le(MAKE_GUID_PTR(LOADER), u"LoaderFeatures", &loader_features) != EFI_SUCCESS ||
0a1d8ac7
JD
390 !FLAGS_SET(loader_features, EFI_LOADER_FEATURE_RANDOM_SEED)) {
391 _cleanup_(file_closep) EFI_FILE *esp_dir = NULL;
392
19f08504 393 err = partition_open(MAKE_GUID_PTR(ESP), loaded_image->DeviceHandle, NULL, &esp_dir);
0a1d8ac7
JD
394 if (err == EFI_SUCCESS) /* Non-fatal on failure, so that we still boot without it. */
395 (void) process_random_seed(esp_dir);
396 }
397
6017eee9
LP
398 err = pe_memory_locate_sections(loaded_image->ImageBase, unified_sections, addrs, szs);
399 if (err != EFI_SUCCESS || szs[UNIFIED_SECTION_LINUX] == 0) {
2a5e4fe4 400 if (err == EFI_SUCCESS)
65ff3d26 401 err = EFI_NOT_FOUND;
c2c62035 402 return log_error_status(err, "Unable to locate embedded .linux section: %m");
65ff3d26 403 }
0fa2cac4 404
72c97c19
LP
405 /* Measure all "payload" of this PE image into a separate PCR (i.e. where nothing else is written
406 * into so far), so that we have one PCR that we can nicely write policies against because it
407 * contains all static data of this image, and thus can be easily be pre-calculated. */
6017eee9 408 for (UnifiedSection section = 0; section < _UNIFIED_SECTION_MAX; section++) {
df7ee6f8
LP
409
410 if (!unified_section_measure(section)) /* shall not measure? */
411 continue;
72c97c19
LP
412
413 if (szs[section] == 0) /* not found */
414 continue;
415
df7ee6f8
LP
416 m = false;
417
72c97c19
LP
418 /* First measure the name of the section */
419 (void) tpm_log_event_ascii(
420 TPM_PCR_INDEX_KERNEL_IMAGE,
6017eee9
LP
421 POINTER_TO_PHYSICAL_ADDRESS(unified_sections[section]),
422 strsize8(unified_sections[section]), /* including NUL byte */
423 unified_sections[section],
72c97c19
LP
424 &m);
425
426 sections_measured = sections_measured < 0 ? m : (sections_measured && m);
427
428 /* Then measure the data of the section */
429 (void) tpm_log_event_ascii(
430 TPM_PCR_INDEX_KERNEL_IMAGE,
431 POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[section],
432 szs[section],
6017eee9 433 unified_sections[section],
72c97c19
LP
434 &m);
435
436 sections_measured = sections_measured < 0 ? m : (sections_measured && m);
437 }
438
439 /* After we are done, set an EFI variable that tells userspace this was done successfully, and encode
440 * in it which PCR was used. */
441 if (sections_measured > 0)
19f08504 442 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrKernelImage", TPM_PCR_INDEX_KERNEL_IMAGE, 0);
72c97c19 443
94b81afb 444 /* Show splash screen as early as possible */
957dfcc9 445 graphics_splash((const uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_SPLASH], szs[UNIFIED_SECTION_SPLASH]);
94b81afb 446
05c9f9c2
LB
447 if (szs[UNIFIED_SECTION_UNAME] > 0)
448 uname = xstrndup8((char *)loaded_image->ImageBase + addrs[UNIFIED_SECTION_UNAME],
449 szs[UNIFIED_SECTION_UNAME]);
450
b17f3b3d 451 if (use_load_options(image, loaded_image, szs[UNIFIED_SECTION_CMDLINE] > 0, &cmdline)) {
e6e24af5
LP
452 /* Let's measure the passed kernel command line into the TPM. Note that this possibly
453 * duplicates what we already did in the boot menu, if that was already used. However, since
454 * we want the boot menu to support an EFI binary, and want to this stub to be usable from
455 * any boot menu, let's measure things anyway. */
599fe002 456 m = false;
927ebebe 457 (void) tpm_log_load_options(cmdline, &m);
599fe002 458 parameters_measured = m;
927ebebe
JJ
459 } else if (szs[UNIFIED_SECTION_CMDLINE] > 0) {
460 cmdline = xstrn8_to_16(
461 (char *) loaded_image->ImageBase + addrs[UNIFIED_SECTION_CMDLINE],
462 szs[UNIFIED_SECTION_CMDLINE]);
463 mangle_stub_cmdline(cmdline);
0fa2cac4
KS
464 }
465
05c9f9c2
LB
466 /* If we have any extra command line to add via PE addons, load them now and append, and
467 * measure the additions separately, after the embedded options, but before the smbios ones,
468 * so that the order is reversed from "most hardcoded" to "most dynamic". The global addons are
469 * loaded first, and the image-specific ones later, for the same reason. */
470 err = cmdline_append_and_measure_addons(
471 image,
472 loaded_image,
473 u"\\loader\\addons",
474 uname,
475 &m,
476 &cmdline);
477 if (err != EFI_SUCCESS)
478 log_error_status(err, "Error loading global addons, ignoring: %m");
479 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
480
481 _cleanup_free_ char16_t *dropin_dir = get_extra_dir(loaded_image->FilePath);
482 err = cmdline_append_and_measure_addons(
483 image,
484 loaded_image,
485 dropin_dir,
486 uname,
487 &m,
488 &cmdline);
489 if (err != EFI_SUCCESS)
490 log_error_status(err, "Error loading UKI-specific addons, ignoring: %m");
491 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
492
4b1153cf
DB
493 /* SMBIOS OEM Strings data is controlled by the host admin and not covered
494 * by the VM attestation, so MUST NOT be trusted when in a confidential VM */
495 if (!is_confidential_vm()) {
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);
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);
507 }
717af0de
DDM
508 }
509
5a186322 510 export_variables(loaded_image);
1aa15def 511
599fe002
LP
512 if (pack_cpio(loaded_image,
513 NULL,
a083aed0 514 u".cred",
599fe002
LP
515 ".extra/credentials",
516 /* dir_mode= */ 0500,
517 /* access_mode= */ 0400,
d84bdadb 518 /* tpm_pcr= */ TPM_PCR_INDEX_KERNEL_PARAMETERS,
a083aed0 519 u"Credentials initrd",
599fe002
LP
520 &credential_initrd,
521 &credential_initrd_size,
522 &m) == EFI_SUCCESS)
523 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
524
525 if (pack_cpio(loaded_image,
a083aed0
JJ
526 u"\\loader\\credentials",
527 u".cred",
599fe002
LP
528 ".extra/global_credentials",
529 /* dir_mode= */ 0500,
530 /* access_mode= */ 0400,
d84bdadb 531 /* tpm_pcr= */ TPM_PCR_INDEX_KERNEL_PARAMETERS,
a083aed0 532 u"Global credentials initrd",
599fe002
LP
533 &global_credential_initrd,
534 &global_credential_initrd_size,
535 &m) == EFI_SUCCESS)
536 parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
f3b6f333 537
de7ad6d4
LP
538 if (pack_cpio(loaded_image,
539 NULL,
a083aed0 540 u".raw",
de7ad6d4
LP
541 ".extra/sysext",
542 /* dir_mode= */ 0555,
543 /* access_mode= */ 0444,
d84bdadb 544 /* tpm_pcr= */ TPM_PCR_INDEX_INITRD_SYSEXTS,
a083aed0 545 u"System extension initrd",
de7ad6d4
LP
546 &sysext_initrd,
547 &sysext_initrd_size,
548 &m) == EFI_SUCCESS)
549 sysext_measured = m;
599fe002
LP
550
551 if (parameters_measured > 0)
19f08504 552 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrKernelParameters", TPM_PCR_INDEX_KERNEL_PARAMETERS, 0);
de7ad6d4 553 if (sysext_measured)
19f08504 554 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrInitRDSysExts", TPM_PCR_INDEX_INITRD_SYSEXTS, 0);
845707aa 555
23002b45
LP
556 /* If the PCR signature was embedded in the PE image, then let's wrap it in a cpio and also pass it
557 * to the kernel, so that it can be read from /.extra/tpm2-pcr-signature.json. Note that this section
558 * is not measured, neither as raw section (see above), nor as cpio (here), because it is the
5dcb9c3c 559 * signature of expected PCR values, i.e. its input are PCR measurements, and hence it shouldn't
23002b45
LP
560 * itself be input for PCR measurements. */
561 if (szs[UNIFIED_SECTION_PCRSIG] > 0)
562 (void) pack_cpio_literal(
563 (uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_PCRSIG],
564 szs[UNIFIED_SECTION_PCRSIG],
565 ".extra",
a083aed0 566 u"tpm2-pcr-signature.json",
23002b45
LP
567 /* dir_mode= */ 0555,
568 /* access_mode= */ 0444,
d84bdadb 569 /* tpm_pcr= */ UINT32_MAX,
23002b45
LP
570 /* tpm_description= */ NULL,
571 &pcrsig_initrd,
572 &pcrsig_initrd_size,
573 /* ret_measured= */ NULL);
574
575 /* If the public key used for the PCR signatures was embedded in the PE image, then let's wrap it in
576 * a cpio and also pass it to the kernel, so that it can be read from
577 * /.extra/tpm2-pcr-public-key.pem. This section is already measure above, hence we won't measure the
578 * cpio. */
579 if (szs[UNIFIED_SECTION_PCRPKEY] > 0)
580 (void) pack_cpio_literal(
581 (uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_PCRPKEY],
582 szs[UNIFIED_SECTION_PCRPKEY],
583 ".extra",
a083aed0 584 u"tpm2-pcr-public-key.pem",
23002b45
LP
585 /* dir_mode= */ 0555,
586 /* access_mode= */ 0444,
d84bdadb 587 /* tpm_pcr= */ UINT32_MAX,
23002b45
LP
588 /* tpm_description= */ NULL,
589 &pcrpkey_initrd,
590 &pcrpkey_initrd_size,
591 /* ret_measured= */ NULL);
592
6017eee9
LP
593 linux_size = szs[UNIFIED_SECTION_LINUX];
594 linux_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_LINUX];
5b5d365d 595
6017eee9
LP
596 initrd_size = szs[UNIFIED_SECTION_INITRD];
597 initrd_base = initrd_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_INITRD] : 0;
37fa3690 598
6017eee9
LP
599 dt_size = szs[UNIFIED_SECTION_DTB];
600 dt_base = dt_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_DTB] : 0;
33bc9b75 601
09173c91 602 _cleanup_pages_ Pages initrd_pages = {};
64650de7 603 if (credential_initrd || global_credential_initrd || sysext_initrd || pcrsig_initrd || pcrpkey_initrd) {
845707aa
LP
604 /* If we have generated initrds dynamically, let's combine them with the built-in initrd. */
605 err = combine_initrd(
606 initrd_base, initrd_size,
23002b45
LP
607 (const void*const[]) {
608 credential_initrd,
609 global_credential_initrd,
610 sysext_initrd,
611 pcrsig_initrd,
612 pcrpkey_initrd,
613 },
614 (const size_t[]) {
615 credential_initrd_size,
616 global_credential_initrd_size,
617 sysext_initrd_size,
618 pcrsig_initrd_size,
619 pcrpkey_initrd_size,
620 },
621 5,
09173c91 622 &initrd_pages, &initrd_size);
2a5e4fe4 623 if (err != EFI_SUCCESS)
845707aa
LP
624 return err;
625
09173c91
JJ
626 initrd_base = initrd_pages.addr;
627
845707aa 628 /* Given these might be large let's free them explicitly, quickly. */
f3b6f333
AV
629 credential_initrd = mfree(credential_initrd);
630 global_credential_initrd = mfree(global_credential_initrd);
631 sysext_initrd = mfree(sysext_initrd);
23002b45
LP
632 pcrsig_initrd = mfree(pcrsig_initrd);
633 pcrpkey_initrd = mfree(pcrpkey_initrd);
845707aa 634 }
0fa2cac4 635
33bc9b75
MR
636 if (dt_size > 0) {
637 err = devicetree_install_from_memory(
638 &dt_state, PHYSICAL_ADDRESS_TO_POINTER(dt_base), dt_size);
2a5e4fe4 639 if (err != EFI_SUCCESS)
c2c62035 640 log_error_status(err, "Error loading embedded devicetree: %m");
33bc9b75
MR
641 }
642
927ebebe 643 err = linux_exec(image, cmdline,
dc467928 644 PHYSICAL_ADDRESS_TO_POINTER(linux_base), linux_size,
a6089431 645 PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
e5a1b8f9 646 graphics_mode(false);
a529d818 647 return err;
0fa2cac4 648}
6ac54809 649
31a131bb 650DEFINE_EFI_MAIN_FUNCTION(run, "systemd-stub", /*wait_for_debugger=*/false);