]> git.proxmox.com Git - systemd.git/commitdiff
backport "boot: Read files in small chunks on broken firmware"
authorThomas Lamprecht <t.lamprecht@proxmox.com>
Sat, 8 Jul 2023 14:25:30 +0000 (16:25 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Sat, 8 Jul 2023 14:26:52 +0000 (16:26 +0200)
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
debian/patches/proxmox/0001-boot-Read-files-in-small-chunks-on-broken-firmware.patch [new file with mode: 0644]
debian/patches/series

diff --git a/debian/patches/proxmox/0001-boot-Read-files-in-small-chunks-on-broken-firmware.patch b/debian/patches/proxmox/0001-boot-Read-files-in-small-chunks-on-broken-firmware.patch
new file mode 100644 (file)
index 0000000..ff80ab3
--- /dev/null
@@ -0,0 +1,106 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jan Janssen <medhefgo@web.de>
+Date: Thu, 5 Jan 2023 18:35:19 +0100
+Subject: [PATCH] boot: Read files in small chunks on broken firmware
+
+Fixes: #25911
+(cherry picked from commit f70f992273a7add1ec98a894ffadb1f1e43c0c31)
+Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
+---
+ src/boot/efi/boot.c |  2 +-
+ src/boot/efi/util.c | 48 +++++++++++++++++++++++++++++++++++++++------
+ src/boot/efi/util.h |  1 +
+ 3 files changed, 44 insertions(+), 7 deletions(-)
+
+diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
+index 1f4a7dbc90..4592ff5fe8 100644
+--- a/src/boot/efi/boot.c
++++ b/src/boot/efi/boot.c
+@@ -2327,7 +2327,7 @@ static EFI_STATUS initrd_prepare(
+                         return EFI_OUT_OF_RESOURCES;
+                 initrd = xrealloc(initrd, size, new_size);
+-                err = handle->Read(handle, &read_size, initrd + size);
++                err = chunked_read(handle, &read_size, initrd + size);
+                 if (err != EFI_SUCCESS)
+                         return err;
+diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
+index 7a0d5c608f..66056f0f15 100644
+--- a/src/boot/efi/util.c
++++ b/src/boot/efi/util.c
+@@ -288,6 +288,44 @@ void mangle_stub_cmdline(char16_t *cmdline) {
+         }
+ }
++EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf) {
++        EFI_STATUS err;
++
++        assert(file);
++        assert(size);
++        assert(buf);
++
++        /* This is a drop-in replacement for EFI_FILE->Read() with the same API behavior.
++         * Some broken firmwares cannot handle large file reads and will instead return
++         * an error. As a workaround, read such files in small chunks.
++         * Note that we cannot just try reading the whole file first on such firmware as
++         * that will permanently break the handle even if it is re-opened.
++         *
++         * https://github.com/systemd/systemd/issues/25911 */
++
++        if (*size == 0)
++                return EFI_SUCCESS;
++
++        size_t read = 0, remaining = *size;
++        while (remaining > 0) {
++                size_t chunk = MIN(1024U * 1024U, remaining);
++
++                err = file->Read(file, &chunk, (uint8_t *) buf + read);
++                if (err != EFI_SUCCESS)
++                        return err;
++                if (chunk == 0)
++                        /* Caller requested more bytes than are in file. */
++                        break;
++
++                assert(chunk <= remaining);
++                read += chunk;
++                remaining -= chunk;
++        }
++
++        *size = read;
++        return EFI_SUCCESS;
++}
++
+ EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, UINTN off, UINTN size, char **ret, UINTN *ret_size) {
+         _cleanup_(file_closep) EFI_FILE *handle = NULL;
+         _cleanup_free_ char *buf = NULL;
+@@ -321,13 +359,11 @@ EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, UINTN off, UINTN size,
+         UINTN extra = size % sizeof(char16_t) + sizeof(char16_t);
+         buf = xmalloc(size + extra);
+-        if (size > 0) {
+-                err = handle->Read(handle, &size, buf);
+-                if (err != EFI_SUCCESS)
+-                        return err;
+-        }
++        err = chunked_read(handle, &size, buf);
++        if (err != EFI_SUCCESS)
++                return err;
+-        /* Note that handle->Read() changes size to reflect the actually bytes read. */
++        /* Note that chunked_read() changes size to reflect the actual bytes read. */
+         memset(buf + size, 0, extra);
+         *ret = TAKE_PTR(buf);
+diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
+index 9f8439480e..565f517d55 100644
+--- a/src/boot/efi/util.h
++++ b/src/boot/efi/util.h
+@@ -116,6 +116,7 @@ void convert_efi_path(char16_t *path);
+ char16_t *xstr8_to_path(const char *stra);
+ void mangle_stub_cmdline(char16_t *cmdline);
++EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf);
+ EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, UINTN off, UINTN size, char **content, UINTN *content_size);
+ static inline void file_closep(EFI_FILE **handle) {
index 661f0c480a264cfdceb00182173bca921dfae870..c2aa4f04125a1ca7e9ff8b74c9b4f473ee5349fe 100644 (file)
@@ -18,3 +18,4 @@ debian/Move-sysusers.d-sysctl.d-binfmt.d-modules-load.d-back-to-.patch
 debian/systemctl-do-not-shutdown-immediately-on-scheduled-shutdo.patch
 debian/Downgrade-a-couple-of-warnings-to-debug.patch
 debian/Skip-flaky-test_resolved_domain_restricted_dns-in-network.patch
+proxmox/0001-boot-Read-files-in-small-chunks-on-broken-firmware.patch