diff mbox series

[1/2] arm64: lds: move special code sections out of kernel exec segment

Message ID 20220429131347.3621090-2-ardb@kernel.org (mailing list archive)
State New, archived
Headers show
Series arm64: pair of minor hardening tweaks | expand

Commit Message

Ard Biesheuvel April 29, 2022, 1:13 p.m. UTC
There are a few code sections that are emitted into the kernel's
executable .text segment simply because they contain code, but are
actually never executed via this mapping, so they can happily live in a
region that gets mapped without executable permissions, reducing the
risk of being gadgetized.

Note that the kexec and hibernate region contents are always copied into
a fresh page, and so there is no need to align them as long as the
overall size of each is below 4 KiB.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
The EL1 and HYP ID maps could receive a similar treatment, but this
requires slightly more work, which I will cover in my boot mapping
cleanup series.

The HYP text section contains branches covered by jump labels, and
moving it out of [_stext.._etext] makes the core jump label code very
unhappy so moving that one out is left for a future effort.

 arch/arm64/kernel/vmlinux.lds.S | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

Comments

Catalin Marinas May 4, 2022, 6:59 p.m. UTC | #1
On Fri, Apr 29, 2022 at 03:13:46PM +0200, Ard Biesheuvel wrote:
> There are a few code sections that are emitted into the kernel's
> executable .text segment simply because they contain code, but are
> actually never executed via this mapping, so they can happily live in a
> region that gets mapped without executable permissions, reducing the
> risk of being gadgetized.
> 
> Note that the kexec and hibernate region contents are always copied into
> a fresh page, and so there is no need to align them as long as the
> overall size of each is below 4 KiB.
> 
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>

This patch doesn't get very far. Under qemu, defconfig:

