Merge branch 'c8-beta' into a8-beta

This commit is contained in:
eabdullin 2022-10-07 10:29:45 +03:00
commit f416e63f99
68 changed files with 6950 additions and 38 deletions

View File

@ -1,4 +1,4 @@
From fe8b1f619fafcd2438e3d86fb07c6a5e9280423c Mon Sep 17 00:00:00 2001
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ian Page Hands <iphands@gmail.com>
Date: Tue, 8 Jun 2021 13:48:56 -0400
Subject: [PATCH] efinet: Add DHCP proxy support
@ -51,6 +51,3 @@ index df7760ad2..25809050b 100644
1, device, path);
grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
}
--
2.34.1

View File

@ -1,7 +1,8 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
Date: Tue, 8 Feb 2022 08:39:10 +0100
Subject: [PATCH] search: fixed bug stopping iteration when --no-floppy is used
Subject: [PATCH] commands/search: Fix bug stopping iteration when --no-floppy
is used
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
@ -10,8 +11,11 @@ When using --no-floppy and a floppy was encountered, iterate_device()
was returning 1, causing the iteration to stop instead of continuing.
Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
(cherry picked from commit e784b4b3367341b0468dd2a83b265d49383f48ae)
(cherry picked from commit 8f4688fd61dcf35de3d7ebbc2b237cfa2f202930)
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 68ba54c2298604146be83cae144dafd1cfd1fe2d)
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit 7ada55e3fcd16e00773d3918955b2b945b7f063a)
(cherry picked from commit 44a58e304fd06155a56b650927728af01bbc647d)
---
grub-core/commands/search.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

View File

