From 005c99a03590114f06c364ef28bfe2a6b53959edb09eaf79032fd1d5421600f2 Mon Sep 17 00:00:00 2001 From: Michael Chang Date: Mon, 27 Dec 2021 06:21:59 +0000 Subject: [PATCH] Accepting request 942210 from home:michael-chang:branches:Base:System - Fix CVE-2021-3981 (bsc#1189644) * 0001-grub-mkconfig-restore-umask-for-grub.cfg.patch - Fix can't allocate initrd error (bsc#1191378) * 0001-Factor-out-grub_efi_linux_boot.patch * 0002-Fix-race-in-EFI-validation.patch * 0003-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch * 0004-Try-to-pick-better-locations-for-kernel-and-initrd.patch * 0005-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch * 0006-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch * 0007-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch * 0008-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch * 0009-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch * 0010-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch * 0011-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch OBS-URL: https://build.opensuse.org/request/show/942210 OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=400 --- 0001-Factor-out-grub_efi_linux_boot.patch | 228 ++++++++++++++ ...-mkconfig-restore-umask-for-grub.cfg.patch | 44 +++ 0002-Fix-race-in-EFI-validation.patch | 92 ++++++ ...rch-64-on-32-boot-in-linuxefi-loader.patch | 290 ++++++++++++++++++ ...tter-locations-for-kernel-and-initrd.patch | 200 ++++++++++++ ...ce-buffers-for-reading-to-addresses-.patch | 105 +++++++ ...-arrange-grub_cmd_linux-a-little-bit.patch | 133 ++++++++ ...e-our-own-allocator-for-kernel-stuff.patch | 249 +++++++++++++++ ...itrd-params-cmdline-allocations-abov.patch | 175 +++++++++++ ...maximum-bounce-buffer-size-to-16-MiB.patch | 43 +++ ...integer-overflows-in-grub_cmd_initrd.patch | 52 ++++ ..._EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch | 27 ++ grub2.changes | 22 ++ grub2.spec | 14 +- 14 files changed, 1673 insertions(+), 1 deletion(-) create mode 100644 0001-Factor-out-grub_efi_linux_boot.patch create mode 100644 0001-grub-mkconfig-restore-umask-for-grub.cfg.patch create mode 100644 0002-Fix-race-in-EFI-validation.patch create mode 100644 0003-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch create mode 100644 0004-Try-to-pick-better-locations-for-kernel-and-initrd.patch create mode 100644 0005-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch create mode 100644 0006-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch create mode 100644 0007-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch create mode 100644 0008-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch create mode 100644 0009-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch create mode 100644 0010-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch create mode 100644 0011-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch diff --git a/0001-Factor-out-grub_efi_linux_boot.patch b/0001-Factor-out-grub_efi_linux_boot.patch new file mode 100644 index 0000000..f8dbced --- /dev/null +++ b/0001-Factor-out-grub_efi_linux_boot.patch @@ -0,0 +1,228 @@ +From 82d95254ca0496c8843113665bb9a99876101025 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 8 Oct 2021 13:36:45 +0800 +Subject: [PATCH 01/11] Factor out grub_efi_linux_boot + +Both x86 and arm64 on efi are using handover protocol to boot linux +kernel. To enable better code reuse, factor out grub_efi_linux_boot from +arm64 so that it can be shared with x86 platform for the common fixes. + +Signed-off-by: Michael Chang +--- + grub-core/Makefile.core.def | 1 + + grub-core/loader/arm64/efi/linux.c | 35 +----------------- + grub-core/loader/efi/linux.c | 58 ++++++++++++++++++++++++++++++ + grub-core/loader/i386/efi/linux.c | 13 ++----- + include/grub/efi/linux.h | 29 +++++++++++++++ + 5 files changed, 92 insertions(+), 44 deletions(-) + create mode 100644 grub-core/loader/efi/linux.c + create mode 100644 include/grub/efi/linux.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index b5328d7a0..46a488131 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1834,6 +1834,7 @@ module = { + riscv64 = loader/riscv/linux.c; + emu = loader/emu/linux.c; + common = loader/linux.c; ++ efi = loader/efi/linux.c; + }; + + module = { +diff --git a/grub-core/loader/arm64/efi/linux.c b/grub-core/loader/arm64/efi/linux.c +index 87cb2f97c..0ebdc48b7 100644 +--- a/grub-core/loader/arm64/efi/linux.c ++++ b/grub-core/loader/arm64/efi/linux.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -51,40 +52,6 @@ static grub_uint32_t cmdline_size; + static grub_addr_t initrd_start; + static grub_addr_t initrd_end; + +-#pragma GCC diagnostic push +-#pragma GCC diagnostic ignored "-Wcast-align" +- +-typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); +- +-static grub_err_t +-grub_efi_linux_boot (void *kernel_address, grub_off_t offset, +- void *kernel_params) +-{ +- grub_efi_loaded_image_t *loaded_image = NULL; +- handover_func hf; +- +- /* +- * Since the EFI loader is not calling the LoadImage() and StartImage() +- * services for loading the kernel and booting respectively, it has to +- * set the Loaded Image base address. +- */ +- loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); +- if (loaded_image) +- loaded_image->image_base = kernel_addr; +- else +- grub_dprintf ("linux", "Loaded Image base address could not be set\n"); +- +- grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", +- kernel_address, (void *)(grub_efi_uintn_t)offset, kernel_params); +- hf = (handover_func)((char *)kernel_address + offset); +- grub_dprintf ("linux", "handover_func() = %p\n", hf); +- hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); +- +- return GRUB_ERR_BUG; +-} +- +-#pragma GCC diagnostic pop +- + grub_err_t + grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) + { +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +new file mode 100644 +index 000000000..442627dc2 +--- /dev/null ++++ b/grub-core/loader/efi/linux.c +@@ -0,0 +1,58 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2014 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-align" ++ ++typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); ++ ++grub_err_t ++grub_efi_linux_boot (void *kernel_addr, grub_off_t offset, ++ void *kernel_params) ++{ ++ grub_efi_loaded_image_t *loaded_image = NULL; ++ handover_func hf; ++ ++ /* ++ * Since the EFI loader is not calling the LoadImage() and StartImage() ++ * services for loading the kernel and booting respectively, it has to ++ * set the Loaded Image base address. ++ */ ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (loaded_image) ++ loaded_image->image_base = kernel_addr; ++ else ++ grub_dprintf ("linux", "Loaded Image base address could not be set\n"); ++ ++ grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", ++ kernel_addr, (void *)(grub_efi_uintn_t)offset, kernel_params); ++ hf = (handover_func)((char *)kernel_addr + offset); ++ hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); ++ ++ return GRUB_ERR_BUG; ++} ++ ++#pragma GCC diagnostic pop +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 355ecc9b9..06814cae3 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -40,26 +41,18 @@ static char *linux_cmdline; + + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) + +-typedef void(*handover_func)(void *, grub_efi_system_table_t *, struct linux_kernel_params *); +- + static grub_err_t + grub_linuxefi_boot (void) + { +- handover_func hf; + int offset = 0; + + #ifdef __x86_64__ + offset = 512; + #endif +- +- hf = (handover_func)((char *)kernel_mem + handover_offset + offset); +- + asm volatile ("cli"); + +- hf (grub_efi_image_handle, grub_efi_system_table, params); +- +- /* Not reached */ +- return GRUB_ERR_NONE; ++ return grub_efi_linux_boot ((char *)kernel_mem, handover_offset + offset, ++ params); + } + + static grub_err_t +diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h +new file mode 100644 +index 000000000..887b02fd9 +--- /dev/null ++++ b/include/grub/efi/linux.h +@@ -0,0 +1,29 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2014 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++#ifndef GRUB_EFI_LINUX_HEADER ++#define GRUB_EFI_LINUX_HEADER 1 ++ ++#include ++#include ++#include ++ ++grub_err_t ++EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset, ++ void *kernel_param); ++ ++#endif /* ! GRUB_EFI_LINUX_HEADER */ +-- +2.31.1 + diff --git a/0001-grub-mkconfig-restore-umask-for-grub.cfg.patch b/0001-grub-mkconfig-restore-umask-for-grub.cfg.patch new file mode 100644 index 0000000..63a0ebd --- /dev/null +++ b/0001-grub-mkconfig-restore-umask-for-grub.cfg.patch @@ -0,0 +1,44 @@ +From 7a5022ea64fd6af859383a1731632abc8755b8f7 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 26 Aug 2021 15:52:00 +0800 +Subject: [PATCH] grub-mkconfig: restore umask for grub.cfg + +Since commit: + + ab2e53c8a grub-mkconfig: Honor a symlink when generating configuration +by grub-mkconfig + +has inadvertently discarded umask for creating grub.cfg in the process +of grub-mkconfig. The resulting wrong permission (0644) would allow +unprivileged users to read grub's configuration file content. This +presents a low confidentiality risk as grub.cfg may contain non-secured +plain-text passwords. + +This patch restores the missing umask and set the file mode of creation +to 0600 preventing unprivileged access. + +Fixes: CVE-2021-3981 + +Signed-off-by: Michael Chang +Reviewed-by: Daniel Kiper +--- + util/grub-mkconfig.in | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 7f6d961d2..4aca09d8e 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -351,7 +351,9 @@ and /etc/grub.d/* files or please file a bug report with + exit 1 + else + # none of the children aborted with error, install the new grub.cfg ++ oldumask=$(umask); umask 077 + cat ${grub_cfg}.new > ${grub_cfg} ++ umask $oldumask + rm -f ${grub_cfg}.new + # check if default entry need to be corrected for updated distributor version + # and/or use fallback entry if default kernel entry removed +-- +2.31.1 + diff --git a/0002-Fix-race-in-EFI-validation.patch b/0002-Fix-race-in-EFI-validation.patch new file mode 100644 index 0000000..c58a65f --- /dev/null +++ b/0002-Fix-race-in-EFI-validation.patch @@ -0,0 +1,92 @@ +From e72dcb40356f56efd86ab88c2f5cb7411d1e898b Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Tue, 14 Jul 2015 16:58:51 -0700 +Subject: [PATCH 02/11] Fix race in EFI validation + +--- + grub-core/loader/i386/efi/linux.c | 40 +++++++------------------------ + 1 file changed, 9 insertions(+), 31 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 06814cae3..1e09c88ab 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -154,7 +154,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_file_t file = 0; + struct linux_i386_kernel_header lh; + grub_ssize_t len, start, filelen; +- void *kernel; ++ void *kernel = NULL; + grub_err_t err; + + grub_dl_ref (my_mod); +@@ -185,10 +185,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- grub_file_seek (file, 0); +- +- grub_free(kernel); +- + params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); + + if (! params) +@@ -199,13 +195,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_memset (params, 0, 16384); + +- if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) +- { +- if (!grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); +- goto fail; +- } ++ grub_memcpy (&lh, kernel, sizeof (lh)); + + if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) + { +@@ -271,26 +261,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- if (grub_file_seek (file, start) == (grub_off_t) -1) +- { +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); +- goto fail; +- } +- +- if (grub_file_read (file, kernel_mem, len) != len && !grub_errno) +- { +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); +- } +- +- if (grub_errno == GRUB_ERR_NONE) +- { +- grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +- loaded = 1; +- lh.code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; +- } ++ grub_memcpy (kernel_mem, (char *)kernel + start, len); ++ grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); ++ loaded=1; + ++ lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; + /* Grub linuxefi erroneously initialize linux's boot_params with non-zero values. (bsc#1025563) + + From https://www.kernel.org/doc/Documentation/x86/boot.txt: +@@ -307,6 +282,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (file) + grub_file_close (file); + ++ if (kernel) ++ grub_free (kernel); ++ + if (grub_errno != GRUB_ERR_NONE) + { + grub_dl_unref (my_mod); +-- +2.31.1 + diff --git a/0003-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch b/0003-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch new file mode 100644 index 0000000..33b81ef --- /dev/null +++ b/0003-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch @@ -0,0 +1,290 @@ +From 25069a23257ba9c6db644bbe6114dafb879063e5 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 8 Jul 2019 12:32:37 +0200 +Subject: [PATCH 03/11] Handle multi-arch (64-on-32) boot in linuxefi loader. + +Allow booting 64-bit kernels on 32-bit EFI on x86. + +Signed-off-by: Peter Jones +--- + grub-core/loader/efi/linux.c | 11 ++- + grub-core/loader/i386/efi/linux.c | 127 +++++++++++++++++++----------- + include/grub/i386/linux.h | 7 +- + 3 files changed, 97 insertions(+), 48 deletions(-) + +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index 442627dc2..9265cf420 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -30,11 +30,16 @@ + typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); + + grub_err_t +-grub_efi_linux_boot (void *kernel_addr, grub_off_t offset, ++grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, + void *kernel_params) + { + grub_efi_loaded_image_t *loaded_image = NULL; + handover_func hf; ++ int offset = 0; ++ ++#ifdef __x86_64__ ++ offset = 512; ++#endif + + /* + * Since the EFI loader is not calling the LoadImage() and StartImage() +@@ -48,8 +53,8 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t offset, + grub_dprintf ("linux", "Loaded Image base address could not be set\n"); + + grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", +- kernel_addr, (void *)(grub_efi_uintn_t)offset, kernel_params); +- hf = (handover_func)((char *)kernel_addr + offset); ++ kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params); ++ hf = (handover_func)((char *)kernel_addr + handover_offset + offset); + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); + + return GRUB_ERR_BUG; +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 1e09c88ab..0b3d20875 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -44,14 +44,10 @@ static char *linux_cmdline; + static grub_err_t + grub_linuxefi_boot (void) + { +- int offset = 0; +- +-#ifdef __x86_64__ +- offset = 512; +-#endif + asm volatile ("cli"); + +- return grub_efi_linux_boot ((char *)kernel_mem, handover_offset + offset, ++ return grub_efi_linux_boot ((char *)kernel_mem, ++ handover_offset, + params); + } + +@@ -147,14 +143,20 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + ++#define MIN(a, b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++ + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; +- struct linux_i386_kernel_header lh; +- grub_ssize_t len, start, filelen; ++ struct linux_i386_kernel_header *lh = NULL; ++ grub_ssize_t start, filelen; + void *kernel = NULL; ++ int setup_header_end_offset; + grub_err_t err; + + grub_dl_ref (my_mod); +@@ -185,45 +187,79 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); +- ++ params = grub_efi_allocate_pages_max (0x3fffffff, ++ BYTES_TO_PAGES(sizeof(*params))); + if (! params) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); + goto fail; + } + +- grub_memset (params, 0, 16384); +- +- grub_memcpy (&lh, kernel, sizeof (lh)); +- +- if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) ++ grub_dprintf ("linux", "params = %p\n", params); ++ ++ grub_memset (params, 0, sizeof(*params)); ++ ++ setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); ++ grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", ++ MIN((grub_size_t)0x202+setup_header_end_offset, ++ sizeof (*params)) - 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ (grub_uint8_t *)params + 0x1f1); ++ grub_memcpy ((grub_uint8_t *)params + 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); ++ lh = (struct linux_i386_kernel_header *)params; ++ grub_dprintf ("linux", "lh is at %p\n", lh); ++ grub_dprintf ("linux", "checking lh->boot_flag\n"); ++ if (lh->boot_flag != grub_cpu_to_le16 (0xaa55)) + { + grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number")); + goto fail; + } + +- if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) ++ grub_dprintf ("linux", "checking lh->setup_sects\n"); ++ if (lh->setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) + { + grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors")); + goto fail; + } + +- if (lh.version < grub_cpu_to_le16 (0x020b)) ++ grub_dprintf ("linux", "checking lh->version\n"); ++ if (lh->version < grub_cpu_to_le16 (0x020b)) + { + grub_error (GRUB_ERR_BAD_OS, N_("kernel too old")); + goto fail; + } + +- if (!lh.handover_offset) ++ grub_dprintf ("linux", "checking lh->handover_offset\n"); ++ if (!lh->handover_offset) + { + grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover")); + goto fail; + } + +- linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, +- BYTES_TO_PAGES(lh.cmdline_size + 1)); ++#if defined(__x86_64__) || defined(__aarch64__) ++ grub_dprintf ("linux", "checking lh->xloadflags\n"); ++ if (!(lh->xloadflags & LINUX_XLF_KERNEL_64)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support 64-bit CPUs")); ++ goto fail; ++ } ++#endif ++ ++#if defined(__i386__) ++ if ((lh->xloadflags & LINUX_XLF_KERNEL_64) && ++ !(lh->xloadflags & LINUX_XLF_EFI_HANDOVER_32)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, ++ N_("kernel doesn't support 32-bit handover")); ++ goto fail; ++ } ++#endif + ++ grub_dprintf ("linux", "setting up cmdline\n"); ++ linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); + if (!linux_cmdline) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); +@@ -233,27 +269,26 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + err = grub_create_loader_cmdline (argc, argv, + linux_cmdline + sizeof (LINUX_IMAGE) - 1, +- lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1), ++ lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1), + GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + goto fail; + +- lh.cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; ++ grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); ++ grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); ++ lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; + +- handover_offset = lh.handover_offset; ++ grub_dprintf ("linux", "computing handover offset\n"); ++ handover_offset = lh->handover_offset; + +- start = (lh.setup_sects + 1) * 512; +- len = grub_file_size(file) - start; ++ start = (lh->setup_sects + 1) * 512; + +- kernel_mem = grub_efi_allocate_fixed (lh.pref_address, +- BYTES_TO_PAGES(lh.init_size)); ++ kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, ++ BYTES_TO_PAGES(lh->init_size)); + + if (!kernel_mem) +- { +- grub_errno = GRUB_ERR_NONE; +- kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, +- BYTES_TO_PAGES(lh.init_size)); +- } ++ kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, ++ BYTES_TO_PAGES(lh->init_size)); + + if (!kernel_mem) + { +@@ -261,21 +296,23 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- grub_memcpy (kernel_mem, (char *)kernel + start, len); ++ grub_dprintf ("linux", "kernel_mem = %lx\n", (unsigned long) kernel_mem); ++ + grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); + loaded=1; ++ grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); ++ lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; + +- lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; +- /* Grub linuxefi erroneously initialize linux's boot_params with non-zero values. (bsc#1025563) ++ grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); + +- From https://www.kernel.org/doc/Documentation/x86/boot.txt: +- The memory for struct boot_params could be allocated anywhere (even above 4G) +- and initialized to all zero. +- Then, the setup header at offset 0x01f1 of kernel image on should be +- loaded into struct boot_params and examined. */ +- grub_memcpy (¶ms->setup_sects, &lh.setup_sects, sizeof (lh) - 0x01f1); ++ grub_dprintf ("linux", "setting lh->type_of_loader\n"); ++ lh->type_of_loader = 0x6; + +- params->type_of_loader = 0x21; ++ grub_dprintf ("linux", "setting lh->ext_loader_{type,ver}\n"); ++ params->ext_loader_type = 0; ++ params->ext_loader_ver = 2; ++ grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n", ++ kernel_mem, handover_offset); + + fail: + +@@ -291,8 +328,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + loaded = 0; + } + +- if (linux_cmdline && !loaded) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)linux_cmdline, BYTES_TO_PAGES(lh.cmdline_size + 1)); ++ if (linux_cmdline && lh && !loaded) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) ++ linux_cmdline, ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); + + if (kernel_mem && !loaded) + grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); +diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h +index eddf9251d..25ef52c04 100644 +--- a/include/grub/i386/linux.h ++++ b/include/grub/i386/linux.h +@@ -138,7 +138,12 @@ struct linux_i386_kernel_header + grub_uint32_t kernel_alignment; + grub_uint8_t relocatable; + grub_uint8_t min_alignment; +- grub_uint8_t pad[2]; ++#define LINUX_XLF_KERNEL_64 (1<<0) ++#define LINUX_XLF_CAN_BE_LOADED_ABOVE_4G (1<<1) ++#define LINUX_XLF_EFI_HANDOVER_32 (1<<2) ++#define LINUX_XLF_EFI_HANDOVER_64 (1<<3) ++#define LINUX_XLF_EFI_KEXEC (1<<4) ++ grub_uint16_t xloadflags; + grub_uint32_t cmdline_size; + grub_uint32_t hardware_subarch; + grub_uint64_t hardware_subarch_data; +-- +2.31.1 + diff --git a/0004-Try-to-pick-better-locations-for-kernel-and-initrd.patch b/0004-Try-to-pick-better-locations-for-kernel-and-initrd.patch new file mode 100644 index 0000000..9af8154 --- /dev/null +++ b/0004-Try-to-pick-better-locations-for-kernel-and-initrd.patch @@ -0,0 +1,200 @@ +From 384763d7990f769839ca74d6756fbd85580873d4 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 17:17:02 +0200 +Subject: [PATCH 04/11] Try to pick better locations for kernel and initrd + +- Don't limit allocations on 64-bit platforms to < 0x[37f]fffffff if + we're using the "large" code model ; use __UINTPTR_MAX__. +- Get the comparison right to check the address we've allocated. +- Fix the allocation for the command line as well. + +*But*, when we did this some systems started failing badly; coudln't +parse partition tables, etc. What's going on here is the disk controller +is silently failing DMAs to addresses above 4GB, so we're trying to parse +uninitialized (or HW zeroed) ram when looking for the partition table, +etc. + +So to limit this, we make grub_malloc() pick addresses below 4GB on +x86_64, but the direct EFI page allocation functions can get addresses +above that. + +Additionally, we now try to locate kernel+initrd+cmdline+etc below +0x7fffffff, and if they're too big to fit any memory window there, then +we try a higher address. + +Signed-off-by: Peter Jones +--- + grub-core/kern/efi/mm.c | 8 ++++---- + grub-core/loader/i386/efi/linux.c | 25 +++++++++++++++++-------- + include/grub/arm/efi/memory.h | 1 + + include/grub/arm64/efi/memory.h | 1 + + include/grub/i386/efi/memory.h | 1 + + include/grub/ia64/efi/memory.h | 1 + + include/grub/x86_64/efi/memory.h | 4 +++- + 7 files changed, 28 insertions(+), 13 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 4ff75a8ce..67a691d89 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -122,7 +122,7 @@ grub_efi_allocate_pages_max (grub_efi_physical_address_t max, + grub_efi_boot_services_t *b; + grub_efi_physical_address_t address = max; + +- if (max > 0xffffffff) ++ if (max > GRUB_EFI_MAX_USABLE_ADDRESS) + return 0; + + b = grub_efi_system_table->boot_services; +@@ -480,7 +480,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + { + if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY + #if 1 +- && desc->physical_start <= GRUB_EFI_MAX_USABLE_ADDRESS ++ && desc->physical_start <= GRUB_EFI_MAX_ALLOCATION_ADDRESS + #endif + && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000 + && desc->num_pages != 0) +@@ -498,9 +498,9 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + #if 1 + if (BYTES_TO_PAGES (filtered_desc->physical_start) + + filtered_desc->num_pages +- > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS)) ++ > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS)) + filtered_desc->num_pages +- = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS) ++ = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS) + - BYTES_TO_PAGES (filtered_desc->physical_start)); + #endif + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 0b3d20875..f3abbd025 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -102,8 +103,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + size += ALIGN_UP (grub_file_size (files[i]), 4); + } + +- initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size)); +- ++ initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size)); ++ if (!initrd_mem) ++ initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size)); + if (!initrd_mem) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); +@@ -187,8 +189,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- params = grub_efi_allocate_pages_max (0x3fffffff, ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, + BYTES_TO_PAGES(sizeof(*params))); ++ if (!params) ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, ++ BYTES_TO_PAGES(sizeof(*params))); + if (! params) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); +@@ -258,8 +263,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + #endif + + grub_dprintf ("linux", "setting up cmdline\n"); +- linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ if (!linux_cmdline) ++ linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); + if (!linux_cmdline) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); +@@ -285,11 +293,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, + BYTES_TO_PAGES(lh->init_size)); +- + if (!kernel_mem) +- kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, ++ kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, ++ BYTES_TO_PAGES(lh->init_size)); ++ if (!kernel_mem) ++ kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, + BYTES_TO_PAGES(lh->init_size)); +- + if (!kernel_mem) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); +diff --git a/include/grub/arm/efi/memory.h b/include/grub/arm/efi/memory.h +index 2c64918e3..a4c2ec835 100644 +--- a/include/grub/arm/efi/memory.h ++++ b/include/grub/arm/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/arm64/efi/memory.h b/include/grub/arm64/efi/memory.h +index c6cb32417..acb61dca4 100644 +--- a/include/grub/arm64/efi/memory.h ++++ b/include/grub/arm64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/i386/efi/memory.h b/include/grub/i386/efi/memory.h +index 2c64918e3..a4c2ec835 100644 +--- a/include/grub/i386/efi/memory.h ++++ b/include/grub/i386/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/ia64/efi/memory.h b/include/grub/ia64/efi/memory.h +index 2c64918e3..a4c2ec835 100644 +--- a/include/grub/ia64/efi/memory.h ++++ b/include/grub/ia64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/x86_64/efi/memory.h b/include/grub/x86_64/efi/memory.h +index 46e9145a3..e81cfb322 100644 +--- a/include/grub/x86_64/efi/memory.h ++++ b/include/grub/x86_64/efi/memory.h +@@ -2,9 +2,11 @@ + #include + + #if defined (__code_model_large__) +-#define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_USABLE_ADDRESS __UINTPTR_MAX__ ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS 0x7fffffff + #else + #define GRUB_EFI_MAX_USABLE_ADDRESS 0x7fffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + #endif + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +-- +2.31.1 + diff --git a/0005-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch b/0005-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch new file mode 100644 index 0000000..217d605 --- /dev/null +++ b/0005-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch @@ -0,0 +1,105 @@ +From a33acb675fe0d0464637175e4f06176e4c329025 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 12 Jul 2019 09:53:32 +0200 +Subject: [PATCH 05/11] x86-efi: Use bounce buffers for reading to addresses > + 4GB + +Lots of machines apparently can't DMA correctly above 4GB during UEFI, +so use bounce buffers for the initramfs read. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 52 ++++++++++++++++++++++++++----- + 1 file changed, 45 insertions(+), 7 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index f3abbd025..d6bed4fb4 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -35,11 +35,16 @@ static grub_dl_t my_mod; + static int loaded; + static void *kernel_mem; + static grub_uint64_t kernel_size; +-static grub_uint8_t *initrd_mem; ++static void *initrd_mem; + static grub_uint32_t handover_offset; + struct linux_kernel_params *params; + static char *linux_cmdline; + ++#define MIN(a, b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++ + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) + + static grub_err_t +@@ -68,6 +73,44 @@ grub_linuxefi_unload (void) + return GRUB_ERR_NONE; + } + ++#define BOUNCE_BUFFER_MAX 0x10000000ull ++ ++static grub_ssize_t ++read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) ++{ ++ grub_ssize_t bufpos = 0; ++ static grub_size_t bbufsz = 0; ++ static char *bbuf = NULL; ++ ++ if (bbufsz == 0) ++ bbufsz = MIN(BOUNCE_BUFFER_MAX, len); ++ ++ while (!bbuf && bbufsz) ++ { ++ bbuf = grub_malloc(bbufsz); ++ if (!bbuf) ++ bbufsz >>= 1; ++ } ++ if (!bbuf) ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate bounce buffer")); ++ ++ while (bufpos < (long long)len) ++ { ++ grub_ssize_t sz; ++ ++ sz = grub_file_read (file, bbuf, MIN(bbufsz, len - bufpos)); ++ if (sz < 0) ++ return sz; ++ if (sz == 0) ++ break; ++ ++ grub_memcpy(bufp + bufpos, bbuf, sz); ++ bufpos += sz; ++ } ++ ++ return bufpos; ++} ++ + static grub_err_t + grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +@@ -120,7 +163,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + for (i = 0; i < nfiles; i++) + { + grub_ssize_t cursize = grub_file_size (files[i]); +- if (grub_file_read (files[i], ptr, cursize) != cursize) ++ if (read (files[i], ptr, cursize) != cursize) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), +@@ -145,11 +188,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + +-#define MIN(a, b) \ +- ({ typeof (a) _a = (a); \ +- typeof (b) _b = (b); \ +- _a < _b ? _a : _b; }) +- + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +-- +2.31.1 + diff --git a/0006-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch b/0006-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch new file mode 100644 index 0000000..fa72fe0 --- /dev/null +++ b/0006-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch @@ -0,0 +1,133 @@ +From 24b5c0a3788c5c02b72ea61312f5cf8c39429db1 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 13 Sep 2018 14:42:34 -0400 +Subject: [PATCH 06/11] x86-efi: Re-arrange grub_cmd_linux() a little bit. + +This just helps the next patch be easier to read. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 73 +++++++++++++++++-------------- + 1 file changed, 40 insertions(+), 33 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index d6bed4fb4..096a52eb5 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -227,32 +227,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); +- if (!params) +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); +- if (! params) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); +- goto fail; +- } +- +- grub_dprintf ("linux", "params = %p\n", params); +- +- grub_memset (params, 0, sizeof(*params)); ++ lh = (struct linux_i386_kernel_header *)kernel; ++ grub_dprintf ("linux", "original lh is at %p\n", kernel); + +- setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); +- grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", +- MIN((grub_size_t)0x202+setup_header_end_offset, +- sizeof (*params)) - 0x1f1, +- (grub_uint8_t *)kernel + 0x1f1, +- (grub_uint8_t *)params + 0x1f1); +- grub_memcpy ((grub_uint8_t *)params + 0x1f1, +- (grub_uint8_t *)kernel + 0x1f1, +- MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); +- lh = (struct linux_i386_kernel_header *)params; +- grub_dprintf ("linux", "lh is at %p\n", lh); + grub_dprintf ("linux", "checking lh->boot_flag\n"); + if (lh->boot_flag != grub_cpu_to_le16 (0xaa55)) + { +@@ -300,6 +277,34 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, ++ BYTES_TO_PAGES(sizeof(*params))); ++ if (!params) ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, ++ BYTES_TO_PAGES(sizeof(*params))); ++ if (! params) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); ++ goto fail; ++ } ++ ++ grub_dprintf ("linux", "params = %p\n", params); ++ ++ grub_memset (params, 0, sizeof(*params)); ++ ++ setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); ++ grub_dprintf ("linux", "copying %" PRIuGRUB_SIZE " bytes from %p to %p\n", ++ MIN((grub_size_t)0x202+setup_header_end_offset, ++ sizeof (*params)) - 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ (grub_uint8_t *)params + 0x1f1); ++ grub_memcpy ((grub_uint8_t *)params + 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); ++ ++ lh = (struct linux_i386_kernel_header *)params; ++ grub_dprintf ("linux", "new lh is at %p\n", lh); ++ + grub_dprintf ("linux", "setting up cmdline\n"); + linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, + BYTES_TO_PAGES(lh->cmdline_size + 1)); +@@ -324,8 +329,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); + lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; + +- grub_dprintf ("linux", "computing handover offset\n"); + handover_offset = lh->handover_offset; ++ grub_dprintf("linux", "handover_offset: %08x\n", handover_offset); + + start = (lh->setup_sects + 1) * 512; + +@@ -342,24 +347,26 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); + goto fail; + } +- +- grub_dprintf ("linux", "kernel_mem = %lx\n", (unsigned long) kernel_mem); ++ grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); + + grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +- loaded=1; ++ ++ loaded = 1; ++ + grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); + lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; + + grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); + +- grub_dprintf ("linux", "setting lh->type_of_loader\n"); + lh->type_of_loader = 0x6; ++ grub_dprintf ("linux", "setting lh->type_of_loader = 0x%02x\n", ++ lh->type_of_loader); + +- grub_dprintf ("linux", "setting lh->ext_loader_{type,ver}\n"); + params->ext_loader_type = 0; + params->ext_loader_ver = 2; +- grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n", +- kernel_mem, handover_offset); ++ grub_dprintf ("linux", ++ "setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n", ++ params->ext_loader_type, params->ext_loader_ver); + + fail: + +-- +2.31.1 + diff --git a/0007-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch b/0007-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch new file mode 100644 index 0000000..63b7369 --- /dev/null +++ b/0007-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch @@ -0,0 +1,249 @@ +From 2a84f1a50c6f8770808fd4ec590eb8cff4228aed Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 12 Sep 2018 16:03:55 -0400 +Subject: [PATCH 07/11] x86-efi: Make our own allocator for kernel stuff + +This helps enable allocations above 4GB. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 155 ++++++++++++++++++------------ + 1 file changed, 94 insertions(+), 61 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 096a52eb5..d284db5d1 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -47,6 +47,65 @@ static char *linux_cmdline; + + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) + ++struct allocation_choice { ++ grub_efi_physical_address_t addr; ++ grub_efi_allocate_type_t alloc_type; ++}; ++ ++static struct allocation_choice max_addresses[] = ++ { ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { 0, 0 } ++ }; ++ ++static inline void ++kernel_free(void *addr, grub_efi_uintn_t size) ++{ ++ if (addr && size) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)addr, ++ BYTES_TO_PAGES(size)); ++} ++ ++static void * ++kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) ++{ ++ void *addr = 0; ++ unsigned int i; ++ grub_efi_physical_address_t prev_max = 0; ++ ++ for (i = 0; max_addresses[i].addr != 0 && addr == 0; i++) ++ { ++ grub_uint64_t max = max_addresses[i].addr; ++ grub_efi_uintn_t pages; ++ ++ if (max == prev_max) ++ continue; ++ ++ pages = BYTES_TO_PAGES(size); ++ grub_dprintf ("linux", "Trying to allocate %" PRIuGRUB_SIZE" pages from %p\n", ++ pages, (void *)(grub_addr_t)max); ++ ++ prev_max = max; ++ addr = grub_efi_allocate_pages_real (max, pages, ++ max_addresses[i].alloc_type, ++ GRUB_EFI_LOADER_DATA); ++ if (addr) ++ grub_dprintf ("linux", "Allocated at %p\n", addr); ++ } ++ ++ while (grub_error_pop ()) ++ { ++ ; ++ } ++ ++ if (addr == NULL) ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "%s", errmsg); ++ ++ return addr; ++} ++ + static grub_err_t + grub_linuxefi_boot (void) + { +@@ -62,14 +121,12 @@ grub_linuxefi_unload (void) + { + grub_dl_unref (my_mod); + loaded = 0; +- if (initrd_mem) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, BYTES_TO_PAGES(params->ramdisk_size)); +- if (linux_cmdline) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)linux_cmdline, BYTES_TO_PAGES(params->cmdline_size + 1)); +- if (kernel_mem) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); +- if (params) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)params, BYTES_TO_PAGES(16384)); ++ ++ kernel_free(initrd_mem, params->ramdisk_size); ++ kernel_free(linux_cmdline, params->cmdline_size + 1); ++ kernel_free(kernel_mem, kernel_size); ++ kernel_free(params, sizeof(*params)); ++ + return GRUB_ERR_NONE; + } + +@@ -146,17 +203,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + size += ALIGN_UP (grub_file_size (files[i]), 4); + } + +- initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size)); +- if (!initrd_mem) +- initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size)); +- if (!initrd_mem) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); +- goto fail; +- } ++ initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ if (initrd_mem == NULL) ++ goto fail; ++ grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); + + params->ramdisk_size = size; +- params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem; ++ params->ramdisk_image = initrd_mem; + + ptr = initrd_mem; + +@@ -214,7 +267,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + filelen = grub_file_size (file); + + kernel = grub_malloc(filelen); +- + if (!kernel) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); +@@ -258,7 +310,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +-#if defined(__x86_64__) || defined(__aarch64__) ++#if defined(__x86_64__) + grub_dprintf ("linux", "checking lh->xloadflags\n"); + if (!(lh->xloadflags & LINUX_XLF_KERNEL_64)) + { +@@ -277,17 +329,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); ++ params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); + if (!params) +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); +- if (! params) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); +- goto fail; +- } +- ++ goto fail; + grub_dprintf ("linux", "params = %p\n", params); + + grub_memset (params, 0, sizeof(*params)); +@@ -306,16 +350,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); + if (!linux_cmdline) +- linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); +- if (!linux_cmdline) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); +- goto fail; +- } ++ goto fail; ++ grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline); + + grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + err = grub_create_loader_cmdline (argc, argv, +@@ -326,27 +364,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + + grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); +- grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); +- lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; ++ grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", ++ linux_cmdline); ++ lh->cmd_line_ptr = linux_cmdline; + + handover_offset = lh->handover_offset; +- grub_dprintf("linux", "handover_offset: %08x\n", handover_offset); ++ grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset); + + start = (lh->setup_sects + 1) * 512; + +- kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, +- BYTES_TO_PAGES(lh->init_size)); +- if (!kernel_mem) +- kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(lh->init_size)); +- if (!kernel_mem) +- kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(lh->init_size)); +- if (!kernel_mem) ++ grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); ++ if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) + { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); +- goto fail; ++ max_addresses[0].addr = lh->pref_address; ++ max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; + } ++ kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); ++ if (!kernel_mem) ++ goto fail; + grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); + + grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +@@ -382,16 +417,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + loaded = 0; + } + +- if (linux_cmdline && lh && !loaded) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) +- linux_cmdline, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); +- +- if (kernel_mem && !loaded) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); ++ if (!loaded) ++ { ++ if (lh) ++ kernel_free (linux_cmdline, lh->cmdline_size + 1); + +- if (params && !loaded) +- grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)params, BYTES_TO_PAGES(16384)); ++ kernel_free (kernel_mem, kernel_size); ++ kernel_free (params, sizeof(*params)); ++ } + + return grub_errno; + } +-- +2.31.1 + diff --git a/0008-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch b/0008-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch new file mode 100644 index 0000000..6c8c61e --- /dev/null +++ b/0008-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch @@ -0,0 +1,175 @@ +From 8fbcf9f2e97c98bdb63ae7d544aa9bb273022403 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 12 Sep 2018 16:12:27 -0400 +Subject: [PATCH 08/11] x86-efi: Allow initrd+params+cmdline allocations above + 4GB. + +This enables everything except the kernel itself to be above 4GB. +Putting the kernel up there still doesn't work, because of the way +params->code32_start is used. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 67 +++++++++++++++++++++++++++---- + include/grub/i386/linux.h | 6 ++- + 2 files changed, 65 insertions(+), 8 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index d284db5d1..d49749269 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -52,13 +52,22 @@ struct allocation_choice { + grub_efi_allocate_type_t alloc_type; + }; + +-static struct allocation_choice max_addresses[] = ++static struct allocation_choice max_addresses[4] = + { ++ /* the kernel overrides this one with pref_address and ++ * GRUB_EFI_ALLOCATE_ADDRESS */ + { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* this one is always below 4GB, which we still *prefer* even if the flag ++ * is set. */ + { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* If the flag in params is set, this one gets changed to be above 4GB. */ + { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + { 0, 0 } + }; ++static struct allocation_choice saved_addresses[4]; ++ ++#define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses)) ++#define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses)) + + static inline void + kernel_free(void *addr, grub_efi_uintn_t size) +@@ -80,6 +89,11 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + grub_uint64_t max = max_addresses[i].addr; + grub_efi_uintn_t pages; + ++ /* ++ * When we're *not* loading the kernel, or >4GB allocations aren't ++ * supported, these entries are basically all the same, so don't re-try ++ * the same parameters. ++ */ + if (max == prev_max) + continue; + +@@ -168,6 +182,9 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) + return bufpos; + } + ++#define LOW_U32(val) ((grub_uint32_t)(((grub_addr_t)(val)) & 0xffffffffull)) ++#define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull)) ++ + static grub_err_t + grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +@@ -208,8 +225,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); + +- params->ramdisk_size = size; +- params->ramdisk_image = initrd_mem; ++ params->ramdisk_size = LOW_U32(size); ++ params->ramdisk_image = LOW_U32(initrd_mem); ++#if defined(__x86_64__) ++ params->ext_ramdisk_size = HIGH_U32(size); ++ params->ext_ramdisk_image = HIGH_U32(initrd_mem); ++#endif + + ptr = initrd_mem; + +@@ -329,6 +350,18 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + ++#if defined(__x86_64__) ++ if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G) ++ { ++ grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n"); ++ max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS; ++ } ++ else ++ { ++ grub_dprintf ("linux", "Loading kernel above 4GB is not supported\n"); ++ } ++#endif ++ + params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); + if (!params) + goto fail; +@@ -365,21 +398,40 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); + grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", +- linux_cmdline); +- lh->cmd_line_ptr = linux_cmdline; ++ LOW_U32(linux_cmdline)); ++ lh->cmd_line_ptr = LOW_U32(linux_cmdline); ++#if defined(__x86_64__) ++ if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull) ++ { ++ grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n", ++ HIGH_U32(linux_cmdline)); ++ params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline); ++ } ++#endif + + handover_offset = lh->handover_offset; + grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset); + + start = (lh->setup_sects + 1) * 512; + ++ /* ++ * AFAICS >4GB for kernel *cannot* work because of params->code32_start being ++ * 32-bit and getting called unconditionally in head_64.S from either entry ++ * point. ++ * ++ * so nerf that out here... ++ */ ++ save_addresses(); + grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); + if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) + { + max_addresses[0].addr = lh->pref_address; + max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; + } ++ max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); ++ restore_addresses(); + if (!kernel_mem) + goto fail; + grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); +@@ -388,8 +440,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + loaded = 1; + +- grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); +- lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; ++ grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n", ++ LOW_U32(kernel_mem)); ++ lh->code32_start = LOW_U32(kernel_mem); + + grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); + +diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h +index 25ef52c04..fac22476c 100644 +--- a/include/grub/i386/linux.h ++++ b/include/grub/i386/linux.h +@@ -236,7 +236,11 @@ struct linux_kernel_params + grub_uint32_t ofw_cif_handler; /* b8 */ + grub_uint32_t ofw_idt; /* bc */ + +- grub_uint8_t padding7[0x1b8 - 0xc0]; ++ grub_uint32_t ext_ramdisk_image; /* 0xc0 */ ++ grub_uint32_t ext_ramdisk_size; /* 0xc4 */ ++ grub_uint32_t ext_cmd_line_ptr; /* 0xc8 */ ++ ++ grub_uint8_t padding7[0x1b8 - 0xcc]; + + union + { +-- +2.31.1 + diff --git a/0009-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch b/0009-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch new file mode 100644 index 0000000..2c1f1ce --- /dev/null +++ b/0009-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch @@ -0,0 +1,43 @@ +From a89b55330ff0930c998cf64ab534cd8ff7e3a74c Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 26 May 2020 16:59:28 +0200 +Subject: [PATCH 09/11] x86-efi: Reduce maximum bounce buffer size to 16 MiB + +The EFI linux loader allocates a bounce buffer to copy the initrd since in +some machines doing DMA on addresses above 4GB is not possible during EFI. + +But the verifiers framework also allocates a buffer to copy the initrd in +its grub_file_open() handler. It does this since the data to verify has to +be passed as a single chunk to modules that use the verifiers framework. + +If the initrd image size is big there may not be enough memory in the heap +to allocate two buffers of that size. This causes an allocation failure in +the verifiers framework and leads to the initrd not being read. + +To prevent these allocation failures, let's reduce the maximum size of the +bounce buffer used in the EFI loader. Since the data read can be copied to +the actual initrd address in multilple chunks. + +Resolves: rhbz#1838633 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/loader/i386/efi/linux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index d49749269..652212227 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -144,7 +144,7 @@ grub_linuxefi_unload (void) + return GRUB_ERR_NONE; + } + +-#define BOUNCE_BUFFER_MAX 0x10000000ull ++#define BOUNCE_BUFFER_MAX 0x1000000ull + + static grub_ssize_t + read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) +-- +2.31.1 + diff --git a/0010-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch b/0010-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch new file mode 100644 index 0000000..d859ee5 --- /dev/null +++ b/0010-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch @@ -0,0 +1,52 @@ +From 1fc593b372bfe9bba82f4c59236d5a0cffebd8e2 Mon Sep 17 00:00:00 2001 +From: Colin Watson +Date: Fri, 24 Jul 2020 17:18:09 +0100 +Subject: [PATCH 10/11] efilinux: Fix integer overflows in grub_cmd_initrd + +These could be triggered by an extremely large number of arguments to +the initrd command on 32-bit architectures, or a crafted filesystem with +very large files on any architecture. + +Signed-off-by: Colin Watson +--- + grub-core/loader/i386/efi/linux.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 652212227..6b06a8f2f 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -28,6 +28,8 @@ + #include + #include + #include ++#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -206,7 +208,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- files = grub_zalloc (argc * sizeof (files[0])); ++ files = grub_calloc (argc, sizeof (files[0])); + if (!files) + goto fail; + +@@ -217,7 +219,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + if (! files[i]) + goto fail; + nfiles++; +- size += ALIGN_UP (grub_file_size (files[i]), 4); ++ if (grub_add (size, ALIGN_UP (grub_file_size (files[i]), 4), &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ goto fail; ++ } + } + + initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); +-- +2.31.1 + diff --git a/0011-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch b/0011-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch new file mode 100644 index 0000000..b49816d --- /dev/null +++ b/0011-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch @@ -0,0 +1,27 @@ +From 76caed15754338f7261b2a95a3c7cc15a25f6a01 Mon Sep 17 00:00:00 2001 +From: David Abdurachmanov +Date: Thu, 16 Jan 2020 13:10:10 +0100 +Subject: [PATCH 11/11] Also define GRUB_EFI_MAX_ALLOCATION_ADDRESS for RISC-V + +The commit "Try to pick better locations for kernel and initrd" missed to +define this macro for the RISC-V (riscv64) architecture, so add it there. + +Signed-off-by: David Abdurachmanov +--- + include/grub/riscv64/efi/memory.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/grub/riscv64/efi/memory.h b/include/grub/riscv64/efi/memory.h +index c6cb32417..acb61dca4 100644 +--- a/include/grub/riscv64/efi/memory.h ++++ b/include/grub/riscv64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +-- +2.31.1 + diff --git a/grub2.changes b/grub2.changes index ba452f4..5b5acb0 100644 --- a/grub2.changes +++ b/grub2.changes @@ -1,3 +1,25 @@ +------------------------------------------------------------------- +Tue Dec 21 03:03:47 UTC 2021 - Michael Chang + +- Fix CVE-2021-3981 (bsc#1189644) + * 0001-grub-mkconfig-restore-umask-for-grub.cfg.patch + +------------------------------------------------------------------- +Fri Dec 17 10:42:33 UTC 2021 - Michael Chang + +- Fix can't allocate initrd error (bsc#1191378) + * 0001-Factor-out-grub_efi_linux_boot.patch + * 0002-Fix-race-in-EFI-validation.patch + * 0003-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch + * 0004-Try-to-pick-better-locations-for-kernel-and-initrd.patch + * 0005-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch + * 0006-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch + * 0007-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch + * 0008-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch + * 0009-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch + * 0010-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch + * 0011-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch + ------------------------------------------------------------------- Wed Dec 8 14:16:58 UTC 2021 - Michal Suchanek diff --git a/grub2.spec b/grub2.spec index e5b1b29..1403f65 100644 --- a/grub2.spec +++ b/grub2.spec @@ -316,6 +316,18 @@ Patch797: 0001-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch Patch798: 0001-arm64-Fix-EFI-loader-kernel-image-allocation.patch Patch799: 0002-Arm-check-for-the-PE-magic-for-the-compiled-arch.patch Patch800: 0001-fs-btrfs-Make-extent-item-iteration-to-handle-gaps.patch +Patch801: 0001-Factor-out-grub_efi_linux_boot.patch +Patch802: 0002-Fix-race-in-EFI-validation.patch +Patch803: 0003-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch +Patch804: 0004-Try-to-pick-better-locations-for-kernel-and-initrd.patch +Patch805: 0005-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch +Patch806: 0006-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch +Patch807: 0007-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch +Patch808: 0008-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch +Patch809: 0009-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch +Patch810: 0010-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch +Patch811: 0011-Also-define-GRUB_EFI_MAX_ALLOCATION_ADDRESS-for-RISC.patch +Patch812: 0001-grub-mkconfig-restore-umask-for-grub.cfg.patch Requires: gettext-runtime %if 0%{?suse_version} >= 1140 @@ -1006,7 +1018,7 @@ fi %doc README.ibm3215 %endif %dir /boot/%{name} -%ghost /boot/%{name}/grub.cfg +%ghost %attr(600, root, root) /boot/%{name}/grub.cfg %{_sysconfdir}/bash_completion.d/grub %config(noreplace) %{_sysconfdir}/default/grub %dir %{_sysconfdir}/grub.d