EFI stub: Booting Linux Kernel...
EFI stub: Generating empty DTB
EFI stub: Exiting boot services...
[    0.000000] Booting Linux on physical CPU 0x0000000000 [0x000f0510]
[    0.000000] Linux version 5.18.0-rc3-00008-gfd536ceae063 (cmarinas@gaia) (aarch64-linux-gcc (GCC) 11.1.0, ...)
[    0.000000] earlycon: pl11 at MMIO 0x0000000009000000 (options '')
[    0.000000] printk: bootconsole [pl11] enabled
[    0.000000] efi: EFI v2.70 by EDK II
[    0.000000] efi: SMBIOS 3.0=0xbbed0000 MEMATTR=0xba919018 ACPI 2.0=0xb61a0018 RNG=0xbbfdbd18 MEMRESERVE=0xb6235f18
[    0.000000] efi: seeding entropy pool
[    0.000000] Unable to handle kernel paging request at virtual address fffffbfffda351b4
[    0.000000] Mem abort info:
[    0.000000]   ESR = 0x96000007
[    0.000000]   EC = 0x25: DABT (current EL), IL = 32 bits
[    0.000000]   SET = 0, FnV = 0
[    0.000000]   EA = 0, S1PTW = 0
[    0.000000]   FSC = 0x07: level 3 translation fault
[    0.000000] Data abort info:
[    0.000000]   ISV = 0, ISS = 0x00000007
[    0.000000]   CM = 0, WnR = 0
[    0.000000] swapper pgtable: 4k pages, 48-bit VAs, pgdp=00000000bf11d000
[    0.000000] [fffffbfffda351b4] pgd=00000000bf09c003, p4d=00000000bf09c003
[    0.000000] Unable to handle kernel paging request at virtual address ffff00007f09cff8
[    0.000000] Mem abort info:
[    0.000000]   ESR = 0x96000004
[    0.000000]   EC = 0x25: DABT (current EL), IL = 32 bits
[    0.000000]   SET = 0, FnV = 0
[    0.000000]   EA = 0, S1PTW = 0
[    0.000000]   FSC = 0x04: level 0 translation fault
[    0.000000] Data abort info:
[    0.000000]   ISV = 0, ISS = 0x00000004
[    0.000000]   CM = 0, WnR = 0
[    0.000000] swapper pgtable: 4k pages, 48-bit VAs, pgdp=00000000bf11d000
[    0.000000] [ffff00007f09cff8] pgd=0000000000000000, p4d=0000000000000000
[    0.000000] Internal error: Oops: 96000004 [#1] PREEMPT SMP
[    0.000000] Modules linked in:
[    0.000000] CPU: 0 PID: 0 Comm: swapper Not tainted 5.18.0-rc3-00008-gfd536ceae063 #4
[    0.000000] pstate: 620000c5 (nZCv daIF -PAN -UAO +TCO -DIT -SSBS BTYPE=--)
[    0.000000] pc : die_kernel_fault+0x2dc/0x394
[    0.000000] lr : die_kernel_fault+0x2ac/0x394
[    0.000000] sp : ffffb594f7963ab0
[    0.000000] x29: ffffb594f7963ab0 x28: ffffb594f7973340 x27: ffffb594f5a20000
[    0.000000] x26: ffffb594f72c0000 x25: ffffb594f7214000 x24: ffffb594f7d1d000
[    0.000000] x23: 0000000000000ff8 x22: ffffb594f7963bc0 x21: ffff00007f09c000
[    0.000000] x20: 0000000096000007 x19: fffffbfffda351b4 x18: ffffffffffffffff
[    0.000000] x17: 6266666666662073 x16: 736572646461206c x15: ffffb594f7caeb38
[    0.000000] x14: 0000000000000010 x13: ffffb594f79824a0 x12: 0000000000000036
[    0.000000] x11: 0000000000000012 x10: ffffb594f79da650 x9 : ffffb594f79824a0
[    0.000000] x8 : 00000000ffffefff x7 : ffffb594f79da4a0 x6 : 00000000000001b0
[    0.000000] x5 : 000000000000bff4 x4 : 00000000fffff012 x3 : 0000000000000000
[    0.000000] x2 : 0000000000000000 x1 : 0000000040000000 x0 : ffffb594f7083618
[    0.000000] Call trace:
[    0.000000]  die_kernel_fault+0x2dc/0x394
[    0.000000]  __do_kernel_fault+0xfc/0x180
[    0.000000]  do_translation_fault+0x58/0xc0
[    0.000000]  do_mem_abort+0x44/0x94
[    0.000000]  el1_abort+0x40/0x6c
[    0.000000]  el1h_64_sync_handler+0xa4/0xd0
[    0.000000]  el1h_64_sync+0x64/0x68
[    0.000000]  paging_init+0x1e4/0x550
[    0.000000]  setup_arch+0x274/0x608
[    0.000000]  start_kernel+0x84/0x668
[    0.000000]  __primary_switched+0xc0/0xc8
[    0.000000] Code: d0003580 91186000 cb0102b5 b2503eb5 (f8776ab8)
[    0.000000] ---[ end trace 0000000000000000 ]---
[    0.000000] Kernel panic - not syncing: Attempted to kill the idle task!
[    0.000000] ---[ end Kernel panic - not syncing: Attempted to kill the idle task! ]---
Ard Biesheuvel May 5, 2022, 7:10 a.m. UTC | #2
On Wed, 4 May 2022 at 20:59, Catalin Marinas <catalin.marinas@arm.com> wrote:
>
> On Fri, Apr 29, 2022 at 03:13:46PM +0200, Ard Biesheuvel wrote:
> > There are a few code sections that are emitted into the kernel's
> > executable .text segment simply because they contain code, but are
> > actually never executed via this mapping, so they can happily live in a
> > region that gets mapped without executable permissions, reducing the
> > risk of being gadgetized.
> >
> > Note that the kexec and hibernate region contents are always copied into
> > a fresh page, and so there is no need to align them as long as the
> > overall size of each is below 4 KiB.
> >
> > Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
>
> This patch doesn't get very far. Under qemu, defconfig:
>

Apologies, this is a local rebase error on my part. The .rodata.text
section needs the below added or the following sections will appear
misaligned in memory.

diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index c33467c6a969..4cea87393c68 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -212,6 +212,7 @@ SECTIONS
                TRAMP_TEXT
                HIBERNATE_TEXT
                KEXEC_TEXT
+               . = ALIGN(PAGE_SIZE);
        }

        idmap_pg_dir = .;




