Package sources for project devel:languages:perl are received through scmsync. This is not supported by the OBS frontend

File 2002-systemd-stub-addons-load-generic-addons-via-EFI-prot.patch of Package systemd

From 6685f5de70af793d4e24c85712ba1effcf2ae0a4 Mon Sep 17 00:00:00 2001
From: Raito Bezarius <masterancpp@gmail.com>
Date: Sun, 18 Jun 2023 04:26:05 +0200
Subject: [PATCH 2002/2007] systemd-stub(addons): load generic addons via EFI
 protocol

- reads from EFI protocol
- make the loading phase agnostic from the "read source"
- restructure the addon entry to be generic and not only cmdline for
  future initrd loading, etc.
- add a feature called `OFFER_ADDONS` on sd-boot to signal support for
  this EFI protocol
---
 src/boot/boot.c                       |   1 +
 src/boot/stub.c                       | 128 +++++++++++++++++++++-----
 src/fundamental/efivars-fundamental.h |   1 +
 3 files changed, 106 insertions(+), 24 deletions(-)

diff --git a/src/boot/boot.c b/src/boot/boot.c
index ea6b8b150e..509e0d9b84 100644
--- a/src/boot/boot.c
+++ b/src/boot/boot.c
@@ -2789,6 +2789,7 @@ static void export_loader_variables(
                 EFI_LOADER_FEATURE_RETAIN_SHIM |
                 EFI_LOADER_FEATURE_MENU_DISABLE |
                 EFI_LOADER_FEATURE_MULTI_PROFILE_UKI |
+                EFI_LOADER_FEATURE_OFFER_ADDONS |
                 0;
 
         assert(loaded_image);
diff --git a/src/boot/stub.c b/src/boot/stub.c
index cf990df2e7..cf3ba95669 100644
--- a/src/boot/stub.c
+++ b/src/boot/stub.c
@@ -49,6 +49,18 @@ DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION
 
 DECLARE_SBAT(SBAT_STUB_SECTION_TEXT);
 
+struct addon_entry {
+        char16_t *source_path;
+        const EFI_DEVICE_PATH *device_path;
+};
+
+static int cmp_addon_entry(const struct addon_entry *s1, const struct addon_entry *s2) {
+        assert(s1);
+        assert(s2);
+
+        return strcmp16((const char16_t*)&s1->source_path, (const char16_t*)&s2->source_path);
+}
+
 static char16_t* pe_section_to_str16(
                 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
                 const PeSectionVector *section) {
@@ -288,20 +300,23 @@ nothing:
 }
 
 static EFI_STATUS load_addons_from_dir(
+                EFI_LOADED_IMAGE_PROTOCOL *current_image,
                 EFI_FILE *root,
                 const char16_t *prefix,
-                char16_t ***items,
+                struct addon_entry **addons,
                 size_t *n_items,
                 size_t *n_allocated) {
 
         _cleanup_(file_closep) EFI_FILE *extra_dir = NULL;
         _cleanup_free_ EFI_FILE_INFO *dirent = NULL;
+        char16_t *addon_spath = NULL;
+        EFI_DEVICE_PATH *addon_path = NULL;
         size_t dirent_size = 0;
         EFI_STATUS err;
 
         assert(root);
         assert(prefix);
-        assert(items);
+        assert(addons);
         assert(n_items);
         assert(n_allocated);
 
@@ -336,16 +351,73 @@ static EFI_STATUS load_addons_from_dir(
 
                 if (*n_items + 2 > *n_allocated) {
                         /* We allocate 16 entries at a time, as a matter of optimization */
-                        if (*n_items > (SIZE_MAX / sizeof(uint16_t)) - 16) /* Overflow check, just in case */
+                        if (*n_items > (SIZE_MAX / sizeof(struct addon_entry)) - 16) /* Overflow check, just in case */
+                                return log_oom();
+
+                        size_t m = *n_items + 16;
+                        *addons = xrealloc(*addons, *n_allocated + sizeof(struct addon_entry), m *
+                                          sizeof(struct addon_entry));
+                        *n_allocated = m;
+                }
+
+                addon_spath = xasprintf("%ls\\%ls", prefix, d);
+                err = make_file_device_path(current_image->DeviceHandle, addon_spath, &addon_path);
+                if (err != EFI_SUCCESS)
+                        return log_error_status(err, "Error making device path for %ls: %m", addon_spath);
+
+                (*addons)[*n_items] = (struct addon_entry) {
+                        .source_path = TAKE_PTR(d),
+                        .device_path = TAKE_PTR(addon_path)
+                };
+                *n_items = *n_items + 1;
+        }
+
+        return EFI_SUCCESS;
+}
+
+static EFI_STATUS load_addons_from_efi(
+                EFI_LOADED_IMAGE_PROTOCOL *image,
+                struct addon_entry **addons,
+                size_t *n_items,
+                size_t *n_allocated) {
+
+        EFI_STATUS err;
+        EFI_DEVICE_PATH **addon_paths = NULL;
+
+        err = BS->HandleProtocol(image->DeviceHandle, MAKE_GUID_PTR(SYSTEMD_ADDON_MEDIA), (void **) &addon_paths);
+
+        if (err == EFI_UNSUPPORTED)
+                /* No addons from EFI, that's OK */
+                return EFI_SUCCESS;
+        if (err != EFI_SUCCESS)
+                return log_error_status(err, "Failed to load addons from EFI protocol: %m");
+
+        while (*addon_paths) {
+                char16_t *spath = NULL;
+                /* If we increment this pointer instead of addon_paths_split, we will arrive on a end node
+                 * marker */
+                const EFI_DEVICE_PATH *addon_dpath = *addon_paths;
+                err = device_path_to_str(addon_dpath, &spath);
+                if (err != EFI_SUCCESS)
+                        return err;
+
+                if (*n_items + 2 > *n_allocated) {
+                        /* We allocate 16 entries at a time, as a matter of optimization */
+                        if (*n_items > (SIZE_MAX / sizeof(struct addon_entry)) - 16) /* Overflow check, just in case */
                                 return log_oom();
 
                         size_t m = *n_items + 16;
-                        *items = xrealloc(*items, *n_allocated * sizeof(uint16_t *), m * sizeof(uint16_t *));
+                        *addons = xrealloc(*addons, *n_allocated + sizeof(struct addon_entry), m *
+                                          sizeof(struct addon_entry));
                         *n_allocated = m;
                 }
 
-                (*items)[(*n_items)++] = TAKE_PTR(d);
-                (*items)[*n_items] = NULL; /* Let's always NUL terminate, to make freeing via strv_free() easy */
+                (*addons)[*n_items] = (struct addon_entry) {
+                        .source_path = TAKE_PTR(spath),
+                        .device_path = TAKE_PTR(addon_dpath)
+                };
+                *n_items = *n_items + 1;
+                addon_paths++;
         }
 
         return EFI_SUCCESS;
@@ -534,6 +606,15 @@ static void extend_initrds(
                 iovec_array_extend(all_initrds, n_all_initrds, *i);
 }
 
+static void items_free(char16_t **items, size_t n_items) {
+        assert(items || n_items == 0);
+
+        for (size_t i = 0; i < n_items; ++i)
+                free(items[i]);
+
+        free(items);
+}
+
 static EFI_STATUS load_addons(
                 EFI_HANDLE stub_image,
                 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
@@ -547,9 +628,10 @@ static EFI_STATUS load_addons(
                 NamedAddon **ucode_addons,                  /* Ditto */
                 size_t *n_ucode_addons) {
 
-        _cleanup_(strv_freep) char16_t **items = NULL;
         _cleanup_(file_closep) EFI_FILE *root = NULL;
+        _cleanup_free_ struct addon_entry *addons = NULL;
         size_t n_items = 0, n_allocated = 0;
+        char16_t **items = NULL;
         EFI_STATUS err;
 
         assert(stub_image);
@@ -559,6 +641,8 @@ static EFI_STATUS load_addons(
         if (!loaded_image->DeviceHandle)
                 return EFI_SUCCESS;
 
+        CLEANUP_ARRAY(items, n_items, items_free);
+
         err = open_volume(loaded_image->DeviceHandle, &root);
         if (err == EFI_UNSUPPORTED)
                 /* Error will be unsupported if the bootloader doesn't implement the file system protocol on
@@ -567,7 +651,11 @@ static EFI_STATUS load_addons(
         if (err != EFI_SUCCESS)
                 return log_error_status(err, "Unable to open root directory: %m");
 
-        err = load_addons_from_dir(root, prefix, &items, &n_items, &n_allocated);
+        err = load_addons_from_dir(loaded_image, root, prefix, &addons, &n_items, &n_allocated);
+        if (err != EFI_SUCCESS)
+                return err;
+
+        err = load_addons_from_efi(loaded_image, &addons, &n_items, &n_allocated);
         if (err != EFI_SUCCESS)
                 return err;
 
@@ -576,28 +664,19 @@ static EFI_STATUS load_addons(
 
         /* Now, sort the files we found, to make this uniform and stable (and to ensure the TPM measurements
          * are not dependent on read order) */
-        sort_pointer_array((void**) items, n_items, (compare_pointer_func_t) strcmp16);
+        sort_pointer_array((void**) addons, n_items, (compare_pointer_func_t) cmp_addon_entry);
 
         for (size_t i = 0; i < n_items; i++) {
                 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;
-                _cleanup_free_ char16_t *addon_spath = NULL;
-
-                addon_spath = xasprintf("%ls\\%ls", prefix, items[i]);
-                err = make_file_device_path(loaded_image->DeviceHandle, addon_spath, &addon_path);
-                if (err != EFI_SUCCESS)
-                        return log_error_status(err, "Error making device path for %ls: %m", addon_spath);
 
                 /* By using shim_load_image, we cover both the case where the PE files are signed with MoK
                  * and with DB, and running with or without shim. */
-                err = shim_load_image(stub_image, addon_path, &addon);
+                err = shim_load_image(stub_image,  addons[i].device_path, &addon);
                 if (err != EFI_SUCCESS) {
                         log_error_status(err,
-                                         "Failed to read '%ls' from '%ls', ignoring: %m",
-                                         items[i],
-                                         addon_spath);
+                                         "Failed to read '%ls', ignoring: %m", addons[i].source_path);
                         continue;
                 }
 
@@ -605,7 +684,8 @@ static EFI_STATUS load_addons(
                                          MAKE_GUID_PTR(EFI_LOADED_IMAGE_PROTOCOL),
                                          (void **) &loaded_addon);
                 if (err != EFI_SUCCESS)
-                        return log_error_status(err, "Failed to find protocol in %ls: %m", items[i]);
+                        return log_error_status(err, "Failed to find protocol in %ls: %m",
+                                                addons[i].source_path);
 
                 err = pe_memory_locate_sections(loaded_addon->ImageBase, unified_sections, sections);
                 if (err != EFI_SUCCESS ||
@@ -618,13 +698,13 @@ static EFI_STATUS load_addons(
                                 err = EFI_NOT_FOUND;
                         log_error_status(err,
                                          "Unable to locate embedded .cmdline/.dtb/.dtbauto/.initrd/.ucode sections in %ls, ignoring: %m",
-                                         items[i]);
+                                         addons[i].source_path);
                         continue;
                 }
 
                 /* We want to enforce that addons are not UKIs, i.e.: they must not embed a kernel. */
                 if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_LINUX)) {
-                        log_error("%ls is a UKI, not an addon, ignoring.", items[i]);
+                        log_error("%ls is a UKI, not an addon, ignoring.", addons[i].source_path);
                         continue;
                 }
 
@@ -634,7 +714,7 @@ static EFI_STATUS load_addons(
                                 !strneq8(uname,
                                          (const char *)loaded_addon->ImageBase + sections[UNIFIED_SECTION_UNAME].memory_offset,
                                          sections[UNIFIED_SECTION_UNAME].memory_size)) {
-                        log_error(".uname mismatch between %ls and UKI, ignoring", items[i]);
+                        log_error(".uname mismatch between %ls and UKI, ignoring", addons[i].source_path);
                         continue;
                 }
 
diff --git a/src/fundamental/efivars-fundamental.h b/src/fundamental/efivars-fundamental.h
index f002e81b53..01bdfee68e 100644
--- a/src/fundamental/efivars-fundamental.h
+++ b/src/fundamental/efivars-fundamental.h
@@ -24,6 +24,7 @@
 #define EFI_LOADER_FEATURE_RETAIN_SHIM             (UINT64_C(1) << 12)
 #define EFI_LOADER_FEATURE_MENU_DISABLE            (UINT64_C(1) << 13)
 #define EFI_LOADER_FEATURE_MULTI_PROFILE_UKI       (UINT64_C(1) << 14)
+#define EFI_LOADER_FEATURE_OFFER_ADDONS            (UINT64_C(1) << 15)
 
 /* Features of the stub, i.e. systemd-stub */
 #define EFI_STUB_FEATURE_REPORT_BOOT_PARTITION     (UINT64_C(1) << 0)
-- 
2.49.0

openSUSE Build Service is sponsored by