]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
efi: introduce PeSectionVector structure, and use it for referencing PE sections
authorLennart Poettering <lennart@poettering.net>
Mon, 24 Jun 2024 15:52:10 +0000 (17:52 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 26 Jun 2024 15:09:44 +0000 (17:09 +0200)
src/boot/efi/boot.c
src/boot/efi/pe.c
src/boot/efi/pe.h
src/boot/efi/stub.c

index 79de121f0d2da51fd4a48257e5eb8a19de16f7ae..99061a1339076bb3f2d1741ef87f56d971305930 100644 (file)
@@ -1855,23 +1855,24 @@ static void generate_boot_entry_titles(Config *config) {
 }
 
 static bool is_sd_boot(EFI_FILE *root_dir, const char16_t *loader_path) {
-        EFI_STATUS err;
         static const char * const sections[] = {
                 ".sdmagic",
                 NULL
         };
-        size_t offset = 0, size = 0, read;
         _cleanup_free_ char *content = NULL;
+        PeSectionVector vector = {};
+        EFI_STATUS err;
+        size_t read;
 
         assert(root_dir);
         assert(loader_path);
 
-        err = pe_file_locate_sections(root_dir, loader_path, sections, &offset, &size);
-        if (err != EFI_SUCCESS || size != sizeof(SD_MAGIC))
+        err = pe_file_locate_sections(root_dir, loader_path, sections, &vector);
+        if (err != EFI_SUCCESS || vector.size != sizeof(SD_MAGIC))
                 return false;
 
-        err = file_read(root_dir, loader_path, offset, size, &content, &read);
-        if (err != EFI_SUCCESS || size != read)
+        err = file_read(root_dir, loader_path, vector.file_offset, vector.size, &content, &read);
+        if (err != EFI_SUCCESS || vector.size != read)
                 return false;
 
         return memcmp(content, SD_MAGIC, sizeof(SD_MAGIC)) == 0;
@@ -2104,7 +2105,7 @@ static void config_load_type2_entries(
                         _SECTION_MAX,
                 };
 
-                static const char * const sections[_SECTION_MAX + 1] = {
+                static const char * const section_names[_SECTION_MAX + 1] = {
                         [SECTION_CMDLINE] = ".cmdline",
                         [SECTION_OSREL]   = ".osrel",
                         NULL,
@@ -2114,8 +2115,9 @@ static void config_load_type2_entries(
                         *os_image_version = NULL, *os_version = NULL, *os_version_id = NULL, *os_build_id = NULL;
                 const char16_t *good_name, *good_version, *good_sort_key;
                 _cleanup_free_ char *content = NULL;
-                size_t offs[_SECTION_MAX] = {}, szs[_SECTION_MAX] = {}, pos = 0;
+                PeSectionVector sections[_SECTION_MAX] = {};
                 char *line, *key, *value;
+                size_t pos = 0;
 
                 err = readdir(linux_dir, &f, &f_size);
                 if (err != EFI_SUCCESS || !f)
@@ -2131,11 +2133,16 @@ static void config_load_type2_entries(
                         continue;
 
                 /* look for .osrel and .cmdline sections in the .efi binary */
-                err = pe_file_locate_sections(linux_dir, f->FileName, sections, offs, szs);
-                if (err != EFI_SUCCESS || szs[SECTION_OSREL] == 0)
+                err = pe_file_locate_sections(linux_dir, f->FileName, section_names, sections);
+                if (err != EFI_SUCCESS || !PE_SECTION_VECTOR_IS_SET(sections + SECTION_OSREL))
                         continue;
 
-                err = file_read(linux_dir, f->FileName, offs[SECTION_OSREL], szs[SECTION_OSREL], &content, NULL);
+                err = file_read(linux_dir,
+                                f->FileName,
+                                sections[SECTION_OSREL].file_offset,
+                                sections[SECTION_OSREL].size,
+                                &content,
+                                NULL);
                 if (err != EFI_SUCCESS)
                         continue;
 
@@ -2206,14 +2213,19 @@ static void config_load_type2_entries(
                 config_add_entry(config, entry);
                 boot_entry_parse_tries(entry, u"\\EFI\\Linux", f->FileName, u".efi");
 
-                if (szs[SECTION_CMDLINE] == 0)
+                if (!PE_SECTION_VECTOR_IS_SET(sections + SECTION_CMDLINE))
                         continue;
 
                 content = mfree(content);
 
                 /* read the embedded cmdline file */
                 size_t cmdline_len;
-                err = file_read(linux_dir, f->FileName, offs[SECTION_CMDLINE], szs[SECTION_CMDLINE], &content, &cmdline_len);
+                err = file_read(linux_dir,
+                                f->FileName,
+                                sections[SECTION_CMDLINE].file_offset,
+                                sections[SECTION_CMDLINE].size,
+                                &content,
+                                &cmdline_len);
                 if (err == EFI_SUCCESS) {
                         entry->options = xstrn8_to_16(content, cmdline_len);
                         mangle_stub_cmdline(entry->options);
index cb75c2b42b81cbc13a127e253e4facf915f8f435..587e3ef7b158a70f0c1fde25562175c6dd637d5a 100644 (file)
@@ -101,7 +101,7 @@ typedef struct PeOptionalHeader {
 } _packed_ PeOptionalHeader;
 
 typedef struct PeFileHeader {
-        uint8_t   Magic[4];
+        uint8_t  Magic[4];
         CoffFileHeader FileHeader;
         PeOptionalHeader OptionalHeader;
 } _packed_ PeFileHeader;
@@ -175,48 +175,78 @@ static bool pe_section_name_equal(const char *a, const char *b) {
         return true;
 }
 
-static void locate_sections(
+static void pe_locate_sections(
                 const PeSectionHeader section_table[],
-                size_t n_table,
+                size_t n_section_table,
                 const char * const sections[],
-                size_t *offsets,
-                size_t *sizes,
-                bool in_memory) {
+                size_t validate_base,
+                PeSectionVector *ret_sections) {
 
-        assert(section_table);
+        assert(section_table || n_section_table == 0);
         assert(sections);
-        assert(offsets);
-        assert(sizes);
+        assert(ret_sections);
 
-        for (size_t i = 0; i < n_table; i++) {
-                const PeSectionHeader *sect = section_table + i;
+        /* Searches for the sections listed in 'sections[]' within the section table. Validates the resulted
+         * data. If 'validate_base' is non-zero also takes base offset when loaded into memory into account for
+         * qchecking for overflows. */
 
-                for (size_t j = 0; sections[j]; j++) {
-                        if (!pe_section_name_equal((const char*) sect->Name, sections[j]))
+        for (size_t i = 0; sections[i]; i++)
+                FOREACH_ARRAY(j, section_table, n_section_table) {
+
+                        if (!pe_section_name_equal((const char*) j->Name, sections[i]))
+                                continue;
+
+                        /* Overflow check: ignore sections that are impossibly large, relative to the file
+                         * address for the section. */
+                        size_t size_max = SIZE_MAX - j->PointerToRawData;
+                        if ((size_t) j->VirtualSize > size_max)
+                                continue;
+
+                        /* Overflow check: ignore sections that are impossibly large, given the virtual
+                         * address for the section */
+                        size_max = SIZE_MAX - j->VirtualAddress;
+                        if (j->VirtualSize > size_max)
                                 continue;
 
-                        offsets[j] = in_memory ? sect->VirtualAddress : sect->PointerToRawData;
-                        sizes[j] = sect->VirtualSize;
+                        /* 2nd overflow check: ignore sections that are impossibly large also taking the
+                         * loaded base into account. */
+                        if (validate_base != 0) {
+                                if (validate_base > size_max)
+                                        continue;
+                                size_max -= validate_base;
+
+                                if (j->VirtualAddress > size_max)
+                                        continue;
+                        }
+
+                        /* At this time, the sizes and offsets have been validated. Store them away */
+                        ret_sections[i] = (PeSectionVector) {
+                                .size = j->VirtualSize,
+                                .file_offset = j->PointerToRawData,
+                                .memory_offset = j->VirtualAddress,
+                        };
+
+                        /* First matching section wins, ignore the rest */
+                        break;
                 }
-        }
 }
 
 static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const PeFileHeader *pe) {
-        size_t addr = 0, size = 0;
         static const char *sections[] = { ".compat", NULL };
+        PeSectionVector vector = {};
 
         /* The kernel may provide alternative PE entry points for different PE architectures. This allows
          * booting a 64-bit kernel on 32-bit EFI that is otherwise running on a 64-bit CPU. The locations of any
          * such compat entry points are located in a special PE section. */
 
-        locate_sections((const PeSectionHeader *) ((const uint8_t *) dos + section_table_offset(dos, pe)),
+        pe_locate_sections(
+                        (const PeSectionHeader *) ((const uint8_t *) dos + section_table_offset(dos, pe)),
                         pe->FileHeader.NumberOfSections,
                         sections,
-                        &addr,
-                        &size,
-                        /*in_memory=*/true);
+                        PTR_TO_SIZE(dos),
+                        &vector);
 
-        if (size == 0)
+        if (vector.size == 0) /* not found */
                 return 0;
 
         typedef struct {
@@ -226,6 +256,8 @@ static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const
                 uint32_t entry_point;
         } _packed_ LinuxPeCompat1;
 
+        size_t addr = vector.memory_offset, size = vector.size;
+
         while (size >= sizeof(LinuxPeCompat1) && addr % alignof(LinuxPeCompat1) == 0) {
                 LinuxPeCompat1 *compat = (LinuxPeCompat1 *) ((uint8_t *) dos + addr);
 
@@ -274,15 +306,18 @@ EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address) {
         return EFI_SUCCESS;
 }
 
-EFI_STATUS pe_memory_locate_sections(const void *base, const char * const sections[], size_t *addrs, size_t *sizes) {
+EFI_STATUS pe_memory_locate_sections(
+                const void *base,
+                const char* const sections[],
+                PeSectionVector *ret_sections) {
+
         const DosFileHeader *dos;
         const PeFileHeader *pe;
         size_t offset;
 
         assert(base);
         assert(sections);
-        assert(addrs);
-        assert(sizes);
+        assert(ret_sections);
 
         dos = (const DosFileHeader *) base;
         if (!verify_dos(dos))
@@ -293,12 +328,12 @@ EFI_STATUS pe_memory_locate_sections(const void *base, const char * const sectio
                 return EFI_LOAD_ERROR;
 
         offset = section_table_offset(dos, pe);
-        locate_sections((PeSectionHeader *) ((uint8_t *) base + offset),
+        pe_locate_sections(
+                        (const PeSectionHeader *) ((const uint8_t *) base + offset),
                         pe->FileHeader.NumberOfSections,
                         sections,
-                        addrs,
-                        sizes,
-                        /*in_memory=*/true);
+                        PTR_TO_SIZE(base),
+                        ret_sections);
 
         return EFI_SUCCESS;
 }
@@ -307,8 +342,7 @@ EFI_STATUS pe_file_locate_sections(
                 EFI_FILE *dir,
                 const char16_t *path,
                 const char * const sections[],
-                size_t *offsets,
-                size_t *sizes) {
+                PeSectionVector *ret_sections) {
         _cleanup_free_ PeSectionHeader *section_table = NULL;
         _cleanup_(file_closep) EFI_FILE *handle = NULL;
         DosFileHeader dos;
@@ -319,8 +353,7 @@ EFI_STATUS pe_file_locate_sections(
         assert(dir);
         assert(path);
         assert(sections);
-        assert(offsets);
-        assert(sizes);
+        assert(ret_sections);
 
         err = dir->Open(dir, &handle, (char16_t *) path, EFI_FILE_MODE_READ, 0ULL);
         if (err != EFI_SUCCESS)
@@ -366,8 +399,12 @@ EFI_STATUS pe_file_locate_sections(
         if (len != section_table_len)
                 return EFI_LOAD_ERROR;
 
-        locate_sections(section_table, pe.FileHeader.NumberOfSections,
-                        sections, offsets, sizes, /*in_memory=*/false);
+        pe_locate_sections(
+                        section_table,
+                        pe.FileHeader.NumberOfSections,
+                        sections,
+                        /* validate_base= */ 0, /* don't validate base */
+                        ret_sections);
 
         return EFI_SUCCESS;
 }
index 7e2258fceb970c6d4e860988566b46b9a269cfaf..bc6d74beeb1211d0f2bef993812586d3df3f9ad4 100644 (file)
@@ -3,17 +3,27 @@
 
 #include "efi.h"
 
+/* This is a subset of the full PE section header structure, with validated values, and without
+ * the noise. */
+typedef struct PeSectionVector {
+        size_t size;
+        size_t memory_offset;   /* Offset in memory, relative to base address */
+        uint64_t file_offset;   /* Offset on disk, relative to beginning of file */
+} PeSectionVector;
+
+static inline bool PE_SECTION_VECTOR_IS_SET(const PeSectionVector *v) {
+        return v && v->size != 0;
+}
+
 EFI_STATUS pe_memory_locate_sections(
                 const void *base,
                 const char * const sections[],
-                size_t *addrs,
-                size_t *sizes);
+                PeSectionVector *ret_sections);
 
 EFI_STATUS pe_file_locate_sections(
                 EFI_FILE *dir,
                 const char16_t *path,
                 const char * const sections[],
-                size_t *offsets,
-                size_t *sizes);
+                PeSectionVector *ret_sections);
 
 EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address);
index f5d2b1d4c54826e65c942d60de01dc2ef8336458..1375b88436947f993fd735983a1b0535102aa0da 100644 (file)
@@ -413,7 +413,7 @@ static EFI_STATUS load_addons(
         sort_pointer_array((void**) items, n_items, (compare_pointer_func_t) strcmp16);
 
         for (size_t i = 0; i < n_items; i++) {
-                size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
+                PeSectionVector sections[ELEMENTSOF(unified_sections)] = {};
                 _cleanup_free_ EFI_DEVICE_PATH *addon_path = NULL;
                 _cleanup_(unload_imagep) EFI_HANDLE addon = NULL;
                 EFI_LOADED_IMAGE_PROTOCOL *loaded_addon = NULL;
@@ -441,9 +441,10 @@ static EFI_STATUS load_addons(
                 if (err != EFI_SUCCESS)
                         return log_error_status(err, "Failed to find protocol in %ls: %m", items[i]);
 
-                err = pe_memory_locate_sections(loaded_addon->ImageBase, unified_sections, addrs, szs);
+                err = pe_memory_locate_sections(loaded_addon->ImageBase, unified_sections, sections);
                 if (err != EFI_SUCCESS ||
-                    (szs[UNIFIED_SECTION_CMDLINE] == 0 && szs[UNIFIED_SECTION_DTB] == 0)) {
+                    (!PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_CMDLINE) &&
+                     !PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTB))) {
                         if (err == EFI_SUCCESS)
                                 err = EFI_NOT_FOUND;
                         log_error_status(err,
@@ -453,38 +454,38 @@ static EFI_STATUS load_addons(
                 }
 
                 /* We want to enforce that addons are not UKIs, i.e.: they must not embed a kernel. */
-                if (szs[UNIFIED_SECTION_LINUX] > 0) {
+                if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_LINUX)) {
                         log_error_status(EFI_INVALID_PARAMETER, "%ls is a UKI, not an addon, ignoring: %m", items[i]);
                         continue;
                 }
 
                 /* Also enforce that, in case it is specified, .uname matches as a quick way to allow
                  * enforcing compatibility with a specific UKI only */
-                if (uname && szs[UNIFIED_SECTION_UNAME] > 0 &&
+                if (uname && PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_UNAME) &&
                                 !strneq8(uname,
-                                         (char *)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_UNAME],
-                                         szs[UNIFIED_SECTION_UNAME])) {
+                                         (char *)loaded_addon->ImageBase + sections[UNIFIED_SECTION_UNAME].memory_offset,
+                                         sections[UNIFIED_SECTION_UNAME].size)) {
                         log_error(".uname mismatch between %ls and UKI, ignoring", items[i]);
                         continue;
                 }
 
-                if (ret_cmdline && szs[UNIFIED_SECTION_CMDLINE] > 0) {
+                if (ret_cmdline && PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_CMDLINE)) {
                         _cleanup_free_ char16_t *tmp = TAKE_PTR(cmdline),
-                                                *extra16 = xstrn8_to_16((char *)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_CMDLINE],
-                                                                        szs[UNIFIED_SECTION_CMDLINE]);
+                                                *extra16 = xstrn8_to_16((char *)loaded_addon->ImageBase + sections[UNIFIED_SECTION_CMDLINE].memory_offset,
+                                                                        sections[UNIFIED_SECTION_CMDLINE].size);
                         cmdline = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", extra16);
                 }
 
-                if (ret_dt_bases && szs[UNIFIED_SECTION_DTB] > 0) {
+                if (ret_dt_bases && PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTB)) {
                         dt_sizes = xrealloc(dt_sizes,
                                             n_dt * sizeof(size_t),
                                             (n_dt + 1)  * sizeof(size_t));
-                        dt_sizes[n_dt] = szs[UNIFIED_SECTION_DTB];
+                        dt_sizes[n_dt] = sections[UNIFIED_SECTION_DTB].size;
 
                         dt_bases = xrealloc(dt_bases,
                                             n_dt * sizeof(void *),
                                             (n_dt + 1) * sizeof(void *));
-                        dt_bases[n_dt] = xmemdup((uint8_t*)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_DTB],
+                        dt_bases[n_dt] = xmemdup((uint8_t*)loaded_addon->ImageBase + sections[UNIFIED_SECTION_DTB].memory_offset,
                                                  dt_sizes[n_dt]);
 
                         dt_filenames = xrealloc(dt_filenames,
@@ -515,11 +516,11 @@ static EFI_STATUS run(EFI_HANDLE image) {
         void **dt_bases_addons_global = NULL, **dt_bases_addons_uki = NULL;
         char16_t **dt_filenames_addons_global = NULL, **dt_filenames_addons_uki = NULL;
         _cleanup_free_ size_t *dt_sizes_addons_global = NULL, *dt_sizes_addons_uki = NULL;
-        size_t linux_size, initrd_size, ucode_size, dt_size, n_dts_addons_global = 0, n_dts_addons_uki = 0;
-        EFI_PHYSICAL_ADDRESS linux_base, initrd_base, ucode_base, dt_base;
+        size_t linux_size, initrd_size = 0, ucode_size = 0, dt_size = 0, n_dts_addons_global = 0, n_dts_addons_uki = 0;
+        EFI_PHYSICAL_ADDRESS linux_base, initrd_base = 0, ucode_base = 0, dt_base = 0;
         _cleanup_(devicetree_cleanup) struct devicetree_state dt_state = {};
         EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
-        size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
+        PeSectionVector sections[ELEMENTSOF(unified_sections)] = {};
         _cleanup_free_ char16_t *cmdline = NULL, *cmdline_addons_global = NULL, *cmdline_addons_uki = NULL;
         int sections_measured = -1, parameters_measured = -1, sysext_measured = -1, confext_measured = -1;
         _cleanup_free_ char *uname = NULL;
@@ -541,8 +542,8 @@ static EFI_STATUS run(EFI_HANDLE image) {
                         (void) process_random_seed(esp_dir);
         }
 
-        err = pe_memory_locate_sections(loaded_image->ImageBase, unified_sections, addrs, szs);
-        if (err != EFI_SUCCESS || szs[UNIFIED_SECTION_LINUX] == 0) {
+        err = pe_memory_locate_sections(loaded_image->ImageBase, unified_sections, sections);
+        if (err != EFI_SUCCESS || !PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_LINUX)) {
                 if (err == EFI_SUCCESS)
                         err = EFI_NOT_FOUND;
                 return log_error_status(err, "Unable to locate embedded .linux section: %m");
@@ -553,9 +554,9 @@ static EFI_STATUS run(EFI_HANDLE image) {
         CLEANUP_ARRAY(dt_filenames_addons_global, n_dts_addons_global, dt_filenames_free);
         CLEANUP_ARRAY(dt_filenames_addons_uki, n_dts_addons_uki, dt_filenames_free);
 
-        if (szs[UNIFIED_SECTION_UNAME] > 0)
-                uname = xstrndup8((char *)loaded_image->ImageBase + addrs[UNIFIED_SECTION_UNAME],
-                                  szs[UNIFIED_SECTION_UNAME]);
+        if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_UNAME))
+                uname = xstrndup8((char *)loaded_image->ImageBase + sections[UNIFIED_SECTION_UNAME].memory_offset,
+                                  sections[UNIFIED_SECTION_UNAME].size);
 
         /* Now that we have the UKI sections loaded, also load global first and then local (per-UKI)
          * addons. The data is loaded at once, and then used later. */
@@ -597,7 +598,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
                 if (!unified_section_measure(section)) /* shall not measure? */
                         continue;
 
-                if (szs[section] == 0) /* not found */
+                if (!PE_SECTION_VECTOR_IS_SET(sections + section)) /* not found */
                         continue;
 
                 /* First measure the name of the section */
@@ -614,11 +615,10 @@ static EFI_STATUS run(EFI_HANDLE image) {
                 m = false;
                 (void) tpm_log_ipl_event_ascii(
                                 TPM2_PCR_KERNEL_BOOT,
-                                POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[section],
-                                szs[section],
+                                POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + sections[section].memory_offset,
+                                sections[section].size,
                                 unified_sections[section],
                                 &m);
-
                 combine_measured_flag(&sections_measured, m);
         }
 
@@ -628,9 +628,10 @@ static EFI_STATUS run(EFI_HANDLE image) {
                 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrKernelImage", TPM2_PCR_KERNEL_BOOT, 0);
 
         /* Show splash screen as early as possible */
-        graphics_splash((const uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_SPLASH], szs[UNIFIED_SECTION_SPLASH]);
+        if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_SPLASH))
+                graphics_splash((const uint8_t*) loaded_image->ImageBase + sections[UNIFIED_SECTION_SPLASH].memory_offset, sections[UNIFIED_SECTION_SPLASH].size);
 
-        if (use_load_options(image, loaded_image, szs[UNIFIED_SECTION_CMDLINE] > 0, &cmdline)) {
+        if (use_load_options(image, loaded_image, /* have_cmdline= */ PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_CMDLINE), &cmdline)) {
                 /* Let's measure the passed kernel command line into the TPM. Note that this possibly
                  * duplicates what we already did in the boot menu, if that was already used. However, since
                  * we want the boot menu to support an EFI binary, and want to this stub to be usable from
@@ -638,10 +639,10 @@ static EFI_STATUS run(EFI_HANDLE image) {
                 m = false;
                 (void) tpm_log_load_options(cmdline, &m);
                 combine_measured_flag(&parameters_measured, m);
-        } else if (szs[UNIFIED_SECTION_CMDLINE] > 0) {
+        } else if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_CMDLINE)) {
                 cmdline = xstrn8_to_16(
-                                (char *) loaded_image->ImageBase + addrs[UNIFIED_SECTION_CMDLINE],
-                                szs[UNIFIED_SECTION_CMDLINE]);
+                                (char *) loaded_image->ImageBase + sections[UNIFIED_SECTION_CMDLINE].memory_offset,
+                                sections[UNIFIED_SECTION_CMDLINE].size);
                 mangle_stub_cmdline(cmdline);
         }
 
@@ -727,8 +728,11 @@ static EFI_STATUS run(EFI_HANDLE image) {
                       &m) == EFI_SUCCESS)
                 combine_measured_flag(&confext_measured, m);
 
-        dt_size = szs[UNIFIED_SECTION_DTB];
-        dt_base = dt_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_DTB] : 0;
+
+        if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTB)) {
+                dt_size = sections[UNIFIED_SECTION_DTB].size;
+                dt_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + sections[UNIFIED_SECTION_DTB].memory_offset;
+        }
 
         /* First load the base device tree, then fix it up using addons - global first, then per-UKI. */
         if (dt_size > 0) {
@@ -767,10 +771,10 @@ static EFI_STATUS run(EFI_HANDLE image) {
          * is not measured, neither as raw section (see above), nor as cpio (here), because it is the
          * signature of expected PCR values, i.e. its input are PCR measurements, and hence it shouldn't
          * itself be input for PCR measurements. */
-        if (szs[UNIFIED_SECTION_PCRSIG] > 0)
+        if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_PCRSIG))
                 (void) pack_cpio_literal(
-                                (uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_PCRSIG],
-                                szs[UNIFIED_SECTION_PCRSIG],
+                                (uint8_t*) loaded_image->ImageBase + sections[UNIFIED_SECTION_PCRSIG].memory_offset,
+                                sections[UNIFIED_SECTION_PCRSIG].size,
                                 ".extra",
                                 u"tpm2-pcr-signature.json",
                                 /* dir_mode= */ 0555,
@@ -785,10 +789,10 @@ static EFI_STATUS run(EFI_HANDLE image) {
          * a cpio and also pass it to the kernel, so that it can be read from
          * /.extra/tpm2-pcr-public-key.pem. This section is already measure above, hence we won't measure the
          * cpio. */
-        if (szs[UNIFIED_SECTION_PCRPKEY] > 0)
+        if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_PCRPKEY))
                 (void) pack_cpio_literal(
-                                (uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_PCRPKEY],
-                                szs[UNIFIED_SECTION_PCRPKEY],
+                                (uint8_t*) loaded_image->ImageBase + sections[UNIFIED_SECTION_PCRPKEY].memory_offset,
+                                sections[UNIFIED_SECTION_PCRPKEY].size,
                                 ".extra",
                                 u"tpm2-pcr-public-key.pem",
                                 /* dir_mode= */ 0555,
@@ -799,14 +803,18 @@ static EFI_STATUS run(EFI_HANDLE image) {
                                 &pcrpkey_initrd_size,
                                 /* ret_measured= */ NULL);
 
-        linux_size = szs[UNIFIED_SECTION_LINUX];
-        linux_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_LINUX];
+        linux_size = sections[UNIFIED_SECTION_LINUX].size;
+        linux_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + sections[UNIFIED_SECTION_LINUX].memory_offset;
 
-        initrd_size = szs[UNIFIED_SECTION_INITRD];
-        initrd_base = initrd_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_INITRD] : 0;
+        if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_INITRD)) {
+                initrd_size = sections[UNIFIED_SECTION_INITRD].size;
+                initrd_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + sections[UNIFIED_SECTION_INITRD].memory_offset;
+        }
 
-        ucode_size = szs[UNIFIED_SECTION_UCODE];
-        ucode_base = ucode_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_UCODE] : 0;
+        if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_UCODE)) {
+                ucode_size = sections[UNIFIED_SECTION_UCODE].size;
+                ucode_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + sections[UNIFIED_SECTION_UCODE].memory_offset;
+        }
 
         _cleanup_pages_ Pages initrd_pages = {};
         if (ucode_base || credential_initrd || global_credential_initrd || sysext_initrd || confext_initrd || pcrsig_initrd || pcrpkey_initrd) {
@@ -857,4 +865,4 @@ static EFI_STATUS run(EFI_HANDLE image) {
         return err;
 }
 
-DEFINE_EFI_MAIN_FUNCTION(run, "systemd-stub", /*wait_for_debugger=*/false);
+DEFINE_EFI_MAIN_FUNCTION(run, "systemd-stub", /* wait_for_debugger= */ false);