> EFI stub: Booting Linux Kernel...
> EFI stub: Generating empty DTB
> EFI stub: Exiting boot services...
> [    0.000000] Booting Linux on physical CPU 0x0000000000 [0x000f0510]
> [    0.000000] Linux version 5.18.0-rc3-00008-gfd536ceae063 (cmarinas@gaia) (aarch64-linux-gcc (GCC) 11.1.0, ...)
> [    0.000000] earlycon: pl11 at MMIO 0x0000000009000000 (options '')
> [    0.000000] printk: bootconsole [pl11] enabled
> [    0.000000] efi: EFI v2.70 by EDK II
> [    0.000000] efi: SMBIOS 3.0=0xbbed0000 MEMATTR=0xba919018 ACPI 2.0=0xb61a0018 RNG=0xbbfdbd18 MEMRESERVE=0xb6235f18
> [    0.000000] efi: seeding entropy pool
> [    0.000000] Unable to handle kernel paging request at virtual address fffffbfffda351b4
> [    0.000000] Mem abort info:
> [    0.000000]   ESR = 0x96000007
> [    0.000000]   EC = 0x25: DABT (current EL), IL = 32 bits
> [    0.000000]   SET = 0, FnV = 0
> [    0.000000]   EA = 0, S1PTW = 0
> [    0.000000]   FSC = 0x07: level 3 translation fault
> [    0.000000] Data abort info:
> [    0.000000]   ISV = 0, ISS = 0x00000007
> [    0.000000]   CM = 0, WnR = 0
> [    0.000000] swapper pgtable: 4k pages, 48-bit VAs, pgdp=00000000bf11d000
> [    0.000000] [fffffbfffda351b4] pgd=00000000bf09c003, p4d=00000000bf09c003
> [    0.000000] Unable to handle kernel paging request at virtual address ffff00007f09cff8
> [    0.000000] Mem abort info:
> [    0.000000]   ESR = 0x96000004
> [    0.000000]   EC = 0x25: DABT (current EL), IL = 32 bits
> [    0.000000]   SET = 0, FnV = 0
> [    0.000000]   EA = 0, S1PTW = 0
> [    0.000000]   FSC = 0x04: level 0 translation fault
> [    0.000000] Data abort info:
> [    0.000000]   ISV = 0, ISS = 0x00000004
> [    0.000000]   CM = 0, WnR = 0
> [    0.000000] swapper pgtable: 4k pages, 48-bit VAs, pgdp=00000000bf11d000
> [    0.000000] [ffff00007f09cff8] pgd=0000000000000000, p4d=0000000000000000
> [    0.000000] Internal error: Oops: 96000004 [#1] PREEMPT SMP
> [    0.000000] Modules linked in:
> [    0.000000] CPU: 0 PID: 0 Comm: swapper Not tainted 5.18.0-rc3-00008-gfd536ceae063 #4
> [    0.000000] pstate: 620000c5 (nZCv daIF -PAN -UAO +TCO -DIT -SSBS BTYPE=--)
> [    0.000000] pc : die_kernel_fault+0x2dc/0x394
> [    0.000000] lr : die_kernel_fault+0x2ac/0x394
> [    0.000000] sp : ffffb594f7963ab0
> [    0.000000] x29: ffffb594f7963ab0 x28: ffffb594f7973340 x27: ffffb594f5a20000
> [    0.000000] x26: ffffb594f72c0000 x25: ffffb594f7214000 x24: ffffb594f7d1d000
> [    0.000000] x23: 0000000000000ff8 x22: ffffb594f7963bc0 x21: ffff00007f09c000
> [    0.000000] x20: 0000000096000007 x19: fffffbfffda351b4 x18: ffffffffffffffff
> [    0.000000] x17: 6266666666662073 x16: 736572646461206c x15: ffffb594f7caeb38
> [    0.000000] x14: 0000000000000010 x13: ffffb594f79824a0 x12: 0000000000000036
> [    0.000000] x11: 0000000000000012 x10: ffffb594f79da650 x9 : ffffb594f79824a0
> [    0.000000] x8 : 00000000ffffefff x7 : ffffb594f79da4a0 x6 : 00000000000001b0
> [    0.000000] x5 : 000000000000bff4 x4 : 00000000fffff012 x3 : 0000000000000000
> [    0.000000] x2 : 0000000000000000 x1 : 0000000040000000 x0 : ffffb594f7083618
> [    0.000000] Call trace:
> [    0.000000]  die_kernel_fault+0x2dc/0x394
> [    0.000000]  __do_kernel_fault+0xfc/0x180
> [    0.000000]  do_translation_fault+0x58/0xc0
> [    0.000000]  do_mem_abort+0x44/0x94
> [    0.000000]  el1_abort+0x40/0x6c
> [    0.000000]  el1h_64_sync_handler+0xa4/0xd0
> [    0.000000]  el1h_64_sync+0x64/0x68
> [    0.000000]  paging_init+0x1e4/0x550
> [    0.000000]  setup_arch+0x274/0x608
> [    0.000000]  start_kernel+0x84/0x668
> [    0.000000]  __primary_switched+0xc0/0xc8
> [    0.000000] Code: d0003580 91186000 cb0102b5 b2503eb5 (f8776ab8)
> [    0.000000] ---[ end trace 0000000000000000 ]---
> [    0.000000] Kernel panic - not syncing: Attempted to kill the idle task!
> [    0.000000] ---[ end Kernel panic - not syncing: Attempted to kill the idle task! ]---
diff mbox series

Patch

diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index edaf0faf766f..cf594c6a7b84 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -93,7 +93,6 @@  jiffies = jiffies_64;
 
 #ifdef CONFIG_HIBERNATION
 #define HIBERNATE_TEXT					\
-	. = ALIGN(SZ_4K);				\
 	__hibernate_exit_text_start = .;		\
 	*(.hibernate_exit.text)				\
 	__hibernate_exit_text_end = .;
@@ -103,7 +102,6 @@  jiffies = jiffies_64;
 
 #ifdef CONFIG_KEXEC_CORE
 #define KEXEC_TEXT					\
-	. = ALIGN(SZ_4K);				\
 	__relocate_new_kernel_start = .;		\
 	*(.kexec_relocate.text)				\
 	__relocate_new_kernel_end = .;
@@ -170,9 +168,6 @@  SECTIONS
 			KPROBES_TEXT
 			HYPERVISOR_TEXT
 			IDMAP_TEXT
-			HIBERNATE_TEXT
-			KEXEC_TEXT
-			TRAMP_TEXT
 			*(.gnu.warning)
 		. = ALIGN(16);
 		*(.got)			/* Global offset table		*/
@@ -194,6 +189,13 @@  SECTIONS
 
 	HYPERVISOR_DATA_SECTIONS
 
+	/* code sections that are never executed via the kernel mapping */
+	.rodata.text : {
+		TRAMP_TEXT
+		HIBERNATE_TEXT
+		KEXEC_TEXT
+	}
+
 	idmap_pg_dir = .;
 	. += IDMAP_DIR_SIZE;
 	idmap_pg_end = .;
@@ -337,8 +339,8 @@  ASSERT(__hyp_idmap_text_end - __hyp_idmap_text_start <= PAGE_SIZE,
 ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,
 	"ID map text too big or misaligned")
 #ifdef CONFIG_HIBERNATION
-ASSERT(__hibernate_exit_text_end - (__hibernate_exit_text_start & ~(SZ_4K - 1))
-	<= SZ_4K, "Hibernate exit text too big or misaligned")
+ASSERT(__hibernate_exit_text_end - __hibernate_exit_text_start <= SZ_4K,
+       "Hibernate exit text is bigger than 4 KiB")
 #endif
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) <= 3*PAGE_SIZE,
@@ -362,7 +364,7 @@  ASSERT(swapper_pg_dir - tramp_pg_dir == TRAMP_SWAPPER_OFFSET,
 
 #ifdef CONFIG_KEXEC_CORE
 /* kexec relocation code should fit into one KEXEC_CONTROL_PAGE_SIZE */
-ASSERT(__relocate_new_kernel_end - (__relocate_new_kernel_start & ~(SZ_4K - 1))
-	<= SZ_4K, "kexec relocation code is too big or misaligned")
+ASSERT(__relocate_new_kernel_end - __relocate_new_kernel_start <= SZ_4K,
+       "kexec relocation code is bigger than 4 KiB")
 ASSERT(KEXEC_CONTROL_PAGE_SIZE >= SZ_4K, "KEXEC_CONTROL_PAGE_SIZE is broken")
 #endif