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