kern/dl: grub_dl_set_mem_attrs()/grub_dl_load_segments() fixes
Resolves: #RHEL-26322 Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
This commit is contained in:
parent
50a93da15d
commit
dfbe55e237
38
0341-grub_dl_set_mem_attrs-fix-format-string.patch
Normal file
38
0341-grub_dl_set_mem_attrs-fix-format-string.patch
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Laszlo Ersek <lersek@redhat.com>
|
||||||
|
Date: Fri, 7 Apr 2023 14:54:35 +0200
|
||||||
|
Subject: [PATCH] grub_dl_set_mem_attrs(): fix format string
|
||||||
|
|
||||||
|
The grub_dprintf() call for printing the message
|
||||||
|
|
||||||
|
updating attributes for GOT and trampolines
|
||||||
|
|
||||||
|
passes the argument "mod->name", but the format string doesn't accept that
|
||||||
|
argument.
|
||||||
|
|
||||||
|
Print the module name too.
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
|
||||||
|
> kern/dl.c:736: updating attributes for GOT and trampolines ("video_fb")
|
||||||
|
|
||||||
|
Fixes: ad1b904d325b (nx: set page permissions for loaded modules.)
|
||||||
|
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
||||||
|
---
|
||||||
|
grub-core/kern/dl.c | 3 ++-
|
||||||
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
|
||||||
|
index ab9101a5ad1a..a97f4a8b1355 100644
|
||||||
|
--- a/grub-core/kern/dl.c
|
||||||
|
+++ b/grub-core/kern/dl.c
|
||||||
|
@@ -733,7 +733,8 @@ grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr)
|
||||||
|
{
|
||||||
|
tgsz = ALIGN_UP(tgsz, arch_addralign);
|
||||||
|
|
||||||
|
- grub_dprintf ("modules", "updating attributes for GOT and trampolines\n",
|
||||||
|
+ grub_dprintf ("modules",
|
||||||
|
+ "updating attributes for GOT and trampolines (\"%s\")\n",
|
||||||
|
mod->name);
|
||||||
|
grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X,
|
||||||
|
GRUB_MEM_ATTR_W);
|
140
0342-grub_dl_set_mem_attrs-add-self-check-for-the-tramp-G.patch
Normal file
140
0342-grub_dl_set_mem_attrs-add-self-check-for-the-tramp-G.patch
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Laszlo Ersek <lersek@redhat.com>
|
||||||
|
Date: Fri, 7 Apr 2023 16:21:54 +0200
|
||||||
|
Subject: [PATCH] grub_dl_set_mem_attrs(): add self-check for the tramp/GOT
|
||||||
|
sizes
|
||||||
|
|
||||||
|
On aarch64 UEFI, we currently have a crasher:
|
||||||
|
|
||||||
|
grub_dl_load_core()
|
||||||
|
grub_dl_load_core_noinit()
|
||||||
|
|
||||||
|
/* independent allocation: must remain writable */
|
||||||
|
mod = grub_zalloc();
|
||||||
|
|
||||||
|
/* allocates module image with incorrect tail alignment */
|
||||||
|
grub_dl_load_segments()
|
||||||
|
|
||||||
|
/* write-protecting the module image makes "mod" read-only! */
|
||||||
|
grub_dl_set_mem_attrs()
|
||||||
|
grub_update_mem_attrs()
|
||||||
|
|
||||||
|
grub_dl_init()
|
||||||
|
/* page fault, crash */
|
||||||
|
mod->next = ...;
|
||||||
|
|
||||||
|
- Commit 887f1d8fa976 ("modules: load module sections at page-aligned
|
||||||
|
addresses", 2023-02-08) forgot to page-align the allocation of the
|
||||||
|
trampolines and GOT areas of grub2 modules, in grub_dl_load_segments().
|
||||||
|
|
||||||
|
- Commit ad1b904d325b ("nx: set page permissions for loaded modules.",
|
||||||
|
2023-02-08) calculated a common bounding box for the trampolines and GOT
|
||||||
|
areas in grub_dl_set_mem_attrs(), rounded the box size up to a whole
|
||||||
|
multiple of EFI page size ("arch_addralign"), and write-protected the
|
||||||
|
resultant page range.
|
||||||
|
|
||||||
|
Consequently, grub_dl_load_segments() places the module image in memory
|
||||||
|
such that its tail -- the end of the trampolines and GOT areas -- lands at
|
||||||
|
the head of a page whose tail in turn contains independent memory
|
||||||
|
allocations, such as "mod". grub_dl_set_mem_attrs() will then unwittingly
|
||||||
|
write-protect these other allocations too.
|
||||||
|
|
||||||
|
But "mod" must remain writable: we assign "mod->next" in grub_dl_init()
|
||||||
|
subsequently. Currently we crash there with a page fault / permission
|
||||||
|
fault.
|
||||||
|
|
||||||
|
(The crash is not trivial to hit: the tramp/GOT areas are irrelevant on
|
||||||
|
x86_64, plus the page protection depends on the UEFI platform firmware
|
||||||
|
providing EFI_MEMORY_ATTRIBUTE_PROTOCOL. In practice, the crash is
|
||||||
|
restricted to aarch64 edk2 (ArmVirtQemu) builds containing commit
|
||||||
|
1c4dfadb4611, "ArmPkg/CpuDxe: Implement EFI memory attributes protocol",
|
||||||
|
2023-03-16.)
|
||||||
|
|
||||||
|
Example log before the patch:
|
||||||
|
|
||||||
|
> kern/dl.c:736: updating attributes for GOT and trampolines ("video_fb")
|
||||||
|
> kern/efi/mm.c:927: set +rx -w on 0x13b88b000-0x13b88bfff before:rwx after:r-x
|
||||||
|
> kern/dl.c:744: done updating module memory attributes for "video_fb"
|
||||||
|
> kern/dl.c:639: flushing 0xe4f0 bytes at 0x13b87d000
|
||||||
|
> kern/arm64/cache.c:42: D$ line size: 64
|
||||||
|
> kern/arm64/cache.c:43: I$ line size: 64
|
||||||
|
> kern/dl.c:839: module name: video_fb
|
||||||
|
> kern/dl.c:840: init function: 0x0
|
||||||
|
> kern/dl.c:865: Initing module video_fb
|
||||||
|
>
|
||||||
|
> Synchronous Exception at 0x000000013B8A76EC
|
||||||
|
> PC 0x00013B8A76EC
|
||||||
|
>
|
||||||
|
> X0 0x000000013B88B960 X1 0x0000000000000000 X2 0x000000013F93587C X3 0x0000000000000075
|
||||||
|
>
|
||||||
|
> SP 0x00000000470745C0 ELR 0x000000013B8A76EC SPSR 0x60000205 FPSR 0x00000000
|
||||||
|
> ESR 0x9600004F FAR 0x000000013B88B9D0
|
||||||
|
>
|
||||||
|
> ESR : EC 0x25 IL 0x1 ISS 0x0000004F
|
||||||
|
>
|
||||||
|
> Data abort: Permission fault, third level
|
||||||
|
|
||||||
|
Note the following:
|
||||||
|
|
||||||
|
- The whole 4K page at 0x1_3B88_B000 is write-protected.
|
||||||
|
|
||||||
|
- The "video_fb" module actually lives at [0x1_3B87_D000, 0x1_3B88_B4F0)
|
||||||
|
-- left-inclusive, right-exclusive --; that is, in the last page (at
|
||||||
|
0x1_3B88_B000), it only occupies the first 0x4F0 bytes.
|
||||||
|
|
||||||
|
- The instruction at 0x1_3B8A_76EC faults. Not shown here, but it is a
|
||||||
|
store instruction, which writes to the field at offset 0x70 of the
|
||||||
|
structure pointed-to by the X0 register. This is the "mod->next"
|
||||||
|
assignment from grub_dl_init().
|
||||||
|
|
||||||
|
- The faulting address is therefore (X0 + 0x70), i.e., 0x1_3B88_B9D0. This
|
||||||
|
is indeed the value held in the FAR register.
|
||||||
|
|
||||||
|
- The faulting address 0x1_3B88_B9D0 falls in the above-noted page (at
|
||||||
|
0x1_3B88_B000), namely at offset 0x9D0. This is *beyond* the first 0x4F0
|
||||||
|
bytes that the very tail of the "video_fb" module occupies at the front
|
||||||
|
of that page.
|
||||||
|
|
||||||
|
For now, add a self-check that reports this bug (and prevents the crash by
|
||||||
|
skipping the write protection).
|
||||||
|
|
||||||
|
Example log after the patch:
|
||||||
|
|
||||||
|
> kern/dl.c:742:BUG: trying to protect pages outside of module allocation
|
||||||
|
> ("video_fb"): module base 0x13b87d000, size 0xe4f0; tramp/GOT base
|
||||||
|
> 0x13b88b000, size 0x1000
|
||||||
|
|
||||||
|
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
||||||
|
---
|
||||||
|
grub-core/kern/dl.c | 11 ++++++++++-
|
||||||
|
1 file changed, 10 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
|
||||||
|
index a97f4a8b1355..3b66fa410e80 100644
|
||||||
|
--- a/grub-core/kern/dl.c
|
||||||
|
+++ b/grub-core/kern/dl.c
|
||||||
|
@@ -682,7 +682,7 @@ grub_dl_set_mem_attrs (grub_dl_t mod, void *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;
|
||||||
|
+ grub_size_t tgsz;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
grub_dprintf ("modules", "updating memory attributes for \"%s\"\n",
|
||||||
|
@@ -736,6 +736,15 @@ grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr)
|
||||||
|
grub_dprintf ("modules",
|
||||||
|
"updating attributes for GOT and trampolines (\"%s\")\n",
|
||||||
|
mod->name);
|
||||||
|
+ if (tgaddr < (grub_addr_t)mod->base ||
|
||||||
|
+ tgsz > (grub_addr_t)-1 - tgaddr ||
|
||||||
|
+ tgaddr + tgsz > (grub_addr_t)mod->base + mod->sz)
|
||||||
|
+ return grub_error (GRUB_ERR_BUG,
|
||||||
|
+ "BUG: trying to protect pages outside of module "
|
||||||
|
+ "allocation (\"%s\"): module base %p, size 0x%"
|
||||||
|
+ PRIxGRUB_SIZE "; tramp/GOT base 0x%" PRIxGRUB_ADDR
|
||||||
|
+ ", size 0x%" PRIxGRUB_SIZE,
|
||||||
|
+ mod->name, mod->base, mod->sz, tgaddr, tgsz);
|
||||||
|
grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X,
|
||||||
|
GRUB_MEM_ATTR_W);
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Laszlo Ersek <lersek@redhat.com>
|
||||||
|
Date: Fri, 7 Apr 2023 16:56:09 +0200
|
||||||
|
Subject: [PATCH] grub_dl_load_segments(): page-align the tramp/GOT areas too
|
||||||
|
|
||||||
|
The tramp/GOT write-protection in grub_dl_set_mem_attrs() requires that
|
||||||
|
the tramp/GOT areas of the module image *not* share a page with any other
|
||||||
|
memory allocations. Page-align the tramp/GOT areas, while satisfying their
|
||||||
|
intrinsic alignment requirements too.
|
||||||
|
|
||||||
|
Fixes: 887f1d8fa976 (modules: load module sections at page-aligned addresses)
|
||||||
|
Fixes: ad1b904d325b (nx: set page permissions for loaded modules.)
|
||||||
|
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
||||||
|
---
|
||||||
|
grub-core/kern/dl.c | 24 ++++++++++++++++--------
|
||||||
|
1 file changed, 16 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
|
||||||
|
index 3b66fa410e80..f3cdb9e0bacf 100644
|
||||||
|
--- a/grub-core/kern/dl.c
|
||||||
|
+++ b/grub-core/kern/dl.c
|
||||||
|
@@ -280,7 +280,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||||
|
grub_size_t tsize = 0, talign = 1, arch_addralign = 1;
|
||||||
|
#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
|
||||||
|
grub_size_t tramp;
|
||||||
|
+ grub_size_t tramp_align;
|
||||||
|
grub_size_t got;
|
||||||
|
+ grub_size_t got_align;
|
||||||
|
grub_err_t err;
|
||||||
|
#endif
|
||||||
|
char *ptr;
|
||||||
|
@@ -311,12 +313,18 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||||
|
err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
- tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
|
||||||
|
- if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
|
||||||
|
- talign = GRUB_ARCH_DL_TRAMP_ALIGN;
|
||||||
|
- tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN);
|
||||||
|
- if (talign < GRUB_ARCH_DL_GOT_ALIGN)
|
||||||
|
- talign = GRUB_ARCH_DL_GOT_ALIGN;
|
||||||
|
+ tramp_align = GRUB_ARCH_DL_TRAMP_ALIGN;
|
||||||
|
+ if (tramp_align < arch_addralign)
|
||||||
|
+ tramp_align = arch_addralign;
|
||||||
|
+ tsize += ALIGN_UP (tramp, tramp_align);
|
||||||
|
+ if (talign < tramp_align)
|
||||||
|
+ talign = tramp_align;
|
||||||
|
+ got_align = GRUB_ARCH_DL_GOT_ALIGN;
|
||||||
|
+ if (got_align < arch_addralign)
|
||||||
|
+ got_align = arch_addralign;
|
||||||
|
+ tsize += ALIGN_UP (got, got_align);
|
||||||
|
+ if (talign < got_align)
|
||||||
|
+ talign = got_align;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GRUB_MACHINE_EMU
|
||||||
|
@@ -376,11 +384,11 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
|
||||||
|
- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
|
||||||
|
+ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, tramp_align);
|
||||||
|
mod->tramp = ptr;
|
||||||
|
mod->trampptr = ptr;
|
||||||
|
ptr += tramp;
|
||||||
|
- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN);
|
||||||
|
+ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, got_align);
|
||||||
|
mod->got = ptr;
|
||||||
|
mod->gotptr = ptr;
|
||||||
|
ptr += got;
|
@ -338,3 +338,6 @@ Patch0337: 0337-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch
|
|||||||
Patch0338: 0338-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch
|
Patch0338: 0338-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch
|
||||||
Patch0339: 0339-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch
|
Patch0339: 0339-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch
|
||||||
Patch0340: 0340-fs-ntfs-Make-code-more-readable.patch
|
Patch0340: 0340-fs-ntfs-Make-code-more-readable.patch
|
||||||
|
Patch0341: 0341-grub_dl_set_mem_attrs-fix-format-string.patch
|
||||||
|
Patch0342: 0342-grub_dl_set_mem_attrs-add-self-check-for-the-tramp-G.patch
|
||||||
|
Patch0343: 0343-grub_dl_load_segments-page-align-the-tramp-GOT-areas.patch
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
Name: grub2
|
Name: grub2
|
||||||
Epoch: 1
|
Epoch: 1
|
||||||
Version: 2.06
|
Version: 2.06
|
||||||
Release: 76%{?dist}
|
Release: 77%{?dist}
|
||||||
Summary: Bootloader with support for Linux, Multiboot and more
|
Summary: Bootloader with support for Linux, Multiboot and more
|
||||||
License: GPLv3+
|
License: GPLv3+
|
||||||
URL: http://www.gnu.org/software/grub/
|
URL: http://www.gnu.org/software/grub/
|
||||||
@ -533,6 +533,10 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu Feb 22 2024 Nicolas Frayer <nfrayer@redhat.com> - 2.06-77
|
||||||
|
- kern/dl: grub_dl_set_mem_attrs()/grub_dl_load_segments() fixes
|
||||||
|
- Resolves: #RHEL-26322
|
||||||
|
|
||||||
* Tue Feb 20 2024 Nicolas Frayer <nfrayer@redhat.com> - 2.06-76
|
* Tue Feb 20 2024 Nicolas Frayer <nfrayer@redhat.com> - 2.06-76
|
||||||
- fs/ntfs: OOB write fix
|
- fs/ntfs: OOB write fix
|
||||||
- (CVE-2023-4692)
|
- (CVE-2023-4692)
|
||||||
|
Loading…
Reference in New Issue
Block a user