@ -17,8 +17,10 @@ effective EFI device behind.
This commit also refactors handling of --no-floppy option.
Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
(cherry picked from commit aedb45f32106dd2a64f906b0db6a76ee09f1b930)
(cherry picked from commit 4fef28d5405f7f986dba6e503e48d6a408588382)
[rharwood: apply rmetrich's flags initialization fix]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit fdd8396f4fa750bbbabd4298f2593942f2b84710)
(cherry picked from commit bea473b58726705bb83a3db88f52d46fdcc6150e)
---
grub-core/commands/search.c | 27 +++++++++++++++++++++++----
grub-core/commands/search_wrap.c | 18 ++++++++++++------
@ -86,7 +88,7 @@ index d3180bf66..2036a756b 100644
.nhints = nhints,
.count = 0,
diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c
index 47fc8eb99..464e6ebb1 100644
index 47fc8eb99..0b62acf85 100644
--- a/grub-core/commands/search_wrap.c
+++ b/grub-core/commands/search_wrap.c
@@ -40,6 +40,7 @@ static const struct grub_arg_option options[] =
@ -109,7 +111,7 @@ index 47fc8eb99..464e6ebb1 100644
const char *id = 0;
int i = 0, j = 0, nhints = 0;
char **hints = NULL;
+ enum search_flags flags;
+ enum search_flags flags = 0;
if (state[SEARCH_HINT].set)
for (i = 0; state[SEARCH_HINT].args[i]; i++)

View File

@ -50,10 +50,10 @@ The code is easily extensible to handle other arguments in the future if
needed.
Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
(cherry picked from commit 73e183ce1e42bd97ae91a9254f8d4acd4d0b1cbc)
(cherry picked from commit 174c3efcf17b1f5ad466f9c5fb83cd9554edb5f9)
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit cc972c27314c841f80ab0fe8318fae06f078c680)
(cherry picked from commit 84b0c3f965a3918be64ca850139bea7c32d23ae9)
---
NEWS | 2 +-
grub-core/Makefile.core.def | 6 ++
grub-core/commands/efi/connectefi.c | 205 ++++++++++++++++++++++++++++++++++++
grub-core/commands/efi/lsefi.c | 1 +
@ -61,22 +61,10 @@ Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
grub-core/kern/efi/efi.c | 13 +++
include/grub/efi/disk.h | 2 +
include/grub/efi/efi.h | 5 +
NEWS | 2 +-
8 files changed, 246 insertions(+), 1 deletion(-)
create mode 100644 grub-core/commands/efi/connectefi.c
diff --git a/NEWS b/NEWS
index 2ebd54e78..b04041507 100644
--- a/NEWS
+++ b/NEWS
@@ -66,7 +66,7 @@ New in 2.02:
* Prefer pmtimer for TSC calibration.
* New/improved platform support:
- * New `efifwsetup' and `lsefi' commands on EFI platforms.
+ * New `efifwsetup', `lsefi' and `connectefi` commands on EFI platforms.
* New `cmosdump' and `cmosset' commands on platforms with CMOS support.
* New command `pcidump' for PCI platforms.
* Improve opcode parsing in ACPI halt implementation.
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 612df2e9c..ef06f8c95 100644
--- a/grub-core/Makefile.core.def
@ -394,3 +382,16 @@ index 570a69361..4411ffa16 100644
void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle,
grub_efi_guid_t *protocol,
grub_efi_uint32_t attributes);
diff --git a/NEWS b/NEWS
index 2ebd54e78..b04041507 100644
--- a/NEWS
+++ b/NEWS
@@ -66,7 +66,7 @@ New in 2.02:
* Prefer pmtimer for TSC calibration.
* New/improved platform support:
- * New `efifwsetup' and `lsefi' commands on EFI platforms.
+ * New `efifwsetup', `lsefi' and `connectefi` commands on EFI platforms.
* New `cmosdump' and `cmosset' commands on platforms with CMOS support.
* New command `pcidump' for PCI platforms.
* Improve opcode parsing in ACPI halt implementation.

View File

@ -0,0 +1,203 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Thu, 11 Jul 2019 17:17:02 +0200
Subject: [PATCH] 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 <pjones@redhat.com>
(cherry picked from commit 9035d4f9ea2f26a9d4412a0918d597ceb5365442)
Conflicts:
grub-core/loader/i386/efi/linux.c
Context diffs in includes.
Signed-off-by: Lenny Szubowicz <lszubowi@redhat.com>
---
grub-core/kern/efi/mm.c | 8 ++++----
grub-core/loader/i386/efi/linux.c | 24 +++++++++++++++++-------
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(+), 12 deletions(-)
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 2d9c9032b..9e76f23e5 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;
@@ -472,7 +472,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)
@@ -490,9 +490,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 576f8c07e..c5fdf522b 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -27,6 +27,7 @@
#include <grub/lib/cmdline.h>
#include <grub/efi/efi.h>
#include <grub/efi/linux.h>
+#include <grub/cpu/efi/memory.h>
#include <grub/tpm.h>
#include <grub/safemath.h>
@@ -113,7 +114,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
}
}
- 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"));
@@ -217,8 +220,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
}
- 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");
@@ -288,8 +294,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"));
@@ -316,11 +325,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 <grub/efi/memory.h>
#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 <grub/efi/memory.h>
#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 <grub/efi/memory.h>
#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 <grub/efi/memory.h>
#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 <grub/efi/memory.h>
#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 */

View File

@ -0,0 +1,109 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Fri, 12 Jul 2019 09:53:32 +0200
Subject: [PATCH] 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 <pjones@redhat.com>
(cherry picked from commit 7765a790dee00f2e0d414cf3a3d016c493cf0d9b)
Conflicts:
grub-core/loader/i386/efi/linux.c
git cherry-pick thought delete of prior def of MIN was a
conflict.
Signed-off-by: Lenny Szubowicz <lszubowi@redhat.com>
---
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 c5fdf522b..73cd838e9 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -37,11 +37,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
@@ -75,6 +80,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[])
@@ -133,7 +176,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"),
@@ -161,11 +204,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[])

View File

@ -0,0 +1,134 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Thu, 13 Sep 2018 14:42:34 -0400
Subject: [PATCH] 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 <pjones@redhat.com>
(cherry picked from commit 486cdd48889b30b03143c393e59a75ea040b5c40)
---
grub-core/loader/i386/efi/linux.c | 75 +++++++++++++++++++++------------------
1 file changed, 41 insertions(+), 34 deletions(-)
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index 73cd838e9..c9650561f 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -258,32 +258,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
}
- 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;
- }
+ lh = (struct linux_i386_kernel_header *)kernel;
+ grub_dprintf ("linux", "original lh is at %p\n", kernel);
- 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))
{
@@ -331,6 +308,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 %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", "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));
@@ -356,8 +361,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;
@@ -374,26 +379,28 @@ 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:
+fail:
if (file)
grub_file_close (file);

View File

@ -0,0 +1,259 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Wed, 12 Sep 2018 16:03:55 -0400
Subject: [PATCH] x86-efi: Make our own allocator for kernel stuff
This helps enable allocations above 4GB.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit cfea4ae780f8860d472cd2d5a9765ec2fe2adc83)
---
grub-core/loader/i386/efi/linux.c | 167 +++++++++++++++++++++-----------------
1 file changed, 94 insertions(+), 73 deletions(-)
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index c9650561f..5eed2014c 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -49,6 +49,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 %lu pages from %p\n",
+ pages, (void *)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)
{
@@ -64,19 +123,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;
}
@@ -157,19 +209,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
}
}
- 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;
- }
-
- grub_dprintf ("linux", "initrd_mem = %lx\n", (unsigned long) initrd_mem);
+ 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;
@@ -230,7 +276,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"));
@@ -289,7 +334,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))
{
@@ -308,17 +353,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));
@@ -337,19 +374,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;
- }
-
- grub_dprintf ("linux", "linux_cmdline = %lx\n",
- (unsigned long)linux_cmdline);
+ goto fail;
+ grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline);
grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
grub_create_loader_cmdline (argc, argv,
@@ -358,27 +386,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
GRUB_VERIFY_KERNEL_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;
+ 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);
@@ -413,18 +438,14 @@ fail:
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 (!loaded)
+ {
+ if (lh)
+ kernel_free (linux_cmdline, 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 (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;
}

View File

@ -0,0 +1,172 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Wed, 12 Sep 2018 16:12:27 -0400
Subject: [PATCH] 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 <pjones@redhat.com>
(cherry picked from commit 2b636967018431b046b625ad4753c8de51f7f6b2)
---
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 5eed2014c..e9d2c85b3 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -54,13 +54,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)
@@ -82,6 +91,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;
@@ -170,6 +184,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[])
@@ -214,8 +231,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;
@@ -353,6 +374,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;
@@ -387,21 +420,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);
@@ -410,8 +462,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 8474a857e..a4b37dcce 100644
--- a/include/grub/i386/linux.h
+++ b/include/grub/i386/linux.h
@@ -230,7 +230,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
{

View File

@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Javier Martinez Canillas <javierm@redhat.com>
Date: Tue, 26 May 2020 16:59:28 +0200
Subject: [PATCH] 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 <javierm@redhat.com>
(cherry picked from commit 1c0d2ebdddf69962395f0fa4578446654512f3c4)
---
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 e9d2c85b3..a043df891 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -146,7 +146,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)

View File

@ -0,0 +1,221 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Stefan Berger <stefanb@linux.ibm.com>
Date: Sun, 15 Mar 2020 12:37:10 -0400
Subject: [PATCH] ibmvtpm: Add support for trusted boot using a vTPM 2.0
Add support for trusted boot using a vTPM 2.0 on the IBM IEEE1275
PowerPC platform. With this patch grub now measures text and binary data
into the TPM's PCRs 8 and 9 in the same way as the x86_64 platform
does.
This patch requires Daniel Axtens's patches for claiming more memory.
For vTPM support to work on PowerVM, system driver levels 1010.30
or 1020.00 are required.
Note: Previous versions of firmware levels with the 2hash-ext-log
API call have a bug that, once this API call is invoked, has the
effect of disabling the vTPM driver under Linux causing an error
message to be displayed in the Linux kernel log. Those users will
have to update their machines to the firmware levels mentioned
above.
Cc: Eric Snowberg <eric.snowberg@oracle.com>
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
---
grub-core/Makefile.core.def | 7 ++
grub-core/commands/ieee1275/ibmvtpm.c | 152 ++++++++++++++++++++++++++++++++++
include/grub/ieee1275/ieee1275.h | 3 +
3 files changed, 162 insertions(+)
create mode 100644 grub-core/commands/ieee1275/ibmvtpm.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index ef06f8c95a..b11f74e6b2 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1104,6 +1104,13 @@ module = {
enable = powerpc_ieee1275;
};
+module = {
+ name = tpm;
+ common = commands/tpm.c;
+ ieee1275 = commands/ieee1275/ibmvtpm.c;
+ enable = powerpc_ieee1275;
+};
+
module = {
name = terminal;
common = commands/terminal.c;
diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
new file mode 100644
index 0000000000..e68b8448bc
--- /dev/null
+++ b/grub-core/commands/ieee1275/ibmvtpm.c
@@ -0,0 +1,152 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2021 Free Software Foundation, Inc.
+ * Copyright (C) 2021 IBM Corporation
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * IBM vTPM support code.
+ */
+
+#include <grub/err.h>
+#include <grub/types.h>
+#include <grub/tpm.h>
+#include <grub/ieee1275/ieee1275.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+static grub_ieee1275_ihandle_t tpm_ihandle;
+static grub_uint8_t tpm_version;
+
+#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t)0)
+
+static void
+tpm_get_tpm_version (void)
+{
+ grub_ieee1275_phandle_t vtpm;
+ char buffer[20];
+
+ if (!grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) &&
+ !grub_ieee1275_get_property (vtpm, "compatible", buffer,
+ sizeof (buffer), NULL) &&
+ !grub_strcmp (buffer, "IBM,vtpm20"))
+ tpm_version = 2;
+}
+
+static grub_err_t
+tpm_init (void)
+{
+ static int init_success = 0;
+
+ if (!init_success)
+ {
+ if (grub_ieee1275_open ("/vdevice/vtpm", &tpm_ihandle) < 0) {
+ tpm_ihandle = IEEE1275_IHANDLE_INVALID;
+ return GRUB_ERR_UNKNOWN_DEVICE;
+ }
+
+ init_success = 1;
+
+ tpm_get_tpm_version ();
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static int
+ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
+ grub_uint32_t eventtype,
+ const char *description,
+ grub_size_t description_size,
+ void *buf, grub_size_t size)
+{
+ struct tpm_2hash_ext_log
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t method;
+ grub_ieee1275_cell_t ihandle;
+ grub_ieee1275_cell_t size;
+ grub_ieee1275_cell_t buf;
+ grub_ieee1275_cell_t description_size;
+ grub_ieee1275_cell_t description;
+ grub_ieee1275_cell_t eventtype;
+ grub_ieee1275_cell_t pcrindex;
+ grub_ieee1275_cell_t catch_result;
+ grub_ieee1275_cell_t rc;
+ }
+ args;
+
+ INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
+ args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
+ args.ihandle = tpm_ihandle;
+ args.pcrindex = pcrindex;
+ args.eventtype = eventtype;
+ args.description = (grub_ieee1275_cell_t) description;
+ args.description_size = description_size;
+ args.buf = (grub_ieee1275_cell_t) buf;
+ args.size = (grub_ieee1275_cell_t) size;
+
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+ return -1;
+
+ /*
+ * catch_result is set if firmware does not support 2hash-ext-log
+ * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
+ */
+ if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
+ return -1;
+
+ return 0;
+}
+
+static grub_err_t
+tpm2_log_event (unsigned char *buf,
+ grub_size_t size, grub_uint8_t pcr,
+ const char *description)
+{
+ static int error_displayed = 0;
+ int err;
+
+ err = ibmvtpm_2hash_ext_log (pcr, EV_IPL,
+ description,
+ grub_strlen(description) + 1,
+ buf, size);
+ if (err && !error_displayed)
+ {
+ error_displayed++;
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ "2HASH-EXT-LOG failed: Firmware is likely too old.\n");
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
+ const char *description)
+{
+ grub_err_t err = tpm_init();
+
+ /* Absence of a TPM isn't a failure. */
+ if (err != GRUB_ERR_NONE)
+ return GRUB_ERR_NONE;
+
+ grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n",
+ pcr, size, description);
+
+ if (tpm_version == 2)
+ return tpm2_log_event (buf, size, pcr, description);
+
+ return GRUB_ERR_NONE;
+}
diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
index 131808d619..87b9f95d34 100644
--- a/include/grub/ieee1275/ieee1275.h
+++ b/include/grub/ieee1275/ieee1275.h
@@ -24,6 +24,9 @@
#include <grub/types.h>
#include <grub/machine/ieee1275.h>
+#define GRUB_IEEE1275_CELL_FALSE ((grub_ieee1275_cell_t) 0)
+#define GRUB_IEEE1275_CELL_TRUE ((grub_ieee1275_cell_t) -1)
+
struct grub_ieee1275_mem_region
{
unsigned int start;

View File

@ -0,0 +1,94 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Stefan Berger <stefanb@linux.vnet.ibm.com>
Date: Fri, 11 Feb 2022 16:34:23 -0500
Subject: [PATCH] ibmvtpm: Backport ibmvtpm support to grub 2.02
Backport ibmvtpm support to grub 2.02 by making as few changes to the
source as possible and building it into the core.
Since ibmvtpm support is built into grub 2.02 do not print the error
message we would typically print if it was a module and the user had
a choice to not use vTPM support if there was no vTPM by avoiding
to use the module.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
---
grub-core/Makefile.core.def | 8 +-------
grub-core/commands/ieee1275/ibmvtpm.c | 13 ++++++++++---
include/grub/tpm.h | 2 +-
3 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index b11f74e6b2..637d7203e3 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -298,6 +298,7 @@ kernel = {
powerpc_ieee1275 = kern/powerpc/cache.S;
powerpc_ieee1275 = kern/powerpc/dl.c;
powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
+ powerpc_ieee1275 = commands/ieee1275/ibmvtpm.c;
sparc64_ieee1275 = kern/sparc64/cache.S;
sparc64_ieee1275 = kern/sparc64/dl.c;
@@ -1104,13 +1105,6 @@ module = {
enable = powerpc_ieee1275;
};
-module = {
- name = tpm;
- common = commands/tpm.c;
- ieee1275 = commands/ieee1275/ibmvtpm.c;
- enable = powerpc_ieee1275;
-};
-
module = {
name = terminal;
common = commands/terminal.c;
diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
index e68b8448bc..728b2cbdcd 100644
--- a/grub-core/commands/ieee1275/ibmvtpm.c
+++ b/grub-core/commands/ieee1275/ibmvtpm.c
@@ -115,7 +115,8 @@ tpm2_log_event (unsigned char *buf,
grub_size_t size, grub_uint8_t pcr,
const char *description)
{
- static int error_displayed = 0;
+ /* Do not print error since vTPM support is built-in */
+ static int error_displayed = 1;
int err;
err = ibmvtpm_2hash_ext_log (pcr, EV_IPL,
@@ -132,8 +133,8 @@ tpm2_log_event (unsigned char *buf,
return GRUB_ERR_NONE;
}
-grub_err_t
-grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
+static grub_err_t
+_grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
const char *description)
{
grub_err_t err = tpm_init();
@@ -150,3 +151,9 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
return GRUB_ERR_NONE;
}
+
+grub_err_t grub_tpm_log_event(unsigned char *buf, grub_size_t size,
+ grub_uint8_t pcr, const char *description)
+{
+ return _grub_tpm_measure(buf, size, pcr, description);
+}
diff --git a/include/grub/tpm.h b/include/grub/tpm.h
index ce52be4ff7..52af2b8448 100644
--- a/include/grub/tpm.h
+++ b/include/grub/tpm.h
@@ -69,7 +69,7 @@ typedef struct {
grub_err_t EXPORT_FUNC(grub_tpm_measure) (unsigned char *buf, grub_size_t size,
grub_uint8_t pcr, const char *kind,
const char *description);
-#if defined (GRUB_MACHINE_EFI)
+#if defined (GRUB_MACHINE_EFI) || defined (GRUB_MACHINE_IEEE1275)
grub_err_t grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
PassThroughToTPM_OutputParamBlock *outbuf);
grub_err_t grub_tpm_log_event(unsigned char *buf, grub_size_t size,

View File

@ -0,0 +1,112 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Fri, 8 Apr 2022 12:35:28 +1000
Subject: [PATCH] powerpc: do CAS in a more compatible way
I wrongly assumed that the most compatible way to perform CAS
negotiation was to only set the minimum number of vectors required
to ask for more memory. It turns out that this messes up booting
if the minimum VP capacity would be less than the default 10% in
vector 4.
Linux configures the minimum capacity to be 1%, so copy it for that
and for vector 3 which we now need to specify as well.
Signed-off-by: Daniel Axtens <dja@axtens.net>
(cherry picked from commit e6f02ad4e75cd995a8ee2954d28949c415b6cbfe)
(cherry picked from commit 9f825ebc319c56ca503741e6dc1a0f27ff36fe2d)
---
grub-core/kern/ieee1275/init.c | 54 ++++++++++++++++++++++++------------------
1 file changed, 31 insertions(+), 23 deletions(-)
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index adf4bd5a88..1414695cc6 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -294,33 +294,37 @@ grub_ieee1275_total_mem (grub_uint64_t *total)
/* Based on linux - arch/powerpc/kernel/prom_init.c */
struct option_vector2 {
- grub_uint8_t byte1;
- grub_uint16_t reserved;
- grub_uint32_t real_base;
- grub_uint32_t real_size;
- grub_uint32_t virt_base;
- grub_uint32_t virt_size;
- grub_uint32_t load_base;
- grub_uint32_t min_rma;
- grub_uint32_t min_load;
- grub_uint8_t min_rma_percent;
- grub_uint8_t max_pft_size;
+ grub_uint8_t byte1;
+ grub_uint16_t reserved;
+ grub_uint32_t real_base;
+ grub_uint32_t real_size;
+ grub_uint32_t virt_base;
+ grub_uint32_t virt_size;
+ grub_uint32_t load_base;
+ grub_uint32_t min_rma;
+ grub_uint32_t min_load;
+ grub_uint8_t min_rma_percent;
+ grub_uint8_t max_pft_size;
} __attribute__((packed));
struct pvr_entry {
- grub_uint32_t mask;
- grub_uint32_t entry;
+ grub_uint32_t mask;
+ grub_uint32_t entry;
};
struct cas_vector {
- struct {
- struct pvr_entry terminal;
- } pvr_list;
- grub_uint8_t num_vecs;
- grub_uint8_t vec1_size;
- grub_uint8_t vec1;
- grub_uint8_t vec2_size;
- struct option_vector2 vec2;
+ struct {
+ struct pvr_entry terminal;
+ } pvr_list;
+ grub_uint8_t num_vecs;
+ grub_uint8_t vec1_size;
+ grub_uint8_t vec1;
+ grub_uint8_t vec2_size;
+ struct option_vector2 vec2;
+ grub_uint8_t vec3_size;
+ grub_uint16_t vec3;
+ grub_uint8_t vec4_size;
+ grub_uint16_t vec4;
} __attribute__((packed));
/* Call ibm,client-architecture-support to try to get more RMA.
@@ -341,13 +345,17 @@ grub_ieee1275_ibm_cas (void)
} args;
struct cas_vector vector = {
.pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */
- .num_vecs = 2 - 1,
+ .num_vecs = 4 - 1,
.vec1_size = 0,
.vec1 = 0x80, /* ignore */
.vec2_size = 1 + sizeof(struct option_vector2) - 2,
.vec2 = {
0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48
},
+ .vec3_size = 2 - 1,
+ .vec3 = 0x00e0, // ask for FP + VMX + DFP but don't halt if unsatisfied
+ .vec4_size = 2 - 1,
+ .vec4 = 0x0001, // set required minimum capacity % to the lowest value
};
INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2);
@@ -360,7 +368,7 @@ grub_ieee1275_ibm_cas (void)
args.ihandle = root;
args.cas_addr = (grub_ieee1275_cell_t)&vector;
- grub_printf("Calling ibm,client-architecture-support...");
+ grub_printf("Calling ibm,client-architecture-support from grub...");
IEEE1275_CALL_ENTRY_FN (&args);
grub_printf("done\n");

View File

@ -0,0 +1,73 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Thu, 24 Mar 2022 14:34:32 +1100
Subject: [PATCH] powerpc: prefix detection: support device names with commas
Frustratingly, the device name itself can contain an embedded comma:
e.g /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b
So my previous approach was wrong: we cannot rely upon the presence
of a comma to say that a partition has been specified!
It turns out for prefixes like (,gpt2)/grub2 we really want to make
up a full (device,partition)/patch prefix, because root discovery code
in 10_linux will reset the root variable and use search to fill it again.
If you have run grub-install, you probably don't have search built in,
and if you don't have prefix containing (device,partition), grub will
construct ($root)$prefix/powerpc-ieee1275/search.mod - but because $root
has just been changed, this will no longer work, and the boot will fail!
Retain the gist of the logic, but instead of looking for a comma, look for
a leading '('. This matches the earlier code better anyway.
There's certainly a better fix to be had. But any time you chose to build
with a bare prefix like '/grub2', you're almost certainly going to build in
search anyway, so this will do.
Signed-off-by: Daniel Axtens <dja@axtens.net>
(cherry picked from commit 80b6eb5e55e6d1a4c9896361e61de31c29e6939d)
(cherry picked from commit f3df9f1c2335df22d020e80583d932e254594f0e)
---
grub-core/kern/main.c | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)
diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
index 40a709117f..abbf8af9e6 100644
--- a/grub-core/kern/main.c
+++ b/grub-core/kern/main.c
@@ -241,14 +241,29 @@ grub_set_prefix_and_root (void)
what sorts of paths represent disks with partition tables and those
without partition tables.
- So we act unless there is a comma in the device, which would indicate
- a partition has already been specified.
+ - Frustratingly, the device name itself can contain an embedded comma:
+ /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b
+ So we cannot even rely upon the presence of a comma to say that a
+ partition has been specified!
- (If we only have a path, the code in normal to discover config files
- will try both without partitions and then with any partitions so we
- will cover both CDs and HDs.)
+ If we only have a path in $prefix, the code in normal to discover
+ config files will try all disks, both without partitions and then with
+ any partitions so we will cover both CDs and HDs.
+
+ However, it doesn't then set the prefix to be something like
+ (discovered partition)/path, and so it is fragile against runtime
+ changes to $root. For example some of the stuff done in 10_linux to
+ reload $root sets root differently and then uses search to find it
+ again. If the search module is not built in, when we change root, grub
+ will look in (new root)/path/powerpc-ieee1275, that won't work, and we
+ will not be able to load the search module and the boot will fail.
+
+ This is particularly likely to hit us in the grub-install
+ (,msdos2)/grub2 case, so we act unless the supplied prefix starts with
+ '(', which would likely indicate a partition has already been
+ specified.
*/
- if (grub_strchr (device, ',') == NULL)
+ if (prefix && prefix[0] != '(')
grub_env_set ("prefix", path);
else
#endif

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Diego Domingos <diegdo@br.ibm.com>
Date: Thu, 24 Mar 2022 13:14:42 -0400
Subject: [PATCH] make ofdisk_retries optional
The feature Retry on Fail added to GRUB can cause a LPM to take
longer if the SAN is slow.
When a LPM to external site occur, the path of the disk can change
and thus the disk search function on grub can take some time since
it is used as a hint. This can cause the Retry on Fail feature to
try to access the disk 20x times (since this is hardcoded number)
and, if the SAN is slow, the boot time can increase a lot.
In some situations not acceptable.
The following patch enables a configuration at user space of the
maximum number of retries we want for this feature.
The variable ofdisk_retries should be set using grub2-editenv
and will be checked by retry function. If the variable is not set,
so the default number of retries will be used instead.
---
include/grub/ieee1275/ofdisk.h | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/include/grub/ieee1275/ofdisk.h b/include/grub/ieee1275/ofdisk.h
index 7d2d540930..0074d55eee 100644
--- a/include/grub/ieee1275/ofdisk.h
+++ b/include/grub/ieee1275/ofdisk.h
@@ -25,7 +25,12 @@ extern void grub_ofdisk_fini (void);
#define MAX_RETRIES 20
-#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) unsigned retry_i=0;for(retry_i=0; retry_i < MAX_RETRIES; retry_i++){ \
+#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) \
+ unsigned max_retries = MAX_RETRIES; \
+ if(grub_env_get("ofdisk_retries") != NULL) \
+ max_retries = grub_strtoul(grub_env_get("ofdisk_retries"), 0, 10)+1; \
+ grub_dprintf("ofdisk","MAX_RETRIES set to %u\n",max_retries); \
+ unsigned retry_i=0;for(retry_i=0; retry_i < max_retries; retry_i++){ \
if(!grub_ieee1275_open(device, last_ihandle)) \
break; \
grub_dprintf("ofdisk","Opening disk %s failed. Retrying...\n",device); }

View File

@ -0,0 +1,71 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Thu, 28 Apr 2022 21:53:36 +0100
Subject: [PATCH] loader/efi/chainloader: grub_load_and_start_image doesn't
load and start
grub_load_and_start_image only loads an image - it still requires the
caller to start it. This renames it to grub_load_image.
It's called from 2 places:
- grub_cmd_chainloader when not using the shim protocol.
- grub_secureboot_chainloader_boot if handle_image returns an error.
In this case, the image is loaded and then nothing else happens which
seems strange. I assume the intention is that it falls back to LoadImage
and StartImage if handle_image fails, so I've made it do that.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit b4d70820a65c00561045856b7b8355461a9545f6)
(cherry picked from commit 05b16a6be50b1910609740a66b561276fa490538)
(cherry picked from commit 16486a34f3aa41a94e334e86db1a1e21e9b0a45f)
---
grub-core/loader/efi/chainloader.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 29663f7180..d75d345003 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -835,7 +835,7 @@ grub_secureboot_chainloader_unload (void)
}
static grub_err_t
-grub_load_and_start_image(void *boot_image)
+grub_load_image(void *boot_image)
{
grub_efi_boot_services_t *b;
grub_efi_status_t status;
@@ -877,13 +877,23 @@ grub_load_and_start_image(void *boot_image)
static grub_err_t
grub_secureboot_chainloader_boot (void)
{
+ grub_efi_boot_services_t *b;
int rc;
+
rc = handle_image ((void *)(unsigned long)address, fsize);
if (rc == 0)
{
- grub_load_and_start_image((void *)(unsigned long)address);
+ /* We weren't able to attempt to execute the image, so fall back
+ * to LoadImage / StartImage.
+ */
+ rc = grub_load_image((void *)(unsigned long)address);
+ if (rc == 0)
+ grub_chainloader_boot ();
}
+ b = grub_efi_system_table->boot_services;
+ efi_call_1 (b->unload_image, image_handle);
+
grub_loader_unset ();
return grub_errno;
}
@@ -1072,7 +1082,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
}
else if (rc == 0)
{
- grub_load_and_start_image(boot_image);
+ grub_load_image(boot_image);
grub_file_close (file);
grub_device_close (dev);
grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);

View File

@ -0,0 +1,334 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Fri, 29 Apr 2022 21:13:08 +0100
Subject: [PATCH] loader/efi/chainloader: simplify the loader state
When not using the shim lock protocol, the chainloader command retains
the source buffer and device path passed to LoadImage, requiring the
unload hook passed to grub_loader_set to free them. It isn't required
to retain this state though - they aren't required by StartImage or
anything else in the boot hook, so clean them up before
grub_cmd_chainloader finishes.
This also wraps the loader state when using the shim lock protocol
inside a struct.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit fa39862933b3be1553a580a3a5c28073257d8046)
(cherry picked from commit 0333343ee99c4e88f062789263c94291c057251b)
[rharwood: verifying twice]
(cherry picked from commit 6080ad5d91d6a80d5f67c592dd33b6dd413e9453)
[rharwood: double frees and unintialized, context fuzz - orig_dp]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
---
grub-core/loader/efi/chainloader.c | 160 +++++++++++++++++++++++--------------
1 file changed, 102 insertions(+), 58 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index d75d345003..afeb1fc97e 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -47,38 +47,21 @@ GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
-static grub_efi_physical_address_t address;
-static grub_efi_uintn_t pages;
-static grub_ssize_t fsize;
-static grub_efi_device_path_t *file_path;
static grub_efi_handle_t image_handle;
-static grub_efi_char16_t *cmdline;
-static grub_ssize_t cmdline_len;
-static grub_efi_handle_t dev_handle;
-static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
+struct grub_secureboot_chainloader_context {
+ grub_efi_physical_address_t address;
+ grub_efi_uintn_t pages;
+ grub_ssize_t fsize;
+ grub_efi_device_path_t *file_path;
+ grub_efi_char16_t *cmdline;
+ grub_ssize_t cmdline_len;
+ grub_efi_handle_t dev_handle;
+};
+static struct grub_secureboot_chainloader_context *sb_context;
static grub_err_t
-grub_chainloader_unload (void)
-{
- grub_efi_boot_services_t *b;
-
- b = grub_efi_system_table->boot_services;
- efi_call_1 (b->unload_image, image_handle);
- grub_efi_free_pages (address, pages);
-
- grub_free (file_path);
- grub_free (cmdline);
- cmdline = 0;
- file_path = 0;
- dev_handle = 0;
-
- grub_dl_unref (my_mod);
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_chainloader_boot (void)
+grub_start_image (grub_efi_handle_t handle)
{
grub_efi_boot_services_t *b;
grub_efi_status_t status;
@@ -86,7 +69,7 @@ grub_chainloader_boot (void)
grub_efi_char16_t *exit_data = NULL;
b = grub_efi_system_table->boot_services;
- status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
+ status = efi_call_3 (b->start_image, handle, &exit_data_size, &exit_data);
if (status != GRUB_EFI_SUCCESS)
{
if (exit_data)
@@ -110,11 +93,37 @@ grub_chainloader_boot (void)
if (exit_data)
grub_efi_free_pool (exit_data);
- grub_loader_unset ();
-
return grub_errno;
}
+static grub_err_t
+grub_chainloader_unload (void)
+{
+ grub_efi_loaded_image_t *loaded_image;
+ grub_efi_boot_services_t *b;
+
+ loaded_image = grub_efi_get_loaded_image (image_handle);
+ if (loaded_image != NULL)
+ grub_free (loaded_image->load_options);
+
+ b = grub_efi_system_table->boot_services;
+ efi_call_1 (b->unload_image, image_handle);
+
+ grub_dl_unref (my_mod);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_chainloader_boot (void)
+{
+ grub_err_t err;
+
+ err = grub_start_image (image_handle);
+
+ grub_loader_unset ();
+ return err;
+}
+
static grub_err_t
copy_file_path (grub_efi_file_path_device_path_t *fp,
const char *str, grub_efi_uint16_t len)
@@ -149,7 +158,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
char *dir_start;
char *dir_end;
grub_size_t size;
- grub_efi_device_path_t *d;
+ grub_efi_device_path_t *d, *file_path;
dir_start = grub_strchr (filename, ')');
if (! dir_start)
@@ -520,10 +529,12 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp)
}
static grub_efi_boolean_t
-handle_image (void *data, grub_efi_uint32_t datasize)
+handle_image (struct grub_secureboot_chainloader_context *load_context)
{
grub_efi_loaded_image_t *li, li_bak;
grub_efi_status_t efi_status;
+ void *data = (void *)(unsigned long)load_context->address;
+ grub_efi_uint32_t datasize = load_context->fsize;
void *buffer = NULL;
char *buffer_aligned = NULL;
grub_efi_uint32_t i;
@@ -534,6 +545,7 @@ handle_image (void *data, grub_efi_uint32_t datasize)
grub_uint32_t buffer_size;
int found_entry_point = 0;
int rc;
+ grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
rc = read_header (data, datasize, &context);
if (rc < 0)
@@ -791,10 +803,10 @@ handle_image (void *data, grub_efi_uint32_t datasize)
grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t));
li->image_base = buffer_aligned;
li->image_size = context.image_size;
- li->load_options = cmdline;
- li->load_options_size = cmdline_len;
- li->file_path = grub_efi_get_media_file_path (file_path);
- li->device_handle = dev_handle;
+ li->load_options = load_context->cmdline;
+ li->load_options_size = load_context->cmdline_len;
+ li->file_path = grub_efi_get_media_file_path (load_context->file_path);
+ li->device_handle = load_context->dev_handle;
if (!li->file_path)
{
grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found");
@@ -823,19 +835,22 @@ error_exit:
static grub_err_t
grub_secureboot_chainloader_unload (void)
{
- grub_efi_free_pages (address, pages);
- grub_free (file_path);
- grub_free (cmdline);
- cmdline = 0;
- file_path = 0;
- dev_handle = 0;
+ grub_efi_free_pages (sb_context->address, sb_context->pages);
+ grub_free (sb_context->file_path);
+ grub_free (sb_context->cmdline);
+ grub_free (sb_context);
+
+ sb_context = 0;
grub_dl_unref (my_mod);
return GRUB_ERR_NONE;
}
static grub_err_t
-grub_load_image(void *boot_image)
+grub_load_image(grub_efi_device_path_t *file_path, void *boot_image,
+ grub_efi_uintn_t image_size, grub_efi_handle_t dev_handle,
+ grub_efi_char16_t *cmdline, grub_ssize_t cmdline_len,
+ grub_efi_handle_t *image_handle_out)
{
grub_efi_boot_services_t *b;
grub_efi_status_t status;
@@ -844,7 +859,7 @@ grub_load_image(void *boot_image)
b = grub_efi_system_table->boot_services;
status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
- boot_image, fsize, &image_handle);
+ boot_image, image_size, image_handle_out);
if (status != GRUB_EFI_SUCCESS)
{
if (status == GRUB_EFI_OUT_OF_RESOURCES)
@@ -857,7 +872,7 @@ grub_load_image(void *boot_image)
/* LoadImage does not set a device handler when the image is
loaded from memory, so it is necessary to set it explicitly here.
This is a mess. */
- loaded_image = grub_efi_get_loaded_image (image_handle);
+ loaded_image = grub_efi_get_loaded_image (*image_handle_out);
if (! loaded_image)
{
grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
@@ -879,20 +894,25 @@ grub_secureboot_chainloader_boot (void)
{
grub_efi_boot_services_t *b;
int rc;
+ grub_efi_handle_t handle = 0;
- rc = handle_image ((void *)(unsigned long)address, fsize);
+ rc = handle_image (sb_context);
if (rc == 0)
{
/* We weren't able to attempt to execute the image, so fall back
* to LoadImage / StartImage.
*/
- rc = grub_load_image((void *)(unsigned long)address);
+ rc = grub_load_image(sb_context->file_path,
+ (void *)(unsigned long)sb_context->address,
+ sb_context->fsize, sb_context->dev_handle,
+ sb_context->cmdline, sb_context->cmdline_len,
+ &handle);
if (rc == 0)
- grub_chainloader_boot ();
+ grub_start_image (handle);
}
b = grub_efi_system_table->boot_services;
- efi_call_1 (b->unload_image, image_handle);
+ efi_call_1 (b->unload_image, handle);
grub_loader_unset ();
return grub_errno;
@@ -906,10 +926,16 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_efi_status_t status;
grub_efi_boot_services_t *b;
grub_device_t dev = 0;
- grub_efi_device_path_t *dp = 0;
+ grub_efi_device_path_t *dp = 0, *file_path = 0;
char *filename;
void *boot_image = 0;
int rc;
+ grub_efi_physical_address_t address = 0;
+ grub_ssize_t fsize;
+ grub_efi_uintn_t pages = 0;
+ grub_efi_char16_t *cmdline = 0;
+ grub_ssize_t cmdline_len = 0;
+ grub_efi_handle_t dev_handle = 0;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
@@ -917,12 +943,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_dl_ref (my_mod);
- /* Initialize some global variables. */
- address = 0;
- image_handle = 0;
- file_path = 0;
- dev_handle = 0;
-
b = grub_efi_system_table->boot_services;
if (argc > 1)
@@ -1074,17 +1094,35 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc);
if (rc > 0)
{
+ sb_context = grub_malloc (sizeof (*sb_context));
+ if (sb_context == NULL)
+ goto fail;
+ sb_context->address = address;
+ sb_context->fsize = fsize;
+ sb_context->pages = pages;
+ sb_context->file_path = file_path;
+ sb_context->cmdline = cmdline;
+ sb_context->cmdline_len = cmdline_len;
+ sb_context->dev_handle = dev_handle;
+
grub_file_close (file);
grub_device_close (dev);
+
grub_loader_set (grub_secureboot_chainloader_boot,
grub_secureboot_chainloader_unload, 0);
return 0;
}
else if (rc == 0)
{
- grub_load_image(boot_image);
+ grub_load_image(file_path, boot_image, fsize, dev_handle, cmdline,
+ cmdline_len, &image_handle);
grub_file_close (file);
grub_device_close (dev);
+
+ /* We're finished with the source image buffer and file path now */
+ efi_call_2 (b->free_pages, address, pages);
+ grub_free (file_path);
+
grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
return 0;
@@ -1106,6 +1144,12 @@ fail:
if (cmdline)
grub_free (cmdline);
+ if (image_handle != 0)
+ {
+ efi_call_1 (b->unload_image, image_handle);
+ image_handle = 0;
+ }
+
grub_dl_unref (my_mod);
return grub_errno;

View File

@ -0,0 +1,160 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Fri, 29 Apr 2022 21:16:02 +0100
Subject: [PATCH] commands/boot: Add API to pass context to loader
Loaders rely on global variables for saving context which is consumed
in the boot hook and freed in the unload hook. In the case where a loader
command is executed twice, calling grub_loader_set a second time executes
the unload hook, but in some cases this runs when the loader's global
context has already been updated, resulting in the updated context being
freed and potential use-after-free bugs when the boot hook is subsequently
called.
This adds a new API (grub_loader_set_ex) which allows a loader to specify
context that is passed to its boot and unload hooks. This is an alternative
to requiring that loaders call grub_loader_unset before mutating their
global context.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit 4322a64dde7e8fedb58e50b79408667129d45dd3)
(cherry picked from commit 937ad0e2159b6b8cb0d2ce3515da3a8b797c7927)
(cherry picked from commit 873038ae7048f6cae8a3ebb2f97a8d361a080e13)
---
grub-core/commands/boot.c | 66 +++++++++++++++++++++++++++++++++++++++++------
include/grub/loader.h | 5 ++++
2 files changed, 63 insertions(+), 8 deletions(-)
diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c
index bbca81e947..53691a62d9 100644
--- a/grub-core/commands/boot.c
+++ b/grub-core/commands/boot.c
@@ -27,10 +27,20 @@
GRUB_MOD_LICENSE ("GPLv3+");
-static grub_err_t (*grub_loader_boot_func) (void);
-static grub_err_t (*grub_loader_unload_func) (void);
+static grub_err_t (*grub_loader_boot_func) (void *);
+static grub_err_t (*grub_loader_unload_func) (void *);
+static void *grub_loader_context;
static int grub_loader_flags;
+struct grub_simple_loader_hooks
+{
+ grub_err_t (*boot) (void);
+ grub_err_t (*unload) (void);
+};
+
+/* Don't heap allocate this to avoid making grub_loader_set fallible. */
+static struct grub_simple_loader_hooks simple_loader_hooks;
+
struct grub_preboot
{
grub_err_t (*preboot_func) (int);
@@ -44,6 +54,29 @@ static int grub_loader_loaded;
static struct grub_preboot *preboots_head = 0,
*preboots_tail = 0;
+static grub_err_t
+grub_simple_boot_hook (void *context)
+{
+ struct grub_simple_loader_hooks *hooks;
+
+ hooks = (struct grub_simple_loader_hooks *) context;
+ return hooks->boot ();
+}
+
+static grub_err_t
+grub_simple_unload_hook (void *context)
+{
+ struct grub_simple_loader_hooks *hooks;
+ grub_err_t ret;
+
+ hooks = (struct grub_simple_loader_hooks *) context;
+
+ ret = hooks->unload ();
+ grub_memset (hooks, 0, sizeof (*hooks));
+
+ return ret;
+}
+
int
grub_loader_is_loaded (void)
{
@@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd)
}
void
-grub_loader_set (grub_err_t (*boot) (void),
- grub_err_t (*unload) (void),
- int flags)
+grub_loader_set_ex (grub_err_t (*boot) (void *),
+ grub_err_t (*unload) (void *),
+ void *context,
+ int flags)
{
if (grub_loader_loaded && grub_loader_unload_func)
- grub_loader_unload_func ();
+ grub_loader_unload_func (grub_loader_context);
grub_loader_boot_func = boot;
grub_loader_unload_func = unload;
+ grub_loader_context = context;
grub_loader_flags = flags;
grub_loader_loaded = 1;
}
+void
+grub_loader_set (grub_err_t (*boot) (void),
+ grub_err_t (*unload) (void),
+ int flags)
+{
+ grub_loader_set_ex (grub_simple_boot_hook,
+ grub_simple_unload_hook,
+ &simple_loader_hooks,
+ flags);
+
+ simple_loader_hooks.boot = boot;
+ simple_loader_hooks.unload = unload;
+}
+
void
grub_loader_unset(void)
{
if (grub_loader_loaded && grub_loader_unload_func)
- grub_loader_unload_func ();
+ grub_loader_unload_func (grub_loader_context);
grub_loader_boot_func = 0;
grub_loader_unload_func = 0;
+ grub_loader_context = 0;
grub_loader_loaded = 0;
}
@@ -158,7 +208,7 @@ grub_loader_boot (void)
return err;
}
}
- err = (grub_loader_boot_func) ();
+ err = (grub_loader_boot_func) (grub_loader_context);
for (cur = preboots_tail; cur; cur = cur->prev)
if (! err)
diff --git a/include/grub/loader.h b/include/grub/loader.h
index b208642821..1846fa6c5f 100644
--- a/include/grub/loader.h
+++ b/include/grub/loader.h
@@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void),
grub_err_t (*unload) (void),
int flags);
+void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *),
+ grub_err_t (*unload) (void *),
+ void *context,
+ int flags);
+
/* Unset current loader, if any. */
void EXPORT_FUNC (grub_loader_unset) (void);

View File

@ -0,0 +1,149 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Fri, 29 Apr 2022 21:30:56 +0100
Subject: [PATCH] loader/efi/chainloader: Use grub_loader_set_ex
This ports the EFI chainloader to use grub_loader_set_ex in order to fix
a use-after-free bug that occurs when grub_cmd_chainloader is executed
more than once before a boot attempt is performed.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit 4b7f0402b7cb0f67a93be736f2b75b818d7f44c9)
(cherry picked from commit fc1a79bf0e0bc019362ace46d908a92b48dcd55b)
(cherry picked from commit f5b653dfe00271384ff7fbd82db926ab95dbd80e)
[rharwood: context sludge from previous commit]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
---
grub-core/loader/efi/chainloader.c | 38 ++++++++++++++++++++++----------------
1 file changed, 22 insertions(+), 16 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index afeb1fc97e..720f6181e5 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -47,8 +47,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
-static grub_efi_handle_t image_handle;
-
struct grub_secureboot_chainloader_context {
grub_efi_physical_address_t address;
grub_efi_uintn_t pages;
@@ -58,7 +56,6 @@ struct grub_secureboot_chainloader_context {
grub_ssize_t cmdline_len;
grub_efi_handle_t dev_handle;
};
-static struct grub_secureboot_chainloader_context *sb_context;
static grub_err_t
grub_start_image (grub_efi_handle_t handle)
@@ -97,11 +94,14 @@ grub_start_image (grub_efi_handle_t handle)
}
static grub_err_t
-grub_chainloader_unload (void)
+grub_chainloader_unload (void *context)
{
+ grub_efi_handle_t image_handle;
grub_efi_loaded_image_t *loaded_image;
grub_efi_boot_services_t *b;
+ image_handle = (grub_efi_handle_t) context;
+
loaded_image = grub_efi_get_loaded_image (image_handle);
if (loaded_image != NULL)
grub_free (loaded_image->load_options);
@@ -114,10 +114,12 @@ grub_chainloader_unload (void)
}
static grub_err_t
-grub_chainloader_boot (void)
+grub_chainloader_boot (void *context)
{
+ grub_efi_handle_t image_handle;
grub_err_t err;
+ image_handle = (grub_efi_handle_t) context;
err = grub_start_image (image_handle);
grub_loader_unset ();
@@ -833,15 +835,17 @@ error_exit:
}
static grub_err_t
-grub_secureboot_chainloader_unload (void)
+grub_secureboot_chainloader_unload (void *context)
{
+ struct grub_secureboot_chainloader_context *sb_context;
+
+ sb_context = (struct grub_secureboot_chainloader_context *) context;
+
grub_efi_free_pages (sb_context->address, sb_context->pages);
grub_free (sb_context->file_path);
grub_free (sb_context->cmdline);
grub_free (sb_context);
- sb_context = 0;
-
grub_dl_unref (my_mod);
return GRUB_ERR_NONE;
}
@@ -890,12 +894,15 @@ grub_load_image(grub_efi_device_path_t *file_path, void *boot_image,
}
static grub_err_t
-grub_secureboot_chainloader_boot (void)
+grub_secureboot_chainloader_boot (void *context)
{
+ struct grub_secureboot_chainloader_context *sb_context;
grub_efi_boot_services_t *b;
int rc;
grub_efi_handle_t handle = 0;
+ sb_context = (struct grub_secureboot_chainloader_context *) context;
+
rc = handle_image (sb_context);
if (rc == 0)
{
@@ -936,6 +943,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_efi_char16_t *cmdline = 0;
grub_ssize_t cmdline_len = 0;
grub_efi_handle_t dev_handle = 0;
+ grub_efi_handle_t image_handle = 0;
+ struct grub_secureboot_chainloader_context *sb_context = 0;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
@@ -1108,8 +1117,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
grub_file_close (file);
grub_device_close (dev);
- grub_loader_set (grub_secureboot_chainloader_boot,
- grub_secureboot_chainloader_unload, 0);
+ grub_loader_set_ex (grub_secureboot_chainloader_boot,
+ grub_secureboot_chainloader_unload, sb_context, 0);
return 0;
}
else if (rc == 0)
@@ -1123,7 +1132,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
efi_call_2 (b->free_pages, address, pages);
grub_free (file_path);
- grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
+ grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0);
return 0;
}
@@ -1145,10 +1154,7 @@ fail:
grub_free (cmdline);
if (image_handle != 0)
- {
- efi_call_1 (b->unload_image, image_handle);
- image_handle = 0;
- }
+ efi_call_1 (b->unload_image, image_handle);
grub_dl_unref (my_mod);

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Mon, 2 May 2022 14:39:31 +0200
Subject: [PATCH] loader/i386/efi/linux: Avoid a use-after-free in the linuxefi
loader
In some error paths in grub_cmd_linux, the pointer to lh may be
dereferenced after the buffer it points to has been freed. There aren't
any security implications from this because nothing else uses the
allocator after the buffer is freed and before the pointer is
dereferenced, but fix it anyway.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit 8224f5a71af94bec8697de17e7e579792db9f9e2)
(cherry picked from commit 4744b62e20d07674017213ac54d7442d679f9d1a)
(cherry picked from commit 329633cb060957c3d2aca677ac733f07b213a63f)
---
grub-core/loader/i386/efi/linux.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index a043df891f..c9a2b47370 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -482,9 +482,6 @@ fail:
if (file)
grub_file_close (file);
- if (kernel)
- grub_free (kernel);
-
if (grub_errno != GRUB_ERR_NONE)
{
grub_dl_unref (my_mod);
@@ -500,6 +497,8 @@ fail:
kernel_free (params, sizeof(*params));
}
+ grub_free (kernel);
+
return grub_errno;
}

View File

@ -0,0 +1,299 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Mon, 2 May 2022 17:04:23 +0200
Subject: [PATCH] loader/i386/efi/linux: Use grub_loader_set_ex
This ports the linuxefi loader to use grub_loader_set_ex in order to fix
a use-after-fre bug that occurs when grub_cmd_linux is executed more than
once before a boot attempt is performed.
This is more complicated than for the chainloader command, as the initrd
command needs access to the loader state. To solve this, the linuxefi
module registers a dummy initrd command at startup that returns an error.
The linuxefi command then registers a proper initrd command with a higher
priority that is passed the loader state.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit 7cf736436b4c934df5ddfa6f44b46a7e07d99fdc)
[rharwood/pjones: set kernel_size in context]
(cherry picked from commit 9c056391f7a36ea480de9a759c12e55a90f2040a)
[rharwood: verifying twice]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit df804892f1a754d88a9779320f9429bf40d2a1b3)
---
grub-core/loader/i386/efi/linux.c | 146 +++++++++++++++++++++++---------------
1 file changed, 87 insertions(+), 59 deletions(-)
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index c9a2b47370..77a0734786 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -34,13 +34,19 @@
GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
-static int loaded;
-static void *kernel_mem;
-static grub_uint64_t kernel_size;
-static void *initrd_mem;
-static grub_uint32_t handover_offset;
-struct linux_kernel_params *params;
-static char *linux_cmdline;
+
+static grub_command_t cmd_linux, cmd_initrd;
+static grub_command_t cmd_linuxefi, cmd_initrdefi;
+
+struct grub_linuxefi_context {
+ void *kernel_mem;
+ grub_uint64_t kernel_size;
+ grub_uint32_t handover_offset;
+ struct linux_kernel_params *params;
+ char *cmdline;
+
+ void *initrd_mem;
+};
#define MIN(a, b) \
({ typeof (a) _a = (a); \
@@ -123,25 +129,32 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
}
static grub_err_t
-grub_linuxefi_boot (void)
+grub_linuxefi_boot (void *data)
{
+ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data;
+
asm volatile ("cli");
- return grub_efi_linux_boot ((char *)kernel_mem,
- handover_offset,
- params);
+ return grub_efi_linux_boot ((char *)context->kernel_mem,
+ context->handover_offset,
+ context->params);
}
static grub_err_t
-grub_linuxefi_unload (void)
+grub_linuxefi_unload (void *data)
{
+ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data;
+ struct linux_kernel_params *params = context->params;
+
grub_dl_unref (my_mod);
- loaded = 0;
- 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));
+ kernel_free (context->initrd_mem, params->ramdisk_size);
+ kernel_free (context->cmdline, params->cmdline_size + 1);
+ kernel_free (context->kernel_mem, context->kernel_size);
+ kernel_free (params, sizeof(*params));
+ cmd_initrd->data = 0;
+ cmd_initrdefi->data = 0;
+ grub_free (context);
return GRUB_ERR_NONE;
}
@@ -188,13 +201,14 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len)
#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[])
+grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
{
grub_file_t *files = 0;
int i, nfiles = 0;
grub_size_t size = 0;
grub_uint8_t *ptr;
+ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data;
+ struct linux_kernel_params *params;
if (argc == 0)
{
@@ -202,12 +216,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
- if (!loaded)
+ if (!context)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
goto fail;
}
+ params = context->params;
+
files = grub_calloc (argc, sizeof (files[0]));
if (!files)
goto fail;
@@ -226,19 +242,19 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
}
}
- initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
- if (initrd_mem == NULL)
+ context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
+ if (context->initrd_mem == NULL)
goto fail;
- grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
+ grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem);
params->ramdisk_size = LOW_U32(size);
- params->ramdisk_image = LOW_U32(initrd_mem);
+ params->ramdisk_image = LOW_U32(context->initrd_mem);
#if defined(__x86_64__)
params->ext_ramdisk_size = HIGH_U32(size);
- params->ext_ramdisk_image = HIGH_U32(initrd_mem);
+ params->ext_ramdisk_image = HIGH_U32(context->initrd_mem);
#endif
- ptr = initrd_mem;
+ ptr = context->initrd_mem;
for (i = 0; i < nfiles; i++)
{
@@ -264,8 +280,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
grub_file_close (files[i]);
grub_free (files);
- if (initrd_mem && grub_errno)
- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem,
+ if (context->initrd_mem && grub_errno)
+ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem,
BYTES_TO_PAGES(size));
return grub_errno;
@@ -281,6 +297,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
void *kernel = NULL;
int setup_header_end_offset;
int rc;
+ void *kernel_mem = 0;
+ grub_uint64_t kernel_size = 0;
+ grub_uint32_t handover_offset;
+ struct linux_kernel_params *params = 0;
+ char *cmdline = 0;
+ struct grub_linuxefi_context *context = 0;
grub_dl_ref (my_mod);
@@ -407,27 +429,27 @@ 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 = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
- if (!linux_cmdline)
+ cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
+ if (!cmdline)
goto fail;
- grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline);
+ grub_dprintf ("linux", "cmdline = %p\n", cmdline);
- grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+ grub_memcpy (cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
grub_create_loader_cmdline (argc, argv,
- linux_cmdline + sizeof (LINUX_IMAGE) - 1,
+ cmdline + sizeof (LINUX_IMAGE) - 1,
lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1),
GRUB_VERIFY_KERNEL_CMDLINE);
- grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline);
+ grub_dprintf ("linux", "cmdline:%s\n", cmdline);
grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n",
- LOW_U32(linux_cmdline));
- lh->cmd_line_ptr = LOW_U32(linux_cmdline);
+ LOW_U32(cmdline));
+ lh->cmd_line_ptr = LOW_U32(cmdline);
#if defined(__x86_64__)
- if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull)
+ if ((grub_efi_uintn_t)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);
+ HIGH_U32(cmdline));
+ params->ext_cmd_line_ptr = HIGH_U32(cmdline);
}
#endif
@@ -452,16 +474,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
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"));
+ kernel_size = lh->init_size;
+ kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel"));
restore_addresses();
if (!kernel_mem)
goto fail;
grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem);
- grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
-
- loaded = 1;
-
grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n",
LOW_U32(kernel_mem));
lh->code32_start = LOW_U32(kernel_mem);
@@ -478,33 +497,42 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
"setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n",
params->ext_loader_type, params->ext_loader_ver);
+ context = grub_zalloc (sizeof (*context));
+ if (!context)
+ goto fail;
+ context->kernel_mem = kernel_mem;
+ context->kernel_size = kernel_size;
+ context->handover_offset = handover_offset;
+ context->params = params;
+ context->cmdline = cmdline;
+
+ grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0);
+
+ cmd_initrd->data = context;
+ cmd_initrdefi->data = context;
+
+ grub_file_close (file);
+ grub_free (kernel);
+ return 0;
+
fail:
if (file)
grub_file_close (file);
- if (grub_errno != GRUB_ERR_NONE)
- {
- grub_dl_unref (my_mod);
- loaded = 0;
- }
+ grub_dl_unref (my_mod);
- if (!loaded)
- {
- if (lh)
- kernel_free (linux_cmdline, lh->cmdline_size + 1);
+ if (lh)
+ kernel_free (cmdline, lh->cmdline_size + 1);
- kernel_free (kernel_mem, kernel_size);
- kernel_free (params, sizeof(*params));
- }
+ kernel_free (kernel_mem, kernel_size);
+ kernel_free (params, sizeof(*params));
+ grub_free (context);
grub_free (kernel);
return grub_errno;
}
-static grub_command_t cmd_linux, cmd_initrd;
-static grub_command_t cmd_linuxefi, cmd_initrdefi;
-
GRUB_MOD_INIT(linux)
{
cmd_linux =

View File

@ -0,0 +1,77 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Tue, 3 May 2022 09:47:35 +0200
Subject: [PATCH] loader/i386/efi/linux: Fix a memory leak in the initrd
command
Subsequent invocations of the initrd command result in the previous
initrd being leaked, so fix that.
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
(cherry picked from commit d98af31ce1e31bb22163960d53f5eb28c66582a0)
(cherry picked from commit 62234d6a00e6d1dd8e017ff161d359feb5234082)
(cherry picked from commit bda5a10716dc9676400dce1374232452f46d0bc4)
---
grub-core/loader/i386/efi/linux.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index 77a0734786..8337191921 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -209,6 +209,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
grub_uint8_t *ptr;
struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data;
struct linux_kernel_params *params;
+ void *initrd_mem = 0;
if (argc == 0)
{
@@ -242,19 +243,19 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
}
}
- context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
- if (context->initrd_mem == NULL)
+ initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
+ if (initrd_mem == NULL)
goto fail;
- grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem);
+ grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
params->ramdisk_size = LOW_U32(size);
- params->ramdisk_image = LOW_U32(context->initrd_mem);
+ params->ramdisk_image = LOW_U32(initrd_mem);
#if defined(__x86_64__)
params->ext_ramdisk_size = HIGH_U32(size);
- params->ext_ramdisk_image = HIGH_U32(context->initrd_mem);
+ params->ext_ramdisk_image = HIGH_U32(initrd_mem);
#endif
- ptr = context->initrd_mem;
+ ptr = initrd_mem;
for (i = 0; i < nfiles; i++)
{
@@ -273,6 +274,9 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
}
+ kernel_free(context->initrd_mem, params->ramdisk_size);
+
+ context->initrd_mem = initrd_mem;
params->ramdisk_size = size;
fail:
@@ -280,9 +284,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
grub_file_close (files[i]);
grub_free (files);
- if (context->initrd_mem && grub_errno)
- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem,
- BYTES_TO_PAGES(size));
+ if (initrd_mem && grub_errno)
+ kernel_free (initrd_mem, size);
return grub_errno;
}

View File

@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Fri, 25 Jun 2021 02:19:05 +1000
Subject: [PATCH] kern/file: Do not leak device_name on error in
grub_file_open()
If we have an error in grub_file_open() before we free device_name, we
will leak it.
Free device_name in the error path and null out the pointer in the good
path once we free it there.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 1499a5068839fa37cb77ecef4b5bdacbd1ed12ea)
(cherry picked from commit 2ec50b289d8b24922433439533113087f111f110)
(cherry picked from commit 17c36ae88d7d6040cabc01cd4a21e71ff4731668)
---
grub-core/kern/file.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
index 2efc31da94..f062fc21e7 100644
--- a/grub-core/kern/file.c
+++ b/grub-core/kern/file.c
@@ -81,6 +81,7 @@ grub_file_open (const char *name, enum grub_file_type type)
device = grub_device_open (device_name);
grub_free (device_name);
+ device_name = NULL;
if (! device)
goto fail;
@@ -135,6 +136,7 @@ grub_file_open (const char *name, enum grub_file_type type)
return file;
fail:
+ grub_free (device_name);
if (device)
grub_device_close (device);

View File

@ -0,0 +1,200 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 6 Jul 2021 14:02:55 +1000
Subject: [PATCH] video/readers/png: Abort sooner if a read operation fails
Fuzzing revealed some inputs that were taking a long time, potentially
forever, because they did not bail quickly upon encountering an I/O error.
Try to catch I/O errors sooner and bail out.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 882be97d1df6449b9fd4d593f0cb70005fde3494)
(cherry picked from commit 3f6fc3ebfd58fcdb3fe6c2f7a5a4fa05772ae786)
(cherry picked from commit aac5b8257d4078c3f764216aeae3367bdc19043f)
---
grub-core/video/readers/png.c | 55 ++++++++++++++++++++++++++++++++++++-------
1 file changed, 47 insertions(+), 8 deletions(-)
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index 0157ff7420..e2a6b1cf3c 100644
--- a/grub-core/video/readers/png.c
+++ b/grub-core/video/readers/png.c
@@ -142,6 +142,7 @@ static grub_uint8_t
grub_png_get_byte (struct grub_png_data *data)
{
grub_uint8_t r;
+ grub_ssize_t bytes_read = 0;
if ((data->inside_idat) && (data->idat_remain == 0))
{
@@ -175,7 +176,14 @@ grub_png_get_byte (struct grub_png_data *data)
}
r = 0;
- grub_file_read (data->file, &r, 1);
+ bytes_read = grub_file_read (data->file, &r, 1);
+
+ if (bytes_read != 1)
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "png: unexpected end of data");
+ return 0;
+ }
if (data->inside_idat)
data->idat_remain--;
@@ -231,15 +239,16 @@ grub_png_decode_image_palette (struct grub_png_data *data,
if (len == 0)
return GRUB_ERR_NONE;
- for (i = 0; 3 * i < len && i < 256; i++)
+ grub_errno = GRUB_ERR_NONE;
+ for (i = 0; 3 * i < len && i < 256 && grub_errno == GRUB_ERR_NONE; i++)
for (j = 0; j < 3; j++)
data->palette[i][j] = grub_png_get_byte (data);
- for (i *= 3; i < len; i++)
+ for (i *= 3; i < len && grub_errno == GRUB_ERR_NONE; i++)
grub_png_get_byte (data);
grub_png_get_dword (data);
- return GRUB_ERR_NONE;
+ return grub_errno;
}
static grub_err_t
@@ -256,9 +265,13 @@ grub_png_decode_image_header (struct grub_png_data *data)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size");
color_bits = grub_png_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
data->is_16bit = (color_bits == 16);
color_type = grub_png_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
/* According to PNG spec, no other types are valid. */
if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR))
@@ -340,14 +353,20 @@ grub_png_decode_image_header (struct grub_png_data *data)
if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: compression method not supported");
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: filter method not supported");
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (grub_png_get_byte (data) != PNG_INTERLACE_NONE)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: interlace method not supported");
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
/* Skip crc checksum. */
grub_png_get_dword (data);
@@ -449,7 +468,7 @@ grub_png_get_huff_code (struct grub_png_data *data, struct huff_table *ht)
int code, i;
code = 0;
- for (i = 0; i < ht->max_length; i++)
+ for (i = 0; i < ht->max_length && grub_errno == GRUB_ERR_NONE; i++)
{
code = (code << 1) + grub_png_get_bits (data, 1);
if (code < ht->maxval[i])
@@ -504,8 +523,14 @@ grub_png_init_dynamic_block (struct grub_png_data *data)
grub_uint8_t lens[DEFLATE_HCLEN_MAX];
nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) ||
(nb > DEFLATE_HCLEN_MAX))
@@ -533,7 +558,7 @@ grub_png_init_dynamic_block (struct grub_png_data *data)
data->dist_offset);
prev = 0;
- for (i = 0; i < nl + nd; i++)
+ for (i = 0; i < nl + nd && grub_errno == GRUB_ERR_NONE; i++)
{
int n, code;
struct huff_table *ht;
@@ -721,17 +746,21 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
len = cplens[n];
if (cplext[n])
len += grub_png_get_bits (data, cplext[n]);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
n = grub_png_get_huff_code (data, &data->dist_table);
dist = cpdist[n];
if (cpdext[n])
dist += grub_png_get_bits (data, cpdext[n]);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
pos = data->wp - dist;
if (pos < 0)
pos += WSIZE;
- while (len > 0)
+ while (len > 0 && grub_errno == GRUB_ERR_NONE)
{
data->slide[data->wp] = data->slide[pos];
grub_png_output_byte (data, data->slide[data->wp]);
@@ -759,7 +788,11 @@ grub_png_decode_image_data (struct grub_png_data *data)
int final;
cmf = grub_png_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
flg = grub_png_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if ((cmf & 0xF) != Z_DEFLATED)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
@@ -774,7 +807,11 @@ grub_png_decode_image_data (struct grub_png_data *data)
int block_type;
final = grub_png_get_bits (data, 1);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
block_type = grub_png_get_bits (data, 2);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
switch (block_type)
{
@@ -790,7 +827,7 @@ grub_png_decode_image_data (struct grub_png_data *data)
grub_png_get_byte (data);
grub_png_get_byte (data);
- for (i = 0; i < len; i++)
+ for (i = 0; i < len && grub_errno == GRUB_ERR_NONE; i++)
grub_png_output_byte (data, grub_png_get_byte (data));
break;
@@ -1045,6 +1082,8 @@ grub_png_decode_png (struct grub_png_data *data)
len = grub_png_get_dword (data);
type = grub_png_get_dword (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ break;
data->next_offset = data->file->offset + len + 4;
switch (type)

View File

@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 6 Jul 2021 14:13:40 +1000
Subject: [PATCH] video/readers/png: Refuse to handle multiple image headers
This causes the bitmap to be leaked. Do not permit multiple image headers.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 8ce433557adeadbc46429aabb9f850b02ad2bdfb)
(cherry picked from commit 6e10bba6a4cbfd6c7bf116f41fd4e037465e19d8)
(cherry picked from commit 812272d919ecfd368c008f15b677d369616ada54)
---
grub-core/video/readers/png.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index e2a6b1cf3c..8955b8ecfd 100644
--- a/grub-core/video/readers/png.c
+++ b/grub-core/video/readers/png.c
@@ -258,6 +258,9 @@ grub_png_decode_image_header (struct grub_png_data *data)
int color_bits;
enum grub_video_blit_format blt;
+ if (data->image_width || data->image_height)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: two image headers found");
+
data->image_width = grub_png_get_dword (data);
data->image_height = grub_png_get_dword (data);

View File

@ -0,0 +1,172 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 6 Jul 2021 18:51:35 +1000
Subject: [PATCH] video/readers/png: Drop greyscale support to fix heap
out-of-bounds write
A 16-bit greyscale PNG without alpha is processed in the following loop:
for (i = 0; i < (data->image_width * data->image_height);
i++, d1 += 4, d2 += 2)
{
d1[R3] = d2[1];
d1[G3] = d2[1];
d1[B3] = d2[1];
}
The increment of d1 is wrong. d1 is incremented by 4 bytes per iteration,
but there are only 3 bytes allocated for storage. This means that image
data will overwrite somewhat-attacker-controlled parts of memory - 3 bytes
out of every 4 following the end of the image.
This has existed since greyscale support was added in 2013 in commit
3ccf16dff98f (grub-core/video/readers/png.c: Support grayscale).
Saving starfield.png as a 16-bit greyscale image without alpha in the gimp
and attempting to load it causes grub-emu to crash - I don't think this code
has ever worked.
Delete all PNG greyscale support.
Fixes: CVE-2021-3695
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 0e1d163382669bd734439d8864ee969616d971d9)
[rharwood: context conflict]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit 4c631c8119206b3178912df2905434d967661c3d)
(cherry picked from commit 6d5d5f51266b8113c6ba560835500e3c135f3722)
---
grub-core/video/readers/png.c | 85 +++----------------------------------------
1 file changed, 6 insertions(+), 79 deletions(-)
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index 8955b8ecfd..a3161e25b6 100644
--- a/grub-core/video/readers/png.c
+++ b/grub-core/video/readers/png.c
@@ -100,7 +100,7 @@ struct grub_png_data
unsigned image_width, image_height;
int bpp, is_16bit;
- int raw_bytes, is_gray, is_alpha, is_palette;
+ int raw_bytes, is_alpha, is_palette;
int row_bytes, color_bits;
grub_uint8_t *image_data;
@@ -296,13 +296,13 @@ grub_png_decode_image_header (struct grub_png_data *data)
data->bpp = 3;
else
{
- data->is_gray = 1;
- data->bpp = 1;
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "png: color type not supported");
}
if ((color_bits != 8) && (color_bits != 16)
&& (color_bits != 4
- || !(data->is_gray || data->is_palette)))
+ || !data->is_palette))
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"png: bit depth must be 8 or 16");
@@ -331,7 +331,7 @@ grub_png_decode_image_header (struct grub_png_data *data)
}
#ifndef GRUB_CPU_WORDS_BIGENDIAN
- if (data->is_16bit || data->is_gray || data->is_palette)
+ if (data->is_16bit || data->is_palette)
#endif
{
data->image_data = grub_calloc (data->image_height, data->row_bytes);
@@ -899,27 +899,8 @@ grub_png_convert_image (struct grub_png_data *data)
int shift;
int mask = (1 << data->color_bits) - 1;
unsigned j;
- if (data->is_gray)
- {
- /* Generic formula is
- (0xff * i) / ((1U << data->color_bits) - 1)
- but for allowed bit depth of 1, 2 and for it's
- equivalent to
- (0xff / ((1U << data->color_bits) - 1)) * i
- Precompute the multipliers to avoid division.
- */
- const grub_uint8_t multipliers[5] = { 0xff, 0xff, 0x55, 0x24, 0x11 };
- for (i = 0; i < (1U << data->color_bits); i++)
- {
- grub_uint8_t col = multipliers[data->color_bits] * i;
- palette[i][0] = col;
- palette[i][1] = col;
- palette[i][2] = col;
- }
- }
- else
- grub_memcpy (palette, data->palette, 3 << data->color_bits);
+ grub_memcpy (palette, data->palette, 3 << data->color_bits);
d1c = d1;
d2c = d2;
for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3,
@@ -956,60 +937,6 @@ grub_png_convert_image (struct grub_png_data *data)
}
return;
}
-
- if (data->is_gray)
- {
- switch (data->bpp)
- {
- case 4:
- /* 16-bit gray with alpha. */
- for (i = 0; i < (data->image_width * data->image_height);
- i++, d1 += 4, d2 += 4)
- {
- d1[R4] = d2[3];
- d1[G4] = d2[3];
- d1[B4] = d2[3];
- d1[A4] = d2[1];
- }
- break;
- case 2:
- if (data->is_16bit)
- /* 16-bit gray without alpha. */
- {
- for (i = 0; i < (data->image_width * data->image_height);
- i++, d1 += 4, d2 += 2)
- {
- d1[R3] = d2[1];
- d1[G3] = d2[1];
- d1[B3] = d2[1];
- }
- }
- else
- /* 8-bit gray with alpha. */
- {
- for (i = 0; i < (data->image_width * data->image_height);
- i++, d1 += 4, d2 += 2)
- {
- d1[R4] = d2[1];
- d1[G4] = d2[1];
- d1[B4] = d2[1];
- d1[A4] = d2[0];
- }
- }
- break;
- /* 8-bit gray without alpha. */
- case 1:
- for (i = 0; i < (data->image_width * data->image_height);
- i++, d1 += 3, d2++)
- {
- d1[R3] = d2[0];
- d1[G3] = d2[0];
- d1[B3] = d2[0];
- }
- break;
- }
- return;
- }
{
/* Only copy the upper 8 bit. */

View File

@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 6 Jul 2021 23:25:07 +1000
Subject: [PATCH] video/readers/png: Avoid heap OOB R/W inserting huff table
items
In fuzzing we observed crashes where a code would attempt to be inserted
into a huffman table before the start, leading to a set of heap OOB reads
and writes as table entries with negative indices were shifted around and
the new code written in.
Catch the case where we would underflow the array and bail.
Fixes: CVE-2021-3696
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 1ae9a91d42cb40da8a6f11fac65541858e340afa)
(cherry picked from commit 132ccc681cf642ad748580f26b54c9259a7f43fd)
(cherry picked from commit 3a70e1f6e69af6e0d3c3cf526faa44dc0c80ac19)
---
grub-core/video/readers/png.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index a3161e25b6..d7ed5aa6cf 100644
--- a/grub-core/video/readers/png.c
+++ b/grub-core/video/readers/png.c
@@ -438,6 +438,13 @@ grub_png_insert_huff_item (struct huff_table *ht, int code, int len)
for (i = len; i < ht->max_length; i++)
n += ht->maxval[i];
+ if (n > ht->num_values)
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "png: out of range inserting huffman table item");
+ return;
+ }
+
for (i = 0; i < n; i++)
ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1];

View File

@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 6 Jul 2021 19:19:11 +1000
Subject: [PATCH] video/readers/png: Sanity check some huffman codes
ASAN picked up two OOB global reads: we weren't checking if some code
values fit within the cplens or cpdext arrays. Check and throw an error
if not.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit c3a8ab0cbd24153ec7b1f84a96ddfdd72ef8d117)
(cherry picked from commit 5d09addf58086aa11d5f9a91af5632ff87c2d2ee)
(cherry picked from commit ff12584f9376a472f37d4ec14213fd29bf3b233a)
---
grub-core/video/readers/png.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c
index d7ed5aa6cf..7f2ba7849b 100644
--- a/grub-core/video/readers/png.c
+++ b/grub-core/video/readers/png.c
@@ -753,6 +753,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
int len, dist, pos;
n -= 257;
+ if (((unsigned int) n) >= ARRAY_SIZE (cplens))
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "png: invalid huff code");
len = cplens[n];
if (cplext[n])
len += grub_png_get_bits (data, cplext[n]);
@@ -760,6 +763,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data)
return grub_errno;
n = grub_png_get_huff_code (data, &data->dist_table);
+ if (((unsigned int) n) >= ARRAY_SIZE (cpdist))
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "png: invalid huff code");
dist = cpdist[n];
if (cpdext[n])
dist += grub_png_get_bits (data, cpdext[n]);

View File

@ -0,0 +1,257 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 28 Jun 2021 14:16:14 +1000
Subject: [PATCH] video/readers/jpeg: Abort sooner if a read operation fails
Fuzzing revealed some inputs that were taking a long time, potentially
forever, because they did not bail quickly upon encountering an I/O error.
Try to catch I/O errors sooner and bail out.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit ab2e5d2e4bff488bbb557ed435a61ae102ef9f0c)
(cherry picked from commit 1ff8df0d2dea8ec7c8575241d5e7d6622c204ec3)
(cherry picked from commit b07767383b74a0ce7135c09ba8701510d4ad32f0)
---
grub-core/video/readers/jpeg.c | 86 ++++++++++++++++++++++++++++++++++--------
1 file changed, 70 insertions(+), 16 deletions(-)
diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
index e31602f766..10225abd53 100644
--- a/grub-core/video/readers/jpeg.c
+++ b/grub-core/video/readers/jpeg.c
@@ -109,9 +109,17 @@ static grub_uint8_t
grub_jpeg_get_byte (struct grub_jpeg_data *data)
{
grub_uint8_t r;
+ grub_ssize_t bytes_read;
r = 0;
- grub_file_read (data->file, &r, 1);
+ bytes_read = grub_file_read (data->file, &r, 1);
+
+ if (bytes_read != 1)
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: unexpected end of data");
+ return 0;
+ }
return r;
}
@@ -120,9 +128,17 @@ static grub_uint16_t
grub_jpeg_get_word (struct grub_jpeg_data *data)
{
grub_uint16_t r;
+ grub_ssize_t bytes_read;
r = 0;
- grub_file_read (data->file, &r, sizeof (grub_uint16_t));
+ bytes_read = grub_file_read (data->file, &r, sizeof (grub_uint16_t));
+
+ if (bytes_read != sizeof (grub_uint16_t))
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: unexpected end of data");
+ return 0;
+ }
return grub_be_to_cpu16 (r);
}
@@ -135,6 +151,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data)
if (data->bit_mask == 0)
{
data->bit_save = grub_jpeg_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE) {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: file read error");
+ return 0;
+ }
if (data->bit_save == JPEG_ESC_CHAR)
{
if (grub_jpeg_get_byte (data) != 0)
@@ -143,6 +164,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data)
"jpeg: invalid 0xFF in data stream");
return 0;
}
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: file read error");
+ return 0;
+ }
}
data->bit_mask = 0x80;
}
@@ -161,7 +187,7 @@ grub_jpeg_get_number (struct grub_jpeg_data *data, int num)
return 0;
msb = value = grub_jpeg_get_bit (data);
- for (i = 1; i < num; i++)
+ for (i = 1; i < num && grub_errno == GRUB_ERR_NONE; i++)
value = (value << 1) + (grub_jpeg_get_bit (data) != 0);
if (!msb)
value += 1 - (1 << num);
@@ -202,6 +228,8 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data)
while (data->file->offset + sizeof (count) + 1 <= next_marker)
{
id = grub_jpeg_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
ac = (id >> 4) & 1;
id &= 0xF;
if (id > 1)
@@ -252,6 +280,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data)
next_marker = data->file->offset;
next_marker += grub_jpeg_get_word (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (next_marker > data->file->size)
{
@@ -263,6 +293,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data)
<= next_marker)
{
id = grub_jpeg_get_byte (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (id >= 0x10) /* Upper 4-bit is precision. */
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: only 8-bit precision is supported");
@@ -294,6 +326,9 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
next_marker = data->file->offset;
next_marker += grub_jpeg_get_word (data);
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
+
if (grub_jpeg_get_byte (data) != 8)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: only 8-bit precision is supported");
@@ -319,6 +354,8 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index");
ss = grub_jpeg_get_byte (data); /* Sampling factor. */
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (!id)
{
grub_uint8_t vs, hs;
@@ -498,7 +535,7 @@ grub_jpeg_idct_transform (jpeg_data_unit_t du)
}
}
-static void
+static grub_err_t
grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
{
int h1, h2, qt;
@@ -513,6 +550,9 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
data->dc_value[id] +=
grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1));
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
+
du[0] = data->dc_value[id] * (int) data->quan_table[qt][0];
pos = 1;
while (pos < ARRAY_SIZE (data->quan_table[qt]))
@@ -527,11 +567,13 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
num >>= 4;
pos += num;
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
+
if (pos >= ARRAY_SIZE (jpeg_zigzag_order))
{
- grub_error (GRUB_ERR_BAD_FILE_TYPE,
- "jpeg: invalid position in zigzag order!?");
- return;
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: invalid position in zigzag order!?");
}
du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos];
@@ -539,6 +581,7 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du)
}
grub_jpeg_idct_transform (du);
+ return GRUB_ERR_NONE;
}
static void
@@ -597,7 +640,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
data_offset += grub_jpeg_get_word (data);
cc = grub_jpeg_get_byte (data);
-
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (cc != 3 && cc != 1)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: component count must be 1 or 3");
@@ -610,7 +654,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
id = grub_jpeg_get_byte (data) - 1;
if ((id < 0) || (id >= 3))
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index");
-
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
ht = grub_jpeg_get_byte (data);
data->comp_index[id][1] = (ht >> 4);
data->comp_index[id][2] = (ht & 0xF) + 2;
@@ -618,11 +663,14 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
if ((data->comp_index[id][1] < 0) || (data->comp_index[id][1] > 3) ||
(data->comp_index[id][2] < 0) || (data->comp_index[id][2] > 3))
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid hufftable index");
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
}
grub_jpeg_get_byte (data); /* Skip 3 unused bytes. */
grub_jpeg_get_word (data);
-
+ if (grub_errno != GRUB_ERR_NONE)
+ return grub_errno;
if (data->file->offset != data_offset)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos");
@@ -640,6 +688,7 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
{
unsigned c1, vb, hb, nr1, nc1;
int rst = data->dri;
+ grub_err_t err = GRUB_ERR_NONE;
vb = 8 << data->log_vs;
hb = 8 << data->log_hs;
@@ -660,17 +709,22 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
for (r2 = 0; r2 < (1U << data->log_vs); r2++)
for (c2 = 0; c2 < (1U << data->log_hs); c2++)
- grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]);
+ {
+ err = grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
if (data->color_components >= 3)
{
- grub_jpeg_decode_du (data, 1, data->cbdu);
- grub_jpeg_decode_du (data, 2, data->crdu);
+ err = grub_jpeg_decode_du (data, 1, data->cbdu);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ err = grub_jpeg_decode_du (data, 2, data->crdu);
+ if (err != GRUB_ERR_NONE)
+ return err;
}
- if (grub_errno)
- return grub_errno;
-
nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb;
nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb;

View File

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 28 Jun 2021 14:16:58 +1000
Subject: [PATCH] video/readers/jpeg: Do not reallocate a given huff table
Fix a memory leak where an invalid file could cause us to reallocate
memory for a huffman table we had already allocated memory for.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit bc06e12b4de55cc6f926af9f064170c82b1403e9)
(cherry picked from commit 5298bf758ea39a90537f9a1c76541ff2f21b970b)
(cherry picked from commit aae6bac7f26c6b848156ed7adcff83309b833664)
---
grub-core/video/readers/jpeg.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
index 10225abd53..caa211f06d 100644
--- a/grub-core/video/readers/jpeg.c
+++ b/grub-core/video/readers/jpeg.c
@@ -245,6 +245,9 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data)
n += count[i];
id += ac * 2;
+ if (data->huff_value[id] != NULL)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: attempt to reallocate huffman table");
data->huff_value[id] = grub_malloc (n);
if (grub_errno)
return grub_errno;

View File

@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 28 Jun 2021 14:25:17 +1000
Subject: [PATCH] video/readers/jpeg: Refuse to handle multiple start of
streams
An invalid file could contain multiple start of stream blocks, which
would cause us to reallocate and leak our bitmap. Refuse to handle
multiple start of streams.
Additionally, fix a grub_error() call formatting.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit f3a854def3e281b7ad4bbea730cd3046de1da52f)
(cherry picked from commit db0154828989a0a52ee59a4dda8c3803752bc827)
(cherry picked from commit 75afb375ef46bc99a7faf5879d0283934e34db97)
---
grub-core/video/readers/jpeg.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
index caa211f06d..1df1171d78 100644
--- a/grub-core/video/readers/jpeg.c
+++ b/grub-core/video/readers/jpeg.c
@@ -677,6 +677,9 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data)
if (data->file->offset != data_offset)
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos");
+ if (*data->bitmap)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many start of scan blocks");
+
if (grub_video_bitmap_create (data->bitmap, data->image_width,
data->image_height,
GRUB_VIDEO_BLIT_FORMAT_RGB_888))
@@ -699,8 +702,8 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
nc1 = (data->image_width + hb - 1) >> (3 + data->log_hs);
if (data->bitmap_ptr == NULL)
- return grub_error(GRUB_ERR_BAD_FILE_TYPE,
- "jpeg: attempted to decode data before start of stream");
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: attempted to decode data before start of stream");
for (; data->r1 < nr1 && (!data->dri || rst);
data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)

View File

@ -0,0 +1,55 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Wed, 7 Jul 2021 15:38:19 +1000
Subject: [PATCH] video/readers/jpeg: Block int underflow -> wild pointer write
Certain 1 px wide images caused a wild pointer write in
grub_jpeg_ycrcb_to_rgb(). This was caused because in grub_jpeg_decode_data(),
we have the following loop:
for (; data->r1 < nr1 && (!data->dri || rst);
data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)
We did not check if vb * width >= hb * nc1.
On a 64-bit platform, if that turns out to be negative, it will underflow,
be interpreted as unsigned 64-bit, then be added to the 64-bit pointer, so
we see data->bitmap_ptr jump, e.g.:
0x6180_0000_0480 to
0x6181_0000_0498
^
~--- carry has occurred and this pointer is now far away from
any object.
On a 32-bit platform, it will decrement the pointer, creating a pointer
that won't crash but will overwrite random data.
Catch the underflow and error out.
Fixes: CVE-2021-3697
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 41aeb2004db9924fecd9f2dd64bc2a5a5594a4b5)
(cherry picked from commit 5f9582490792108306d047379fed2371bee286f8)
(cherry picked from commit 7e4bf25d9bb5219fbf11c523296dc3bd78b80698)
---
grub-core/video/readers/jpeg.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c
index 1df1171d78..2da04094b3 100644
--- a/grub-core/video/readers/jpeg.c
+++ b/grub-core/video/readers/jpeg.c
@@ -705,6 +705,10 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data)
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
"jpeg: attempted to decode data before start of stream");
+ if (vb * data->image_width <= hb * nc1)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE,
+ "jpeg: cannot decode image with these dimensions");
+
for (; data->r1 < nr1 && (!data->dri || rst);
data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3)
for (c1 = 0; c1 < nc1 && (!data->dri || rst);

View File

@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 13 Jul 2021 13:24:38 +1000
Subject: [PATCH] normal/charset: Fix array out-of-bounds formatting unicode
for display
In some cases attempting to display arbitrary binary strings leads
to ASAN splats reading the widthspec array out of bounds.
Check the index. If it would be out of bounds, return a width of 1.
I don't know if that's strictly correct, but we're not really expecting
great display of arbitrary binary data, and it's certainly not worse than
an OOB read.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit fdf32abc7a3928852422c0f291d8cd1dd6b34a8d)
(cherry picked from commit f2c10aaf335b88a69885375c4d68ffab2429df77)
(cherry picked from commit 4c942e1ba8d1f1199a58d2eb139022ae22f75cb2)
---
grub-core/normal/charset.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c
index f902b13b44..7b2de12001 100644
--- a/grub-core/normal/charset.c
+++ b/grub-core/normal/charset.c
@@ -395,6 +395,8 @@ grub_unicode_estimate_width (const struct grub_unicode_glyph *c)
{
if (grub_unicode_get_comb_type (c->base))
return 0;
+ if (((unsigned long) (c->base >> 3)) >= ARRAY_SIZE (widthspec))
+ return 1;
if (widthspec[c->base >> 3] & (1 << (c->base & 7)))
return 2;
else

View File

@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 8 Mar 2022 23:47:46 +1100
Subject: [PATCH] net/netbuff: Block overly large netbuff allocs
A netbuff shouldn't be too huge. It's bounded by MTU and TCP segment
reassembly.
This helps avoid some bugs (and provides a spot to instrument to catch
them at their source).
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit ee9591103004cd13b4efadda671536090ca7fd57)
(cherry picked from commit acde668bb9d9fa862a1a63e3bbd5fa47fdfa9183)
(cherry picked from commit e47ad2eb4fe38ef2bdcab52245286f31170e73e3)
---
grub-core/net/netbuff.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c
index dbeeefe478..d5e9e9a0d7 100644
--- a/grub-core/net/netbuff.c
+++ b/grub-core/net/netbuff.c
@@ -79,10 +79,23 @@ grub_netbuff_alloc (grub_size_t len)
COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0);
+ /*
+ * The largest size of a TCP packet is 64 KiB, and everything else
+ * should be a lot smaller - most MTUs are 1500 or less. Cap data
+ * size at 64 KiB + a buffer.
+ */
+ if (len > 0xffffUL + 0x1000UL)
+ {
+ grub_error (GRUB_ERR_BUG,
+ "attempted to allocate a packet that is too big");
+ return NULL;
+ }
+
if (len < NETBUFFMINLEN)
len = NETBUFFMINLEN;
len = ALIGN_UP (len, NETBUFF_ALIGN);
+
#ifdef GRUB_MACHINE_EMU
data = grub_malloc (len + sizeof (*nb));
#else

View File

@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 20 Dec 2021 19:41:21 +1100
Subject: [PATCH] net/ip: Do IP fragment maths safely
This avoids an underflow and subsequent unpleasantness.
Fixes: CVE-2022-28733
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit eb74e5743ca7e18a5e75c392fe0b21d1549a1936)
(cherry picked from commit 552ad34583e788542e9ca08524a0d4bc8f98c297)
(cherry picked from commit 2c8cb7e3b8b48b136a950e5692fa6251b76df90e)
---
grub-core/net/ip.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
index 9a4e589aa3..c766ac65f5 100644
--- a/grub-core/net/ip.c
+++ b/grub-core/net/ip.c
@@ -25,6 +25,7 @@
#include <grub/net/netbuff.h>
#include <grub/mm.h>
#include <grub/priority_queue.h>
+#include <grub/safemath.h>
#include <grub/time.h>
struct iphdr {
@@ -552,7 +553,14 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb,
{
rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK)
+ (nb->tail - nb->data));
- rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t));
+
+ if (grub_sub (rsm->total_len, (iph->verhdrlen & 0xf) * sizeof (grub_uint32_t),
+ &rsm->total_len))
+ {
+ grub_dprintf ("net", "IP reassembly size underflow\n");
+ return GRUB_ERR_NONE;
+ }
+
rsm->asm_netbuff = grub_netbuff_alloc (rsm->total_len);
if (!rsm->asm_netbuff)
{

View File

@ -0,0 +1,58 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Thu, 16 Sep 2021 01:29:54 +1000
Subject: [PATCH] net/dns: Fix double-free addresses on corrupt DNS response
grub_net_dns_lookup() takes as inputs a pointer to an array of addresses
("addresses") for the given name, and pointer to a number of addresses
("naddresses"). grub_net_dns_lookup() is responsible for allocating
"addresses", and the caller is responsible for freeing it if
"naddresses" > 0.
The DNS recv_hook will sometimes set and free the addresses array,
for example if the packet is too short:
if (ptr + 10 >= nb->tail)
{
if (!*data->naddresses)
grub_free (*data->addresses);
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}
Later on the nslookup command code unconditionally frees the "addresses"
array. Normally this is fine: the array is either populated with valid
data or is NULL. But in these sorts of error cases it is neither NULL
nor valid and we get a double-free.
Only free "addresses" if "naddresses" > 0.
It looks like the other use of grub_net_dns_lookup() is not affected.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit eb2e69fcf51307757e43f55ee8c9354d1ee42dd1)
(cherry picked from commit d801a27e7acec6c1a83067fab0bb975877eaf704)
(cherry picked from commit 4d8b6e36ddfda4084e370b3b08c432e8a462e9be)
---
grub-core/net/dns.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c
index 906ec7d678..135faac035 100644
--- a/grub-core/net/dns.c
+++ b/grub-core/net/dns.c
@@ -667,9 +667,11 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)),
grub_net_addr_to_str (&addresses[i], buf);
grub_printf ("%s\n", buf);
}
- grub_free (addresses);
if (naddresses)
- return GRUB_ERR_NONE;
+ {
+ grub_free (addresses);
+ return GRUB_ERR_NONE;
+ }
return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found"));
}

View File

@ -0,0 +1,73 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 20 Dec 2021 21:55:43 +1100
Subject: [PATCH] net/dns: Don't read past the end of the string we're checking
against
I don't really understand what's going on here but fuzzing found
a bug where we read past the end of check_with. That's a C string,
so use grub_strlen() to make sure we don't overread it.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 6a97b3f4b1d5173aa516edc6dedbc63de7306d21)
(cherry picked from commit e0589624e86bc96666cbdb62f6e55cafec2871b3)
(cherry picked from commit 95ecbc0b9aacfd43ba96cccc50daaf39eccd9f7f)
---
grub-core/net/dns.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c
index 135faac035..17961a9f18 100644
--- a/grub-core/net/dns.c
+++ b/grub-core/net/dns.c
@@ -146,11 +146,18 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
int *length, char *set)
{
const char *readable_ptr = check_with;
+ int readable_len;
const grub_uint8_t *ptr;
char *optr = set;
int bytes_processed = 0;
if (length)
*length = 0;
+
+ if (readable_ptr != NULL)
+ readable_len = grub_strlen (readable_ptr);
+ else
+ readable_len = 0;
+
for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; )
{
/* End marker. */
@@ -172,13 +179,16 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]);
continue;
}
- if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)
+ if (readable_ptr != NULL && (*ptr > readable_len || grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0))
return 0;
if (grub_memchr (ptr + 1, 0, *ptr)
|| grub_memchr (ptr + 1, '.', *ptr))
return 0;
if (readable_ptr)
- readable_ptr += *ptr;
+ {
+ readable_ptr += *ptr;
+ readable_len -= *ptr;
+ }
if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0)
return 0;
bytes_processed += *ptr + 1;
@@ -192,7 +202,10 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
if (optr)
*optr++ = '.';
if (readable_ptr && *readable_ptr)
- readable_ptr++;
+ {
+ readable_ptr++;
+ readable_len--;
+ }
ptr += *ptr + 1;
}
return 0;

View File

@ -0,0 +1,114 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 20 Sep 2021 01:12:24 +1000
Subject: [PATCH] net/tftp: Prevent a UAF and double-free from a failed seek
A malicious tftp server can cause UAFs and a double free.
An attempt to read from a network file is handled by grub_net_fs_read(). If
the read is at an offset other than the current offset, grub_net_seek_real()
is invoked.
In grub_net_seek_real(), if a backwards seek cannot be satisfied from the
currently received packets, and the underlying transport does not provide
a seek method, then grub_net_seek_real() will close and reopen the network
protocol layer.
For tftp, the ->close() call goes to tftp_close() and frees the tftp_data_t
file->data. The file->data pointer is not nulled out after the free.
If the ->open() call fails, the file->data will not be reallocated and will
continue point to a freed memory block. This could happen from a server
refusing to send the requisite ack to the new tftp request, for example.
The seek and the read will then fail, but the grub_file continues to exist:
the failed seek does not necessarily cause the entire file to be thrown
away (e.g. where the file is checked to see if it is gzipped/lzio/xz/etc.,
a read failure is interpreted as a decompressor passing on the file, not as
an invalidation of the entire grub_file_t structure).
This means subsequent attempts to read or seek the file will use the old
file->data after free. Eventually, the file will be close()d again and
file->data will be freed again.
Mark a net_fs file that doesn't reopen as broken. Do not permit read() or
close() on a broken file (seek is not exposed directly to the file API -
it is only called as part of read, so this blocks seeks as well).
As an additional defence, null out the ->data pointer if tftp_open() fails.
That would have lead to a simple null pointer dereference rather than
a mess of UAFs.
This may affect other protocols, I haven't checked.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit dada1dda695439bb55b2848dddc2d89843552f81)
(cherry picked from commit 352c5ae8a9fc715712e6ecbd7ccb6218122c748f)
(cherry picked from commit 61a010085ab9f0ecf42677773a6fc212f1579b0a)
---
grub-core/net/net.c | 11 +++++++++--
grub-core/net/tftp.c | 1 +
include/grub/net.h | 1 +
3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index a27c53eee1..b9e2a4d100 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -1625,7 +1625,8 @@ grub_net_fs_close (grub_file_t file)
grub_netbuff_free (file->device->net->packs.first->nb);
grub_net_remove_packet (file->device->net->packs.first);
}
- file->device->net->protocol->close (file);
+ if (!file->device->net->broken)
+ file->device->net->protocol->close (file);
grub_free (file->device->net->name);
return GRUB_ERR_NONE;
}
@@ -1847,7 +1848,10 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset)
file->device->net->stall = 0;
err = file->device->net->protocol->open (file, file->device->net->name);
if (err)
- return err;
+ {
+ file->device->net->broken = 1;
+ return err;
+ }
grub_net_fs_read_real (file, NULL, offset);
return grub_errno;
}
@@ -1856,6 +1860,9 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset)
static grub_ssize_t
grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len)
{
+ if (file->device->net->broken)
+ return -1;
+
if (file->offset != file->device->net->offset)
{
grub_err_t err;
diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
index aa0424dcee..85be965470 100644
--- a/grub-core/net/tftp.c
+++ b/grub-core/net/tftp.c
@@ -402,6 +402,7 @@ tftp_open (struct grub_file *file, const char *filename)
{
grub_net_udp_close (data->sock);
grub_free (data);
+ file->data = NULL;
return grub_errno;
}
diff --git a/include/grub/net.h b/include/grub/net.h
index 9cf6da6897..0d31f00664 100644
--- a/include/grub/net.h
+++ b/include/grub/net.h
@@ -280,6 +280,7 @@ typedef struct grub_net
grub_fs_t fs;
int eof;
int stall;
+ int broken;
} *grub_net_t;
extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name);

View File

@ -0,0 +1,53 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Thu, 4 Mar 2021 18:22:32 -0600
Subject: [PATCH] misc: Format string for grub_error() should be a literal
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry-picked from commit 60875f4e15d704b875969b415501802b531c4db3)
---
grub-core/loader/efi/chainloader.c | 2 +-
grub-core/net/tftp.c | 2 +-
grub-core/script/lexer.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 720f6181e5..8e658f713e 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -79,7 +79,7 @@ grub_start_image (grub_efi_handle_t handle)
*grub_utf16_to_utf8 ((grub_uint8_t *) buf,
exit_data, exit_data_size) = 0;
- grub_error (GRUB_ERR_BAD_OS, buf);
+ grub_error (GRUB_ERR_BAD_OS, "%s", buf);
grub_free (buf);
}
}
diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
index 85be965470..69a9ba6979 100644
--- a/grub-core/net/tftp.c
+++ b/grub-core/net/tftp.c
@@ -253,7 +253,7 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
case TFTP_ERROR:
data->have_oack = 1;
grub_netbuff_free (nb);
- grub_error (GRUB_ERR_IO, (char *) tftph->u.err.errmsg);
+ grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg);
grub_error_save (&data->save_err);
return GRUB_ERR_NONE;
default:
diff --git a/grub-core/script/lexer.c b/grub-core/script/lexer.c
index 5fb0cbd0bc..27daad791c 100644
--- a/grub-core/script/lexer.c
+++ b/grub-core/script/lexer.c
@@ -349,7 +349,7 @@ void
grub_script_yyerror (struct grub_parser_param *state, char const *err)
{
if (err)
- grub_error (GRUB_ERR_INVALID_COMMAND, err);
+ grub_error (GRUB_ERR_INVALID_COMMAND, "%s", err);
grub_print_error ();
state->err++;

View File

@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 18 Jan 2022 14:29:20 +1100
Subject: [PATCH] net/tftp: Avoid a trivial UAF
Under tftp errors, we print a tftp error message from the tftp header.
However, the tftph pointer is a pointer inside nb, the netbuff. Previously,
we were freeing the nb and then dereferencing it. Don't do that, use it
and then free it later.
This isn't really _bad_ per se, especially as we're single-threaded, but
it trips up fuzzers.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 956f4329cec23e4375182030ca9b2be631a61ba5)
(cherry picked from commit dbe9abcdee6ce796811111b67e3f24eefe2135d1)
(cherry picked from commit 72ae9c5d389d2c0337c44edead6e00db0bb84039)
---
grub-core/net/tftp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
index 69a9ba6979..09e1511ccf 100644
--- a/grub-core/net/tftp.c
+++ b/grub-core/net/tftp.c
@@ -252,9 +252,9 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
return GRUB_ERR_NONE;
case TFTP_ERROR:
data->have_oack = 1;
- grub_netbuff_free (nb);
grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg);
grub_error_save (&data->save_err);
+ grub_netbuff_free (nb);
return GRUB_ERR_NONE;
default:
grub_netbuff_free (nb);

View File

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 1 Mar 2022 23:14:15 +1100
Subject: [PATCH] net/http: Do not tear down socket if it's already been torn
down
It's possible for data->sock to get torn down in tcp error handling.
If we unconditionally tear it down again we will end up doing writes
to an offset of the NULL pointer when we go to tear it down again.
Detect if it has been torn down and don't do it again.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit ec233d3ecf995293304de443579aab5c46c49e85)
(cherry picked from commit d39cf87ed701b9f0900daed7f672e07994d37ce8)
(cherry picked from commit e0aa5c3acec70eac3489d6df1893a93726cbce3a)
---
grub-core/net/http.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/grub-core/net/http.c b/grub-core/net/http.c
index b52b558d63..5223ca57a4 100644
--- a/grub-core/net/http.c
+++ b/grub-core/net/http.c
@@ -427,7 +427,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
return err;
}
- for (i = 0; !data->headers_recv && i < 100; i++)
+ for (i = 0; data->sock && !data->headers_recv && i < 100; i++)
{
grub_net_tcp_retransmit ();
grub_net_poll_cards (300, &data->headers_recv);
@@ -435,7 +435,8 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
if (!data->headers_recv)
{
- grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
+ if (data->sock)
+ grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
if (data->err)
{
char *str = data->errmsg;

View File

@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 8 Mar 2022 18:17:03 +1100
Subject: [PATCH] net/http: Fix OOB write for split http headers
GRUB has special code for handling an http header that is split
across two packets.
The code tracks the end of line by looking for a "\n" byte. The
code for split headers has always advanced the pointer just past the
end of the line, whereas the code that handles unsplit headers does
not advance the pointer. This extra advance causes the length to be
one greater, which breaks an assumption in parse_line(), leading to
it writing a NUL byte one byte past the end of the buffer where we
reconstruct the line from the two packets.
It's conceivable that an attacker controlled set of packets could
cause this to zero out the first byte of the "next" pointer of the
grub_mm_region structure following the current_line buffer.
Do not advance the pointer in the split header case.
Fixes: CVE-2022-28734
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit e9fb459638811c12b0989dbf64e3e124974ef617)
(cherry picked from commit b604916beb6c39e8ed27f72851eb16f3eaa293c5)
(cherry picked from commit c3c6b1167a43275991efd6847160a46ce3839fae)
---
grub-core/net/http.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/grub-core/net/http.c b/grub-core/net/http.c
index 5223ca57a4..7fa2dcaea7 100644
--- a/grub-core/net/http.c
+++ b/grub-core/net/http.c
@@ -193,9 +193,7 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)),
int have_line = 1;
char *t;
ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data);
- if (ptr)
- ptr++;
- else
+ if (ptr == NULL)
{
have_line = 0;
ptr = (char *) nb->tail;

View File

@ -0,0 +1,50 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Tue, 8 Mar 2022 19:04:40 +1100
Subject: [PATCH] net/http: Error out on headers with LF without CR
In a similar vein to the previous patch, parse_line() would write
a NUL byte past the end of the buffer if there was an HTTP header
with a LF rather than a CRLF.
RFC-2616 says:
Many HTTP/1.1 header field values consist of words separated by LWS
or special characters. These special characters MUST be in a quoted
string to be used within a parameter value (as defined in section 3.6).
We don't support quoted sections or continuation lines, etc.
If we see an LF that's not part of a CRLF, bail out.
Fixes: CVE-2022-28734
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit d232ad41ac4979a9de4d746e5fdff9caf0e303de)
(cherry picked from commit 8960e6d6137090a7e8c6592077da6e387a4ef972)
(cherry picked from commit 9b6b9398c90dd76ce0b935d21c4ecb8954c4b2b7)
---
grub-core/net/http.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/grub-core/net/http.c b/grub-core/net/http.c
index 7fa2dcaea7..745f429b51 100644
--- a/grub-core/net/http.c
+++ b/grub-core/net/http.c
@@ -69,7 +69,15 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len)
char *end = ptr + len;
while (end > ptr && *(end - 1) == '\r')
end--;
+
+ /* LF without CR. */
+ if (end == ptr + len)
+ {
+ data->errmsg = grub_strdup (_("invalid HTTP header - LF without CR"));
+ return GRUB_ERR_NONE;
+ }
*end = 0;
+
/* Trailing CRLF. */
if (data->in_chunk_len == 1)
{

View File

@ -0,0 +1,74 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 6 Apr 2022 18:03:37 +0530
Subject: [PATCH] fs/f2fs: Do not read past the end of nat journal entries
A corrupt f2fs file system could specify a nat journal entry count
that is beyond the maximum NAT_JOURNAL_ENTRIES.
Check if the specified nat journal entry count before accessing the
array, and throw an error if it is too large.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit a3988cb3f0a108dd67ac127a79a4c8479d23334e)
(cherry picked from commit 7125978aa7d6068812ef6da0ab38ce521ae7eba1)
(cherry picked from commit e488538cbf9fc63796c7047550b0598e1ef95c03)
---
grub-core/fs/f2fs.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
index 1cad2615f3..09dc932420 100644
--- a/grub-core/fs/f2fs.c
+++ b/grub-core/fs/f2fs.c
@@ -632,23 +632,27 @@ get_nat_journal (struct grub_f2fs_data *data)
return err;
}
-static grub_uint32_t
-get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid)
+static grub_err_t
+get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid,
+ grub_uint32_t *blkaddr)
{
grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats);
- grub_uint32_t blkaddr = 0;
grub_uint16_t i;
+ if (n >= NAT_JOURNAL_ENTRIES)
+ return grub_error (GRUB_ERR_BAD_FS,
+ "invalid number of nat journal entries");
+
for (i = 0; i < n; i++)
{
if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid)
{
- blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr);
+ *blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr);
break;
}
}
- return blkaddr;
+ return GRUB_ERR_NONE;
}
static grub_uint32_t
@@ -656,10 +660,13 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
{
struct grub_f2fs_nat_block *nat_block;
grub_uint32_t seg_off, block_off, entry_off, block_addr;
- grub_uint32_t blkaddr;
+ grub_uint32_t blkaddr = 0;
grub_err_t err;
- blkaddr = get_blkaddr_from_nat_journal (data, nid);
+ err = get_blkaddr_from_nat_journal (data, nid, &blkaddr);
+ if (err != GRUB_ERR_NONE)
+ return 0;
+
if (blkaddr)
return blkaddr;

View File

@ -0,0 +1,134 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 6 Apr 2022 18:49:09 +0530
Subject: [PATCH] fs/f2fs: Do not read past the end of nat bitmap
A corrupt f2fs filesystem could have a block offset or a bitmap
offset that would cause us to read beyond the bounds of the nat
bitmap.
Introduce the nat_bitmap_size member in grub_f2fs_data which holds
the size of nat bitmap.
Set the size when loading the nat bitmap in nat_bitmap_ptr(), and
catch when an invalid offset would create a pointer past the end of
the allocated space.
Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid
reading past the end of the nat bitmap.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 62d63d5e38c67a6e349148bf7cb87c560e935a7e)
(cherry picked from commit 92219e6d379b5b4d30b05361830b72ab1d95d281)
(cherry picked from commit c23d97e3b56594bf0f802d94062e14b221143115)
---
grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------
1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
index 09dc932420..33e565b180 100644
--- a/grub-core/fs/f2fs.c
+++ b/grub-core/fs/f2fs.c
@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define F2FS_INLINE_DOTS 0x10 /* File having implicit dot dentries. */
#define MAX_VOLUME_NAME 512
+#define MAX_NAT_BITMAP_SIZE 3900
enum FILE_TYPE
{
@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint
grub_uint32_t checksum_offset;
grub_uint64_t elapsed_time;
grub_uint8_t alloc_type[MAX_ACTIVE_LOGS];
- grub_uint8_t sit_nat_version_bitmap[3900];
+ grub_uint8_t sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE];
grub_uint32_t checksum;
} GRUB_PACKED;
@@ -302,6 +303,7 @@ struct grub_f2fs_data
struct grub_f2fs_nat_journal nat_j;
char *nat_bitmap;
+ grub_uint32_t nat_bitmap_size;
grub_disk_t disk;
struct grub_f2fs_node *inode;
@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type)
}
static void *
-nat_bitmap_ptr (struct grub_f2fs_data *data)
+nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size)
{
struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
grub_uint32_t offset;
+ *nat_bitmap_size = MAX_NAT_BITMAP_SIZE;
if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0)
return ckpt->sit_nat_version_bitmap;
offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize);
+ if (offset >= MAX_NAT_BITMAP_SIZE)
+ return NULL;
+
+ *nat_bitmap_size = *nat_bitmap_size - offset;
return ckpt->sit_nat_version_bitmap + offset;
}
@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len)
}
static int
-grub_f2fs_test_bit (grub_uint32_t nr, const char *p)
+grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len)
{
int mask;
+ grub_uint32_t shifted_nr = (nr >> 3);
- p += (nr >> 3);
+ if (shifted_nr >= len)
+ return -1;
+
+ p += shifted_nr;
mask = 1 << (7 - (nr & 0x07));
return mask & *p;
@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
grub_uint32_t seg_off, block_off, entry_off, block_addr;
grub_uint32_t blkaddr = 0;
grub_err_t err;
+ int result_bit;
err = get_blkaddr_from_nat_journal (data, nid, &blkaddr);
if (err != GRUB_ERR_NONE)
@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
((seg_off * data->blocks_per_seg) << 1) +
(block_off & (data->blocks_per_seg - 1));
- if (grub_f2fs_test_bit (block_off, data->nat_bitmap))
+ result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap,
+ data->nat_bitmap_size);
+ if (result_bit > 0)
block_addr += data->blocks_per_seg;
+ else if (result_bit == -1)
+ {
+ grub_free (nat_block);
+ return 0;
+ }
err = grub_f2fs_block_read (data, block_addr, nat_block);
if (err)
@@ -832,7 +851,9 @@ grub_f2fs_mount (grub_disk_t disk)
if (err)
goto fail;
- data->nat_bitmap = nat_bitmap_ptr (data);
+ data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size);
+ if (data->nat_bitmap == NULL)
+ goto fail;
err = get_nat_journal (data);
if (err)

View File

@ -0,0 +1,40 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 6 Apr 2022 18:17:43 +0530
Subject: [PATCH] fs/f2fs: Do not copy file names that are too long
A corrupt f2fs file system might specify a name length which is greater
than the maximum name length supported by the GRUB f2fs driver.
We will allocate enough memory to store the overly long name, but there
are only F2FS_NAME_LEN bytes in the source, so we would read past the end
of the source.
While checking directory entries, do not copy a file name with an invalid
length.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 9a891f638509e031d322c94e3cbcf38d36f3993a)
(cherry picked from commit 13f9160ae0d2806baed459884999356817096cd7)
(cherry picked from commit a48ba4d48b3c66431e6bbeb386078efc6602110c)
---
grub-core/fs/f2fs.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
index 33e565b180..07ea34196c 100644
--- a/grub-core/fs/f2fs.c
+++ b/grub-core/fs/f2fs.c
@@ -998,6 +998,10 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx)
ftype = ctx->dentry[i].file_type;
name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len);
+
+ if (name_len >= F2FS_NAME_LEN)
+ return 0;
+
filename = grub_malloc (name_len + 1);
if (!filename)
return 0;

View File

@ -0,0 +1,81 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Darren Kenny <darren.kenny@oracle.com>
Date: Tue, 29 Mar 2022 10:49:56 +0000
Subject: [PATCH] fs/btrfs: Fix several fuzz issues with invalid dir item
sizing
According to the btrfs code in Linux, the structure of a directory item
leaf should be of the form:
|struct btrfs_dir_item|name|data|
in GRUB the name len and data len are in the grub_btrfs_dir_item
structure's n and m fields respectively.
The combined size of the structure, name and data should be less than
the allocated memory, a difference to the Linux kernel's struct
btrfs_dir_item is that the grub_btrfs_dir_item has an extra field for
where the name is stored, so we adjust for that too.
Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 6d3f06c0b6a8992b9b1bb0e62af93ac5ff2781f0)
[rharwood: we've an extra variable here]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit e3e21b9a81aea09dd43368cf097c1029a8380d82)
(cherry picked from commit ab14a39777edb60c99751d4fdf1cc254a4faebf5)
---
grub-core/fs/btrfs.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
index 3faf9056c7..9da2952f70 100644
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -1834,6 +1834,7 @@ grub_btrfs_dir (grub_device_t device, const char *path,
grub_uint64_t tree;
grub_uint8_t type;
char *new_path = NULL;
+ grub_size_t est_size = 0;
if (!data)
return grub_errno;
@@ -1900,6 +1901,18 @@ grub_btrfs_dir (grub_device_t device, const char *path,
break;
}
+ if (direl == NULL ||
+ grub_add (grub_le_to_cpu16 (direl->n),
+ grub_le_to_cpu16 (direl->m), &est_size) ||
+ grub_add (est_size, sizeof (*direl), &est_size) ||
+ grub_sub (est_size, sizeof (direl->name), &est_size) ||
+ est_size > allocated)
+ {
+ grub_errno = GRUB_ERR_OUT_OF_RANGE;
+ r = -grub_errno;
+ goto out;
+ }
+
for (cdirel = direl;
(grub_uint8_t *) cdirel - (grub_uint8_t *) direl
< (grub_ssize_t) elemsize;
@@ -1910,6 +1923,19 @@ grub_btrfs_dir (grub_device_t device, const char *path,
char c;
struct grub_btrfs_inode inode;
struct grub_dirhook_info info;
+
+ if (cdirel == NULL ||
+ grub_add (grub_le_to_cpu16 (cdirel->n),
+ grub_le_to_cpu16 (cdirel->m), &est_size) ||
+ grub_add (est_size, sizeof (*cdirel), &est_size) ||
+ grub_sub (est_size, sizeof (cdirel->name), &est_size) ||
+ est_size > allocated)
+ {
+ grub_errno = GRUB_ERR_OUT_OF_RANGE;
+ r = -grub_errno;
+ goto out;
+ }
+
err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id,
tree);
grub_memset (&info, 0, sizeof (info));

View File

@ -0,0 +1,143 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Kiper <daniel.kiper@oracle.com>
Date: Thu, 3 Dec 2020 16:01:46 +0100
Subject: [PATCH] efi: Return grub_efi_status_t from grub_efi_get_variable()
This is needed to properly detect and report UEFI Secure Boot status
to the x86 Linux kernel. The functionality will be added by subsequent
patches.
Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
Signed-off-by: Marco A Benatto <mbenatto@redhat.com>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit 04ae030d0eea8668d4417702d88bf2cf04713d80)
---
grub-core/commands/efi/efifwsetup.c | 8 ++++----
grub-core/kern/efi/efi.c | 16 +++++++++-------
grub-core/video/efi_gop.c | 2 +-
include/grub/efi/efi.h | 7 ++++---
4 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/grub-core/commands/efi/efifwsetup.c b/grub-core/commands/efi/efifwsetup.c
index 7a137a72a2..eaca032838 100644
--- a/grub-core/commands/efi/efifwsetup.c
+++ b/grub-core/commands/efi/efifwsetup.c
@@ -38,8 +38,8 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)),
grub_size_t oi_size;
grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
- old_os_indications = grub_efi_get_variable ("OsIndications", &global,
- &oi_size);
+ grub_efi_get_variable ("OsIndications", &global, &oi_size,
+ (void **) &old_os_indications);
if (old_os_indications != NULL && oi_size == sizeof (os_indications))
os_indications |= *old_os_indications;
@@ -63,8 +63,8 @@ efifwsetup_is_supported (void)
grub_size_t oi_size = 0;
grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID;
- os_indications_supported = grub_efi_get_variable ("OsIndicationsSupported",
- &global, &oi_size);
+ grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size,
+ (void **) &os_indications_supported);
if (!os_indications_supported)
return 0;
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
index 2863956458..335033975d 100644
--- a/grub-core/kern/efi/efi.c
+++ b/grub-core/kern/efi/efi.c
@@ -241,9 +241,9 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid,
return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var);
}
-void *
+grub_efi_status_t
grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
- grub_size_t *datasize_out)
+ grub_size_t *datasize_out, void **data_out)
{
grub_efi_status_t status;
grub_efi_uintn_t datasize = 0;
@@ -252,13 +252,14 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
void *data;
grub_size_t len, len16;
+ *data_out = NULL;
*datasize_out = 0;
len = grub_strlen (var);
len16 = len * GRUB_MAX_UTF16_PER_UTF8;
var16 = grub_calloc (len16 + 1, sizeof (var16[0]));
if (!var16)
- return NULL;
+ return GRUB_EFI_OUT_OF_RESOURCES;
len16 = grub_utf8_to_utf16 (var16, len16, (grub_uint8_t *) var, len, NULL);
var16[len16] = 0;
@@ -269,14 +270,14 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
if (status != GRUB_EFI_BUFFER_TOO_SMALL || !datasize)
{
grub_free (var16);
- return NULL;
+ return status;
}
data = grub_malloc (datasize);
if (!data)
{
grub_free (var16);
- return NULL;
+ return GRUB_EFI_OUT_OF_RESOURCES;
}
status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, data);
@@ -284,12 +285,13 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
if (status == GRUB_EFI_SUCCESS)
{
+ *data_out = data;
*datasize_out = datasize;
- return data;
+ return status;
}
grub_free (data);
- return NULL;
+ return status;
}
#pragma GCC diagnostic ignored "-Wcast-align"
diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c
index 9fcc41ac03..ec217db70f 100644
--- a/grub-core/video/efi_gop.c
+++ b/grub-core/video/efi_gop.c
@@ -302,7 +302,7 @@ grub_video_gop_get_edid (struct grub_video_edid_info *edid_info)
char edidname[] = "agp-internal-edid";
grub_size_t datasize;
grub_uint8_t *data;
- data = grub_efi_get_variable (edidname, &efi_var_guid, &datasize);
+ grub_efi_get_variable (edidname, &efi_var_guid, &datasize, (void **) &data);
if (data && datasize > 16)
{
copy_size = datasize - 16;
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 4411ffa16b..90a85d7d9a 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -113,9 +113,10 @@ grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memo
grub_efi_uintn_t descriptor_size,
grub_efi_uint32_t descriptor_version,
grub_efi_memory_descriptor_t *virtual_map);
-void *EXPORT_FUNC (grub_efi_get_variable) (const char *variable,
- const grub_efi_guid_t *guid,
- grub_size_t *datasize_out);
+grub_efi_status_t EXPORT_FUNC (grub_efi_get_variable) (const char *variable,
+ const grub_efi_guid_t *guid,
+ grub_size_t *datasize_out,
+ void **data_out);
grub_err_t
EXPORT_FUNC (grub_efi_set_variable) (const char *var,
const grub_efi_guid_t *guid,

View File

@ -0,0 +1,76 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Kiper <daniel.kiper@oracle.com>
Date: Thu, 3 Dec 2020 16:01:47 +0100
Subject: [PATCH] efi: Add a function to read EFI variables with attributes
It will be used to properly detect and report UEFI Secure Boot status to
the x86 Linux kernel. The functionality will be added by subsequent patches.
Signed-off-by: Ignat Korchagin <ignat@cloudflare.com>
Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
Signed-off-by: Marco A Benatto <mbenatto@redhat.com>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
(cherry picked from commit ac5c9367548750e75ed1e7fc4354a3d20186d733)
---
grub-core/kern/efi/efi.c | 16 +++++++++++++---
include/grub/efi/efi.h | 5 +++++
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
index 335033975d..fccea20a01 100644
--- a/grub-core/kern/efi/efi.c
+++ b/grub-core/kern/efi/efi.c
@@ -242,8 +242,11 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid,
}
grub_efi_status_t
-grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
- grub_size_t *datasize_out, void **data_out)
+grub_efi_get_variable_with_attributes (const char *var,
+ const grub_efi_guid_t *guid,
+ grub_size_t *datasize_out,
+ void **data_out,
+ grub_efi_uint32_t *attributes)
{
grub_efi_status_t status;
grub_efi_uintn_t datasize = 0;
@@ -280,7 +283,7 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
return GRUB_EFI_OUT_OF_RESOURCES;
}
- status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, data);
+ status = efi_call_5 (r->get_variable, var16, guid, attributes, &datasize, data);
grub_free (var16);
if (status == GRUB_EFI_SUCCESS)
@@ -294,6 +297,13 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
return status;
}
+grub_efi_status_t
+grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
+ grub_size_t *datasize_out, void **data_out)
+{
+ return grub_efi_get_variable_with_attributes (var, guid, datasize_out, data_out, NULL);
+}
+
#pragma GCC diagnostic ignored "-Wcast-align"
/* Search the mods section from the PE32/PE32+ image. This code uses
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 90a85d7d9a..7af979b184 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -113,6 +113,11 @@ grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memo
grub_efi_uintn_t descriptor_size,
grub_efi_uint32_t descriptor_version,
grub_efi_memory_descriptor_t *virtual_map);
+grub_efi_status_t EXPORT_FUNC (grub_efi_get_variable_with_attributes) (const char *variable,
+ const grub_efi_guid_t *guid,
+ grub_size_t *datasize_out,
+ void **data_out,
+ grub_efi_uint32_t *attributes);
grub_efi_status_t EXPORT_FUNC (grub_efi_get_variable) (const char *variable,
const grub_efi_guid_t *guid,
grub_size_t *datasize_out,

View File

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Wed, 11 May 2022 16:20:52 -0400
Subject: [PATCH] Define GRUB_EFI_SHIM_LOCK_GUID
Added in f76a27996c34900f2c369a8a0d6ac72ae2faa988 ("efi: Make shim_lock
GUID and protocol type public"), but that commit also manipulates the
lock protocol definition and some other guids we don't care about right
now.
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
---
include/grub/efi/api.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 37e7b16287..2a243fd290 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -349,6 +349,11 @@
{ 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \
}
+#define GRUB_EFI_SHIM_LOCK_GUID \
+ { 0x605dab50, 0xe046, 0x4300, \
+ { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } \
+ }
+
struct grub_efi_sal_system_table
{
grub_uint32_t signature;

View File

@ -0,0 +1,84 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 21 Mar 2022 16:06:10 -0400
Subject: [PATCH] misc: Make grub_min() and grub_max() more resilient.
grub_min(a,b) and grub_max(a,b) use a relatively naive implementation
which leads to several problems:
- they evaluate their parameters more than once
- the naive way to address this, to declare temporary variables in a
statement-expression, isn't resilient against nested uses, because
MIN(a,MIN(b,c)) results in the temporary variables being declared in
two nested scopes, which may result in a build warning depending on
your build options.
This patch changes our implementation to use a statement-expression
inside a helper macro, and creates the symbols for the temporary
variables with __COUNTER__ (A GNU C cpp extension) and token pasting to
create uniquely named internal variables.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 2d6800450fa731d7b3ef9893986806e88e819eb6)
(cherry picked from commit adaf6a5ae66fb8a23274e3030e9df2714d0fc396)
---
grub-core/loader/multiboot_elfxx.c | 4 +---
include/grub/misc.h | 25 +++++++++++++++++++++++--
2 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c
index f2318e0d16..87f6e31aa6 100644
--- a/grub-core/loader/multiboot_elfxx.c
+++ b/grub-core/loader/multiboot_elfxx.c
@@ -35,9 +35,7 @@
#endif
#include <grub/i386/relocator.h>
-
-#define CONCAT(a,b) CONCAT_(a, b)
-#define CONCAT_(a,b) a ## b
+#include <grub/misc.h>
#pragma GCC diagnostic ignored "-Wcast-align"
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 6be6a88f65..7ef1a1a87e 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -35,6 +35,14 @@
#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
#define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; }
+#ifndef CONCAT_
+#define CONCAT_(a, b) a ## b
+#endif
+
+#ifndef CONCAT
+#define CONCAT(a, b) CONCAT_(a, b)
+#endif
+
#define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__)
void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n);
@@ -524,7 +532,20 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file,
#define grub_boot_time(...)
#endif
-#define grub_max(a, b) (((a) > (b)) ? (a) : (b))
-#define grub_min(a, b) (((a) < (b)) ? (a) : (b))
+#define _grub_min(a, b, _a, _b) \
+ ({ typeof (a) _a = (a); \
+ typeof (b) _b = (b); \
+ _a < _b ? _a : _b; })
+#define grub_min(a, b) _grub_min(a, b, \
+ CONCAT(_a_,__COUNTER__), \
+ CONCAT(_b_,__COUNTER__))
+
+#define _grub_max(a, b, _a, _b) \
+ ({ typeof (a) _a = (a); \
+ typeof (b) _b = (b); \
+ _a > _b ? _a : _b; })
+#define grub_max(a, b) _grub_max(a, b, \
+ CONCAT(_a_,__COUNTER__), \
+ CONCAT(_b_,__COUNTER__))
#endif /* ! GRUB_MISC_HEADER */

View File

@ -0,0 +1,94 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Thu, 21 Apr 2022 16:31:17 -0400
Subject: [PATCH] ReiserFS: switch to using grub_min()/grub_max()
This is a minor cleanup patch to remove the bespoke MIN() and MAX()
definitions from the reiserfs driver, and uses grub_min() / grub_max()
instead.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 5fc601574fce99b32fe4dfb55bd8f3ab0175fd6a)
(cherry picked from commit 31e581893c564582c729fd0c033d3ce021854be8)
---
grub-core/fs/reiserfs.c | 28 +++++++++-------------------
1 file changed, 9 insertions(+), 19 deletions(-)
diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c
index 39736f63c6..9556c15ff0 100644
--- a/grub-core/fs/reiserfs.c
+++ b/grub-core/fs/reiserfs.c
@@ -42,16 +42,6 @@
GRUB_MOD_LICENSE ("GPLv3+");
-#define MIN(a, b) \
- ({ typeof (a) _a = (a); \
- typeof (b) _b = (b); \
- _a < _b ? _a : _b; })
-
-#define MAX(a, b) \
- ({ typeof (a) _a = (a); \
- typeof (b) _b = (b); \
- _a > _b ? _a : _b; })
-
#define REISERFS_SUPER_BLOCK_OFFSET 0x10000
#define REISERFS_MAGIC_LEN 12
#define REISERFS_MAGIC_STRING "ReIsEr"
@@ -1076,7 +1066,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2);
initial_position = off;
current_position = 0;
- final_position = MIN (len + initial_position, node->size);
+ final_position = grub_min (len + initial_position, node->size);
grub_dprintf ("reiserfs",
"Reading from %lld to %lld (%lld instead of requested %ld)\n",
(unsigned long long) initial_position,
@@ -1115,8 +1105,8 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block);
if (initial_position < current_position + item_size)
{
- offset = MAX ((signed) (initial_position - current_position), 0);
- length = (MIN (item_size, final_position - current_position)
+ offset = grub_max ((signed) (initial_position - current_position), 0);
+ length = (grub_min (item_size, final_position - current_position)
- offset);
grub_dprintf ("reiserfs",
"Reading direct block %u from %u to %u...\n",
@@ -1161,9 +1151,9 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block);
if (current_position + block_size >= initial_position)
{
- offset = MAX ((signed) (initial_position - current_position),
- 0);
- length = (MIN (block_size, final_position - current_position)
+ offset = grub_max ((signed) (initial_position - current_position),
+ 0);
+ length = (grub_min (block_size, final_position - current_position)
- offset);
grub_dprintf ("reiserfs",
"Reading indirect block %u from %u to %u...\n",
@@ -1205,7 +1195,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
switch (found.type)
{
case GRUB_REISERFS_DIRECT:
- read_length = MIN (len, item_size - file->offset);
+ read_length = grub_min (len, item_size - file->offset);
grub_disk_read (found.data->disk,
(found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE,
grub_le_to_cpu16 (found.header.item_location) + file->offset,
@@ -1224,12 +1214,12 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node,
item_size, (char *) indirect_block_ptr);
if (grub_errno)
goto fail;
- len = MIN (len, file->size - file->offset);
+ len = grub_min (len, file->size - file->offset);
for (indirect_block = file->offset / block_size;
indirect_block < indirect_block_count && read_length < len;
indirect_block++)
{
- read = MIN (block_size, len - read_length);
+ read = grub_min (block_size, len - read_length);
grub_disk_read (found.data->disk,
(grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE,
file->offset % block_size, read,

View File

@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Thu, 24 Mar 2022 14:40:01 -0400
Subject: [PATCH] misc: make grub_boot_time() also call
grub_dprintf("boot",...)
Currently grub_boot_time() includes valuable debugging messages, but if
you build without BOOT_TIME_STATS enabled, they are silently and
confusingly compiled away.
This patch changes grub_boot_time() to also log when "boot" is enabled
in DEBUG, regardless of BOOT_TIME_STATS.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 4fd282de00df05ce289467861deb7a0e186cfbd7)
(cherry picked from commit cc7e60a9f3ad1fa74b9cd48a7e66b1976f9a554a)
---
grub-core/kern/misc.c | 3 ++-
include/grub/misc.h | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
index 859d71659a..b375e486a4 100644
--- a/grub-core/kern/misc.c
+++ b/grub-core/kern/misc.c
@@ -1336,7 +1336,8 @@ grub_real_boot_time (const char *file,
n->next = 0;
va_start (args, fmt);
- n->msg = grub_xvasprintf (fmt, args);
+ n->msg = grub_xvasprintf (fmt, args);
+ grub_dprintf ("boot", "%s\n", n->msg);
va_end (args);
*boot_time_last = n;
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 7ef1a1a87e..1b722c8185 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -529,7 +529,7 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file,
const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4)));
#define grub_boot_time(...) grub_real_boot_time(GRUB_FILE, __LINE__, __VA_ARGS__)
#else
-#define grub_boot_time(...)
+#define grub_boot_time(fmt, ...) grub_dprintf("boot", fmt "\n", ##__VA_ARGS__)
#endif
#define _grub_min(a, b, _a, _b) \

View File

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Thu, 24 Feb 2022 16:32:51 -0500
Subject: [PATCH] modules: make .module_license read-only
Currently .module_license is set writable (that is, the section has the
SHF_WRITE flag set) in the module's ELF headers. This probably never
actually matters, but it can't possibly be correct.
This patch sets that data as "const", which causes that flag not to be
set.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 2eff3e2c9d9e6b75daa81b840c96f112ef7d5de6)
(cherry picked from commit 3c3c1858d1c056eee660d67888be80e7eae498ca)
---
include/grub/dl.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/grub/dl.h b/include/grub/dl.h
index 6a3e251b45..9ec6caf3f9 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -121,7 +121,7 @@ grub_mod_fini (void)
#define ATTRIBUTE_USED __unused__
#endif
#define GRUB_MOD_LICENSE(license) \
- static char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license;
+ static const char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license;
#define GRUB_MOD_DEP(name) \
static const char grub_module_depend_##name[] \
__attribute__((section(GRUB_MOD_SECTION(moddeps)), ATTRIBUTE_USED)) = #name

View File

@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Thu, 24 Feb 2022 16:40:11 -0500
Subject: [PATCH] modules: strip .llvm_addrsig sections and similar.
Currently grub modules built with clang or gcc have several sections
which we don't actually need or support.
We already have a list of section to skip in genmod.sh, and this patch
adds the following sections to that list (as well as a few newlines):
.note.gnu.property
.llvm*
Note that the glob there won't work without a new enough linker, but the
failure is just reversion to the status quo, so that's not a big problem.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit e85d1c4d795f8135ad0acfa36d64760d12d6fed1)
(cherry picked from commit d3024204b2e2c69ecb91392eeb87c1e6835c3743)
---
grub-core/genmod.sh.in | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in
index 1250589b3f..c2c5280d75 100644
--- a/grub-core/genmod.sh.in
+++ b/grub-core/genmod.sh.in
@@ -57,8 +57,11 @@ if test x@TARGET_APPLE_LINKER@ != x1; then
@TARGET_STRIP@ --strip-unneeded \
-K grub_mod_init -K grub_mod_fini \
-K _grub_mod_init -K _grub_mod_fini \
- -R .note.gnu.gold-version -R .note.GNU-stack \
+ -R .note.GNU-stack \
+ -R .note.gnu.gold-version \
+ -R .note.gnu.property \
-R .gnu.build.attributes \
+ -R '.llvm*' \
-R .rel.gnu.build.attributes \
-R .rela.gnu.build.attributes \
-R .eh_frame -R .rela.eh_frame -R .rel.eh_frame \

View File

@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 21 Mar 2022 16:56:10 -0400
Subject: [PATCH] modules: Don't allocate space for non-allocable sections.
Currently when loading grub modules, we allocate space for all sections,
including those without SHF_ALLOC set. We then copy the sections that
/do/ have SHF_ALLOC set into the allocated memory, leaving some of our
allocation untouched forever. Additionally, on platforms with GOT
fixups and trampolines, we currently compute alignment round-ups for the
sections and sections with sh_size = 0.
This patch removes the extra space from the allocation computation, and
makes the allocation computation loop skip empty sections as the loading
loop does.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 03215e342f552396ab08125ea769b1e166417ec1)
(cherry picked from commit 91518751b9bcba078e3f4385f4b2f6c39cab49cd)
---
grub-core/kern/dl.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index 520126beab..ba1b33c20b 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -290,6 +290,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
i < e->e_shnum;
i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
{
+ if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC))
+ continue;
+
tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
if (talign < s->sh_addralign)
talign = s->sh_addralign;

View File

@ -0,0 +1,83 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Fri, 25 Mar 2022 15:40:12 -0400
Subject: [PATCH] pe: add the DOS header struct and fix some bad naming.
In order to properly validate a loaded kernel's support for being loaded
without a writable stack or executable, we need to be able to properly
parse arbitrary PE headers.
Currently, pe32.h is written in such a way that the MS-DOS header that
tells us where to find the PE header in the binary can't be accessed.
Further, for some reason it calls the DOS MZ magic "GRUB_PE32_MAGIC".
This patch adds the structure for the DOS header, renames the DOS magic
define, and adds defines for the actual PE magic.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 955f47aa8300387eecf18b0866d21dde7720593d)
(cherry picked from commit 662744c2e986cb770fe49e71e019aaf33a66272d)
---
grub-core/loader/arm64/linux.c | 2 +-
include/grub/efi/pe32.h | 28 ++++++++++++++++++++++++++--
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
index e1923cf725..24ab0f0074 100644
--- a/grub-core/loader/arm64/linux.c
+++ b/grub-core/loader/arm64/linux.c
@@ -57,7 +57,7 @@ grub_armxx_efi_linux_check_image (struct linux_armxx_kernel_header * lh)
if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE)
return grub_error(GRUB_ERR_BAD_OS, "invalid magic number");
- if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC)
+ if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled"));
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
index c03cc599f6..2241f6317b 100644
--- a/include/grub/efi/pe32.h
+++ b/include/grub/efi/pe32.h
@@ -45,7 +45,30 @@
#define GRUB_PE32_MSDOS_STUB_SIZE 0x80
-#define GRUB_PE32_MAGIC 0x5a4d
+#define GRUB_DOS_MAGIC 0x5a4d
+
+struct grub_dos_header
+{
+ grub_uint16_t magic;
+ grub_uint16_t cblp;
+ grub_uint16_t cp;
+ grub_uint16_t crlc;
+ grub_uint16_t cparhdr;
+ grub_uint16_t minalloc;
+ grub_uint16_t maxalloc;
+ grub_uint16_t ss;
+ grub_uint16_t sp;
+ grub_uint16_t csum;
+ grub_uint16_t ip;
+ grub_uint16_t cs;
+ grub_uint16_t lfarlc;
+ grub_uint16_t ovno;
+ grub_uint16_t res0[4];
+ grub_uint16_t oemid;
+ grub_uint16_t oeminfo;
+ grub_uint16_t res1[10];
+ grub_uint32_t lfanew;
+};
/* According to the spec, the minimal alignment is 512 bytes...
But some examples (such as EFI drivers in the Intel
@@ -271,7 +294,8 @@ struct grub_pe32_section_table
-#define GRUB_PE32_SIGNATURE_SIZE 4
+#define GRUB_PE32_SIGNATURE_SIZE 4
+#define GRUB_PE32_SIGNATURE "PE\0\0"
struct grub_pe32_header
{

View File

@ -0,0 +1,87 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Wed, 9 Feb 2022 16:08:20 -0500
Subject: [PATCH] EFI: allocate kernel in EFI_RUNTIME_SERVICES_CODE instead of
EFI_LOADER_DATA.
On some of the firmwares with more security mitigations, EFI_LOADER_DATA
doesn't get you executable memory, and we take a fault and reboot when
we enter kernel.
This patch correctly allocates the kernel code as EFI_RUNTIME_SERVICES_CODE
rather than EFI_LOADER_DATA.
Signed-off-by: Peter Jones <pjones@redhat.com>
[rharwood: use kernel_size]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry picked from commit 8b31058a12d3e85f0f0180ac90b98d6465fccbb7)
(cherry picked from commit 460df66aab9b3a57fc0d14a21a595cd467c4b13e)
---
grub-core/loader/i386/efi/linux.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index 8337191921..3d4069e4c6 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -86,7 +86,9 @@ kernel_free(void *addr, grub_efi_uintn_t size)
}
static void *
-kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
+kernel_alloc(grub_efi_uintn_t size,
+ grub_efi_memory_type_t memtype,
+ const char * const errmsg)
{
void *addr = 0;
unsigned int i;
@@ -112,7 +114,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
prev_max = max;
addr = grub_efi_allocate_pages_real (max, pages,
max_addresses[i].alloc_type,
- GRUB_EFI_LOADER_DATA);
+ memtype);
if (addr)
grub_dprintf ("linux", "Allocated at %p\n", addr);
}
@@ -243,7 +245,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[])
}
}
- initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
+ initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA,
+ N_("can't allocate initrd"));
if (initrd_mem == NULL)
goto fail;
grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem);
@@ -411,7 +414,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
#endif
- params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters");
+ params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA,
+ "cannot allocate kernel parameters");
if (!params)
goto fail;
grub_dprintf ("linux", "params = %p\n", params);
@@ -432,7 +436,9 @@ 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");
- cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline"));
+ cmdline = kernel_alloc (lh->cmdline_size + 1,
+ GRUB_EFI_RUNTIME_SERVICES_DATA,
+ N_("can't allocate cmdline"));
if (!cmdline)
goto fail;
grub_dprintf ("linux", "cmdline = %p\n", cmdline);
@@ -478,7 +484,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS;
kernel_size = lh->init_size;
- kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel"));
+ kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE,
+ N_("can't allocate kernel"));
restore_addresses();
if (!kernel_mem)
goto fail;

View File

@ -0,0 +1,360 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 21 Mar 2022 17:45:40 -0400
Subject: [PATCH] modules: load module sections at page-aligned addresses
Currently we load module sections at whatever alignment gcc+ld happened
to dump into the ELF section header, which is often pretty useless. For
example, by default time.mod has these sections on a current x86_64
build:
$ eu-readelf -a grub-core/time.mod |& grep ^Section -A13
Section Headers:
[Nr] Name Type Addr Off Size ES Flags Lk Inf Al
[ 0] NULL 0 00000000 00000000 0 0 0 0
[ 1] .text PROGBITS 0 00000040 0000015e 0 AX 0 0 1
[ 2] .rela.text RELA 0 00000458 000001e0 24 I 8 1 8
[ 3] .rodata.str1.1 PROGBITS 0 0000019e 000000a1 1 AMS 0 0 1
[ 4] .module_license PROGBITS 0 00000240 0000000f 0 A 0 0 8
[ 5] .data PROGBITS 0 0000024f 00000000 0 WA 0 0 1
[ 6] .bss NOBITS 0 00000250 00000008 0 WA 0 0 8
[ 7] .modname PROGBITS 0 00000250 00000005 0 0 0 1
[ 8] .symtab SYMTAB 0 00000258 00000150 24 9 6 8
[ 9] .strtab STRTAB 0 000003a8 000000ab 0 0 0 1
[10] .shstrtab STRTAB 0 00000638 00000059 0 0 0 1
With NX protections being page based, loading sections with either a 1
or 8 *byte* alignment does absolutely nothing to help us out.
This patch switches most EFI platforms to load module sections at 4kB
page-aligned addresses. To do so, it adds an new per-arch function,
grub_arch_dl_min_alignment(), which returns the alignment needed for
dynamically loaded sections (in bytes). Currently it sets it to 4096
when GRUB_MACHINE_EFI is true on x86_64, i386, arm, arm64, and emu, and
1-byte alignment on everything else.
It then changes the allocation size computation and the loader code in
grub_dl_load_segments() to align the locations and sizes up to these
boundaries, and fills any added padding with zeros.
All of this happens before relocations are applied, so the relocations
factor that in with no change.
As an aside, initially Daniel Kiper and I thought that it might be a
better idea to split the modules up into top-level sections as
.text.modules, .rodata.modules, .data.modules, etc., so that their page
permissions would get set by the loader that's loading grub itself.
This turns out to have two significant downsides: 1) either in mkimage
or in grub_dl_relocate_symbols(), you wind up having to dynamically
process the relocations to accommodate the moved module sections, and 2)
you then need to change the permissions on the modules and change them
back while relocating them in grub_dl_relocate_symbols(), which means
that any loader that /does/ honor the section flags but does /not/
generally support NX with the memory attributes API will cause grub to
fail.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 31d52500b281619d92b03b2c2d30fe15aedaf326)
(cherry picked from commit 04f1df6b665493e38de66018aebe377fdac4ceec)
[rharwood: not risc-v yet]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
---
grub-core/kern/arm/dl.c | 13 +++++++++++++
grub-core/kern/arm64/dl.c | 13 +++++++++++++
grub-core/kern/dl.c | 29 +++++++++++++++++++++--------
grub-core/kern/emu/full.c | 13 +++++++++++++
grub-core/kern/i386/dl.c | 13 +++++++++++++
grub-core/kern/ia64/dl.c | 9 +++++++++
grub-core/kern/mips/dl.c | 8 ++++++++
grub-core/kern/powerpc/dl.c | 9 +++++++++
grub-core/kern/sparc64/dl.c | 9 +++++++++
grub-core/kern/x86_64/dl.c | 13 +++++++++++++
include/grub/dl.h | 2 ++
docs/grub-dev.texi | 6 +++---
12 files changed, 126 insertions(+), 11 deletions(-)
diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c
index eab9d17ff2..9260737936 100644
--- a/grub-core/kern/arm/dl.c
+++ b/grub-core/kern/arm/dl.c
@@ -278,3 +278,16 @@ grub_arch_dl_check_header (void *ehdr)
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+ return 4096;
+#else
+ return 1;
+#endif
+}
diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c
index fb03373190..826f8e721e 100644
--- a/grub-core/kern/arm64/dl.c
+++ b/grub-core/kern/arm64/dl.c
@@ -191,3 +191,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+ return 4096;
+#else
+ return 1;
+#endif
+}
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index ba1b33c20b..5c2153acf9 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -278,7 +278,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
{
unsigned i;
const Elf_Shdr *s;
- grub_size_t tsize = 0, talign = 1;
+ grub_size_t tsize = 0, talign = 1, arch_addralign = 1;
#if !defined (__i386__) && !defined (__x86_64__)
grub_size_t tramp;
grub_size_t got;
@@ -286,16 +286,24 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
#endif
char *ptr;
+ arch_addralign = grub_arch_dl_min_alignment ();
+
for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
{
+ grub_size_t sh_addralign;
+ grub_size_t sh_size;
+
if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC))
continue;
- tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
- if (talign < s->sh_addralign)
- talign = s->sh_addralign;
+ sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign);
+ sh_size = ALIGN_UP(s->sh_size, sh_addralign);
+
+ tsize = ALIGN_UP (tsize, sh_addralign) + sh_size;
+ if (talign < sh_addralign)
+ talign = sh_addralign;
}
#if !defined (__i386__) && !defined (__x86_64__)
@@ -324,6 +332,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
i < e->e_shnum;
i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
{
+ grub_size_t sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign);
+ grub_size_t sh_size = ALIGN_UP(s->sh_size, sh_addralign);
+
if (s->sh_flags & SHF_ALLOC)
{
grub_dl_segment_t seg;
@@ -336,17 +347,19 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
{
void *addr;
- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
+ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, sh_addralign);
addr = ptr;
- ptr += s->sh_size;
+ ptr += sh_size;
switch (s->sh_type)
{
case SHT_PROGBITS:
grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
+ grub_memset ((char *)addr + s->sh_size, 0,
+ sh_size - s->sh_size);
break;
case SHT_NOBITS:
- grub_memset (addr, 0, s->sh_size);
+ grub_memset (addr, 0, sh_size);
break;
}
@@ -355,7 +368,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
else
seg->addr = 0;
- seg->size = s->sh_size;
+ seg->size = sh_size;
seg->section = i;
seg->next = mod->segment;
mod->segment = seg;
diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c
index e8d63b1f5f..1de1c28eb0 100644
--- a/grub-core/kern/emu/full.c
+++ b/grub-core/kern/emu/full.c
@@ -67,3 +67,16 @@ grub_arch_dl_init_linker (void)
}
#endif
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+ return 4096;
+#else
+ return 1;
+#endif
+}
diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c
index 1346da5cc9..d6b4681fc9 100644
--- a/grub-core/kern/i386/dl.c
+++ b/grub-core/kern/i386/dl.c
@@ -79,3 +79,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+ return 4096;
+#else
+ return 1;
+#endif
+}
diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c
index ebcf316298..3bb753a89b 100644
--- a/grub-core/kern/ia64/dl.c
+++ b/grub-core/kern/ia64/dl.c
@@ -143,3 +143,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
}
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+ return 1;
+}
diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c
index 5d7d299c74..6d83bd71e9 100644
--- a/grub-core/kern/mips/dl.c
+++ b/grub-core/kern/mips/dl.c
@@ -272,3 +272,11 @@ grub_arch_dl_init_linker (void)
grub_dl_register_symbol ("_gp_disp", &_gp_disp_dummy, 0, 0);
}
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+ return 1;
+}
diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c
index 3a7fa3ed3d..577e27d871 100644
--- a/grub-core/kern/powerpc/dl.c
+++ b/grub-core/kern/powerpc/dl.c
@@ -165,3 +165,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+ return 1;
+}
diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c
index 739be47174..c741c1782e 100644
--- a/grub-core/kern/sparc64/dl.c
+++ b/grub-core/kern/sparc64/dl.c
@@ -184,3 +184,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+ return 1;
+}
diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c
index 3a73e6e6ce..6c20b7c367 100644
--- a/grub-core/kern/x86_64/dl.c
+++ b/grub-core/kern/x86_64/dl.c
@@ -114,3 +114,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
return GRUB_ERR_NONE;
}
+
+/*
+ * Tell the loader what our minimum section alignment is.
+ */
+grub_size_t
+grub_arch_dl_min_alignment (void)
+{
+#ifdef GRUB_MACHINE_EFI
+ return 4096;
+#else
+ return 1;
+#endif
+}
diff --git a/include/grub/dl.h b/include/grub/dl.h
index 9ec6caf3f9..dd4c3e7ff4 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -280,6 +280,8 @@ grub_err_t grub_arch_dl_check_header (void *ehdr);
grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
Elf_Shdr *s, grub_dl_segment_t seg);
+grub_size_t
+grub_arch_dl_min_alignment (void);
#endif
#if defined (_mips)
diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index 03d53498c5..dbfb94bc06 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -638,9 +638,9 @@ declare startup asm file ($cpu_$platform_startup) as well as any other files
(e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c).
At this stage you will also need to add dummy dl.c and cache.S with functions
grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t
-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and
-void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They
-won't be used for now.
+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c), grub_uint32_t
+grub_arch_dl_min_alignment (void), and void grub_arch_sync_caches (void
+*address, grub_size_t len) (cache.S). They won't be used for now.
You will need to create directory include/$cpu/$platform and a file
include/$cpu/types.h. The later folowing this template:

View File

@ -0,0 +1,320 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Tue, 22 Mar 2022 10:56:21 -0400
Subject: [PATCH] nx: add memory attribute get/set API
For NX, we need to set the page access permission attributes for write
and execute permissions.
This patch adds two new primitives, grub_set_mem_attrs() and
grub_clear_mem_attrs(), and associated constant definitions, to be used
for that purpose.
For most platforms, it adds a dummy implementation that returns
GRUB_ERR_NONE. On EFI platforms, it adds a common helper function,
grub_efi_status_to_err(), which translates EFI error codes to grub error
codes, adds headers for the EFI Memory Attribute Protocol (still pending
standardization), and an implementation of the grub nx primitives using
it.
Signed-off-by: Peter Jones <pjones@redhat.com>
[rharwood: add pjones's none/nyi fixup]
(cherry picked from commit 35de78a8d32b9fad5291ec96fd3cbb9cf2f4a80b)
(cherry picked from commit 46cb4f9557bdba1db0a17d012df705d94d81a9f6)
[rharwood: context fuzz, guids]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
---
grub-core/kern/efi/efi.c | 36 +++++++++++++
grub-core/kern/efi/mm.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++
include/grub/efi/api.h | 25 +++++++++
include/grub/efi/efi.h | 2 +
include/grub/mm.h | 32 ++++++++++++
5 files changed, 226 insertions(+)
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
index fccea20a01..09468dc5d5 100644
--- a/grub-core/kern/efi/efi.c
+++ b/grub-core/kern/efi/efi.c
@@ -1093,3 +1093,39 @@ grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1,
return 0;
}
+
+grub_err_t
+grub_efi_status_to_err (grub_efi_status_t status)
+{
+ grub_err_t err;
+ switch (status)
+ {
+ case GRUB_EFI_SUCCESS:
+ err = GRUB_ERR_NONE;
+ break;
+ case GRUB_EFI_INVALID_PARAMETER:
+ default:
+ err = GRUB_ERR_BAD_ARGUMENT;
+ break;
+ case GRUB_EFI_OUT_OF_RESOURCES:
+ err = GRUB_ERR_OUT_OF_MEMORY;
+ break;
+ case GRUB_EFI_DEVICE_ERROR:
+ err = GRUB_ERR_IO;
+ break;
+ case GRUB_EFI_WRITE_PROTECTED:
+ err = GRUB_ERR_WRITE_ERROR;
+ break;
+ case GRUB_EFI_SECURITY_VIOLATION:
+ err = GRUB_ERR_ACCESS_DENIED;
+ break;
+ case GRUB_EFI_NOT_FOUND:
+ err = GRUB_ERR_FILE_NOT_FOUND;
+ break;
+ case GRUB_EFI_ABORTED:
+ err = GRUB_ERR_WAIT;
+ break;
+ }
+
+ return err;
+}
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 9e76f23e5f..2cf4a4883a 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -730,3 +730,134 @@ grub_efi_get_ram_base(grub_addr_t *base_addr)
return GRUB_ERR_NONE;
}
#endif
+
+static inline grub_uint64_t
+grub_mem_attrs_to_uefi_mem_attrs (grub_uint64_t attrs)
+{
+ grub_uint64_t ret = GRUB_EFI_MEMORY_RP |
+ GRUB_EFI_MEMORY_RO |
+ GRUB_EFI_MEMORY_XP;
+
+ if (attrs & GRUB_MEM_ATTR_R)
+ ret &= ~GRUB_EFI_MEMORY_RP;
+
+ if (attrs & GRUB_MEM_ATTR_W)
+ ret &= ~GRUB_EFI_MEMORY_RO;
+
+ if (attrs & GRUB_MEM_ATTR_X)
+ ret &= ~GRUB_EFI_MEMORY_XP;
+
+ return ret;
+}
+
+static inline grub_uint64_t
+uefi_mem_attrs_to_grub_mem_attrs (grub_uint64_t attrs)
+{
+ grub_uint64_t ret = GRUB_MEM_ATTR_R |
+ GRUB_MEM_ATTR_W |
+ GRUB_MEM_ATTR_X;
+
+ if (attrs & GRUB_EFI_MEMORY_RP)
+ ret &= ~GRUB_MEM_ATTR_R;
+
+ if (attrs & GRUB_EFI_MEMORY_RO)
+ ret &= ~GRUB_MEM_ATTR_W;
+
+ if (attrs & GRUB_EFI_MEMORY_XP)
+ ret &= ~GRUB_MEM_ATTR_X;
+
+ return ret;
+}
+
+grub_err_t
+grub_get_mem_attrs (grub_addr_t addr, grub_size_t size, grub_uint64_t *attrs)
+{
+ grub_efi_memory_attribute_protocol_t *proto;
+ grub_efi_physical_address_t physaddr = addr;
+ grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
+ grub_efi_status_t efi_status;
+
+ proto = grub_efi_locate_protocol (&protocol_guid, 0);
+ if (!proto)
+ return GRUB_ERR_NOT_IMPLEMENTED_YET;
+
+ if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL)
+ {
+ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" and attrs %p\n",
+ __func__, physaddr, physaddr+size-1, attrs);
+ return 0;
+ }
+
+ efi_status = efi_call_4(proto->get_memory_attributes,
+ proto, physaddr, size, attrs);
+ *attrs = uefi_mem_attrs_to_grub_mem_attrs (*attrs);
+
+ return grub_efi_status_to_err (efi_status);
+}
+
+grub_err_t
+grub_update_mem_attrs (grub_addr_t addr, grub_size_t size,
+ grub_uint64_t set_attrs, grub_uint64_t clear_attrs)
+{
+ grub_efi_memory_attribute_protocol_t *proto;
+ grub_efi_physical_address_t physaddr = addr;
+ grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID;
+ grub_efi_status_t efi_status = GRUB_EFI_SUCCESS;
+ grub_uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs;
+ grub_err_t err;
+
+ proto = grub_efi_locate_protocol (&protocol_guid, 0);
+ if (!proto)
+ return GRUB_ERR_NONE;
+
+ err = grub_get_mem_attrs (addr, size, &before);
+ if (err)
+ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n",
+ addr, size, &before, err);
+
+ if (physaddr & 0xfff || size & 0xfff || size == 0)
+ {
+ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" +%s%s%s -%s%s%s\n",
+ __func__, physaddr, physaddr + size - 1,
+ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
+ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "");
+ return 0;
+ }
+
+ uefi_set_attrs = grub_mem_attrs_to_uefi_mem_attrs (set_attrs);
+ grub_dprintf ("nx", "translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_attrs);
+ uefi_clear_attrs = grub_mem_attrs_to_uefi_mem_attrs (clear_attrs);
+ grub_dprintf ("nx", "translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs);
+ if (uefi_set_attrs)
+ efi_status = efi_call_4(proto->set_memory_attributes,
+ proto, physaddr, size, uefi_set_attrs);
+ if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs)
+ efi_status = efi_call_4(proto->clear_memory_attributes,
+ proto, physaddr, size, uefi_clear_attrs);
+
+ err = grub_get_mem_attrs (addr, size, &after);
+ if (err)
+ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n",
+ addr, size, &after, err);
+
+ grub_dprintf ("nx", "set +%s%s%s -%s%s%s on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" before:%c%c%c after:%c%c%c\n",
+ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
+ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
+ addr, addr + size - 1,
+ (before & GRUB_MEM_ATTR_R) ? 'r' : '-',
+ (before & GRUB_MEM_ATTR_W) ? 'w' : '-',
+ (before & GRUB_MEM_ATTR_X) ? 'x' : '-',
+ (after & GRUB_MEM_ATTR_R) ? 'r' : '-',
+ (after & GRUB_MEM_ATTR_W) ? 'w' : '-',
+ (after & GRUB_MEM_ATTR_X) ? 'x' : '-');
+
+ return grub_efi_status_to_err (efi_status);
+}
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 2a243fd290..510a4030f5 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -354,6 +354,11 @@
{ 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } \
}
+#define GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \
+ { 0xf4560cf6, 0x40ec, 0x4b4a, \
+ { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \
+ }
+
struct grub_efi_sal_system_table
{
grub_uint32_t signature;
@@ -2091,6 +2096,26 @@ struct grub_efi_rng_protocol
};
typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t;
+struct grub_efi_memory_attribute_protocol
+{
+ grub_efi_status_t (*get_memory_attributes) (
+ struct grub_efi_memory_attribute_protocol *this,
+ grub_efi_physical_address_t base_address,
+ grub_efi_uint64_t length,
+ grub_efi_uint64_t *attributes);
+ grub_efi_status_t (*set_memory_attributes) (
+ struct grub_efi_memory_attribute_protocol *this,
+ grub_efi_physical_address_t base_address,
+ grub_efi_uint64_t length,
+ grub_efi_uint64_t attributes);
+ grub_efi_status_t (*clear_memory_attributes) (
+ struct grub_efi_memory_attribute_protocol *this,
+ grub_efi_physical_address_t base_address,
+ grub_efi_uint64_t length,
+ grub_efi_uint64_t attributes);
+};
+typedef struct grub_efi_memory_attribute_protocol grub_efi_memory_attribute_protocol_t;
+
#if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
|| defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__)
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 7af979b184..a635bcb0a9 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -159,4 +159,6 @@ struct grub_net_card;
grub_efi_handle_t
grub_efinet_get_device_handle (struct grub_net_card *card);
+grub_err_t EXPORT_FUNC(grub_efi_status_to_err) (grub_efi_status_t status);
+
#endif /* ! GRUB_EFI_EFI_HEADER */
diff --git a/include/grub/mm.h b/include/grub/mm.h
index 9c38dd3ca5..d81623d226 100644
--- a/include/grub/mm.h
+++ b/include/grub/mm.h
@@ -22,6 +22,7 @@
#include <grub/types.h>
#include <grub/symbol.h>
+#include <grub/err.h>
#include <config.h>
#ifndef NULL
@@ -38,6 +39,37 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size);
void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size);
#endif
+#define GRUB_MEM_ATTR_R 0x0000000000000004LLU
+#define GRUB_MEM_ATTR_W 0x0000000000000002LLU
+#define GRUB_MEM_ATTR_X 0x0000000000000001LLU
+
+#ifdef GRUB_MACHINE_EFI
+grub_err_t EXPORT_FUNC(grub_get_mem_attrs) (grub_addr_t addr,
+ grub_size_t size,
+ grub_uint64_t *attrs);
+grub_err_t EXPORT_FUNC(grub_update_mem_attrs) (grub_addr_t addr,
+ grub_size_t size,
+ grub_uint64_t set_attrs,
+ grub_uint64_t clear_attrs);
+#else /* !GRUB_MACHINE_EFI */
+static inline grub_err_t
+grub_get_mem_attrs (grub_addr_t addr __attribute__((__unused__)),
+ grub_size_t size __attribute__((__unused__)),
+ grub_uint64_t *attrs __attribute__((__unused__)))
+{
+ return GRUB_ERR_NONE;
+}
+
+static inline grub_err_t
+grub_update_mem_attrs (grub_addr_t addr __attribute__((__unused__)),
+ grub_size_t size __attribute__((__unused__)),
+ grub_uint64_t set_attrs __attribute__((__unused__)),
+ grub_uint64_t clear_attrs __attribute__((__unused__)))
+{
+ return GRUB_ERR_NONE;
+}
+#endif /* GRUB_MACHINE_EFI */
+
void grub_mm_check_real (const char *file, int line);
#define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__);

View File

@ -0,0 +1,265 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 21 Mar 2022 17:46:35 -0400
Subject: [PATCH] nx: set page permissions for loaded modules.
For NX, we need to set write and executable permissions on the sections
of grub modules when we load them.
On sections with SHF_ALLOC set, which is typically everything except
.modname and the symbol and string tables, this patch clears the Read
Only flag on sections that have the ELF flag SHF_WRITE set, and clears
the No eXecute flag on sections with SHF_EXECINSTR set. In all other
cases it sets both flags.
Signed-off-by: Peter Jones <pjones@redhat.com>
[rharwood: arm tgptr -> tgaddr]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
(cherry-picked from commit ca74904ede0406b594cbedc52ce8e38a6633d2ae)
(cherry picked from commit 2e2e72026f41cf7cffeb46a6a47f3c67d0b3be45)
---
grub-core/kern/dl.c | 120 +++++++++++++++++++++++++++++++++++++++-------------
include/grub/dl.h | 44 +++++++++++++++++++
2 files changed, 134 insertions(+), 30 deletions(-)
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index 5c2153acf9..68d3177f5e 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -286,6 +286,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
#endif
char *ptr;
+ grub_dprintf ("modules", "loading segments for \"%s\"\n", mod->name);
+
arch_addralign = grub_arch_dl_min_alignment ();
for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
@@ -385,6 +387,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
ptr += got;
#endif
+ grub_dprintf ("modules", "done loading segments for \"%s\"\n", mod->name);
return GRUB_ERR_NONE;
}
@@ -518,23 +521,6 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name)
return s;
return NULL;
}
-static long
-grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
-{
- Elf_Shdr *s;
- const char *str;
- unsigned i;
-
- s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
- str = (char *) e + s->sh_offset;
-
- for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
- i < e->e_shnum;
- i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
- if (grub_strcmp (str + s->sh_name, name) == 0)
- return (long)i;
- return -1;
-}
/* Me, Vladimir Serbinenko, hereby I add this module check as per new
GNU module policy. Note that this license check is informative only.
@@ -661,6 +647,7 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
Elf_Shdr *s;
unsigned i;
+ grub_dprintf ("modules", "relocating symbols for \"%s\"\n", mod->name);
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
@@ -669,24 +656,95 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
grub_dl_segment_t seg;
grub_err_t err;
- /* Find the target segment. */
- for (seg = mod->segment; seg; seg = seg->next)
- if (seg->section == s->sh_info)
- break;
+ seg = grub_dl_find_segment(mod, s->sh_info);
+ if (!seg)
+ continue;
- if (seg)
- {
- if (!mod->symtab)
- return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table");
+ if (!mod->symtab)
+ return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table");
- err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
- if (err)
- return err;
- }
+ err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg);
+ if (err)
+ return err;
}
+ grub_dprintf ("modules", "done relocating symbols for \"%s\"\n", mod->name);
return GRUB_ERR_NONE;
}
+
+static grub_err_t
+grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr)
+{
+ unsigned i;
+ const Elf_Shdr *s;
+ const Elf_Ehdr *e = ehdr;
+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
+ grub_size_t arch_addralign = grub_arch_dl_min_alignment ();
+ grub_addr_t tgaddr;
+ grub_uint64_t tgsz;
+#endif
+
+ grub_dprintf ("modules", "updating memory attributes for \"%s\"\n",
+ mod->name);
+ for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff);
+ i < e->e_shnum;
+ i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize))
+ {
+ grub_dl_segment_t seg;
+ grub_uint64_t set_attrs = GRUB_MEM_ATTR_R;
+ grub_uint64_t clear_attrs = GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X;
+
+ seg = grub_dl_find_segment(mod, i);
+ if (!seg)
+ continue;
+
+ if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC))
+ continue;
+
+ if (s->sh_flags & SHF_WRITE)
+ {
+ set_attrs |= GRUB_MEM_ATTR_W;
+ clear_attrs &= ~GRUB_MEM_ATTR_W;
+ }
+
+ if (s->sh_flags & SHF_EXECINSTR)
+ {
+ set_attrs |= GRUB_MEM_ATTR_X;
+ clear_attrs &= ~GRUB_MEM_ATTR_X;
+ }
+
+ grub_dprintf ("modules", "setting memory attrs for section \"%s\" to -%s%s%s+%s%s%s\n",
+ grub_dl_get_section_name(e, s),
+ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "",
+ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "",
+ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "",
+ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "");
+ grub_update_mem_attrs ((grub_addr_t)(seg->addr), seg->size, set_attrs, clear_attrs);
+ }
+
+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
+ tgaddr = grub_min((grub_addr_t)mod->tramp, (grub_addr_t)mod->got);
+ tgsz = grub_max((grub_addr_t)mod->trampptr, (grub_addr_t)mod->gotptr) - tgaddr;
+
+ if (tgsz)
+ {
+ tgsz = ALIGN_UP(tgsz, arch_addralign);
+
+ grub_dprintf ("modules", "updating attributes for GOT and trampolines\n",
+ mod->name);
+ grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X,
+ GRUB_MEM_ATTR_W);
+ }
+#endif
+
+ grub_dprintf ("modules", "done updating module memory attributes for \"%s\"\n",
+ mod->name);
+
+ return GRUB_ERR_NONE;
+}
+
static void
grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e)
{
@@ -752,6 +810,7 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
mod->ref_count = 1;
grub_dprintf ("modules", "relocating to %p\n", mod);
+
/* Me, Vladimir Serbinenko, hereby I add this module check as per new
GNU module policy. Note that this license check is informative only.
Modules have to be licensed under GPLv3 or GPLv3+ (optionally
@@ -765,7 +824,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
|| grub_dl_resolve_dependencies (mod, e)
|| grub_dl_load_segments (mod, e)
|| grub_dl_resolve_symbols (mod, e)
- || grub_dl_relocate_symbols (mod, e))
+ || grub_dl_relocate_symbols (mod, e)
+ || grub_dl_set_mem_attrs (mod, e))
{
mod->fini = 0;
grub_dl_unload (mod);
diff --git a/include/grub/dl.h b/include/grub/dl.h
index dd4c3e7ff4..6f46b7e86f 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -27,6 +27,7 @@
#include <grub/elf.h>
#include <grub/list.h>
#include <grub/misc.h>
+#include <grub/mm.h>
#endif
/*
@@ -268,6 +269,49 @@ grub_dl_is_persistent (grub_dl_t mod)
return mod->persistent;
}
+static inline const char *
+grub_dl_get_section_name (const Elf_Ehdr *e, const Elf_Shdr *s)
+{
+ Elf_Shdr *str_s;
+ const char *str;
+
+ str_s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
+ str = (char *) e + str_s->sh_offset;
+
+ return str + s->sh_name;
+}
+
+static inline long
+grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
+{
+ Elf_Shdr *s;
+ const char *str;
+ unsigned i;
+
+ s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
+ str = (char *) e + s->sh_offset;
+
+ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
+ i < e->e_shnum;
+ i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
+ if (grub_strcmp (str + s->sh_name, name) == 0)
+ return (long)i;
+ return -1;
+}
+
+/* Return the segment for a section of index N */
+static inline grub_dl_segment_t
+grub_dl_find_segment (grub_dl_t mod, unsigned n)
+{
+ grub_dl_segment_t seg;
+
+ for (seg = mod->segment; seg; seg = seg->next)
+ if (seg->section == n)
+ return seg;
+
+ return NULL;
+}
+
#endif
void * EXPORT_FUNC(grub_resolve_symbol) (const char *name);

View File

@ -0,0 +1,571 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Tue, 22 Mar 2022 10:57:07 -0400
Subject: [PATCH] nx: set attrs in our kernel loaders
For NX, our kernel loaders need to set write and execute page
permissions on allocated pages and the stack.
This patch adds those calls.
Signed-off-by: Peter Jones <pjones@redhat.com>
[rharwood: fix aarch64 callsites]
(cherry-picked from commit a9f79a997f01a83b36cdfa89ef2e72ac2a17c06c)
[rharwood: double verification]
(cherry picked from commit daba852bd3e4d7b7784b19cf7acf107dc3c0dce4)
[rharwood: stack_attrs initialization, no risc-v, arm renames, arm age]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
---
grub-core/kern/efi/mm.c | 78 ++++++++++++++++++
grub-core/loader/arm64/linux.c | 16 +++-
grub-core/loader/arm64/xen_boot.c | 4 +-
grub-core/loader/efi/chainloader.c | 11 +++
grub-core/loader/efi/linux.c | 162 ++++++++++++++++++++++++++++++++++++-
grub-core/loader/i386/efi/linux.c | 26 +++++-
grub-core/loader/i386/linux.c | 5 ++
include/grub/efi/efi.h | 6 +-
include/grub/efi/linux.h | 17 +++-
include/grub/efi/pe32.h | 2 +
10 files changed, 312 insertions(+), 15 deletions(-)
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 2cf4a4883a..8a896144df 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -602,6 +602,82 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map,
}
#endif
+grub_addr_t grub_stack_addr = (grub_addr_t)-1ll;
+grub_size_t grub_stack_size = 0;
+
+static void
+grub_nx_init (void)
+{
+ grub_uint64_t attrs, stack_attrs;
+ grub_err_t err;
+ grub_addr_t stack_current, stack_end;
+ const grub_uint64_t page_size = 4096;
+ const grub_uint64_t page_mask = ~(page_size - 1);
+
+ /*
+ * These are to confirm that the flags are working as expected when
+ * debugging.
+ */
+ attrs = 0;
+ stack_current = (grub_addr_t)grub_nx_init & page_mask;
+ err = grub_get_mem_attrs (stack_current, page_size, &attrs);
+ if (err)
+ {
+ grub_dprintf ("nx",
+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
+ stack_current, err);
+ grub_error_pop ();
+ }
+ else
+ grub_dprintf ("nx", "page attrs for grub_nx_init (%p) are %c%c%c\n",
+ grub_dl_load_core,
+ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
+ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-',
+ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-');
+
+ stack_current = (grub_addr_t)&stack_current & page_mask;
+ err = grub_get_mem_attrs (stack_current, page_size, &stack_attrs);
+ if (err)
+ {
+ grub_dprintf ("nx",
+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
+ stack_current, err);
+ grub_error_pop ();
+ }
+ else
+ {
+ attrs = stack_attrs;
+ grub_dprintf ("nx", "page attrs for stack (%p) are %c%c%c\n",
+ &attrs,
+ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-',
+ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-',
+ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-');
+ }
+
+ for (stack_end = stack_current + page_size ;
+ !(attrs & GRUB_MEM_ATTR_R);
+ stack_end += page_size)
+ {
+ err = grub_get_mem_attrs (stack_current, page_size, &attrs);
+ if (err)
+ {
+ grub_dprintf ("nx",
+ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n",
+ stack_current, err);
+ grub_error_pop ();
+ break;
+ }
+ }
+ if (stack_end > stack_current)
+ {
+ grub_stack_addr = stack_current;
+ grub_stack_size = stack_end - stack_current;
+ grub_dprintf ("nx",
+ "detected stack from 0x%"PRIxGRUB_ADDR" to 0x%"PRIxGRUB_ADDR"\n",
+ grub_stack_addr, grub_stack_addr + grub_stack_size - 1);
+ }
+}
+
void
grub_efi_mm_init (void)
{
@@ -615,6 +691,8 @@ grub_efi_mm_init (void)
grub_efi_uint64_t required_pages;
int mm_status;
+ grub_nx_init ();
+
/* Prepare a memory region to store two memory maps. */
memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
if (! memory_map)
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
index 24ab0f0074..37f5d0c7eb 100644
--- a/grub-core/loader/arm64/linux.c
+++ b/grub-core/loader/arm64/linux.c
@@ -191,7 +191,8 @@ free_params (void)
}
grub_err_t
-grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args)
+grub_armxx_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args,
+ int nx_supported)
{
grub_err_t retval;
@@ -201,7 +202,8 @@ grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args)
grub_dprintf ("linux", "linux command line: '%s'\n", args);
- retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr);
+ retval = grub_efi_linux_boot (addr, size, handover_offset,
+ (void *)addr, nx_supported);
/* Never reached... */
free_params();
@@ -211,7 +213,10 @@ grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args)
static grub_err_t
grub_linux_boot (void)
{
- return grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args);
+ return grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr,
+ (grub_size_t)kernel_size,
+ linux_args,
+ 0);
}
static grub_err_t
@@ -340,6 +345,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
struct grub_armxx_linux_pe_header *pe;
int rc;
grub_err_t err;
+ int nx_supported = 1;
grub_dl_ref (my_mod);
@@ -395,6 +401,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
}
+ err = grub_efi_check_nx_image_support((grub_addr_t) kernel_addr, kernel_size, &nx_supported);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
handover_offset = pe->opt.entry_addr;
diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
index 1a337866f0..1fd1bbb4bd 100644
--- a/grub-core/loader/arm64/xen_boot.c
+++ b/grub-core/loader/arm64/xen_boot.c
@@ -266,7 +266,9 @@ xen_boot (void)
return err;
return grub_armxx_efi_linux_boot_image (xen_hypervisor->start,
- xen_hypervisor->cmdline);
+ xen_hypervisor->size,
+ xen_hypervisor->cmdline,
+ 0);
}
static void
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 8e658f713e..b72e6bd5e3 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -1055,6 +1055,17 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
+ /*
+ * The OS kernel is going to set its own permissions when it takes over
+ * paging a few million instructions from now, and load_image() will set up
+ * anything that's needed based on the section headers, so there's no point
+ * in doing anything but clearing the protection bits here.
+ */
+ grub_dprintf("nx", "setting attributes for %p (%lu bytes) to %llx\n",
+ (void *)(grub_addr_t)address, fsize, 0llu);
+ grub_update_mem_attrs (address, fsize,
+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X, 0);
+
#if defined (__i386__) || defined (__x86_64__)
if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
{
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
index 927d89a90d..421502bd25 100644
--- a/grub-core/loader/efi/linux.c
+++ b/grub-core/loader/efi/linux.c
@@ -66,16 +66,125 @@ grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
+#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
+
+grub_err_t
+grub_efi_check_nx_image_support (grub_addr_t kernel_addr,
+ grub_size_t kernel_size,
+ int *nx_supported)
+{
+ struct grub_dos_header *doshdr;
+ grub_size_t sz = sizeof (*doshdr);
+
+ struct grub_pe32_header_32 *pe32;
+ struct grub_pe32_header_64 *pe64;
+
+ int image_is_compatible = 0;
+ int is_64_bit;
+
+ if (kernel_size < sz)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
+
+ doshdr = (void *)kernel_addr;
+
+ if ((doshdr->magic & 0xffff) != GRUB_DOS_MAGIC)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel DOS magic is invalid"));
+
+ sz = doshdr->lfanew + sizeof (*pe32);
+ if (kernel_size < sz)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
+
+ pe32 = (struct grub_pe32_header_32 *)(kernel_addr + doshdr->lfanew);
+ pe64 = (struct grub_pe32_header_64 *)pe32;
+
+ if (grub_memcmp (pe32->signature, GRUB_PE32_SIGNATURE,
+ GRUB_PE32_SIGNATURE_SIZE) != 0)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid"));
+
+ switch (pe32->coff_header.machine)
+ {
+ case GRUB_PE32_MACHINE_ARMTHUMB_MIXED:
+ case GRUB_PE32_MACHINE_I386:
+ is_64_bit = 0;
+ break;
+ case GRUB_PE32_MACHINE_ARM64:
+ case GRUB_PE32_MACHINE_IA64:
+ case GRUB_PE32_MACHINE_X86_64:
+ is_64_bit = 1;
+ break;
+ default:
+ return grub_error (GRUB_ERR_BAD_OS, N_("PE machine type 0x%04hx unknown"),
+ pe32->coff_header.machine);
+ }
+
+ if (is_64_bit)
+ {
+ sz = doshdr->lfanew + sizeof (*pe64);
+ if (kernel_size < sz)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small"));
+
+ if (pe64->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT)
+ image_is_compatible = 1;
+ }
+ else
+ {
+ if (pe32->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT)
+ image_is_compatible = 1;
+ }
+
+ *nx_supported = image_is_compatible;
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_efi_check_nx_required (int *nx_required)
+{
+ grub_efi_status_t status;
+ grub_efi_guid_t guid = GRUB_EFI_SHIM_LOCK_GUID;
+ grub_size_t mok_policy_sz = 0;
+ char *mok_policy = NULL;
+ grub_uint32_t mok_policy_attrs = 0;
+
+ status = grub_efi_get_variable_with_attributes ("MokPolicy", &guid,
+ &mok_policy_sz,
+ (void **)&mok_policy,
+ &mok_policy_attrs);
+ if (status == GRUB_EFI_NOT_FOUND ||
+ mok_policy_sz == 0 ||
+ mok_policy == NULL)
+ {
+ *nx_required = 0;
+ return GRUB_ERR_NONE;
+ }
+
+ *nx_required = 0;
+ if (mok_policy_sz < 1 ||
+ mok_policy_attrs != (GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ GRUB_EFI_VARIABLE_RUNTIME_ACCESS) ||
+ (mok_policy[mok_policy_sz-1] & GRUB_MOK_POLICY_NX_REQUIRED))
+ *nx_required = 1;
+
+ return GRUB_ERR_NONE;
+}
typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
grub_err_t
-grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
- void *kernel_params)
+grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size,
+ grub_off_t handover_offset, void *kernel_params,
+ int nx_supported)
{
grub_efi_loaded_image_t *loaded_image = NULL;
handover_func hf;
int offset = 0;
+ grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R |
+ GRUB_MEM_ATTR_W |
+ GRUB_MEM_ATTR_X;
+ grub_uint64_t stack_clear_attrs = 0;
+ grub_uint64_t kernel_set_attrs = stack_set_attrs;
+ grub_uint64_t kernel_clear_attrs = stack_clear_attrs;
+ grub_uint64_t attrs;
+ int nx_required = 0;
#ifdef __x86_64__
offset = 512;
@@ -88,12 +197,57 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
*/
loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (loaded_image)
- loaded_image->image_base = kernel_addr;
+ loaded_image->image_base = (void *)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)handover_offset, kernel_params);
+ (void *)kernel_addr, (void *)handover_offset, kernel_params);
+
+
+ if (nx_required && !nx_supported)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy"));
+
+ if (nx_supported)
+ {
+ kernel_set_attrs &= ~GRUB_MEM_ATTR_W;
+ kernel_clear_attrs |= GRUB_MEM_ATTR_W;
+ stack_set_attrs &= ~GRUB_MEM_ATTR_X;
+ stack_clear_attrs |= GRUB_MEM_ATTR_X;
+ }
+
+ grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n",
+ kernel_addr, kernel_addr + kernel_size - 1,
+ (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-');
+ grub_update_mem_attrs (kernel_addr, kernel_size,
+ kernel_set_attrs, kernel_clear_attrs);
+
+ grub_get_mem_attrs (kernel_addr, 4096, &attrs);
+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
+ (grub_addr_t)kernel_addr,
+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
+ if (grub_stack_addr != (grub_addr_t)-1ll)
+ {
+ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n",
+ grub_stack_addr, grub_stack_addr + grub_stack_size - 1,
+ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-');
+ grub_update_mem_attrs (grub_stack_addr, grub_stack_size,
+ stack_set_attrs, stack_clear_attrs);
+
+ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs);
+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
+ grub_stack_addr,
+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
+ }
+
+#if defined(__i386__) || defined(__x86_64__)
+ asm volatile ("cli");
+#endif
+
hf = (handover_func)((char *)kernel_addr + handover_offset + offset);
grub_dprintf ("linux", "handover_func() = %p\n", hf);
hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index 3d4069e4c6..d80d6ec312 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -44,7 +44,7 @@ struct grub_linuxefi_context {
grub_uint32_t handover_offset;
struct linux_kernel_params *params;
char *cmdline;
-
+ int nx_supported;
void *initrd_mem;
};
@@ -110,13 +110,19 @@ kernel_alloc(grub_efi_uintn_t size,
pages = BYTES_TO_PAGES(size);
grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n",
pages, (void *)max);
+ size = pages * GRUB_EFI_PAGE_SIZE;
prev_max = max;
addr = grub_efi_allocate_pages_real (max, pages,
max_addresses[i].alloc_type,
memtype);
if (addr)
- grub_dprintf ("linux", "Allocated at %p\n", addr);
+ {
+ grub_dprintf ("linux", "Allocated at %p\n", addr);
+ grub_update_mem_attrs ((grub_addr_t)addr, size,
+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W,
+ GRUB_MEM_ATTR_X);
+ }
}
while (grub_error_pop ())
@@ -137,9 +143,11 @@ grub_linuxefi_boot (void *data)
asm volatile ("cli");
- return grub_efi_linux_boot ((char *)context->kernel_mem,
+ return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem,
+ context->kernel_size,
context->handover_offset,
- context->params);
+ context->params,
+ context->nx_supported);
}
static grub_err_t
@@ -308,7 +316,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_uint32_t handover_offset;
struct linux_kernel_params *params = 0;
char *cmdline = 0;
+ int nx_supported = 1;
struct grub_linuxefi_context *context = 0;
+ grub_err_t err;
grub_dl_ref (my_mod);
@@ -352,6 +362,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
}
+ err = grub_efi_check_nx_image_support ((grub_addr_t)kernel, filelen,
+ &nx_supported);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ grub_dprintf ("linux", "nx is%s supported by this kernel\n",
+ nx_supported ? "" : " not");
+
lh = (struct linux_i386_kernel_header *)kernel;
grub_dprintf ("linux", "original lh is at %p\n", kernel);
@@ -515,6 +532,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
context->handover_offset = handover_offset;
context->params = params;
context->cmdline = cmdline;
+ context->nx_supported = nx_supported;
grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0);
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
index ef8fcb9e1b..c160ddb0ea 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -831,6 +831,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_memset (&linux_params, 0, sizeof (linux_params));
grub_memcpy (&linux_params.setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
+ grub_dprintf("efi", "setting attributes for %p (%zu bytes) to +rw-x\n",
+ &linux_params, sizeof (lh) + len);
+ grub_update_mem_attrs ((grub_addr_t)&linux_params, sizeof (lh) + len,
+ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X);
+
linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
linux_params.kernel_alignment = (1 << align);
linux_params.ps_mouse = linux_params.padding10 = 0;
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index a635bcb0a9..8ca8c38f9a 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -135,12 +135,16 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd,
char **device,
char **path);
+extern grub_addr_t EXPORT_VAR(grub_stack_addr);
+extern grub_size_t EXPORT_VAR(grub_stack_size);
+
#if defined(__arm__) || defined(__aarch64__)
void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void);
grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *);
#include <grub/cpu/linux.h>
grub_err_t grub_armxx_efi_linux_check_image(struct linux_armxx_kernel_header *lh);
-grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, char *args);
+grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, grub_size_t size,
+ char *args, int nx_enabled);
#endif
grub_addr_t grub_efi_section_addr (const char *section);
diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
index 0033d9305a..8130b19590 100644
--- a/include/grub/efi/linux.h
+++ b/include/grub/efi/linux.h
@@ -22,10 +22,23 @@
#include <grub/err.h>
#include <grub/symbol.h>
+#define GRUB_MOK_POLICY_NX_REQUIRED 0x1
+
int
EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size);
+
grub_err_t
-EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
- void *kernel_param);
+EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address,
+ grub_size_t kernel_size,
+ grub_off_t handover_offset,
+ void *kernel_param, int nx_enabled);
+
+grub_err_t
+EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr,
+ grub_size_t kernel_size,
+ int *nx_supported);
+
+grub_err_t
+EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required);
#endif /* ! GRUB_EFI_LINUX_HEADER */
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
index 2241f6317b..45c9f8b756 100644
--- a/include/grub/efi/pe32.h
+++ b/include/grub/efi/pe32.h
@@ -172,6 +172,8 @@ struct grub_pe32_optional_header
struct grub_pe32_data_directory reserved_entry;
};
+#define GRUB_PE32_NX_COMPAT 0x0100
+
struct grub_pe64_optional_header
{
grub_uint16_t magic;

View File

@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Tue, 22 Mar 2022 10:57:20 -0400
Subject: [PATCH] nx: set the nx compatible flag in EFI grub images
For NX, we need the grub binary to announce that it is compatible with
the NX feature. This implies that when loading the executable grub
image, several attributes are true:
- the binary doesn't need an executable stack
- the binary doesn't need sections to be both executable and writable
- the binary knows how to use the EFI Memory Attributes protocol on code
it is loading.
This patch adds a definition for the PE DLL Characteristics flag
GRUB_PE32_NX_COMPAT, and changes grub-mkimage to set that flag.
Signed-off-by: Peter Jones <pjones@redhat.com>
(cherry picked from commit 0c7f1aed5a87f75051b421903a900ccb4bbd795a)
(cherry picked from commit 2f9446d488da96de963f4ffe03b0a1c60a4664f5)
[rharwood: fix uninitialized use of stack_attrs]
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
---
util/mkimage.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/util/mkimage.c b/util/mkimage.c
index 16418e245d..c77025904c 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -1358,6 +1358,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
section = (struct grub_pe32_section_table *)(o64 + 1);
}
+ PE_OHDR (o32, o64, dll_characteristics) = grub_host_to_target16 (GRUB_PE32_NX_COMPAT);
PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size);
PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address);
PE_OHDR (o32, o64, image_base) = 0;

View File

@ -0,0 +1,51 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Wed, 11 May 2022 16:37:14 -0400
Subject: [PATCH] Fixup grub_efi_get_variable() type in our loaders
Has a new type now that we have 04ae030d0eea8668d4417702d88bf2cf04713d80
("efi: Return grub_efi_status_t from grub_efi_get_variable()").
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
---
grub-core/kern/efi/init.c | 4 ++--
grub-core/kern/efi/sb.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
index 501608f743..565ce541f5 100644
--- a/grub-core/kern/efi/init.c
+++ b/grub-core/kern/efi/init.c
@@ -104,8 +104,8 @@ grub_efi_env_init (void)
struct grub_envblk envblk_s = { NULL, 0 };
grub_envblk_t envblk = &envblk_s;
- envblk_s.buf = grub_efi_get_variable ("GRUB_ENV", &efi_grub_guid,
- &envblk_s.size);
+ grub_efi_get_variable ("GRUB_ENV", &efi_grub_guid, &envblk_s.size,
+ &envblk_s.buf);
if (!envblk_s.buf || envblk_s.size < 1)
return;
diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
index d74778b0ca..f84d7d3080 100644
--- a/grub-core/kern/efi/sb.c
+++ b/grub-core/kern/efi/sb.c
@@ -35,7 +35,7 @@ grub_efi_secure_boot (void)
char *setup_mode = NULL;
grub_efi_boolean_t ret = 0;
- secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize);
+ grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize, &secure_boot);
if (datasize != 1 || !secure_boot)
{
grub_dprintf ("secureboot", "No SecureBoot variable\n");
@@ -43,7 +43,7 @@ grub_efi_secure_boot (void)
}
grub_dprintf ("secureboot", "SecureBoot: %d\n", *secure_boot);
- setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize);
+ grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize, &setup_mode);
if (datasize != 1 || !setup_mode)
{
grub_dprintf ("secureboot", "No SetupMode variable\n");

View File

@ -379,11 +379,11 @@ for x in grub-mkimage ; do \\\
done \
%{nil}
%global grub_modules " all_video boot blscfg btrfs \\\
%global grub_modules " all_video boot blscfg \\\
cat configfile cryptodisk echo ext2 \\\
fat font gcry_rijndael gcry_rsa gcry_serpent \\\
gcry_sha256 gcry_twofish gcry_whirlpool \\\
gfxmenu gfxterm gzio halt hfsplus http \\\
gfxmenu gfxterm gzio halt http \\\
increment iso9660 jpeg loadenv loopback linux \\\
lvm luks mdraid09 mdraid1x minicmd net \\\
normal part_apple part_msdos part_gpt \\\
@ -596,7 +596,7 @@ touch ${RPM_BUILD_ROOT}/boot/%{name}/grub.cfg \
%{expand:%%files %{1}} \
%defattr(-,root,root,-) \
%config(noreplace) %{_sysconfdir}/%{name}.cfg \
%ghost %config(noreplace) /boot/%{name}/grub.cfg \
%ghost %config(noreplace) %attr(0700,root,root)/boot/%{name}/grub.cfg \
%dir %attr(0700,root,root)/boot/loader/entries \
%ifarch ppc64le \
%dir %{_libdir}/grub/%{2}/ \

View File

@ -489,6 +489,66 @@ Patch0488: 0488-powerpc-fix-prefix-signed-grub-special-case-for-Powe.patch
Patch0489: 0489-grub-mkconfig-restore-umask-for-grub.cfg.patch
Patch0490: 0490-efinet-Add-DHCP-proxy-support.patch
Patch0491: 0491-at_keyboard-Fix-unreliable-key-presses.patch
Patch0492: 0492-search-fixed-bug-stopping-iteration-when-no-floppy-i.patch
Patch0492: 0492-commands-search-Fix-bug-stopping-iteration-when-no-f.patch
Patch0493: 0493-search-new-efidisk-only-option-on-EFI-systems.patch
Patch0494: 0494-efi-new-connectefi-command.patch
Patch0495: 0495-Try-to-pick-better-locations-for-kernel-and-initrd.patch
Patch0496: 0496-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch
Patch0497: 0497-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch
Patch0498: 0498-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch
Patch0499: 0499-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch
Patch0500: 0500-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch
Patch0501: 0501-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch
Patch0502: 0502-ibmvtpm-Backport-ibmvtpm-support-to-grub-2.02.patch
Patch0503: 0503-powerpc-do-CAS-in-a-more-compatible-way.patch
Patch0504: 0504-powerpc-prefix-detection-support-device-names-with-c.patch
Patch0505: 0505-make-ofdisk_retries-optional.patch
Patch0506: 0506-loader-efi-chainloader-grub_load_and_start_image-doe.patch
Patch0507: 0507-loader-efi-chainloader-simplify-the-loader-state.patch
Patch0508: 0508-commands-boot-Add-API-to-pass-context-to-loader.patch
Patch0509: 0509-loader-efi-chainloader-Use-grub_loader_set_ex.patch
Patch0510: 0510-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch
Patch0511: 0511-loader-i386-efi-linux-Use-grub_loader_set_ex.patch
Patch0512: 0512-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch
Patch0513: 0513-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch
Patch0514: 0514-video-readers-png-Abort-sooner-if-a-read-operation-f.patch
Patch0515: 0515-video-readers-png-Refuse-to-handle-multiple-image-he.patch
Patch0516: 0516-video-readers-png-Drop-greyscale-support-to-fix-heap.patch
Patch0517: 0517-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch
Patch0518: 0518-video-readers-png-Sanity-check-some-huffman-codes.patch
Patch0519: 0519-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch
Patch0520: 0520-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch
Patch0521: 0521-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch
Patch0522: 0522-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch
Patch0523: 0523-normal-charset-Fix-array-out-of-bounds-formatting-un.patch
Patch0524: 0524-net-netbuff-Block-overly-large-netbuff-allocs.patch
Patch0525: 0525-net-ip-Do-IP-fragment-maths-safely.patch
Patch0526: 0526-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch
Patch0527: 0527-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch
Patch0528: 0528-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch
Patch0529: 0529-misc-Format-string-for-grub_error-should-be-a-litera.patch
Patch0530: 0530-net-tftp-Avoid-a-trivial-UAF.patch
Patch0531: 0531-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch
Patch0532: 0532-net-http-Fix-OOB-write-for-split-http-headers.patch
Patch0533: 0533-net-http-Error-out-on-headers-with-LF-without-CR.patch
Patch0534: 0534-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch
Patch0535: 0535-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch
Patch0536: 0536-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch
Patch0537: 0537-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch
Patch0538: 0538-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch
Patch0539: 0539-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch
Patch0540: 0540-Define-GRUB_EFI_SHIM_LOCK_GUID.patch
Patch0541: 0541-misc-Make-grub_min-and-grub_max-more-resilient.patch
Patch0542: 0542-ReiserFS-switch-to-using-grub_min-grub_max.patch
Patch0543: 0543-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch
Patch0544: 0544-modules-make-.module_license-read-only.patch
Patch0545: 0545-modules-strip-.llvm_addrsig-sections-and-similar.patch
Patch0546: 0546-modules-Don-t-allocate-space-for-non-allocable-secti.patch
Patch0547: 0547-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch
Patch0548: 0548-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch
Patch0549: 0549-modules-load-module-sections-at-page-aligned-address.patch
Patch0550: 0550-nx-add-memory-attribute-get-set-API.patch
Patch0551: 0551-nx-set-page-permissions-for-loaded-modules.patch
Patch0552: 0552-nx-set-attrs-in-our-kernel-loaders.patch
Patch0553: 0553-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch
Patch0554: 0554-Fixup-grub_efi_get_variable-type-in-our-loaders.patch

View File

@ -1,4 +1,4 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
grub,1,Free Software Foundation,grub,2.02,https://www.gnu.org/software/grub/
grub.rhel8,1,Red Hat Enterprise Linux 8,grub2,@@RHEL_VERSION@@,mail:secalert@redhat.com
grub.almalinux8,1,AlmaLinux 8,grub2,@@VERSION@@,mail:security@almalinux.org
grub,2,Free Software Foundation,grub,@@VERSION@@,https//www.gnu.org/software/grub/
grub.rh,2,Red Hat,grub2,@@VERSION_RELEASE@@,mailto:secalert@redhat.com
grub.almalinux8,2,AlmaLinux 8,grub2,@@VERSION_RELEASE@@,mail:security@almalinux.org

View File

@ -7,7 +7,7 @@
Name: grub2
Epoch: 1
Version: 2.02
Release: 120%{?dist}.alma
Release: 138%{?dist}.alma
Summary: Bootloader with support for Linux, Multiboot and more
Group: System Environment/Base
License: GPLv3+
@ -164,8 +164,8 @@ This subpackage provides tools for support of all platforms.
mkdir grub-%{grubefiarch}-%{tarversion}
grep -A100000 '# stuff "make" creates' .gitignore > grub-%{grubefiarch}-%{tarversion}/.gitignore
cp %{SOURCE4} grub-%{grubefiarch}-%{tarversion}/unifont.pcf.gz
sed -e "s,@@VERSION@@,%{evr},g" -e "s,@@RHEL_VERSION@@,%{rhel_evr},g" %{SOURCE19} \
> grub-%{grubefiarch}-%{tarversion}/sbat.csv
sed -e "s,@@VERSION@@,%{version},g" -e "s,@@VERSION_RELEASE@@,%{version}-%{release},g" \
%{SOURCE19} > grub-%{grubefiarch}-%{tarversion}/sbat.csv
git add grub-%{grubefiarch}-%{tarversion}
%endif
%if 0%{with_alt_efi_arch}
@ -508,14 +508,55 @@ fi
%endif
%changelog
<<<<<<< HEAD
* Tue Apr 05 2022 Andrew Lukoshko <alukoshko@almalinux.org> - 2.06-120.alma
- Use AlmaLinux cert and SBAT
* Fri Feb 28 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-120
=======
* Wed Jul 20 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-138
- Rotate signing keys on ppc64le
- Resolves: #2074762
* Fri Jun 03 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-137
- CVE fixes for 2022-06-07
- CVE-2022-28736 CVE-2022-28735 CVE-2022-28734 CVE-2022-28733
- CVE-2021-3697 CVE-2021-3696 CVE-2021-3695
- Resolves: #2070687
* Mon May 16 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-129
- ppc64le: Slow boot after LPM
- Resolves: #2070347
* Wed May 04 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-127
- ppc64le: CAS improvements, prefix detection, and vTPM support
- Resolves: #2076795
- Resolves: #2026568
- Resolves: #2051331
* Wed May 04 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-126
- Fix rpm verification error on grub.cfg permissions
- Resolves: #2071643
* Wed Apr 20 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-125
- RHEL 8.6.0 import; no code changes
- Resolves: #2062892
* Mon Mar 28 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-123
- Bump for signing
* Wed Mar 09 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-122
- Fix initialization on efidisk patch
* Tue Mar 08 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-121
- Backport support for loading initrd above 4GB
* Mon Feb 28 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-120
>>>>>>> c8-beta
- Bump signing
- Resolves: #2032294
* Fri Feb 28 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-119
* Mon Feb 28 2022 Robbie Harwood <rharwood@redhat.com> - 2.06-119
- Enable connectefi module
- Resolves: #2032294