diff --git a/SOURCES/0576-efi-http-change-uint32_t-to-uintn_t-for-grub_efi_htt.patch b/SOURCES/0576-efi-http-change-uint32_t-to-uintn_t-for-grub_efi_htt.patch new file mode 100644 index 0000000..65ac476 --- /dev/null +++ b/SOURCES/0576-efi-http-change-uint32_t-to-uintn_t-for-grub_efi_htt.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matt Hsiao +Date: Mon, 24 Apr 2023 13:39:05 +0800 +Subject: [PATCH] efi/http: change uint32_t to uintn_t for + grub_efi_http_message_t + +Modify UINT32 to UINTN in EFI_HTTP_MESSAGE to be UEFI 2.9 compliant. + +Signed-off-by: Matt Hsiao +Signed-off-by: Nicolas Frayer +--- + include/grub/efi/http.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/grub/efi/http.h b/include/grub/efi/http.h +index c5e9a89f5050..ad164ba1913d 100644 +--- a/include/grub/efi/http.h ++++ b/include/grub/efi/http.h +@@ -171,9 +171,9 @@ typedef struct { + grub_efi_http_request_data_t *request; + grub_efi_http_response_data_t *response; + } data; +- grub_efi_uint32_t header_count; ++ grub_efi_uintn_t header_count; + grub_efi_http_header_t *headers; +- grub_efi_uint32_t body_length; ++ grub_efi_uintn_t body_length; + void *body; + } grub_efi_http_message_t; + diff --git a/SOURCES/0577-ieee1275-Converting-plain-numbers-to-constants-in-Ve.patch b/SOURCES/0577-ieee1275-Converting-plain-numbers-to-constants-in-Ve.patch new file mode 100644 index 0000000..ce3e113 --- /dev/null +++ b/SOURCES/0577-ieee1275-Converting-plain-numbers-to-constants-in-Ve.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Avnish Chouhan +Date: Thu, 23 Mar 2023 08:16:25 -0400 +Subject: [PATCH] ieee1275 : Converting plain numbers to constants in Vec5 + +This patch converts the plain numbers used in Vec5 properties to +constants. + +1. LPAR : Client program supports logical partitioning and + associated hcall()s. +2. SPLPAR : Client program supports the Shared + Processor LPAR Option. +3. CMO : Enables the Cooperative Memory Over-commitment Option. +4. MAX_CPU : Defines maximum number of CPUs supported. + +Signed-off-by: Avnish Chouhan +--- + grub-core/kern/ieee1275/init.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 3ea9b73b2a59..2516e02091cb 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -56,6 +56,12 @@ extern char _end[]; + grub_addr_t grub_ieee1275_original_stack; + #endif + ++#define LPAR 0x80 ++#define SPLPAR 0x40 ++#define BYTE2 (LPAR | SPLPAR) ++#define CMO 0x80 ++#define MAX_CPU 256 ++ + void + grub_exit (int rc __attribute__((unused))) + { +@@ -372,7 +378,7 @@ grub_ieee1275_ibm_cas (void) + .vec4 = 0x0001, // set required minimum capacity % to the lowest value + .vec5_size = 1 + sizeof(struct option_vector5) - 2, + .vec5 = { +- 0, 192, 0, 128, 0, 0, 0, 0, 256 ++ 0, BYTE2, 0, CMO, 0, 0, 0, 0, MAX_CPU + } + }; + diff --git a/SOURCES/0578-ieee1275-extended-support-in-options-vector5.patch b/SOURCES/0578-ieee1275-extended-support-in-options-vector5.patch new file mode 100644 index 0000000..48b224c --- /dev/null +++ b/SOURCES/0578-ieee1275-extended-support-in-options-vector5.patch @@ -0,0 +1,125 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Avnish Chouhan +Date: Thu, 23 Mar 2023 08:33:12 -0400 +Subject: [PATCH] ieee1275 : extended support in options vector5 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch enables the multiple options in Options Vector5 which are +required and solves the boot issue seen on some machines which are looking for these specific options. + +1. LPAR : Client program supports logical partitioning and + associated hcall()s. +2. SPLPAR : Client program supports the Shared + Processor LPAR Option. +3. DYN_RCON_MEM : Client program supports the + “ibm,dynamic-reconfiguration-memory” property and it may be + presented in the device tree. +4. LARGE_PAGES : Client supports pages larger than 4 KB. +5. DONATE_DCPU_CLS : Client supports donating dedicated processor cycles. +6. PCI_EXP : Client supports PCI Express implementations + utilizing Message Signaled Interrupts (MSIs). + +7. CMOC : Enables the Cooperative Memory Over-commitment Option. +8. EXT_CMO : Enables the Extended Cooperative Memory Over-commit + Option. + +9. ASSOC_REF : Enables “ibm,associativity” and + “ibm,associativity-reference-points” properties. +10. AFFINITY : Enables Platform Resource Reassignment Notification. +11. NUMA : Supports NUMA Distance Lookup Table Option. + +12. HOTPLUG_INTRPT : Supports Hotplug Interrupts. +13. HPT_RESIZE : Enable Hash Page Table Resize Option. + +14. MAX_CPU : Defines maximum number of CPUs supported. + +15. PFO_HWRNG : Supports Random Number Generator. +16. PFO_HW_COMP : Supports Compression Engine. +17. PFO_ENCRYPT : Supports Encryption Engine. + +18. SUB_PROCESSORS : Supports Sub-Processors. + +19. DY_MEM_V2 : Client program supports the “ibm,dynamic-memory-v2” property in the + “ibm,dynamic-reconfiguration-memory” node and it may be presented in the device tree. +20. DRC_INFO : Client program supports the “ibm,drc-info” property definition and it may be + presented in the device tree. + +Signed-off-by: Avnish Chouhan +--- + grub-core/kern/ieee1275/init.c | 47 ++++++++++++++++++++++++++++++++++++------ + 1 file changed, 41 insertions(+), 6 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 2516e02091cb..1fae84440403 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -56,11 +56,41 @@ extern char _end[]; + grub_addr_t grub_ieee1275_original_stack; + #endif + +-#define LPAR 0x80 +-#define SPLPAR 0x40 +-#define BYTE2 (LPAR | SPLPAR) +-#define CMO 0x80 +-#define MAX_CPU 256 ++/* Options vector5 properties */ ++ ++#define LPAR 0x80 ++#define SPLPAR 0x40 ++#define DYN_RCON_MEM 0x20 ++#define LARGE_PAGES 0x10 ++#define DONATE_DCPU_CLS 0x02 ++#define PCI_EXP 0x01 ++#define BYTE2 (LPAR | SPLPAR | DYN_RCON_MEM | LARGE_PAGES | DONATE_DCPU_CLS | PCI_EXP) ++ ++#define CMOC 0x80 ++#define EXT_CMO 0x40 ++#define CMO (CMOC | EXT_CMO) ++ ++#define ASSOC_REF 0x80 ++#define AFFINITY 0x40 ++#define NUMA 0x20 ++#define ASSOCIATIVITY (ASSOC_REF | AFFINITY | NUMA) ++ ++#define HOTPLUG_INTRPT 0x04 ++#define HPT_RESIZE 0x01 ++#define BIN_OPTS (HOTPLUG_INTRPT | HPT_RESIZE) ++ ++#define MAX_CPU 256 ++ ++#define PFO_HWRNG 0x80000000 ++#define PFO_HW_COMP 0x40000000 ++#define PFO_ENCRYPT 0x20000000 ++#define PLATFORM_FACILITIES (PFO_HWRNG | PFO_HW_COMP | PFO_ENCRYPT) ++ ++#define SUB_PROCESSORS 1 ++ ++#define DY_MEM_V2 0x80 ++#define DRC_INFO 0x40 ++#define BYTE22 (DY_MEM_V2 | DRC_INFO) + + void + grub_exit (int rc __attribute__((unused))) +@@ -323,6 +353,11 @@ struct option_vector5 { + grub_uint8_t micro_checkpoint; + grub_uint8_t reserved0; + grub_uint32_t max_cpus; ++ grub_uint16_t base_PAPR; ++ grub_uint16_t mem_reference; ++ grub_uint32_t platform_facilities; ++ grub_uint8_t sub_processors; ++ grub_uint8_t byte22; + } __attribute__((packed)); + + struct pvr_entry { +@@ -378,7 +413,7 @@ grub_ieee1275_ibm_cas (void) + .vec4 = 0x0001, // set required minimum capacity % to the lowest value + .vec5_size = 1 + sizeof(struct option_vector5) - 2, + .vec5 = { +- 0, BYTE2, 0, CMO, 0, 0, 0, 0, MAX_CPU ++ 0, BYTE2, 0, CMO, ASSOCIATIVITY, BIN_OPTS, 0, 0, MAX_CPU, 0, 0, PLATFORM_FACILITIES, SUB_PROCESSORS, BYTE22 + } + }; + diff --git a/SOURCES/0579-Regenerate-kernelopts-if-missing-on-ppc.patch b/SOURCES/0579-Regenerate-kernelopts-if-missing-on-ppc.patch new file mode 100644 index 0000000..4895dd1 --- /dev/null +++ b/SOURCES/0579-Regenerate-kernelopts-if-missing-on-ppc.patch @@ -0,0 +1,36 @@ +From 8c74431327e0c7d7fe47462b0e69fcbe3bbac56e Mon Sep 17 00:00:00 2001 +From: Marta Lewandowska +Date: Fri, 24 Mar 2023 09:14:29 -0400 +Subject: [PATCH] Regenerate kernelopts if missing on ppc + +Signed-off-by: Marta Lewandowska +--- + util/grub.d/10_linux_bls.in | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/util/grub.d/10_linux_bls.in b/util/grub.d/10_linux_bls.in +index 855dbdd..f2281bc 100644 +--- a/util/grub.d/10_linux_bls.in ++++ b/util/grub.d/10_linux_bls.in +@@ -117,6 +117,18 @@ cat < +Date: Tue, 8 Aug 2023 12:21:55 -0400 +Subject: [PATCH] kern/ieee1275/init: ppc64: Restrict high memory in presence + of fadump + +This is a backport of the patch with the same name to grub 2.02. + +When a kernel dump is present then restrict the high memory regions to +avoid allocating memory where the kernel dump resides. Use the +ibm,kernel-dump node under /rtas to determine whether a kernel dump exists +and up to which limit grub can use available memory. Set the +upper_mem_limit to the size of the kernel dump section of type +'REAL_MODE_REGION' and therefore only allow grub's memory usage for high +addresses from 768MB to 'upper_mem_limit'. This means that grub can +use high memory in the range of 768MB to upper_mem_limit and +the kernel-dump memory regions above 'upper_mem_limit' remain untouched. +This change has no effect on memory allocations below 640MB. + +Also, fall back to allocating below 640MB in case the chunk of +memory there would be larger than the chunk of memory above 768MB. +This can for example occur if a free memory area is found starting at 300MB +extending up to 1GB but a kernel dump is located at 768MB and therefore +does not allow the allocation of the high memory area but requiring to use +the chunk starting at 300MB to avoid an unnecessary out-of-memory +condition. + +Signed-off-by: Stefan Berger +Cc: Hari Bathini +Cc: Pavithra Prakash +Cc: Michael Ellerman +Cc: Carolyn Scherrer +Cc: Mahesh Salgaonkar +Cc: Sourabh Jain +--- + grub-core/kern/ieee1275/init.c | 139 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 139 insertions(+) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 1fae84440403..31843ab70a62 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -17,6 +17,8 @@ + * along with GRUB. If not, see . + */ + ++#include /* offsetof() */ ++ + #include + #include + #include +@@ -180,6 +182,97 @@ grub_claim_heap (void) + + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000); + } + #else ++ ++/* ibm,kernel-dump data structures */ ++struct kd_section ++{ ++ grub_uint32_t flags; ++ grub_uint16_t src_datatype; ++#define KD_SRC_DATATYPE_REAL_MODE_REGION 0x0011 ++ grub_uint16_t error_flags; ++ grub_uint64_t src_address; ++ grub_uint64_t num_bytes; ++ grub_uint64_t act_bytes; ++ grub_uint64_t dst_address; ++} GRUB_PACKED; ++ ++#define MAX_KD_SECTIONS 10 ++ ++struct kernel_dump ++{ ++ grub_uint32_t format; ++ grub_uint16_t num_sections; ++ grub_uint16_t status_flags; ++ grub_uint32_t offset_1st_section; ++ grub_uint32_t num_blocks; ++ grub_uint64_t start_block; ++ grub_uint64_t num_blocks_avail; ++ grub_uint32_t offet_path_string; ++ grub_uint32_t max_time_allowed; ++ struct kd_section kds[MAX_KD_SECTIONS]; /* offset_1st_section should point to kds[0] */ ++} GRUB_PACKED; ++ ++/* ++ * Determine if a kernel dump exists and if it does, then determine the highest ++ * address that grub can use for memory allocations. ++ * The caller must have initialized *highest to ~0. *highest will not ++ * be modified if no kernel dump is found. ++ */ ++static int ++check_kernel_dump (grub_uint64_t *highest) ++{ ++ struct kernel_dump kernel_dump; ++ grub_ssize_t kernel_dump_size; ++ grub_ieee1275_phandle_t rtas; ++ struct kd_section *kds; ++ grub_size_t i; ++ ++ /* If there's a kernel-dump it must have at least one section */ ++ if (grub_ieee1275_finddevice ("/rtas", &rtas) || ++ grub_ieee1275_get_property (rtas, "ibm,kernel-dump", &kernel_dump, ++ sizeof (kernel_dump), &kernel_dump_size) || ++ kernel_dump_size <= (grub_ssize_t) offsetof (struct kernel_dump, kds[1])) ++ return 0; ++ ++ kernel_dump_size = grub_min (kernel_dump_size, (grub_ssize_t) sizeof (kernel_dump)); ++ ++ if (grub_be_to_cpu32 (kernel_dump.format) != 1) ++ { ++ grub_printf (_("Error: ibm,kernel-dump has an unexpected format version '%u'\n"), ++ grub_be_to_cpu32 (kernel_dump.format)); ++ return 0; ++ } ++ ++ if (grub_be_to_cpu16 (kernel_dump.num_sections) > MAX_KD_SECTIONS) ++ { ++ grub_printf (_("Error: Too many kernel dump sections: %d\n"), ++ grub_be_to_cpu32 (kernel_dump.num_sections)); ++ return 0; ++ } ++ ++ for (i = 0; i < grub_be_to_cpu16 (kernel_dump.num_sections); i++) ++ { ++ kds = (struct kd_section *) ((grub_addr_t) &kernel_dump + ++ grub_be_to_cpu32 (kernel_dump.offset_1st_section) + ++ i * sizeof (struct kd_section)); ++ /* sanity check the address is within the 'kernel_dump' struct */ ++ if ((grub_addr_t) kds > (grub_addr_t) &kernel_dump + kernel_dump_size + sizeof (*kds)) ++ { ++ grub_printf (_("Error: 'kds' address beyond last available section\n")); ++ return 0; ++ } ++ ++ if ((grub_be_to_cpu16 (kds->src_datatype) == KD_SRC_DATATYPE_REAL_MODE_REGION) && ++ (grub_be_to_cpu64 (kds->src_address) == 0)) ++ { ++ *highest = grub_min (*highest, grub_be_to_cpu64 (kds->num_bytes)); ++ break; ++ } ++ } ++ ++ return 1; ++} ++ + /* Helper for grub_claim_heap on powerpc. */ + static int + heap_size (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, +@@ -207,7 +300,9 @@ static int + heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + void *data) + { ++ grub_uint64_t upper_mem_limit = ~0; + grub_uint32_t total = *(grub_uint32_t *)data; ++ int has_kernel_dump; + + if (type != GRUB_MEMORY_AVAILABLE) + return 0; +@@ -243,6 +338,50 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + len = 0; + } + ++ has_kernel_dump = check_kernel_dump (&upper_mem_limit); ++ if (has_kernel_dump) ++ { ++ grub_uint64_t lo_len = 0, hi_len = 0; ++ ++ if (addr > upper_mem_limit || upper_mem_limit == (grub_uint64_t)~0) ++ return 0; ++ ++ /* limit len to stay below upper_mem_limit */ ++ if (addr < upper_mem_limit && (addr + len) > upper_mem_limit) ++ { ++ len = grub_min (len, upper_mem_limit - addr); ++ } ++ ++ /* We can allocate below 640MB or above 768MB. ++ * Choose the bigger chunk below 640MB or above 768MB. ++ */ ++ if (addr < 0x28000000) ++ { ++ lo_len = grub_min (len, 0x28000000 - addr); ++ } ++ if (addr + len > 0x30000000) ++ { ++ if (addr < 0x30000000) ++ hi_len = len - (0x30000000 - addr); ++ else ++ hi_len = len; ++ } ++ ++ if (hi_len > lo_len) ++ { ++ len = hi_len; ++ if (addr < 0x30000000) ++ addr = 0x30000000; ++ } ++ else ++ { ++ len = lo_len; ++ } ++ ++ if (len == 0) ++ return 0; ++ } ++ + /* If this block contains 0x30000000 (768MB), do not claim below that. + Linux likes to claim memory at min(RMO top, 768MB) and works down + without reference to /memory/available. */ diff --git a/SOURCES/0581-util-Enable-default-kernel-for-updates.patch b/SOURCES/0581-util-Enable-default-kernel-for-updates.patch new file mode 100644 index 0000000..64c5def --- /dev/null +++ b/SOURCES/0581-util-Enable-default-kernel-for-updates.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nicolas Frayer +Date: Wed, 24 May 2023 11:22:47 +0200 +Subject: [PATCH] util: Enable default kernel for updates + +Several kernel variants can be installed on a system in parallel. +In order to allow the user to choose which kernel will be set to +default after an update, re-enable grub's usage of DEFAULTKERNEL as +set in /etc/sysconfig/kernel + +Signed-off-by: Nicolas Frayer +--- + util/grub-get-kernel-settings.in | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/util/grub-get-kernel-settings.in b/util/grub-get-kernel-settings.in +index 7e87dfccc0e4..f71bc64360b0 100644 +--- a/util/grub-get-kernel-settings.in ++++ b/util/grub-get-kernel-settings.in +@@ -68,6 +68,14 @@ if test -f /etc/sysconfig/kernel ; then + . /etc/sysconfig/kernel + fi + ++GRUB_DEFAULT_KERNEL_TYPE=${DEFAULTKERNEL/-core/} ++if [ "$GRUB_DEFAULT_KERNEL_TYPE" != "kernel" ]; then ++ echo GRUB_NON_STANDARD_KERNEL=true ++ echo export GRUB_NON_STANDARD_KERNEL ++ GRUB_DEFAULT_KERNEL_TYPE=${GRUB_DEFAULT_KERNEL_TYPE/kernel-/} ++fi ++echo GRUB_DEFAULT_KERNEL_TYPE=$GRUB_DEFAULT_KERNEL_TYPE ++echo export GRUB_DEFAULT_KERNEL_TYPE + if [ "$MAKEDEBUG" = "yes" ]; then + echo GRUB_LINUX_MAKE_DEBUG=true + echo export GRUB_LINUX_MAKE_DEBUG diff --git a/SOURCES/0582-grub-set-bootflag-Conservative-partial-fix-for-CVE-2.patch b/SOURCES/0582-grub-set-bootflag-Conservative-partial-fix-for-CVE-2.patch new file mode 100644 index 0000000..ca9d396 --- /dev/null +++ b/SOURCES/0582-grub-set-bootflag-Conservative-partial-fix-for-CVE-2.patch @@ -0,0 +1,150 @@ +From 9ca4c3fe1c7dbd62e8ad6a23cb1b1fda695fdb44 Mon Sep 17 00:00:00 2001 +From: Solar Designer +Date: Tue, 6 Feb 2024 21:39:41 +0100 +Subject: [PATCH 1/3] grub-set-bootflag: Conservative partial fix for + CVE-2024-1048 + +Following up on CVE-2019-14865 and taking a fresh look at +grub2-set-bootflag now (through my work at CIQ on Rocky Linux), I saw some +other ways in which users could still abuse this little program: + +1. After CVE-2019-14865 fix, grub2-set-bootflag no longer rewrites the +grubenv file in-place, but writes into a temporary file and renames it +over the original, checking for error returns from each call first. +This prevents the original file truncation vulnerability, but it can +leave the temporary file around if the program is killed before it can +rename or remove the file. There are still many ways to get the program +killed, such as through RLIMIT_FSIZE triggering SIGXFSZ (tested, +reliable) or by careful timing (tricky) of signals sent by process group +leader, pty, pre-scheduled timers, SIGXCPU (probably not an exhaustive +list). Invoking the program multiple times fills up /boot (or if /boot +is not separate, then it can fill up the root filesystem). Since the +files are tiny, the filesystem is likely to run out of free inodes +before it'd run out of blocks, but the effect is similar - can't create +new files after this point (but still can add data to existing files, +such as logs). + +2. After CVE-2019-14865 fix, grub2-set-bootflag naively tries to protect +itself from signals by becoming full root. (This does protect it from +signals sent by the user directly to the PID, but e.g. "kill -9 -1" by +the user still works.) A side effect of such "protection" is that it's +possible to invoke more concurrent instances of grub2-set-bootflag than +the user's RLIMIT_NPROC would normally permit (as specified e.g. in +/etc/security/limits.conf, or say in Apache httpd's RLimitNPROC if +grub2-set-bootflag would be abused by a website script), thereby +exhausting system resources (e.g., bypassing RAM usage limit if +RLIMIT_AS was also set). + +3. umask is inherited. Again, due to how the CVE-2019-14865 fix creates +a new file, and due to how mkstemp() works, this affects grubenv's new +file permissions. Luckily, mkstemp() forces them to be no more relaxed +than 0600, but the user ends up being able to set them e.g. to 0. +Luckily, at least in my testing GRUB still works fine even when the file +has such (lack of) permissions. + +This commit deals with the abuses above as follows: + +1. RLIMIT_FSIZE is pre-checked, so this specific way to get the process +killed should no longer work. However, this isn't a complete fix +because there are other ways to get the process killed after it has +created the temporary file. + +The commit also fixes bug 1975892 ("RFE: grub2-set-bootflag should not +write the grubenv when the flag being written is already set") and +similar for "menu_show_once", which further reduces the abuse potential. + +2. RLIMIT_NPROC bypass should be avoided by not becoming full root (aka +dropping the partial "kill protection"). + +3. A safe umask is set. + +This is a partial fix (temporary files can still accumulate, but this is +harder to trigger). + +While at it, this commit also fixes potential 1- or 2-byte over-read of +env[] if its content is malformed - this was not a security issue since the +grubenv file is trusted input, and the fix is just for robustness. + +Signed-off-by: Solar Designer +--- + util/grub-set-bootflag.c | 29 ++++++++++++++++------------- + 1 file changed, 16 insertions(+), 13 deletions(-) + +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +index a85f11fceacb..5b932f76b6f4 100644 +--- a/util/grub-set-bootflag.c ++++ b/util/grub-set-bootflag.c +@@ -32,6 +32,8 @@ + #include + #include + #include ++#include ++#include + + #define GRUBENV "/" GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME "/" GRUB_ENVBLK_DEFCFG + #define GRUBENV_SIZE 1024 +@@ -54,12 +56,17 @@ static void usage(void) + int main(int argc, char *argv[]) + { + /* NOTE buf must be at least the longest bootflag length + 4 bytes */ +- char env[GRUBENV_SIZE + 1], buf[64], *s; ++ char env[GRUBENV_SIZE + 1 + 2], buf[64], *s; + /* +1 for 0 termination, +6 for "XXXXXX" in tmp filename */ + char env_filename[PATH_MAX + 1], tmp_filename[PATH_MAX + 6 + 1]; + const char *bootflag; + int i, fd, len, ret; + FILE *f; ++ struct rlimit rlim; ++ ++ if (getrlimit(RLIMIT_FSIZE, &rlim) || rlim.rlim_cur < GRUBENV_SIZE || rlim.rlim_max < GRUBENV_SIZE) ++ return 1; ++ umask(077); + + if (argc != 2) + { +@@ -81,20 +88,11 @@ int main(int argc, char *argv[]) + len = strlen (bootflag); + + /* +- * Really become root. setuid avoids an user killing us, possibly leaking +- * the tmpfile. setgid avoids the new grubenv's gid being that of the user. ++ * setegid avoids the new grubenv's gid being that of the user. + */ +- ret = setuid(0); +- if (ret) +- { +- perror ("Error setuid(0) failed"); +- return 1; +- } +- +- ret = setgid(0); +- if (ret) ++ if (setegid(0)) + { +- perror ("Error setgid(0) failed"); ++ perror ("Error setegid(0) failed"); + return 1; + } + +@@ -123,6 +121,9 @@ int main(int argc, char *argv[]) + + /* 0 terminate env */ + env[GRUBENV_SIZE] = 0; ++ /* not a valid flag value */ ++ env[GRUBENV_SIZE + 1] = 0; ++ env[GRUBENV_SIZE + 2] = 0; + + if (strncmp (env, GRUB_ENVBLK_SIGNATURE, strlen (GRUB_ENVBLK_SIGNATURE))) + { +@@ -158,6 +159,8 @@ int main(int argc, char *argv[]) + + /* The grubenv is not 0 terminated, so memcpy the name + '=' , '1', '\n' */ + snprintf(buf, sizeof(buf), "%s=1\n", bootflag); ++ if (!memcmp(s, buf, len + 3)) ++ return 0; /* nothing to do */ + memcpy(s, buf, len + 3); + + +-- +2.43.0 + diff --git a/SOURCES/0583-grub-set-bootflag-More-complete-fix-for-CVE-2024-104.patch b/SOURCES/0583-grub-set-bootflag-More-complete-fix-for-CVE-2024-104.patch new file mode 100644 index 0000000..a7416c1 --- /dev/null +++ b/SOURCES/0583-grub-set-bootflag-More-complete-fix-for-CVE-2024-104.patch @@ -0,0 +1,187 @@ +From f4c7783c2b695794938748a6567e86456ed2314a Mon Sep 17 00:00:00 2001 +From: Solar Designer +Date: Tue, 6 Feb 2024 21:56:21 +0100 +Subject: [PATCH 2/3] grub-set-bootflag: More complete fix for CVE-2024-1048 + +Switch to per-user fixed temporary filenames along with a weird locking +mechanism, which is explained in source code comments. This is a more +complete fix than the previous commit (temporary files can't accumulate). +Unfortunately, it introduces new risks (by working on a temporary file +shared between the user's invocations), which are _hopefully_ avoided by +the patch's elaborate logic. I actually got it wrong at first, which +suggests that this logic is hard to reason about, and more errors or +omissions are possible. It also relies on the kernel's primitives' exact +semantics to a greater extent (nothing out of the ordinary, though). + +Remaining issues that I think cannot reasonably be fixed without a +redesign (e.g., having per-flag files with nothing else in them) and +without introducing new issues: + +A. A user can still revert a concurrent user's attempt of setting the +other flag - or of making other changes to grubenv by means other than +this program. + +B. One leftover temporary file per user is still possible. + +Signed-off-by: Solar Designer +--- + util/grub-set-bootflag.c | 87 ++++++++++++++++++++++++++++++++++------ + 1 file changed, 75 insertions(+), 12 deletions(-) + +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +index 5b932f76b6f4..698b55a1ab93 100644 +--- a/util/grub-set-bootflag.c ++++ b/util/grub-set-bootflag.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -57,15 +58,12 @@ int main(int argc, char *argv[]) + { + /* NOTE buf must be at least the longest bootflag length + 4 bytes */ + char env[GRUBENV_SIZE + 1 + 2], buf[64], *s; +- /* +1 for 0 termination, +6 for "XXXXXX" in tmp filename */ +- char env_filename[PATH_MAX + 1], tmp_filename[PATH_MAX + 6 + 1]; ++ /* +1 for 0 termination, +11 for ".%u" in tmp filename */ ++ char env_filename[PATH_MAX + 1], tmp_filename[PATH_MAX + 11 + 1]; + const char *bootflag; + int i, fd, len, ret; + FILE *f; +- struct rlimit rlim; + +- if (getrlimit(RLIMIT_FSIZE, &rlim) || rlim.rlim_cur < GRUBENV_SIZE || rlim.rlim_max < GRUBENV_SIZE) +- return 1; + umask(077); + + if (argc != 2) +@@ -92,7 +90,7 @@ int main(int argc, char *argv[]) + */ + if (setegid(0)) + { +- perror ("Error setegid(0) failed"); ++ perror ("setegid(0) failed"); + return 1; + } + +@@ -163,19 +161,82 @@ int main(int argc, char *argv[]) + return 0; /* nothing to do */ + memcpy(s, buf, len + 3); + ++ struct rlimit rlim; ++ if (getrlimit(RLIMIT_FSIZE, &rlim) || rlim.rlim_cur < GRUBENV_SIZE || rlim.rlim_max < GRUBENV_SIZE) ++ { ++ fprintf (stderr, "Resource limits undetermined or too low\n"); ++ return 1; ++ } ++ ++ /* ++ * Here we work under the premise that we shouldn't write into the target ++ * file directly because we might not be able to have all of our changes ++ * written completely and atomically. That was CVE-2019-14865, known to ++ * have been triggerable via RLIMIT_FSIZE. While we've dealt with that ++ * specific attack via the check above, there may be other possibilities. ++ */ + + /* + * Create a tempfile for writing the new env. Use the canonicalized filename + * for the template so that the tmpfile is in the same dir / on same fs. ++ * ++ * We now use per-user fixed temporary filenames, so that a user cannot cause ++ * multiple files to accumulate. ++ * ++ * We don't use O_EXCL so that a stale temporary file doesn't prevent further ++ * usage of the program by the user. + */ +- snprintf(tmp_filename, sizeof(tmp_filename), "%sXXXXXX", env_filename); +- fd = mkstemp(tmp_filename); ++ snprintf(tmp_filename, sizeof(tmp_filename), "%s.%u", env_filename, getuid()); ++ fd = open(tmp_filename, O_CREAT | O_WRONLY, 0600); + if (fd == -1) + { + perror ("Creating tmpfile failed"); + return 1; + } + ++ /* ++ * The lock prevents the same user from reaching further steps ending in ++ * rename() concurrently, in which case the temporary file only partially ++ * written by one invocation could be renamed to the target file by another. ++ * ++ * The lock also guards the slow fsync() from concurrent calls. After the ++ * first time that and the rename() complete, further invocations for the ++ * same flag become no-ops. ++ * ++ * We lock the temporary file rather than the target file because locking the ++ * latter would allow any user having SIGSTOP'ed their process to make all ++ * other users' invocations fail (or lock up if we'd use blocking mode). ++ * ++ * We use non-blocking mode (LOCK_NB) because the lock having been taken by ++ * another process implies that the other process would normally have already ++ * renamed the file to target by the time it releases the lock (and we could ++ * acquire it), so we'd be working directly on the target if we proceeded, ++ * which is undesirable, and we'd kind of fail on the already-done rename. ++ */ ++ if (flock(fd, LOCK_EX | LOCK_NB)) ++ { ++ perror ("Locking tmpfile failed"); ++ return 1; ++ } ++ ++ /* ++ * Deal with the potential that another invocation proceeded all the way to ++ * rename() and process exit while we were between open() and flock(). ++ */ ++ { ++ struct stat st1, st2; ++ if (fstat(fd, &st1) || stat(tmp_filename, &st2)) ++ { ++ perror ("stat of tmpfile failed"); ++ return 1; ++ } ++ if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) ++ { ++ fprintf (stderr, "Another invocation won race\n"); ++ return 1; ++ } ++ } ++ + f = fdopen (fd, "w"); + if (!f) + { +@@ -200,23 +261,25 @@ int main(int argc, char *argv[]) + return 1; + } + +- ret = fsync (fileno (f)); ++ ret = ftruncate (fileno (f), GRUBENV_SIZE); + if (ret) + { +- perror ("Error syncing tmpfile"); ++ perror ("Error truncating tmpfile"); + unlink(tmp_filename); + return 1; + } + +- ret = fclose (f); ++ ret = fsync (fileno (f)); + if (ret) + { +- perror ("Error closing tmpfile"); ++ perror ("Error syncing tmpfile"); + unlink(tmp_filename); + return 1; + } + + /* ++ * We must not close the file before rename() as that would remove the lock. ++ * + * And finally rename the tmpfile with the new env over the old env, the + * linux kernel guarantees that this is atomic (from a syscall pov). + */ +-- +2.43.0 + diff --git a/SOURCES/0584-grub-set-bootflag-Exit-calmly-when-not-running-as-ro.patch b/SOURCES/0584-grub-set-bootflag-Exit-calmly-when-not-running-as-ro.patch new file mode 100644 index 0000000..3e13dfc --- /dev/null +++ b/SOURCES/0584-grub-set-bootflag-Exit-calmly-when-not-running-as-ro.patch @@ -0,0 +1,39 @@ +From a7192a650c1e94221a86b49f5132fb47a4dda6ea Mon Sep 17 00:00:00 2001 +From: Solar Designer +Date: Tue, 6 Feb 2024 22:05:45 +0100 +Subject: [PATCH 3/3] grub-set-bootflag: Exit calmly when not running as root + +Exit calmly when not installed SUID root and invoked by non-root. This +allows installing user/grub-boot-success.service unconditionally while +supporting non-SUID installation of the program for some limited usage. + +Signed-off-by: Solar Designer +--- + util/grub-set-bootflag.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +index 698b55a1ab93..a51805fa8cec 100644 +--- a/util/grub-set-bootflag.c ++++ b/util/grub-set-bootflag.c +@@ -85,6 +85,17 @@ int main(int argc, char *argv[]) + bootflag = bootflags[i]; + len = strlen (bootflag); + ++ /* ++ * Exit calmly when not installed SUID root and invoked by non-root. This ++ * allows installing user/grub-boot-success.service unconditionally while ++ * supporting non-SUID installation of the program for some limited usage. ++ */ ++ if (geteuid()) ++ { ++ printf ("grub-set-bootflag not running as root, no action taken\n"); ++ return 0; ++ } ++ + /* + * setegid avoids the new grubenv's gid being that of the user. + */ +-- +2.43.0 + diff --git a/SOURCES/0585-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch b/SOURCES/0585-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch new file mode 100644 index 0000000..8234f67 --- /dev/null +++ b/SOURCES/0585-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch @@ -0,0 +1,93 @@ +From 43651027d24e62a7a463254165e1e46e42aecdea Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:31:57 +0300 +Subject: [PATCH 1/6] fs/ntfs: Fix an OOB write when parsing the + $ATTRIBUTE_LIST attribute for the $MFT file + +When parsing an extremely fragmented $MFT file, i.e., the file described +using the $ATTRIBUTE_LIST attribute, current NTFS code will reuse a buffer +containing bytes read from the underlying drive to store sector numbers, +which are consumed later to read data from these sectors into another buffer. + +These sectors numbers, two 32-bit integers, are always stored at predefined +offsets, 0x10 and 0x14, relative to first byte of the selected entry within +the $ATTRIBUTE_LIST attribute. Usually, this won't cause any problem. + +However, when parsing a specially-crafted file system image, this may cause +the NTFS code to write these integers beyond the buffer boundary, likely +causing the GRUB memory allocator to misbehave or fail. These integers contain +values which are controlled by on-disk structures of the NTFS file system. + +Such modification and resulting misbehavior may touch a memory range not +assigned to the GRUB and owned by firmware or another EFI application/driver. + +This fix introduces checks to ensure that these sector numbers are never +written beyond the boundary. + +Fixes: CVE-2023-4692 + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index bbdbe24ada83..c3c4db117bba 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -184,7 +184,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + } + if (at->attr_end) + { +- grub_uint8_t *pa; ++ grub_uint8_t *pa, *pa_end; + + at->emft_buf = grub_malloc (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + if (at->emft_buf == NULL) +@@ -209,11 +209,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + } + at->attr_nxt = at->edat_buf; + at->attr_end = at->edat_buf + u32at (pa, 0x30); ++ pa_end = at->edat_buf + n; + } + else + { + at->attr_nxt = at->attr_end + u16at (pa, 0x14); + at->attr_end = at->attr_end + u32at (pa, 4); ++ pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + } + at->flags |= GRUB_NTFS_AF_ALST; + while (at->attr_nxt < at->attr_end) +@@ -230,6 +232,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + at->flags |= GRUB_NTFS_AF_GPOS; + at->attr_cur = at->attr_nxt; + pa = at->attr_cur; ++ ++ if ((pa >= pa_end) || (pa_end - pa < 0x18)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse attribute list"); ++ return NULL; ++ } ++ + grub_set_unaligned32 ((char *) pa + 0x10, + grub_cpu_to_le32 (at->mft->data->mft_start)); + grub_set_unaligned32 ((char *) pa + 0x14, +@@ -240,6 +249,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + { + if (*pa != attr) + break; ++ ++ if ((pa >= pa_end) || (pa_end - pa < 0x18)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse attribute list"); ++ return NULL; ++ } ++ + if (read_attr + (at, pa + 0x10, + u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), +-- +2.43.0 + diff --git a/SOURCES/0586-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch b/SOURCES/0586-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch new file mode 100644 index 0000000..a90e077 --- /dev/null +++ b/SOURCES/0586-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch @@ -0,0 +1,58 @@ +From 0ed2458cc4eff6d9a9199527e2a0b6d445802f94 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:32:33 +0300 +Subject: [PATCH 2/6] fs/ntfs: Fix an OOB read when reading data from the + resident $DATA attribute + +When reading a file containing resident data, i.e., the file data is stored in +the $DATA attribute within the NTFS file record, not in external clusters, +there are no checks that this resident data actually fits the corresponding +file record segment. + +When parsing a specially-crafted file system image, the current NTFS code will +read the file data from an arbitrary, attacker-chosen memory offset and of +arbitrary, attacker-chosen length. + +This allows an attacker to display arbitrary chunks of memory, which could +contain sensitive information like password hashes or even plain-text, +obfuscated passwords from BS EFI variables. + +This fix implements a check to ensure that resident data is read from the +corresponding file record segment only. + +Fixes: CVE-2023-4693 + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index c3c4db117bba..a68e173d8285 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -401,7 +401,18 @@ read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_uint8_t *dest, + { + if (ofs + len > u32at (pa, 0x10)) + return grub_error (GRUB_ERR_BAD_FS, "read out of range"); +- grub_memcpy (dest, pa + u32at (pa, 0x14) + ofs, len); ++ ++ if (u32at (pa, 0x10) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute too large"); ++ ++ if (pa >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); ++ ++ if (u16at (pa, 0x14) + u32at (pa, 0x10) > ++ (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) pa) ++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); ++ ++ grub_memcpy (dest, pa + u16at (pa, 0x14) + ofs, len); + return 0; + } + +-- +2.43.0 + diff --git a/SOURCES/0587-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch b/SOURCES/0587-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch new file mode 100644 index 0000000..fb3eb31 --- /dev/null +++ b/SOURCES/0587-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch @@ -0,0 +1,73 @@ +From 7e5f031a6a6a3decc2360a7b0c71abbe598e7354 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:33:17 +0300 +Subject: [PATCH 3/6] fs/ntfs: Fix an OOB read when parsing directory entries + from resident and non-resident index attributes + +This fix introduces checks to ensure that index entries are never read +beyond the corresponding directory index. + +The lack of this check is a minor issue, likely not exploitable in any way. + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index a68e173d8285..2d78b96e19fb 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -599,7 +599,7 @@ get_utf8 (grub_uint8_t *in, grub_size_t len) + } + + static int +-list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, ++list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, grub_uint8_t *end_pos, + grub_fshelp_iterate_dir_hook_t hook, void *hook_data) + { + grub_uint8_t *np; +@@ -610,6 +610,9 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, + grub_uint8_t namespace; + char *ustr; + ++ if ((pos >= end_pos) || (end_pos - pos < 0x52)) ++ break; ++ + if (pos[0xC] & 2) /* end signature */ + break; + +@@ -617,6 +620,9 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, + ns = *(np++); + namespace = *(np++); + ++ if (2 * ns > end_pos - pos - 0x52) ++ break; ++ + /* + * Ignore files in DOS namespace, as they will reappear as Win32 + * names. +@@ -806,7 +812,9 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + } + + cur_pos += 0x10; /* Skip index root */ +- ret = list_file (mft, cur_pos + u16at (cur_pos, 0), hook, hook_data); ++ ret = list_file (mft, cur_pos + u16at (cur_pos, 0), ++ at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), ++ hook, hook_data); + if (ret) + goto done; + +@@ -893,6 +901,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + (const grub_uint8_t *) "INDX"))) + goto done; + ret = list_file (mft, &indx[0x18 + u16at (indx, 0x18)], ++ indx + (mft->data->idx_size << GRUB_NTFS_BLK_SHR), + hook, hook_data); + if (ret) + goto done; +-- +2.43.0 + diff --git a/SOURCES/0588-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch b/SOURCES/0588-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch new file mode 100644 index 0000000..c121cf3 --- /dev/null +++ b/SOURCES/0588-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch @@ -0,0 +1,51 @@ +From 7a5a116739fa6d8a625da7d6b9272c9a2462f967 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:33:44 +0300 +Subject: [PATCH 4/6] fs/ntfs: Fix an OOB read when parsing bitmaps for index + attributes + +This fix introduces checks to ensure that bitmaps for directory indices +are never read beyond their actual sizes. + +The lack of this check is a minor issue, likely not exploitable in any way. + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 2d78b96e19fb..bb70c89fb803 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -843,6 +843,25 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + + if (is_resident) + { ++ if (bitmap_len > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap too large"); ++ goto done; ++ } ++ ++ if (cur_pos >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range"); ++ goto done; ++ } ++ ++ if (u16at (cur_pos, 0x14) + u32at (cur_pos, 0x10) > ++ (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) cur_pos) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range"); ++ goto done; ++ } ++ + grub_memcpy (bmp, cur_pos + u16at (cur_pos, 0x14), + bitmap_len); + } +-- +2.43.0 + diff --git a/SOURCES/0589-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch b/SOURCES/0589-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch new file mode 100644 index 0000000..efeb21d --- /dev/null +++ b/SOURCES/0589-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch @@ -0,0 +1,61 @@ +From 1fe82c41e070385e273d7bb1cfb482627a3c28e8 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:38:19 +0300 +Subject: [PATCH 5/6] fs/ntfs: Fix an OOB read when parsing a volume label + +This fix introduces checks to ensure that an NTFS volume label is always +read from the corresponding file record segment. + +The current NTFS code allows the volume label string to be read from an +arbitrary, attacker-chosen memory location. However, the bytes read are +always treated as UTF-16LE. So, the final string displayed is mostly +unreadable and it can't be easily converted back to raw bytes. + +The lack of this check is a minor issue, likely not causing a significant +data leak. + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index bb70c89fb803..ff5e3740f0dd 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -1213,13 +1213,29 @@ grub_ntfs_label (grub_device_t device, char **label) + + init_attr (&mft->attr, mft); + pa = find_attr (&mft->attr, GRUB_NTFS_AT_VOLUME_NAME); ++ ++ if (pa >= mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label"); ++ goto fail; ++ } ++ ++ if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa < 0x16) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label"); ++ goto fail; ++ } ++ + if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10))) + { + int len; + + len = u32at (pa, 0x10) / 2; + pa += u16at (pa, 0x14); +- *label = get_utf8 (pa, len); ++ if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa >= 2 * len) ++ *label = get_utf8 (pa, len); ++ else ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label"); + } + + fail: +-- +2.43.0 + diff --git a/SOURCES/0590-fs-ntfs-Make-code-more-readable.patch b/SOURCES/0590-fs-ntfs-Make-code-more-readable.patch new file mode 100644 index 0000000..2f00384 --- /dev/null +++ b/SOURCES/0590-fs-ntfs-Make-code-more-readable.patch @@ -0,0 +1,159 @@ +From e58b870ff926415e23fc386af41ff81b2f588763 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:40:07 +0300 +Subject: [PATCH 6/6] fs/ntfs: Make code more readable + +Move some calls used to access NTFS attribute header fields into +functions with human-readable names. + +Suggested-by: Daniel Kiper +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 48 +++++++++++++++++++++++++++++++-------------- + 1 file changed, 33 insertions(+), 15 deletions(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index ff5e3740f0dd..de435aa14d85 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -52,6 +52,24 @@ u64at (void *ptr, grub_size_t ofs) + return grub_le_to_cpu64 (grub_get_unaligned64 ((char *) ptr + ofs)); + } + ++static grub_uint16_t ++first_attr_off (void *mft_buf_ptr) ++{ ++ return u16at (mft_buf_ptr, 0x14); ++} ++ ++static grub_uint16_t ++res_attr_data_off (void *res_attr_ptr) ++{ ++ return u16at (res_attr_ptr, 0x14); ++} ++ ++static grub_uint32_t ++res_attr_data_len (void *res_attr_ptr) ++{ ++ return u32at (res_attr_ptr, 0x10); ++} ++ + grub_ntfscomp_func_t grub_ntfscomp_func; + + static grub_err_t +@@ -106,7 +124,7 @@ init_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft) + { + at->mft = mft; + at->flags = (mft == &mft->data->mmft) ? GRUB_NTFS_AF_MMFT : 0; +- at->attr_nxt = mft->buf + u16at (mft->buf, 0x14); ++ at->attr_nxt = mft->buf + first_attr_off (mft->buf); + at->attr_end = at->emft_buf = at->edat_buf = at->sbuf = NULL; + } + +@@ -154,7 +172,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + return NULL; + } + +- new_pos = &at->emft_buf[u16at (at->emft_buf, 0x14)]; ++ new_pos = &at->emft_buf[first_attr_off (at->emft_buf)]; + while (*new_pos != 0xFF) + { + if ((*new_pos == *at->attr_cur) +@@ -213,7 +231,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + } + else + { +- at->attr_nxt = at->attr_end + u16at (pa, 0x14); ++ at->attr_nxt = at->attr_end + res_attr_data_off (pa); + at->attr_end = at->attr_end + u32at (pa, 4); + pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + } +@@ -399,20 +417,20 @@ read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_uint8_t *dest, + + if (pa[8] == 0) + { +- if (ofs + len > u32at (pa, 0x10)) ++ if (ofs + len > res_attr_data_len (pa)) + return grub_error (GRUB_ERR_BAD_FS, "read out of range"); + +- if (u32at (pa, 0x10) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ if (res_attr_data_len (pa) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) + return grub_error (GRUB_ERR_BAD_FS, "resident attribute too large"); + + if (pa >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) + return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); + +- if (u16at (pa, 0x14) + u32at (pa, 0x10) > ++ if (res_attr_data_off (pa) + res_attr_data_len (pa) > + (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) pa) + return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); + +- grub_memcpy (dest, pa + u16at (pa, 0x14) + ofs, len); ++ grub_memcpy (dest, pa + res_attr_data_off (pa) + ofs, len); + return 0; + } + +@@ -556,7 +574,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint64_t mftno) + (unsigned long long) mftno); + + if (!pa[8]) +- mft->size = u32at (pa, 0x10); ++ mft->size = res_attr_data_len (pa); + else + mft->size = u64at (pa, 0x30); + +@@ -805,7 +823,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + (u32at (cur_pos, 0x18) != 0x490024) || + (u32at (cur_pos, 0x1C) != 0x300033)) + continue; +- cur_pos += u16at (cur_pos, 0x14); ++ cur_pos += res_attr_data_off (cur_pos); + if (*cur_pos != 0x30) /* Not filename index */ + continue; + break; +@@ -834,7 +852,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + { + int is_resident = (cur_pos[8] == 0); + +- bitmap_len = ((is_resident) ? u32at (cur_pos, 0x10) : ++ bitmap_len = ((is_resident) ? res_attr_data_len (cur_pos) : + u32at (cur_pos, 0x28)); + + bmp = grub_malloc (bitmap_len); +@@ -855,14 +873,14 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + goto done; + } + +- if (u16at (cur_pos, 0x14) + u32at (cur_pos, 0x10) > ++ if (res_attr_data_off (cur_pos) + res_attr_data_len (cur_pos) > + (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) cur_pos) + { + grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range"); + goto done; + } + +- grub_memcpy (bmp, cur_pos + u16at (cur_pos, 0x14), ++ grub_memcpy (bmp, cur_pos + res_attr_data_off (cur_pos), + bitmap_len); + } + else +@@ -1226,12 +1244,12 @@ grub_ntfs_label (grub_device_t device, char **label) + goto fail; + } + +- if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10))) ++ if ((pa) && (pa[8] == 0) && (res_attr_data_len (pa))) + { + int len; + +- len = u32at (pa, 0x10) / 2; +- pa += u16at (pa, 0x14); ++ len = res_attr_data_len (pa) / 2; ++ pa += res_attr_data_off (pa); + if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa >= 2 * len) + *label = get_utf8 (pa, len); + else +-- +2.43.0 + diff --git a/SOURCES/20-grub.install b/SOURCES/20-grub.install index 9b74538..dd2018a 100755 --- a/SOURCES/20-grub.install +++ b/SOURCES/20-grub.install @@ -109,7 +109,11 @@ case "$COMMAND" in sed -i -e "s,^initrd.*,initrd ${BOOTPREFIX}${INITRD},g" "${BLS_TARGET}" fi - if [[ "$KERNEL_VERSION" == *\+* ]] && [ "x$GRUB_DEFAULT_TO_DEBUG" != "xtrue" ]; then + if ( [[ "$KERNEL_VERSION" != *${GRUB_DEFAULT_KERNEL_TYPE}* ]] && \ + [ "x$GRUB_NON_STANDARD_KERNEL" == "xtrue" ] ) || \ + ( echo "$KERNEL_VERSION" | grep -E -q "64k|auto|rt|uki" && \ + [ "x$GRUB_NON_STANDARD_KERNEL" != "xtrue" ] ) || \ + ( [[ "$KERNEL_VERSION" == *debug* ]] && [ "x$GRUB_DEFAULT_TO_DEBUG" != "xtrue" ] ); then GRUB_UPDATE_DEFAULT_KERNEL=false fi diff --git a/SOURCES/grub.patches b/SOURCES/grub.patches index 3eacbac..505a35f 100644 --- a/SOURCES/grub.patches +++ b/SOURCES/grub.patches @@ -573,3 +573,18 @@ Patch0572: 0572-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch Patch0573: 0573-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch Patch0574: 0574-Enable-TDX-measurement-to-RTMR-register.patch Patch0575: 0575-Enable-shared-processor-mode-in-vector-5.patch +Patch0576: 0576-efi-http-change-uint32_t-to-uintn_t-for-grub_efi_htt.patch +Patch0577: 0577-ieee1275-Converting-plain-numbers-to-constants-in-Ve.patch +Patch0578: 0578-ieee1275-extended-support-in-options-vector5.patch +Patch0579: 0579-Regenerate-kernelopts-if-missing-on-ppc.patch +Patch0580: 0580-kern-ieee1275-init-ppc64-Restrict-high-memory-in-pre.patch +Patch0581: 0581-util-Enable-default-kernel-for-updates.patch +Patch0582: 0582-grub-set-bootflag-Conservative-partial-fix-for-CVE-2.patch +Patch0583: 0583-grub-set-bootflag-More-complete-fix-for-CVE-2024-104.patch +Patch0584: 0584-grub-set-bootflag-Exit-calmly-when-not-running-as-ro.patch +Patch0585: 0585-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch +Patch0586: 0586-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch +Patch0587: 0587-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch +Patch0588: 0588-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch +Patch0589: 0589-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch +Patch0590: 0590-fs-ntfs-Make-code-more-readable.patch diff --git a/SPECS/grub2.spec b/SPECS/grub2.spec index 64bb124..3d3ece3 100644 --- a/SPECS/grub2.spec +++ b/SPECS/grub2.spec @@ -7,7 +7,7 @@ Name: grub2 Epoch: 1 Version: 2.02 -Release: 148%{?dist} +Release: 156%{?dist} Summary: Bootloader with support for Linux, Multiboot and more Group: System Environment/Base License: GPLv3+ @@ -510,6 +510,41 @@ fi %endif %changelog +* Tue Feb 20 2024 Nicolas Frayer - 2.02-156 +- fs/ntfs: OOB write fix +- (CVE-2023-4692) +- Resolves: #RHEL-11566 + +* Thu Feb 8 2024 Nicolas Frayer - 2.06-155 +- grub-set-bootflag: Fix for CVE-2024-1048 +- (CVE-2024-1048) +- Resolves: #RHEL-20746 + +* Mon Nov 27 2023 Nicolas Frayer - 2.02-154 +- Missing install script for previous commit +- Related: #RHEL-4343 + +* Fri Nov 24 2023 Nicolas Frayer - 2.02-153 +- util: Enable default kernel for updates +- Resolves: #RHEL-4343 + +* Fri Oct 20 2023 Nicolas Frayer - 2.02-152 +- kern/ieee1275/init: ppc64: Restrict high memory in presence + of fadump +- Resolves: #RHEL-14283 + +* Mon Aug 28 2023 Nicolas Frayer - 2.02-151 +- util: Regenerate kernelopts if missing on ppc +- Resolves: #2051889 + +* Fri Jun 16 2023 Nicolas Frayer - 2.02-150 +- kern/ieee1275/init: sync vec5 patchset with upstream +- Resolves: #2172111 + +* Wed Jun 14 2023 Nicolas Frayer - 2.02-149 +- efi/http: change uint32_t to uintn_t for grub_efi_http_message_t +- Resolves: #2178388 + * Mon Feb 06 2023 Robbie Harwood - 2.02-148 - ppc64le: cas5, take 3 - Resolves: #2139508