* [RFC PATCH 00/10] arm64: implement support for KASLR
@ 2015-12-28 11:20 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel
This series implements KASLR for arm64, by building the kernel as a PIE
executable that can relocate itself at runtime, and moving it to a random
offset in the vmalloc area.
Notes:
- These patches apply on top of Mark Rutland's pagetable rework series:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/462438
- The arm64 Image is uncompressed by default, and the Elf64_Rela format uses
24 bytes per relocation entry. This results in considerable bloat (i.e., a
couple of MBs worth of relocation data in an .init section). However, no
build time postprocessing is required, we rely fully on the toolchain to
produce the image (modulo some byte swapping in the Image header for BE
kernels)
- We have to rely on the bootloader to supply some randomness in register x1
upon kernel entry. Since we have no decompressor, it is simply not feasible
to collect randomness in the head.S code path before mapping the kernel and
enabling the MMU.
- The EFI_RNG_PROTOCOL that is invoked in patch #10 to supply randomness on
UEFI systems is not universally available. A QEMU/KVM firmware image that
implements a pseudo-random version is available here:
http://people.linaro.org/~ard.biesheuvel/QEMU_EFI.fd.aarch64-rng.bz2
(requires access to PMCCNTR_EL0 and support for AES instructions)
See below for instructions how to run the pseudo-random version on real
hardware.
- Only mildly tested. Help appreciated.
Code can be found here:
git://git.linaro.org/people/ard.biesheuvel/linux-arm.git arm64-kaslr
https://git.linaro.org/people/ard.biesheuvel/linux-arm.git/shortlog/refs/heads/arm64-kaslr
Patch #1 introduces KIMAGE_VADDR as the base of the kernel virtual region.
Patch #2 memblock_reserve()'s the .bss, swapper_pg_dir and idmap_pg_dir
individually.
Patch #3 rewrites early_fixmap_init() so it does not rely on the linear mapping
(i.e., the use of phys_to_virt() is avoided)
Patch #4 moves the kernel virtual mapping to the vmalloc area, along with the
module region which is kept right below it, as before.
Patch #5 adds support for PLTs in modules so that relative branches can be
resolved via a PLT if the target is out of range.
Patch #6 moves to the x86 version of the extable implementation so that it no
longer contains absolute addresses that require fixing up at relocation time,
but uses relative offsets instead.
Patch #7 reverts some changes to the Image header population code so we no
longer depend on the linker to populate the header fields. This is necessary
since the R_AARCH64_ABS relocations that are emitted for these fields are not
resolved at build time for PIE executables.
Patch #8 updates the code in head.S that needs to execute before relocation to
avoid the use of values that are subject to dynamic relocation. These values
will not be populated in PIE executables.
Patch #9 implements the core KASLR, by taking randomness supplied in register x1
and using it to move the kernel inside the vmalloc area.
Patch #10 adds an invocation of the EFI_RNG_PROTOCOL to supply randomness to the
kernel proper.
Ard Biesheuvel (10):
arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
arm64: use more granular reservations for static page table
allocations
arm64: decouple early fixmap init from linear mapping
arm64: move kernel image to base of vmalloc area
arm64: add support for module PLTs
arm64: use relative references in exception tables
arm64: use assembly time constants for Image header fields
arm64: avoid dynamic relocations in early boot code
arm64: add support for relocatable kernel
arm64: efi: invoke EFI_RNG_PROTOCOL to supply KASLR randomness
Documentation/arm64/booting.txt | 3 +-
arch/arm64/Kconfig | 18 +++
arch/arm64/Makefile | 10 +-
arch/arm64/boot/Makefile | 1 +
arch/arm64/include/asm/assembler.h | 2 +-
arch/arm64/include/asm/compiler.h | 2 +
arch/arm64/include/asm/futex.h | 4 +-
arch/arm64/include/asm/kasan.h | 17 +--
arch/arm64/include/asm/memory.h | 29 ++++-
arch/arm64/include/asm/module.h | 11 ++
arch/arm64/include/asm/pgtable.h | 7 -
arch/arm64/include/asm/uaccess.h | 16 +--
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/arm64ksyms.c | 5 +
arch/arm64/kernel/armv8_deprecated.c | 4 +-
arch/arm64/kernel/efi-entry.S | 9 +-
arch/arm64/kernel/head.S | 120 ++++++++++++++---
arch/arm64/kernel/image.h | 40 ------
arch/arm64/kernel/module-plts.c | 137 ++++++++++++++++++++
arch/arm64/kernel/module.c | 7 +
arch/arm64/kernel/module.lds | 4 +
arch/arm64/kernel/setup.c | 15 ++-
arch/arm64/kernel/vmlinux.lds.S | 27 ++--
arch/arm64/mm/dump.c | 12 +-
arch/arm64/mm/extable.c | 102 ++++++++++++++-
arch/arm64/mm/init.c | 25 ++--
arch/arm64/mm/mmu.c | 122 +++++------------
drivers/firmware/efi/libstub/arm-stub.c | 31 +++++
include/linux/efi.h | 5 +-
scripts/arm64fixhdr.pl | 25 ++++
scripts/sortextable.c | 6 +-
31 files changed, 605 insertions(+), 212 deletions(-)
create mode 100644 arch/arm64/kernel/module-plts.c
create mode 100644 arch/arm64/kernel/module.lds
create mode 100755 scripts/arm64fixhdr.pl
EFI_RNG_PROTOCOL on real hardware
=================================
To test whether your UEFI implements the EFI_RNG_PROTOCOL, download the
following executable and run it from the UEFI Shell:
http://people.linaro.org/~ard.biesheuvel/RngTest.efi
FS0:\> rngtest
UEFI RNG Protocol Testing :
----------------------------
-- Locate UEFI RNG Protocol : [Fail - Status = Not Found]
If your UEFI does not implement the EFI_RNG_PROTOCOL, you can download and
install the pseudo-random version that uses the generic timer and PMCCNTR_EL0
values and permutes them using a couple of rounds of AES.
http://people.linaro.org/~ard.biesheuvel/RngDxe.efi
NOTE: not for production!! This is a quick and dirty hack to test the KASLR
code, and is not suitable for anything else.
FS0:\> rngdxe
FS0:\> rngtest
UEFI RNG Protocol Testing :
----------------------------
-- Locate UEFI RNG Protocol : [Pass]
-- Call RNG->GetInfo() interface :
>> Supported RNG Algorithm (Count = 2) :
0) 44F0DE6E-4D8C-4045-A8C7-4DD168856B9E
1) E43176D7-B6E8-4827-B784-7FFDC4B68561
-- Call RNG->GetRNG() interface :
>> RNG with default algorithm : [Pass]
>> RNG with SP800-90-HMAC-256 : [Fail - Status = Unsupported]
>> RNG with SP800-90-Hash-256 : [Fail - Status = Unsupported]
>> RNG with SP800-90-CTR-256 : [Pass]
>> RNG with X9.31-3DES : [Fail - Status = Unsupported]
>> RNG with X9.31-AES : [Fail - Status = Unsupported]
>> RNG with RAW Entropy : [Pass]
-- Random Number Generation Test with default RNG Algorithm (20 Rounds):
01) - 27
02) - 61E8
03) - 496FD8
04) - DDD793BF
05) - B6C37C8E23
06) - 4D183C604A96
07) - 9363311DB61298
08) - 5715A7294F4E436E
09) - F0D4D7BAA0DD52318E
10) - C88C6EBCF4C0474D87C3
11) - B5594602B482A643932172
12) - CA7573F704B2089B726B9CF1
13) - A93E9451CB533DCFBA87B97C33
14) - 45AA7B83DB6044F7BBAB031F0D24
15) - 3DD7A4D61F34ADCB400B5976730DCF
16) - 4DD168D21FAB8F59708330D6A9BEB021
17) - 4BBB225E61C465F174254159467E65939F
18) - 030A156C9616337A20070941E702827DA8E1
19) - AB0FC11C9A4E225011382A9D164D9D55CA2B64
20) - 72B9B4735DC445E5DA6AF88DE965B7E87CB9A23C
^ permalink raw reply [flat|nested] 45+ messages in thread
* [kernel-hardening] [RFC PATCH 00/10] arm64: implement support for KASLR
@ 2015-12-28 11:20 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, lkml
Cc: stuart.yoder, bhupesh.sharma, Ard Biesheuvel
This series implements KASLR for arm64, by building the kernel as a PIE
executable that can relocate itself at runtime, and moving it to a random
offset in the vmalloc area.
Notes:
- These patches apply on top of Mark Rutland's pagetable rework series:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/462438
- The arm64 Image is uncompressed by default, and the Elf64_Rela format uses
24 bytes per relocation entry. This results in considerable bloat (i.e., a
couple of MBs worth of relocation data in an .init section). However, no
build time postprocessing is required, we rely fully on the toolchain to
produce the image (modulo some byte swapping in the Image header for BE
kernels)
- We have to rely on the bootloader to supply some randomness in register x1
upon kernel entry. Since we have no decompressor, it is simply not feasible
to collect randomness in the head.S code path before mapping the kernel and
enabling the MMU.
- The EFI_RNG_PROTOCOL that is invoked in patch #10 to supply randomness on
UEFI systems is not universally available. A QEMU/KVM firmware image that
implements a pseudo-random version is available here:
http://people.linaro.org/~ard.biesheuvel/QEMU_EFI.fd.aarch64-rng.bz2
(requires access to PMCCNTR_EL0 and support for AES instructions)
See below for instructions how to run the pseudo-random version on real
hardware.
- Only mildly tested. Help appreciated.
Code can be found here:
git://git.linaro.org/people/ard.biesheuvel/linux-arm.git arm64-kaslr
https://git.linaro.org/people/ard.biesheuvel/linux-arm.git/shortlog/refs/heads/arm64-kaslr
Patch #1 introduces KIMAGE_VADDR as the base of the kernel virtual region.
Patch #2 memblock_reserve()'s the .bss, swapper_pg_dir and idmap_pg_dir
individually.
Patch #3 rewrites early_fixmap_init() so it does not rely on the linear mapping
(i.e., the use of phys_to_virt() is avoided)
Patch #4 moves the kernel virtual mapping to the vmalloc area, along with the
module region which is kept right below it, as before.
Patch #5 adds support for PLTs in modules so that relative branches can be
resolved via a PLT if the target is out of range.
Patch #6 moves to the x86 version of the extable implementation so that it no
longer contains absolute addresses that require fixing up at relocation time,
but uses relative offsets instead.
Patch #7 reverts some changes to the Image header population code so we no
longer depend on the linker to populate the header fields. This is necessary
since the R_AARCH64_ABS relocations that are emitted for these fields are not
resolved at build time for PIE executables.
Patch #8 updates the code in head.S that needs to execute before relocation to
avoid the use of values that are subject to dynamic relocation. These values
will not be populated in PIE executables.
Patch #9 implements the core KASLR, by taking randomness supplied in register x1
and using it to move the kernel inside the vmalloc area.
Patch #10 adds an invocation of the EFI_RNG_PROTOCOL to supply randomness to the
kernel proper.
Ard Biesheuvel (10):
arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
arm64: use more granular reservations for static page table
allocations
arm64: decouple early fixmap init from linear mapping
arm64: move kernel image to base of vmalloc area
arm64: add support for module PLTs
arm64: use relative references in exception tables
arm64: use assembly time constants for Image header fields
arm64: avoid dynamic relocations in early boot code
arm64: add support for relocatable kernel
arm64: efi: invoke EFI_RNG_PROTOCOL to supply KASLR randomness
Documentation/arm64/booting.txt | 3 +-
arch/arm64/Kconfig | 18 +++
arch/arm64/Makefile | 10 +-
arch/arm64/boot/Makefile | 1 +
arch/arm64/include/asm/assembler.h | 2 +-
arch/arm64/include/asm/compiler.h | 2 +
arch/arm64/include/asm/futex.h | 4 +-
arch/arm64/include/asm/kasan.h | 17 +--
arch/arm64/include/asm/memory.h | 29 ++++-
arch/arm64/include/asm/module.h | 11 ++
arch/arm64/include/asm/pgtable.h | 7 -
arch/arm64/include/asm/uaccess.h | 16 +--
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/arm64ksyms.c | 5 +
arch/arm64/kernel/armv8_deprecated.c | 4 +-
arch/arm64/kernel/efi-entry.S | 9 +-
arch/arm64/kernel/head.S | 120 ++++++++++++++---
arch/arm64/kernel/image.h | 40 ------
arch/arm64/kernel/module-plts.c | 137 ++++++++++++++++++++
arch/arm64/kernel/module.c | 7 +
arch/arm64/kernel/module.lds | 4 +
arch/arm64/kernel/setup.c | 15 ++-
arch/arm64/kernel/vmlinux.lds.S | 27 ++--
arch/arm64/mm/dump.c | 12 +-
arch/arm64/mm/extable.c | 102 ++++++++++++++-
arch/arm64/mm/init.c | 25 ++--
arch/arm64/mm/mmu.c | 122 +++++------------
drivers/firmware/efi/libstub/arm-stub.c | 31 +++++
include/linux/efi.h | 5 +-
scripts/arm64fixhdr.pl | 25 ++++
scripts/sortextable.c | 6 +-
31 files changed, 605 insertions(+), 212 deletions(-)
create mode 100644 arch/arm64/kernel/module-plts.c
create mode 100644 arch/arm64/kernel/module.lds
create mode 100755 scripts/arm64fixhdr.pl
EFI_RNG_PROTOCOL on real hardware
=================================
To test whether your UEFI implements the EFI_RNG_PROTOCOL, download the
following executable and run it from the UEFI Shell:
http://people.linaro.org/~ard.biesheuvel/RngTest.efi
FS0:\> rngtest
UEFI RNG Protocol Testing :
----------------------------
-- Locate UEFI RNG Protocol : [Fail - Status = Not Found]
If your UEFI does not implement the EFI_RNG_PROTOCOL, you can download and
install the pseudo-random version that uses the generic timer and PMCCNTR_EL0
values and permutes them using a couple of rounds of AES.
http://people.linaro.org/~ard.biesheuvel/RngDxe.efi
NOTE: not for production!! This is a quick and dirty hack to test the KASLR
code, and is not suitable for anything else.
FS0:\> rngdxe
FS0:\> rngtest
UEFI RNG Protocol Testing :
----------------------------
-- Locate UEFI RNG Protocol : [Pass]
-- Call RNG->GetInfo() interface :
>> Supported RNG Algorithm (Count = 2) :
0) 44F0DE6E-4D8C-4045-A8C7-4DD168856B9E
1) E43176D7-B6E8-4827-B784-7FFDC4B68561
-- Call RNG->GetRNG() interface :
>> RNG with default algorithm : [Pass]
>> RNG with SP800-90-HMAC-256 : [Fail - Status = Unsupported]
>> RNG with SP800-90-Hash-256 : [Fail - Status = Unsupported]
>> RNG with SP800-90-CTR-256 : [Pass]
>> RNG with X9.31-3DES : [Fail - Status = Unsupported]
>> RNG with X9.31-AES : [Fail - Status = Unsupported]
>> RNG with RAW Entropy : [Pass]
-- Random Number Generation Test with default RNG Algorithm (20 Rounds):
01) - 27
02) - 61E8
03) - 496FD8
04) - DDD793BF
05) - B6C37C8E23
06) - 4D183C604A96
07) - 9363311DB61298
08) - 5715A7294F4E436E
09) - F0D4D7BAA0DD52318E
10) - C88C6EBCF4C0474D87C3
11) - B5594602B482A643932172
12) - CA7573F704B2089B726B9CF1
13) - A93E9451CB533DCFBA87B97C33
14) - 45AA7B83DB6044F7BBAB031F0D24
15) - 3DD7A4D61F34ADCB400B5976730DCF
16) - 4DD168D21FAB8F59708330D6A9BEB021
17) - 4BBB225E61C465F174254159467E65939F
18) - 030A156C9616337A20070941E702827DA8E1
19) - AB0FC11C9A4E225011382A9D164D9D55CA2B64
20) - 72B9B4735DC445E5DA6AF88DE965B7E87CB9A23C
^ permalink raw reply [flat|nested] 45+ messages in thread
* [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
@ 2015-12-28 11:20 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel
This introduces the preprocessor symbol KIMAGE_VADDR which will serve as
the symbolic virtual base of the kernel region, i.e., the kernel's virtual
offset will be KIMAGE_VADDR + TEXT_OFFSET. For now, we define it as being
equal to PAGE_OFFSET, but in the future, it will be moved below it once
we move the kernel virtual mapping out of the linear mapping.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/include/asm/memory.h | 10 ++++++++--
arch/arm64/kernel/head.S | 2 +-
arch/arm64/kernel/vmlinux.lds.S | 4 ++--
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 853953cd1f08..bea9631b34a8 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -51,7 +51,8 @@
#define VA_BITS (CONFIG_ARM64_VA_BITS)
#define VA_START (UL(0xffffffffffffffff) << VA_BITS)
#define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1))
-#define MODULES_END (PAGE_OFFSET)
+#define KIMAGE_VADDR (PAGE_OFFSET)
+#define MODULES_END (KIMAGE_VADDR)
#define MODULES_VADDR (MODULES_END - SZ_64M)
#define PCI_IO_END (MODULES_VADDR - SZ_2M)
#define PCI_IO_START (PCI_IO_END - PCI_IO_SIZE)
@@ -75,8 +76,13 @@
* private definitions which should NOT be used outside memory.h
* files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
*/
-#define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))
+#define __virt_to_phys(x) ({ \
+ phys_addr_t __x = (phys_addr_t)(x); \
+ __x >= PAGE_OFFSET ? (__x - PAGE_OFFSET + PHYS_OFFSET) : \
+ (__x - KIMAGE_VADDR + PHYS_OFFSET); })
+
#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
+#define __phys_to_kimg(x) ((unsigned long)((x) - PHYS_OFFSET + KIMAGE_VADDR))
/*
* Convert a page to/from a physical address
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 23cfc08fc8ba..6434c844a0e4 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -389,7 +389,7 @@ __create_page_tables:
* Map the kernel image (starting with PHYS_OFFSET).
*/
mov x0, x26 // swapper_pg_dir
- mov x5, #PAGE_OFFSET
+ ldr x5, =KIMAGE_VADDR
create_pgd_entry x0, x5, x3, x6
ldr x6, =KERNEL_END // __va(KERNEL_END)
mov x3, x24 // phys offset
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 7de6c39858a5..ced0dedcabcc 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -88,7 +88,7 @@ SECTIONS
*(.discard.*)
}
- . = PAGE_OFFSET + TEXT_OFFSET;
+ . = KIMAGE_VADDR + TEXT_OFFSET;
.head.text : {
_text = .;
@@ -185,4 +185,4 @@ ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,
/*
* If padding is applied before .head.text, virt<->phys conversions will fail.
*/
-ASSERT(_text == (PAGE_OFFSET + TEXT_OFFSET), "HEAD is misaligned")
+ASSERT(_text == (KIMAGE_VADDR + TEXT_OFFSET), "HEAD is misaligned")
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [kernel-hardening] [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2015-12-28 11:20 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, lkml
Cc: stuart.yoder, bhupesh.sharma, Ard Biesheuvel
This introduces the preprocessor symbol KIMAGE_VADDR which will serve as
the symbolic virtual base of the kernel region, i.e., the kernel's virtual
offset will be KIMAGE_VADDR + TEXT_OFFSET. For now, we define it as being
equal to PAGE_OFFSET, but in the future, it will be moved below it once
we move the kernel virtual mapping out of the linear mapping.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/include/asm/memory.h | 10 ++++++++--
arch/arm64/kernel/head.S | 2 +-
arch/arm64/kernel/vmlinux.lds.S | 4 ++--
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 853953cd1f08..bea9631b34a8 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -51,7 +51,8 @@
#define VA_BITS (CONFIG_ARM64_VA_BITS)
#define VA_START (UL(0xffffffffffffffff) << VA_BITS)
#define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1))
-#define MODULES_END (PAGE_OFFSET)
+#define KIMAGE_VADDR (PAGE_OFFSET)
+#define MODULES_END (KIMAGE_VADDR)
#define MODULES_VADDR (MODULES_END - SZ_64M)
#define PCI_IO_END (MODULES_VADDR - SZ_2M)
#define PCI_IO_START (PCI_IO_END - PCI_IO_SIZE)
@@ -75,8 +76,13 @@
* private definitions which should NOT be used outside memory.h
* files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
*/
-#define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))
+#define __virt_to_phys(x) ({ \
+ phys_addr_t __x = (phys_addr_t)(x); \
+ __x >= PAGE_OFFSET ? (__x - PAGE_OFFSET + PHYS_OFFSET) : \
+ (__x - KIMAGE_VADDR + PHYS_OFFSET); })
+
#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
+#define __phys_to_kimg(x) ((unsigned long)((x) - PHYS_OFFSET + KIMAGE_VADDR))
/*
* Convert a page to/from a physical address
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 23cfc08fc8ba..6434c844a0e4 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -389,7 +389,7 @@ __create_page_tables:
* Map the kernel image (starting with PHYS_OFFSET).
*/
mov x0, x26 // swapper_pg_dir
- mov x5, #PAGE_OFFSET
+ ldr x5, =KIMAGE_VADDR
create_pgd_entry x0, x5, x3, x6
ldr x6, =KERNEL_END // __va(KERNEL_END)
mov x3, x24 // phys offset
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 7de6c39858a5..ced0dedcabcc 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -88,7 +88,7 @@ SECTIONS
*(.discard.*)
}
- . = PAGE_OFFSET + TEXT_OFFSET;
+ . = KIMAGE_VADDR + TEXT_OFFSET;
.head.text : {
_text = .;
@@ -185,4 +185,4 @@ ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,
/*
* If padding is applied before .head.text, virt<->phys conversions will fail.
*/
-ASSERT(_text == (PAGE_OFFSET + TEXT_OFFSET), "HEAD is misaligned")
+ASSERT(_text == (KIMAGE_VADDR + TEXT_OFFSET), "HEAD is misaligned")
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [RFC PATCH 02/10] arm64: use more granular reservations for static page table allocations
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
@ 2015-12-28 11:20 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel
Before introducing new statically allocated page tables and increasing
their alignment in subsequent patches, update the reservation logic
so that only pages that are in actual use end up as reserved with
memblock.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/mm/init.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 6bacba847923..8e678d05ad84 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -36,6 +36,7 @@
#include <linux/swiotlb.h>
#include <asm/fixmap.h>
+#include <asm/kernel-pgtable.h>
#include <asm/memory.h>
#include <asm/sections.h>
#include <asm/setup.h>
@@ -165,11 +166,13 @@ void __init arm64_memblock_init(void)
* Register the kernel text, kernel data, initrd, and initial
* pagetables with memblock.
*/
- memblock_reserve(__pa(_text), _end - _text);
+ memblock_reserve(__pa(_text), __bss_stop - _text);
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start)
memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start);
#endif
+ memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE);
+ memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE);
early_init_fdt_scan_reserved_mem();
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [kernel-hardening] [RFC PATCH 02/10] arm64: use more granular reservations for static page table allocations
@ 2015-12-28 11:20 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, lkml
Cc: stuart.yoder, bhupesh.sharma, Ard Biesheuvel
Before introducing new statically allocated page tables and increasing
their alignment in subsequent patches, update the reservation logic
so that only pages that are in actual use end up as reserved with
memblock.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/mm/init.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 6bacba847923..8e678d05ad84 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -36,6 +36,7 @@
#include <linux/swiotlb.h>
#include <asm/fixmap.h>
+#include <asm/kernel-pgtable.h>
#include <asm/memory.h>
#include <asm/sections.h>
#include <asm/setup.h>
@@ -165,11 +166,13 @@ void __init arm64_memblock_init(void)
* Register the kernel text, kernel data, initrd, and initial
* pagetables with memblock.
*/
- memblock_reserve(__pa(_text), _end - _text);
+ memblock_reserve(__pa(_text), __bss_stop - _text);
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start)
memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start);
#endif
+ memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE);
+ memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE);
early_init_fdt_scan_reserved_mem();
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [RFC PATCH 03/10] arm64: decouple early fixmap init from linear mapping
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
@ 2015-12-28 11:20 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel
Since the early fixmap page tables are populated using pages that are
part of the static footprint of the kernel, they are covered by the
initial kernel mapping, and we can refer to them without using __va/__pa
translations, which are tied to the linear mapping.
Instead, let's introduce __phys_to_kimg, which will be tied to the kernel
virtual mapping, regardless of whether or not it intersects with the linear
mapping. This will allow us to move the kernel out of the linear mapping in
a subsequent patch.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/include/asm/compiler.h | 2 +
arch/arm64/kernel/vmlinux.lds.S | 12 +--
arch/arm64/mm/mmu.c | 85 ++++++++------------
3 files changed, 42 insertions(+), 57 deletions(-)
diff --git a/arch/arm64/include/asm/compiler.h b/arch/arm64/include/asm/compiler.h
index ee35fd0f2236..dd342af63673 100644
--- a/arch/arm64/include/asm/compiler.h
+++ b/arch/arm64/include/asm/compiler.h
@@ -27,4 +27,6 @@
*/
#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
+#define __pgdir __attribute__((section(".pgdir"),aligned(PAGE_SIZE)))
+
#endif /* __ASM_COMPILER_H */
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index ced0dedcabcc..363c2f529951 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -160,11 +160,13 @@ SECTIONS
BSS_SECTION(0, 0, 0)
- . = ALIGN(PAGE_SIZE);
- idmap_pg_dir = .;
- . += IDMAP_DIR_SIZE;
- swapper_pg_dir = .;
- . += SWAPPER_DIR_SIZE;
+ .pgdir (NOLOAD) : ALIGN(PAGE_SIZE) {
+ idmap_pg_dir = .;
+ . += IDMAP_DIR_SIZE;
+ swapper_pg_dir = .;
+ . += SWAPPER_DIR_SIZE;
+ *(.pgdir)
+ }
_end = .;
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 50b1de8e127b..3435c316d607 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -540,39 +540,11 @@ void vmemmap_free(unsigned long start, unsigned long end)
}
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
-static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
-#if CONFIG_PGTABLE_LEVELS > 2
-static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss;
-#endif
-#if CONFIG_PGTABLE_LEVELS > 3
-static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss;
-#endif
-
-static inline pud_t * fixmap_pud(unsigned long addr)
-{
- pgd_t *pgd = pgd_offset_k(addr);
-
- BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
-
- return pud_offset(pgd, addr);
-}
-
-static inline pmd_t * fixmap_pmd(unsigned long addr)
-{
- pud_t *pud = fixmap_pud(addr);
-
- BUG_ON(pud_none(*pud) || pud_bad(*pud));
+static pte_t *__fixmap_pte;
- return pmd_offset(pud, addr);
-}
-
-static inline pte_t * fixmap_pte(unsigned long addr)
+static inline pte_t *fixmap_pte(unsigned long addr)
{
- pmd_t *pmd = fixmap_pmd(addr);
-
- BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd));
-
- return pte_offset_kernel(pmd, addr);
+ return __fixmap_pte + pte_index(addr);
}
void __init early_fixmap_init(void)
@@ -583,33 +555,42 @@ void __init early_fixmap_init(void)
unsigned long addr = FIXADDR_START;
pgd = pgd_offset_k(addr);
- pgd_populate(&init_mm, pgd, bm_pud);
- pud = pud_offset(pgd, addr);
- pud_populate(&init_mm, pud, bm_pmd);
- pmd = pmd_offset(pud, addr);
- pmd_populate_kernel(&init_mm, pmd, bm_pte);
+#if CONFIG_PGTABLE_LEVELS > 3
+ if (pgd_none(*pgd)) {
+ static pud_t bm_pud[PTRS_PER_PUD] __pgdir;
+
+ __pgd_populate(pgd, __pa(bm_pud), PUD_TYPE_TABLE);
+ memblock_reserve(__pa(bm_pud), sizeof(bm_pud));
+ }
+ pud = (pud_t *)__phys_to_kimg(pud_offset_phys(pgd, addr));
+#else
+ pud = (pud_t *)pgd;
+#endif
+#if CONFIG_PGTABLE_LEVELS > 2
+ if (pud_none(*pud)) {
+ static pmd_t bm_pmd[PTRS_PER_PMD] __pgdir;
+
+ __pud_populate(pud, __pa(bm_pmd), PMD_TYPE_TABLE);
+ memblock_reserve(__pa(bm_pmd), sizeof(bm_pmd));
+ }
+ pmd = (pmd_t *)__phys_to_kimg(pmd_offset_phys(pud, addr));
+#else
+ pmd = (pmd_t *)pud;
+#endif
+ if (pmd_none(*pmd)) {
+ static pte_t bm_pte[PTRS_PER_PTE] __pgdir;
+
+ __pmd_populate(pmd, __pa(bm_pte), PMD_TYPE_TABLE);
+ memblock_reserve(__pa(bm_pte), sizeof(bm_pte));
+ }
+ __fixmap_pte = (pte_t *)__phys_to_kimg(pmd_page_paddr(*pmd));
/*
* The boot-ioremap range spans multiple pmds, for which
- * we are not preparted:
+ * we are not prepared:
*/
BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
!= (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
-
- if ((pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)))
- || pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) {
- WARN_ON(1);
- pr_warn("pmd %p != %p, %p\n",
- pmd, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)),
- fixmap_pmd(fix_to_virt(FIX_BTMAP_END)));
- pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
- fix_to_virt(FIX_BTMAP_BEGIN));
- pr_warn("fix_to_virt(FIX_BTMAP_END): %08lx\n",
- fix_to_virt(FIX_BTMAP_END));
-
- pr_warn("FIX_BTMAP_END: %d\n", FIX_BTMAP_END);
- pr_warn("FIX_BTMAP_BEGIN: %d\n", FIX_BTMAP_BEGIN);
- }
}
void __set_fixmap(enum fixed_addresses idx,
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [kernel-hardening] [RFC PATCH 03/10] arm64: decouple early fixmap init from linear mapping
@ 2015-12-28 11:20 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, lkml
Cc: stuart.yoder, bhupesh.sharma, Ard Biesheuvel
Since the early fixmap page tables are populated using pages that are
part of the static footprint of the kernel, they are covered by the
initial kernel mapping, and we can refer to them without using __va/__pa
translations, which are tied to the linear mapping.
Instead, let's introduce __phys_to_kimg, which will be tied to the kernel
virtual mapping, regardless of whether or not it intersects with the linear
mapping. This will allow us to move the kernel out of the linear mapping in
a subsequent patch.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/include/asm/compiler.h | 2 +
arch/arm64/kernel/vmlinux.lds.S | 12 +--
arch/arm64/mm/mmu.c | 85 ++++++++------------
3 files changed, 42 insertions(+), 57 deletions(-)
diff --git a/arch/arm64/include/asm/compiler.h b/arch/arm64/include/asm/compiler.h
index ee35fd0f2236..dd342af63673 100644
--- a/arch/arm64/include/asm/compiler.h
+++ b/arch/arm64/include/asm/compiler.h
@@ -27,4 +27,6 @@
*/
#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
+#define __pgdir __attribute__((section(".pgdir"),aligned(PAGE_SIZE)))
+
#endif /* __ASM_COMPILER_H */
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index ced0dedcabcc..363c2f529951 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -160,11 +160,13 @@ SECTIONS
BSS_SECTION(0, 0, 0)
- . = ALIGN(PAGE_SIZE);
- idmap_pg_dir = .;
- . += IDMAP_DIR_SIZE;
- swapper_pg_dir = .;
- . += SWAPPER_DIR_SIZE;
+ .pgdir (NOLOAD) : ALIGN(PAGE_SIZE) {
+ idmap_pg_dir = .;
+ . += IDMAP_DIR_SIZE;
+ swapper_pg_dir = .;
+ . += SWAPPER_DIR_SIZE;
+ *(.pgdir)
+ }
_end = .;
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 50b1de8e127b..3435c316d607 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -540,39 +540,11 @@ void vmemmap_free(unsigned long start, unsigned long end)
}
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
-static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
-#if CONFIG_PGTABLE_LEVELS > 2
-static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss;
-#endif
-#if CONFIG_PGTABLE_LEVELS > 3
-static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss;
-#endif
-
-static inline pud_t * fixmap_pud(unsigned long addr)
-{
- pgd_t *pgd = pgd_offset_k(addr);
-
- BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
-
- return pud_offset(pgd, addr);
-}
-
-static inline pmd_t * fixmap_pmd(unsigned long addr)
-{
- pud_t *pud = fixmap_pud(addr);
-
- BUG_ON(pud_none(*pud) || pud_bad(*pud));
+static pte_t *__fixmap_pte;
- return pmd_offset(pud, addr);
-}
-
-static inline pte_t * fixmap_pte(unsigned long addr)
+static inline pte_t *fixmap_pte(unsigned long addr)
{
- pmd_t *pmd = fixmap_pmd(addr);
-
- BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd));
-
- return pte_offset_kernel(pmd, addr);
+ return __fixmap_pte + pte_index(addr);
}
void __init early_fixmap_init(void)
@@ -583,33 +555,42 @@ void __init early_fixmap_init(void)
unsigned long addr = FIXADDR_START;
pgd = pgd_offset_k(addr);
- pgd_populate(&init_mm, pgd, bm_pud);
- pud = pud_offset(pgd, addr);
- pud_populate(&init_mm, pud, bm_pmd);
- pmd = pmd_offset(pud, addr);
- pmd_populate_kernel(&init_mm, pmd, bm_pte);
+#if CONFIG_PGTABLE_LEVELS > 3
+ if (pgd_none(*pgd)) {
+ static pud_t bm_pud[PTRS_PER_PUD] __pgdir;
+
+ __pgd_populate(pgd, __pa(bm_pud), PUD_TYPE_TABLE);
+ memblock_reserve(__pa(bm_pud), sizeof(bm_pud));
+ }
+ pud = (pud_t *)__phys_to_kimg(pud_offset_phys(pgd, addr));
+#else
+ pud = (pud_t *)pgd;
+#endif
+#if CONFIG_PGTABLE_LEVELS > 2
+ if (pud_none(*pud)) {
+ static pmd_t bm_pmd[PTRS_PER_PMD] __pgdir;
+
+ __pud_populate(pud, __pa(bm_pmd), PMD_TYPE_TABLE);
+ memblock_reserve(__pa(bm_pmd), sizeof(bm_pmd));
+ }
+ pmd = (pmd_t *)__phys_to_kimg(pmd_offset_phys(pud, addr));
+#else
+ pmd = (pmd_t *)pud;
+#endif
+ if (pmd_none(*pmd)) {
+ static pte_t bm_pte[PTRS_PER_PTE] __pgdir;
+
+ __pmd_populate(pmd, __pa(bm_pte), PMD_TYPE_TABLE);
+ memblock_reserve(__pa(bm_pte), sizeof(bm_pte));
+ }
+ __fixmap_pte = (pte_t *)__phys_to_kimg(pmd_page_paddr(*pmd));
/*
* The boot-ioremap range spans multiple pmds, for which
- * we are not preparted:
+ * we are not prepared:
*/
BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
!= (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
-
- if ((pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)))
- || pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) {
- WARN_ON(1);
- pr_warn("pmd %p != %p, %p\n",
- pmd, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)),
- fixmap_pmd(fix_to_virt(FIX_BTMAP_END)));
- pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
- fix_to_virt(FIX_BTMAP_BEGIN));
- pr_warn("fix_to_virt(FIX_BTMAP_END): %08lx\n",
- fix_to_virt(FIX_BTMAP_END));
-
- pr_warn("FIX_BTMAP_END: %d\n", FIX_BTMAP_END);
- pr_warn("FIX_BTMAP_BEGIN: %d\n", FIX_BTMAP_BEGIN);
- }
}
void __set_fixmap(enum fixed_addresses idx,
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [RFC PATCH 04/10] arm64: move kernel image to base of vmalloc area
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
@ 2015-12-28 11:20 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel
This moves the module area to right before the vmalloc area, and
moves the kernel image to the base of the vmalloc area. This is
an intermediate step towards implementing kASLR, where the kernel
image can be located anywhere in the vmalloc area.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/include/asm/kasan.h | 17 ++++-----
arch/arm64/include/asm/memory.h | 17 ++++++---
arch/arm64/include/asm/pgtable.h | 7 ----
arch/arm64/kernel/setup.c | 13 +++++++
arch/arm64/mm/dump.c | 12 +++----
arch/arm64/mm/init.c | 20 +++++------
arch/arm64/mm/mmu.c | 37 ++------------------
7 files changed, 53 insertions(+), 70 deletions(-)
diff --git a/arch/arm64/include/asm/kasan.h b/arch/arm64/include/asm/kasan.h
index 2774fa384c47..476d56e0f04c 100644
--- a/arch/arm64/include/asm/kasan.h
+++ b/arch/arm64/include/asm/kasan.h
@@ -1,19 +1,16 @@
#ifndef __ASM_KASAN_H
#define __ASM_KASAN_H
-#ifndef __ASSEMBLY__
-
#ifdef CONFIG_KASAN
#include <linux/linkage.h>
-#include <asm/memory.h>
/*
* KASAN_SHADOW_START: beginning of the kernel virtual addresses.
* KASAN_SHADOW_END: KASAN_SHADOW_START + 1/8 of kernel virtual addresses.
*/
-#define KASAN_SHADOW_START (VA_START)
-#define KASAN_SHADOW_END (KASAN_SHADOW_START + (1UL << (VA_BITS - 3)))
+#define KASAN_SHADOW_START (VA_START)
+#define KASAN_SHADOW_END (KASAN_SHADOW_START + (_AC(1, UL) << (VA_BITS - 3)))
/*
* This value is used to map an address to the corresponding shadow
@@ -25,14 +22,18 @@
* should satisfy the following equation:
* KASAN_SHADOW_OFFSET = KASAN_SHADOW_END - (1ULL << 61)
*/
-#define KASAN_SHADOW_OFFSET (KASAN_SHADOW_END - (1ULL << (64 - 3)))
+#define KASAN_SHADOW_OFFSET (KASAN_SHADOW_END - (_AC(1, ULL) << (64 - 3)))
+#ifndef __ASSEMBLY__
void kasan_init(void);
asmlinkage void kasan_early_init(void);
+#endif
#else
+
+#ifndef __ASSEMBLY__
static inline void kasan_init(void) { }
#endif
-#endif
-#endif
+#endif /* CONFIG_KASAN */
+#endif /* __ASM_KASAN_H */
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index bea9631b34a8..1dcbf142d36c 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -51,14 +51,23 @@
#define VA_BITS (CONFIG_ARM64_VA_BITS)
#define VA_START (UL(0xffffffffffffffff) << VA_BITS)
#define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1))
-#define KIMAGE_VADDR (PAGE_OFFSET)
-#define MODULES_END (KIMAGE_VADDR)
-#define MODULES_VADDR (MODULES_END - SZ_64M)
-#define PCI_IO_END (MODULES_VADDR - SZ_2M)
+#define PCI_IO_END (PAGE_OFFSET - SZ_2M)
#define PCI_IO_START (PCI_IO_END - PCI_IO_SIZE)
#define FIXADDR_TOP (PCI_IO_START - SZ_2M)
#define TASK_SIZE_64 (UL(1) << VA_BITS)
+#ifndef CONFIG_KASAN
+#define MODULES_VADDR (VA_START)
+#else
+#include <asm/kasan.h>
+#define MODULES_VADDR (KASAN_SHADOW_END)
+#endif
+
+#define MODULES_END (MODULES_VADDR + SZ_64M)
+
+#define KIMAGE_VADDR (MODULES_END)
+#define VMALLOC_START (MODULES_END)
+
#ifdef CONFIG_COMPAT
#define TASK_SIZE_32 UL(0x100000000)
#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 0664468466fb..93203a6b9574 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -42,13 +42,6 @@
*/
#define VMEMMAP_SIZE ALIGN((1UL << (VA_BITS - PAGE_SHIFT)) * sizeof(struct page), PUD_SIZE)
-#ifndef CONFIG_KASAN
-#define VMALLOC_START (VA_START)
-#else
-#include <asm/kasan.h>
-#define VMALLOC_START (KASAN_SHADOW_END + SZ_64K)
-#endif
-
#define VMALLOC_END (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
#define vmemmap ((struct page *)(VMALLOC_END + SZ_64K))
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index cfed56f0ad26..96177a7c0f05 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -53,6 +53,7 @@
#include <asm/cpufeature.h>
#include <asm/cpu_ops.h>
#include <asm/kasan.h>
+#include <asm/kernel-pgtable.h>
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/smp_plat.h>
@@ -291,6 +292,18 @@ u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
void __init setup_arch(char **cmdline_p)
{
+ static struct vm_struct vmlinux_vm __initdata = {
+ .addr = (void *)KIMAGE_VADDR,
+ .size = 0,
+ .flags = VM_IOREMAP,
+ .caller = setup_arch,
+ };
+
+ vmlinux_vm.size = round_up((unsigned long)_end - KIMAGE_VADDR,
+ 1 << SWAPPER_BLOCK_SHIFT);
+ vmlinux_vm.phys_addr = __pa(KIMAGE_VADDR);
+ vm_area_add_early(&vmlinux_vm);
+
pr_info("Boot CPU: AArch64 Processor [%08x]\n", read_cpuid_id());
sprintf(init_utsname()->machine, ELF_PLATFORM);
diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c
index 5a22a119a74c..e83ffb00560c 100644
--- a/arch/arm64/mm/dump.c
+++ b/arch/arm64/mm/dump.c
@@ -35,7 +35,9 @@ struct addr_marker {
};
enum address_markers_idx {
- VMALLOC_START_NR = 0,
+ MODULES_START_NR = 0,
+ MODULES_END_NR,
+ VMALLOC_START_NR,
VMALLOC_END_NR,
#ifdef CONFIG_SPARSEMEM_VMEMMAP
VMEMMAP_START_NR,
@@ -45,12 +47,12 @@ enum address_markers_idx {
FIXADDR_END_NR,
PCI_START_NR,
PCI_END_NR,
- MODULES_START_NR,
- MODUELS_END_NR,
KERNEL_SPACE_NR,
};
static struct addr_marker address_markers[] = {
+ { MODULES_VADDR, "Modules start" },
+ { MODULES_END, "Modules end" },
{ VMALLOC_START, "vmalloc() Area" },
{ VMALLOC_END, "vmalloc() End" },
#ifdef CONFIG_SPARSEMEM_VMEMMAP
@@ -61,9 +63,7 @@ static struct addr_marker address_markers[] = {
{ FIXADDR_TOP, "Fixmap end" },
{ PCI_IO_START, "PCI I/O start" },
{ PCI_IO_END, "PCI I/O end" },
- { MODULES_VADDR, "Modules start" },
- { MODULES_END, "Modules end" },
- { PAGE_OFFSET, "Kernel Mapping" },
+ { PAGE_OFFSET, "Linear Mapping" },
{ -1, NULL },
};
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 8e678d05ad84..2cfc9c54bf51 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -305,22 +305,26 @@ void __init mem_init(void)
#ifdef CONFIG_KASAN
" kasan : 0x%16lx - 0x%16lx (%6ld GB)\n"
#endif
+ " modules : 0x%16lx - 0x%16lx (%6ld MB)\n"
" vmalloc : 0x%16lx - 0x%16lx (%6ld GB)\n"
+ " .init : 0x%p" " - 0x%p" " (%6ld KB)\n"
+ " .text : 0x%p" " - 0x%p" " (%6ld KB)\n"
+ " .data : 0x%p" " - 0x%p" " (%6ld KB)\n"
#ifdef CONFIG_SPARSEMEM_VMEMMAP
" vmemmap : 0x%16lx - 0x%16lx (%6ld GB maximum)\n"
" 0x%16lx - 0x%16lx (%6ld MB actual)\n"
#endif
" fixed : 0x%16lx - 0x%16lx (%6ld KB)\n"
" PCI I/O : 0x%16lx - 0x%16lx (%6ld MB)\n"
- " modules : 0x%16lx - 0x%16lx (%6ld MB)\n"
- " memory : 0x%16lx - 0x%16lx (%6ld MB)\n"
- " .init : 0x%p" " - 0x%p" " (%6ld KB)\n"
- " .text : 0x%p" " - 0x%p" " (%6ld KB)\n"
- " .data : 0x%p" " - 0x%p" " (%6ld KB)\n",
+ " memory : 0x%16lx - 0x%16lx (%6ld MB)\n",
#ifdef CONFIG_KASAN
MLG(KASAN_SHADOW_START, KASAN_SHADOW_END),
#endif
+ MLM(MODULES_VADDR, MODULES_END),
MLG(VMALLOC_START, VMALLOC_END),
+ MLK_ROUNDUP(__init_begin, __init_end),
+ MLK_ROUNDUP(_text, _etext),
+ MLK_ROUNDUP(_sdata, _edata),
#ifdef CONFIG_SPARSEMEM_VMEMMAP
MLG((unsigned long)vmemmap,
(unsigned long)vmemmap + VMEMMAP_SIZE),
@@ -329,11 +333,7 @@ void __init mem_init(void)
#endif
MLK(FIXADDR_START, FIXADDR_TOP),
MLM(PCI_IO_START, PCI_IO_END),
- MLM(MODULES_VADDR, MODULES_END),
- MLM(PAGE_OFFSET, (unsigned long)high_memory),
- MLK_ROUNDUP(__init_begin, __init_end),
- MLK_ROUNDUP(_text, _etext),
- MLK_ROUNDUP(_sdata, _edata));
+ MLM(PAGE_OFFSET, (unsigned long)high_memory));
#undef MLK
#undef MLM
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 3435c316d607..8042f88f42b5 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -322,40 +322,6 @@ static void create_mapping_late(phys_addr_t phys, unsigned long virt,
__create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, late_alloc);
}
-static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end)
-{
-
- unsigned long kernel_start = __pa(_stext);
- unsigned long kernel_end = __pa(_end);
-
- /*
- * The kernel itself is mapped at page granularity. Map all other
- * memory, making sure we don't overwrite the existing kernel mappings.
- */
-
- /* No overlap with the kernel. */
- if (end < kernel_start || start >= kernel_end) {
- __create_pgd_mapping(pgd, start, __phys_to_virt(start),
- end - start, PAGE_KERNEL, early_alloc);
- return;
- }
-
- /*
- * This block overlaps the kernel mapping. Map the portion(s) which
- * don't overlap.
- */
- if (start < kernel_start)
- __create_pgd_mapping(pgd, start,
- __phys_to_virt(start),
- kernel_start - start, PAGE_KERNEL,
- early_alloc);
- if (kernel_end < end)
- __create_pgd_mapping(pgd, kernel_end,
- __phys_to_virt(kernel_end),
- end - kernel_end, PAGE_KERNEL,
- early_alloc);
-}
-
static void __init map_mem(pgd_t *pgd)
{
struct memblock_region *reg;
@@ -370,7 +336,8 @@ static void __init map_mem(pgd_t *pgd)
if (memblock_is_nomap(reg))
continue;
- __map_memblock(pgd, start, end);
+ __create_pgd_mapping(pgd, start, __phys_to_virt(start),
+ end - start, PAGE_KERNEL, early_alloc);
}
}
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [kernel-hardening] [RFC PATCH 04/10] arm64: move kernel image to base of vmalloc area
@ 2015-12-28 11:20 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, lkml
Cc: stuart.yoder, bhupesh.sharma, Ard Biesheuvel
This moves the module area to right before the vmalloc area, and
moves the kernel image to the base of the vmalloc area. This is
an intermediate step towards implementing kASLR, where the kernel
image can be located anywhere in the vmalloc area.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/include/asm/kasan.h | 17 ++++-----
arch/arm64/include/asm/memory.h | 17 ++++++---
arch/arm64/include/asm/pgtable.h | 7 ----
arch/arm64/kernel/setup.c | 13 +++++++
arch/arm64/mm/dump.c | 12 +++----
arch/arm64/mm/init.c | 20 +++++------
arch/arm64/mm/mmu.c | 37 ++------------------
7 files changed, 53 insertions(+), 70 deletions(-)
diff --git a/arch/arm64/include/asm/kasan.h b/arch/arm64/include/asm/kasan.h
index 2774fa384c47..476d56e0f04c 100644
--- a/arch/arm64/include/asm/kasan.h
+++ b/arch/arm64/include/asm/kasan.h
@@ -1,19 +1,16 @@
#ifndef __ASM_KASAN_H
#define __ASM_KASAN_H
-#ifndef __ASSEMBLY__
-
#ifdef CONFIG_KASAN
#include <linux/linkage.h>
-#include <asm/memory.h>
/*
* KASAN_SHADOW_START: beginning of the kernel virtual addresses.
* KASAN_SHADOW_END: KASAN_SHADOW_START + 1/8 of kernel virtual addresses.
*/
-#define KASAN_SHADOW_START (VA_START)
-#define KASAN_SHADOW_END (KASAN_SHADOW_START + (1UL << (VA_BITS - 3)))
+#define KASAN_SHADOW_START (VA_START)
+#define KASAN_SHADOW_END (KASAN_SHADOW_START + (_AC(1, UL) << (VA_BITS - 3)))
/*
* This value is used to map an address to the corresponding shadow
@@ -25,14 +22,18 @@
* should satisfy the following equation:
* KASAN_SHADOW_OFFSET = KASAN_SHADOW_END - (1ULL << 61)
*/
-#define KASAN_SHADOW_OFFSET (KASAN_SHADOW_END - (1ULL << (64 - 3)))
+#define KASAN_SHADOW_OFFSET (KASAN_SHADOW_END - (_AC(1, ULL) << (64 - 3)))
+#ifndef __ASSEMBLY__
void kasan_init(void);
asmlinkage void kasan_early_init(void);
+#endif
#else
+
+#ifndef __ASSEMBLY__
static inline void kasan_init(void) { }
#endif
-#endif
-#endif
+#endif /* CONFIG_KASAN */
+#endif /* __ASM_KASAN_H */
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index bea9631b34a8..1dcbf142d36c 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -51,14 +51,23 @@
#define VA_BITS (CONFIG_ARM64_VA_BITS)
#define VA_START (UL(0xffffffffffffffff) << VA_BITS)
#define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1))
-#define KIMAGE_VADDR (PAGE_OFFSET)
-#define MODULES_END (KIMAGE_VADDR)
-#define MODULES_VADDR (MODULES_END - SZ_64M)
-#define PCI_IO_END (MODULES_VADDR - SZ_2M)
+#define PCI_IO_END (PAGE_OFFSET - SZ_2M)
#define PCI_IO_START (PCI_IO_END - PCI_IO_SIZE)
#define FIXADDR_TOP (PCI_IO_START - SZ_2M)
#define TASK_SIZE_64 (UL(1) << VA_BITS)
+#ifndef CONFIG_KASAN
+#define MODULES_VADDR (VA_START)
+#else
+#include <asm/kasan.h>
+#define MODULES_VADDR (KASAN_SHADOW_END)
+#endif
+
+#define MODULES_END (MODULES_VADDR + SZ_64M)
+
+#define KIMAGE_VADDR (MODULES_END)
+#define VMALLOC_START (MODULES_END)
+
#ifdef CONFIG_COMPAT
#define TASK_SIZE_32 UL(0x100000000)
#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 0664468466fb..93203a6b9574 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -42,13 +42,6 @@
*/
#define VMEMMAP_SIZE ALIGN((1UL << (VA_BITS - PAGE_SHIFT)) * sizeof(struct page), PUD_SIZE)
-#ifndef CONFIG_KASAN
-#define VMALLOC_START (VA_START)
-#else
-#include <asm/kasan.h>
-#define VMALLOC_START (KASAN_SHADOW_END + SZ_64K)
-#endif
-
#define VMALLOC_END (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
#define vmemmap ((struct page *)(VMALLOC_END + SZ_64K))
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index cfed56f0ad26..96177a7c0f05 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -53,6 +53,7 @@
#include <asm/cpufeature.h>
#include <asm/cpu_ops.h>
#include <asm/kasan.h>
+#include <asm/kernel-pgtable.h>
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/smp_plat.h>
@@ -291,6 +292,18 @@ u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
void __init setup_arch(char **cmdline_p)
{
+ static struct vm_struct vmlinux_vm __initdata = {
+ .addr = (void *)KIMAGE_VADDR,
+ .size = 0,
+ .flags = VM_IOREMAP,
+ .caller = setup_arch,
+ };
+
+ vmlinux_vm.size = round_up((unsigned long)_end - KIMAGE_VADDR,
+ 1 << SWAPPER_BLOCK_SHIFT);
+ vmlinux_vm.phys_addr = __pa(KIMAGE_VADDR);
+ vm_area_add_early(&vmlinux_vm);
+
pr_info("Boot CPU: AArch64 Processor [%08x]\n", read_cpuid_id());
sprintf(init_utsname()->machine, ELF_PLATFORM);
diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c
index 5a22a119a74c..e83ffb00560c 100644
--- a/arch/arm64/mm/dump.c
+++ b/arch/arm64/mm/dump.c
@@ -35,7 +35,9 @@ struct addr_marker {
};
enum address_markers_idx {
- VMALLOC_START_NR = 0,
+ MODULES_START_NR = 0,
+ MODULES_END_NR,
+ VMALLOC_START_NR,
VMALLOC_END_NR,
#ifdef CONFIG_SPARSEMEM_VMEMMAP
VMEMMAP_START_NR,
@@ -45,12 +47,12 @@ enum address_markers_idx {
FIXADDR_END_NR,
PCI_START_NR,
PCI_END_NR,
- MODULES_START_NR,
- MODUELS_END_NR,
KERNEL_SPACE_NR,
};
static struct addr_marker address_markers[] = {
+ { MODULES_VADDR, "Modules start" },
+ { MODULES_END, "Modules end" },
{ VMALLOC_START, "vmalloc() Area" },
{ VMALLOC_END, "vmalloc() End" },
#ifdef CONFIG_SPARSEMEM_VMEMMAP
@@ -61,9 +63,7 @@ static struct addr_marker address_markers[] = {
{ FIXADDR_TOP, "Fixmap end" },
{ PCI_IO_START, "PCI I/O start" },
{ PCI_IO_END, "PCI I/O end" },
- { MODULES_VADDR, "Modules start" },
- { MODULES_END, "Modules end" },
- { PAGE_OFFSET, "Kernel Mapping" },
+ { PAGE_OFFSET, "Linear Mapping" },
{ -1, NULL },
};
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 8e678d05ad84..2cfc9c54bf51 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -305,22 +305,26 @@ void __init mem_init(void)
#ifdef CONFIG_KASAN
" kasan : 0x%16lx - 0x%16lx (%6ld GB)\n"
#endif
+ " modules : 0x%16lx - 0x%16lx (%6ld MB)\n"
" vmalloc : 0x%16lx - 0x%16lx (%6ld GB)\n"
+ " .init : 0x%p" " - 0x%p" " (%6ld KB)\n"
+ " .text : 0x%p" " - 0x%p" " (%6ld KB)\n"
+ " .data : 0x%p" " - 0x%p" " (%6ld KB)\n"
#ifdef CONFIG_SPARSEMEM_VMEMMAP
" vmemmap : 0x%16lx - 0x%16lx (%6ld GB maximum)\n"
" 0x%16lx - 0x%16lx (%6ld MB actual)\n"
#endif
" fixed : 0x%16lx - 0x%16lx (%6ld KB)\n"
" PCI I/O : 0x%16lx - 0x%16lx (%6ld MB)\n"
- " modules : 0x%16lx - 0x%16lx (%6ld MB)\n"
- " memory : 0x%16lx - 0x%16lx (%6ld MB)\n"
- " .init : 0x%p" " - 0x%p" " (%6ld KB)\n"
- " .text : 0x%p" " - 0x%p" " (%6ld KB)\n"
- " .data : 0x%p" " - 0x%p" " (%6ld KB)\n",
+ " memory : 0x%16lx - 0x%16lx (%6ld MB)\n",
#ifdef CONFIG_KASAN
MLG(KASAN_SHADOW_START, KASAN_SHADOW_END),
#endif
+ MLM(MODULES_VADDR, MODULES_END),
MLG(VMALLOC_START, VMALLOC_END),
+ MLK_ROUNDUP(__init_begin, __init_end),
+ MLK_ROUNDUP(_text, _etext),
+ MLK_ROUNDUP(_sdata, _edata),
#ifdef CONFIG_SPARSEMEM_VMEMMAP
MLG((unsigned long)vmemmap,
(unsigned long)vmemmap + VMEMMAP_SIZE),
@@ -329,11 +333,7 @@ void __init mem_init(void)
#endif
MLK(FIXADDR_START, FIXADDR_TOP),
MLM(PCI_IO_START, PCI_IO_END),
- MLM(MODULES_VADDR, MODULES_END),
- MLM(PAGE_OFFSET, (unsigned long)high_memory),
- MLK_ROUNDUP(__init_begin, __init_end),
- MLK_ROUNDUP(_text, _etext),
- MLK_ROUNDUP(_sdata, _edata));
+ MLM(PAGE_OFFSET, (unsigned long)high_memory));
#undef MLK
#undef MLM
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 3435c316d607..8042f88f42b5 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -322,40 +322,6 @@ static void create_mapping_late(phys_addr_t phys, unsigned long virt,
__create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, late_alloc);
}
-static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end)
-{
-
- unsigned long kernel_start = __pa(_stext);
- unsigned long kernel_end = __pa(_end);
-
- /*
- * The kernel itself is mapped at page granularity. Map all other
- * memory, making sure we don't overwrite the existing kernel mappings.
- */
-
- /* No overlap with the kernel. */
- if (end < kernel_start || start >= kernel_end) {
- __create_pgd_mapping(pgd, start, __phys_to_virt(start),
- end - start, PAGE_KERNEL, early_alloc);
- return;
- }
-
- /*
- * This block overlaps the kernel mapping. Map the portion(s) which
- * don't overlap.
- */
- if (start < kernel_start)
- __create_pgd_mapping(pgd, start,
- __phys_to_virt(start),
- kernel_start - start, PAGE_KERNEL,
- early_alloc);
- if (kernel_end < end)
- __create_pgd_mapping(pgd, kernel_end,
- __phys_to_virt(kernel_end),
- end - kernel_end, PAGE_KERNEL,
- early_alloc);
-}
-
static void __init map_mem(pgd_t *pgd)
{
struct memblock_region *reg;
@@ -370,7 +336,8 @@ static void __init map_mem(pgd_t *pgd)
if (memblock_is_nomap(reg))
continue;
- __map_memblock(pgd, start, end);
+ __create_pgd_mapping(pgd, start, __phys_to_virt(start),
+ end - start, PAGE_KERNEL, early_alloc);
}
}
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [RFC PATCH 05/10] arm64: add support for module PLTs
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
@ 2015-12-28 11:20 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel
This adds support for emitting PLTs at module load time for relative
branches that are out of range. This is a prerequisite for KASLR,
which may place the kernel and the modules anywhere in the vmalloc
area, making it likely that branch target offsets exceed the maximum
range of +/- 128 MB.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/Kconfig | 4 +
arch/arm64/Makefile | 4 +
arch/arm64/include/asm/module.h | 11 ++
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/module-plts.c | 137 ++++++++++++++++++++
arch/arm64/kernel/module.c | 7 +
arch/arm64/kernel/module.lds | 4 +
7 files changed, 168 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 871f21783866..827e78f33944 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -704,6 +704,10 @@ config ARM64_LSE_ATOMICS
endmenu
+config ARM64_MODULE_PLTS
+ bool
+ select HAVE_MOD_ARCH_SPECIFIC
+
endmenu
menu "Boot options"
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index cd822d8454c0..d4654830e536 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -45,6 +45,10 @@ ifeq ($(CONFIG_ARM64_ERRATUM_843419), y)
KBUILD_CFLAGS_MODULE += -mcmodel=large
endif
+ifeq ($(CONFIG_ARM64_MODULE_PLTS),y)
+KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/arm64/kernel/module.lds
+endif
+
# Default value
head-y := arch/arm64/kernel/head.o
diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h
index e80e232b730e..7b8cd3dc9d8e 100644
--- a/arch/arm64/include/asm/module.h
+++ b/arch/arm64/include/asm/module.h
@@ -20,4 +20,15 @@
#define MODULE_ARCH_VERMAGIC "aarch64"
+#ifdef CONFIG_ARM64_MODULE_PLTS
+struct mod_arch_specific {
+ struct elf64_shdr *core_plt;
+ struct elf64_shdr *init_plt;
+ int core_plt_count;
+ int init_plt_count;
+};
+#endif
+
+u64 get_module_plt(struct module *mod, void *loc, u64 val);
+
#endif /* __ASM_MODULE_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 474691f8b13a..f42b0fff607f 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -30,6 +30,7 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
../../arm/kernel/opcodes.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
+arm64-obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c
new file mode 100644
index 000000000000..b4199f2b4e69
--- /dev/null
+++ b/arch/arm64/kernel/module-plts.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2014-2015 Linaro Ltd. <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/elf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+struct plt_entry {
+ u32 mov0; /* movn x16, #0x...., lsl #32 */
+ u32 mov1; /* movk x16, #0x...., lsl #16 */
+ u32 mov2; /* movk x16, #0x.... */
+ u32 br; /* br x16 */
+};
+
+static bool in_init(const struct module *mod, void *addr)
+{
+ return (u64)addr - (u64)mod->module_init < mod->init_size;
+}
+
+u64 get_module_plt(struct module *mod, void *loc, u64 val)
+{
+ struct plt_entry entry, *plt;
+ int i, *count;
+
+ entry.mov0 = 0x92c00010 | ((~val & 0xffff00000000) >> (32 - 5));
+ entry.mov1 = 0xf2a00010 | (( val & 0xffff0000) >> (16 - 5));
+ entry.mov2 = 0xf2800010 | (( val & 0xffff) << 5);
+ entry.br = 0xd61f0200;
+
+ if (in_init(mod, loc)) {
+ plt = (struct plt_entry *)mod->arch.init_plt->sh_addr;
+ count = &mod->arch.init_plt_count;
+ } else {
+ plt = (struct plt_entry *)mod->arch.core_plt->sh_addr;
+ count = &mod->arch.core_plt_count;
+ }
+
+ /* Look for an existing entry pointing to 'val' */
+ for (i = 0; i < *count; i++)
+ if (plt[i].mov2 == entry.mov2 &&
+ plt[i].mov1 == entry.mov1 &&
+ plt[i].mov0 == entry.mov0)
+ return (u64)&plt[i];
+
+ i = (*count)++;
+ plt[i] = entry;
+ return (u64)&plt[i];
+}
+
+static int duplicate_rel(Elf64_Addr base, const Elf64_Rela *rela, int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ if (rela[i].r_info == rela[num].r_info &&
+ rela[i].r_addend == rela[num].r_addend)
+ return 1;
+ }
+ return 0;
+}
+
+/* Count how many PLT entries we may need */
+static unsigned int count_plts(Elf64_Addr base, const Elf64_Rela *rela, int num)
+{
+ unsigned int ret = 0;
+ int i;
+
+ /*
+ * Sure, this is order(n^2), but it's usually short, and not
+ * time critical
+ */
+ for (i = 0; i < num; i++)
+ switch (ELF64_R_TYPE(rela[i].r_info)) {
+ case R_AARCH64_JUMP26:
+ case R_AARCH64_CALL26:
+ if (!duplicate_rel(base, rela, i))
+ ret++;
+ break;
+ }
+ return ret;
+}
+
+int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
+ char *secstrings, struct module *mod)
+{
+ unsigned long core_plts = 0, init_plts = 0;
+ Elf64_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum;
+
+ /*
+ * To store the PLTs, we expand the .text section for core module code
+ * and the .init.text section for initialization code.
+ */
+ for (s = sechdrs; s < sechdrs_end; ++s)
+ if (strcmp(".core.plt", secstrings + s->sh_name) == 0)
+ mod->arch.core_plt = s;
+ else if (strcmp(".init.plt", secstrings + s->sh_name) == 0)
+ mod->arch.init_plt = s;
+
+ if (!mod->arch.core_plt || !mod->arch.init_plt) {
+ pr_err("%s: sections missing\n", mod->name);
+ return -ENOEXEC;
+ }
+
+ for (s = sechdrs + 1; s < sechdrs_end; ++s) {
+ const Elf64_Rela *rels = (void *)ehdr + s->sh_offset;
+ int numrels = s->sh_size / sizeof(Elf64_Rela);
+ Elf64_Shdr *dstsec = sechdrs + s->sh_info;
+
+ if (s->sh_type != SHT_RELA)
+ continue;
+
+ if (strstr(secstrings + s->sh_name, ".init"))
+ init_plts += count_plts(dstsec->sh_addr, rels, numrels);
+ else
+ core_plts += count_plts(dstsec->sh_addr, rels, numrels);
+ }
+
+ mod->arch.core_plt->sh_type = SHT_NOBITS;
+ mod->arch.core_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+ mod->arch.core_plt->sh_addralign = L1_CACHE_BYTES;
+ mod->arch.core_plt->sh_size = core_plts * sizeof(struct plt_entry);
+ mod->arch.core_plt_count = 0;
+
+ mod->arch.init_plt->sh_type = SHT_NOBITS;
+ mod->arch.init_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+ mod->arch.init_plt->sh_addralign = L1_CACHE_BYTES;
+ mod->arch.init_plt->sh_size = init_plts * sizeof(struct plt_entry);
+ mod->arch.init_plt_count = 0;
+ pr_debug("%s: core.plt=%lld, init.plt=%lld\n", __func__,
+ mod->arch.core_plt->sh_size, mod->arch.init_plt->sh_size);
+ return 0;
+}
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index f4bc779e62e8..14880d77ec6f 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -388,6 +388,13 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
case R_AARCH64_CALL26:
ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26,
AARCH64_INSN_IMM_26);
+
+ if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) &&
+ ovf == -ERANGE) {
+ val = get_module_plt(me, loc, val);
+ ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2,
+ 26, AARCH64_INSN_IMM_26);
+ }
break;
default:
diff --git a/arch/arm64/kernel/module.lds b/arch/arm64/kernel/module.lds
new file mode 100644
index 000000000000..3682fa107918
--- /dev/null
+++ b/arch/arm64/kernel/module.lds
@@ -0,0 +1,4 @@
+SECTIONS {
+ .core.plt : { BYTE(0) }
+ .init.plt : { BYTE(0) }
+}
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [kernel-hardening] [RFC PATCH 05/10] arm64: add support for module PLTs
@ 2015-12-28 11:20 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, lkml
Cc: stuart.yoder, bhupesh.sharma, Ard Biesheuvel
This adds support for emitting PLTs at module load time for relative
branches that are out of range. This is a prerequisite for KASLR,
which may place the kernel and the modules anywhere in the vmalloc
area, making it likely that branch target offsets exceed the maximum
range of +/- 128 MB.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/Kconfig | 4 +
arch/arm64/Makefile | 4 +
arch/arm64/include/asm/module.h | 11 ++
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/module-plts.c | 137 ++++++++++++++++++++
arch/arm64/kernel/module.c | 7 +
arch/arm64/kernel/module.lds | 4 +
7 files changed, 168 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 871f21783866..827e78f33944 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -704,6 +704,10 @@ config ARM64_LSE_ATOMICS
endmenu
+config ARM64_MODULE_PLTS
+ bool
+ select HAVE_MOD_ARCH_SPECIFIC
+
endmenu
menu "Boot options"
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index cd822d8454c0..d4654830e536 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -45,6 +45,10 @@ ifeq ($(CONFIG_ARM64_ERRATUM_843419), y)
KBUILD_CFLAGS_MODULE += -mcmodel=large
endif
+ifeq ($(CONFIG_ARM64_MODULE_PLTS),y)
+KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/arm64/kernel/module.lds
+endif
+
# Default value
head-y := arch/arm64/kernel/head.o
diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h
index e80e232b730e..7b8cd3dc9d8e 100644
--- a/arch/arm64/include/asm/module.h
+++ b/arch/arm64/include/asm/module.h
@@ -20,4 +20,15 @@
#define MODULE_ARCH_VERMAGIC "aarch64"
+#ifdef CONFIG_ARM64_MODULE_PLTS
+struct mod_arch_specific {
+ struct elf64_shdr *core_plt;
+ struct elf64_shdr *init_plt;
+ int core_plt_count;
+ int init_plt_count;
+};
+#endif
+
+u64 get_module_plt(struct module *mod, void *loc, u64 val);
+
#endif /* __ASM_MODULE_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 474691f8b13a..f42b0fff607f 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -30,6 +30,7 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
../../arm/kernel/opcodes.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
+arm64-obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c
new file mode 100644
index 000000000000..b4199f2b4e69
--- /dev/null
+++ b/arch/arm64/kernel/module-plts.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2014-2015 Linaro Ltd. <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/elf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+struct plt_entry {
+ u32 mov0; /* movn x16, #0x...., lsl #32 */
+ u32 mov1; /* movk x16, #0x...., lsl #16 */
+ u32 mov2; /* movk x16, #0x.... */
+ u32 br; /* br x16 */
+};
+
+static bool in_init(const struct module *mod, void *addr)
+{
+ return (u64)addr - (u64)mod->module_init < mod->init_size;
+}
+
+u64 get_module_plt(struct module *mod, void *loc, u64 val)
+{
+ struct plt_entry entry, *plt;
+ int i, *count;
+
+ entry.mov0 = 0x92c00010 | ((~val & 0xffff00000000) >> (32 - 5));
+ entry.mov1 = 0xf2a00010 | (( val & 0xffff0000) >> (16 - 5));
+ entry.mov2 = 0xf2800010 | (( val & 0xffff) << 5);
+ entry.br = 0xd61f0200;
+
+ if (in_init(mod, loc)) {
+ plt = (struct plt_entry *)mod->arch.init_plt->sh_addr;
+ count = &mod->arch.init_plt_count;
+ } else {
+ plt = (struct plt_entry *)mod->arch.core_plt->sh_addr;
+ count = &mod->arch.core_plt_count;
+ }
+
+ /* Look for an existing entry pointing to 'val' */
+ for (i = 0; i < *count; i++)
+ if (plt[i].mov2 == entry.mov2 &&
+ plt[i].mov1 == entry.mov1 &&
+ plt[i].mov0 == entry.mov0)
+ return (u64)&plt[i];
+
+ i = (*count)++;
+ plt[i] = entry;
+ return (u64)&plt[i];
+}
+
+static int duplicate_rel(Elf64_Addr base, const Elf64_Rela *rela, int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ if (rela[i].r_info == rela[num].r_info &&
+ rela[i].r_addend == rela[num].r_addend)
+ return 1;
+ }
+ return 0;
+}
+
+/* Count how many PLT entries we may need */
+static unsigned int count_plts(Elf64_Addr base, const Elf64_Rela *rela, int num)
+{
+ unsigned int ret = 0;
+ int i;
+
+ /*
+ * Sure, this is order(n^2), but it's usually short, and not
+ * time critical
+ */
+ for (i = 0; i < num; i++)
+ switch (ELF64_R_TYPE(rela[i].r_info)) {
+ case R_AARCH64_JUMP26:
+ case R_AARCH64_CALL26:
+ if (!duplicate_rel(base, rela, i))
+ ret++;
+ break;
+ }
+ return ret;
+}
+
+int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
+ char *secstrings, struct module *mod)
+{
+ unsigned long core_plts = 0, init_plts = 0;
+ Elf64_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum;
+
+ /*
+ * To store the PLTs, we expand the .text section for core module code
+ * and the .init.text section for initialization code.
+ */
+ for (s = sechdrs; s < sechdrs_end; ++s)
+ if (strcmp(".core.plt", secstrings + s->sh_name) == 0)
+ mod->arch.core_plt = s;
+ else if (strcmp(".init.plt", secstrings + s->sh_name) == 0)
+ mod->arch.init_plt = s;
+
+ if (!mod->arch.core_plt || !mod->arch.init_plt) {
+ pr_err("%s: sections missing\n", mod->name);
+ return -ENOEXEC;
+ }
+
+ for (s = sechdrs + 1; s < sechdrs_end; ++s) {
+ const Elf64_Rela *rels = (void *)ehdr + s->sh_offset;
+ int numrels = s->sh_size / sizeof(Elf64_Rela);
+ Elf64_Shdr *dstsec = sechdrs + s->sh_info;
+
+ if (s->sh_type != SHT_RELA)
+ continue;
+
+ if (strstr(secstrings + s->sh_name, ".init"))
+ init_plts += count_plts(dstsec->sh_addr, rels, numrels);
+ else
+ core_plts += count_plts(dstsec->sh_addr, rels, numrels);
+ }
+
+ mod->arch.core_plt->sh_type = SHT_NOBITS;
+ mod->arch.core_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+ mod->arch.core_plt->sh_addralign = L1_CACHE_BYTES;
+ mod->arch.core_plt->sh_size = core_plts * sizeof(struct plt_entry);
+ mod->arch.core_plt_count = 0;
+
+ mod->arch.init_plt->sh_type = SHT_NOBITS;
+ mod->arch.init_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+ mod->arch.init_plt->sh_addralign = L1_CACHE_BYTES;
+ mod->arch.init_plt->sh_size = init_plts * sizeof(struct plt_entry);
+ mod->arch.init_plt_count = 0;
+ pr_debug("%s: core.plt=%lld, init.plt=%lld\n", __func__,
+ mod->arch.core_plt->sh_size, mod->arch.init_plt->sh_size);
+ return 0;
+}
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index f4bc779e62e8..14880d77ec6f 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -388,6 +388,13 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
case R_AARCH64_CALL26:
ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26,
AARCH64_INSN_IMM_26);
+
+ if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) &&
+ ovf == -ERANGE) {
+ val = get_module_plt(me, loc, val);
+ ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2,
+ 26, AARCH64_INSN_IMM_26);
+ }
break;
default:
diff --git a/arch/arm64/kernel/module.lds b/arch/arm64/kernel/module.lds
new file mode 100644
index 000000000000..3682fa107918
--- /dev/null
+++ b/arch/arm64/kernel/module.lds
@@ -0,0 +1,4 @@
+SECTIONS {
+ .core.plt : { BYTE(0) }
+ .init.plt : { BYTE(0) }
+}
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [RFC PATCH 06/10] arm64: use relative references in exception tables
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
@ 2015-12-28 11:20 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel
Instead of using absolute addresses for both the exception location and
the fixup, use offsets relative to the exception table entry values. This
is a prerequisite for KASLR, since absolute exception table entries are
subject to dynamic relocation, which is incompatible with the sorting of
the exception table that occurs at build time.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/assembler.h | 2 +-
arch/arm64/include/asm/futex.h | 4 +-
arch/arm64/include/asm/uaccess.h | 16 +--
arch/arm64/kernel/armv8_deprecated.c | 4 +-
arch/arm64/mm/extable.c | 102 +++++++++++++++++++-
scripts/sortextable.c | 2 +-
7 files changed, 116 insertions(+), 15 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 827e78f33944..54eeab140bca 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -7,6 +7,7 @@ config ARM64
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_SG_CHAIN
+ select ARCH_HAS_SORT_EXTABLE
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_USE_CMPXCHG_LOCKREF
select ARCH_SUPPORTS_ATOMIC_RMW
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 12eff928ef8b..8094d50f05bc 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -98,7 +98,7 @@
9999: x; \
.section __ex_table,"a"; \
.align 3; \
- .quad 9999b,l; \
+ .long (9999b - .), (l - .); \
.previous
/*
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
index 007a69fc4f40..35e73e255ad3 100644
--- a/arch/arm64/include/asm/futex.h
+++ b/arch/arm64/include/asm/futex.h
@@ -44,7 +44,7 @@
" .popsection\n" \
" .pushsection __ex_table,\"a\"\n" \
" .align 3\n" \
-" .quad 1b, 4b, 2b, 4b\n" \
+" .long (1b - .), (4b - .), (2b - .), (4b - .)\n" \
" .popsection\n" \
ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \
CONFIG_ARM64_PAN) \
@@ -135,7 +135,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
" .popsection\n"
" .pushsection __ex_table,\"a\"\n"
" .align 3\n"
-" .quad 1b, 4b, 2b, 4b\n"
+" .long (1b - .), (4b - .), (2b - .), (4b - .)\n"
" .popsection\n"
: "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp)
: "r" (oldval), "r" (newval), "Ir" (-EFAULT)
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index b2ede967fe7d..064efe4b0063 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -36,11 +36,11 @@
#define VERIFY_WRITE 1
/*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue. No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
+ * The exception table consists of pairs of relative offsets: the first
+ * is the relative offset to an instruction that is allowed to fault,
+ * and the second is the relative offset at which the program should
+ * continue. No registers are modified, so it is entirely up to the
+ * continuation code to figure out what to do.
*
* All the routines below use bits of fixup code that are out of line
* with the main instruction path. This means when everything is well,
@@ -50,7 +50,7 @@
struct exception_table_entry
{
- unsigned long insn, fixup;
+ int insn, fixup;
};
extern int fixup_exception(struct pt_regs *regs);
@@ -125,7 +125,7 @@ static inline void set_fs(mm_segment_t fs)
" .previous\n" \
" .section __ex_table,\"a\"\n" \
" .align 3\n" \
- " .quad 1b, 3b\n" \
+ " .long (1b - .), (3b - .)\n" \
" .previous" \
: "+r" (err), "=&r" (x) \
: "r" (addr), "i" (-EFAULT))
@@ -192,7 +192,7 @@ do { \
" .previous\n" \
" .section __ex_table,\"a\"\n" \
" .align 3\n" \
- " .quad 1b, 3b\n" \
+ " .long (1b - .), (3b - .)\n" \
" .previous" \
: "+r" (err) \
: "r" (x), "r" (addr), "i" (-EFAULT))
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 937f5e58a4d3..8f21b1363387 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -299,8 +299,8 @@ static void register_insn_emulation_sysctl(struct ctl_table *table)
" .popsection" \
" .pushsection __ex_table,\"a\"\n" \
" .align 3\n" \
- " .quad 0b, 4b\n" \
- " .quad 1b, 4b\n" \
+ " .long (0b - .), (4b - .)\n" \
+ " .long (1b - .), (4b - .)\n" \
" .popsection\n" \
ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \
CONFIG_ARM64_PAN) \
diff --git a/arch/arm64/mm/extable.c b/arch/arm64/mm/extable.c
index 79444279ba8c..d803e3e5d3da 100644
--- a/arch/arm64/mm/extable.c
+++ b/arch/arm64/mm/extable.c
@@ -3,15 +3,115 @@
*/
#include <linux/module.h>
+#include <linux/sort.h>
#include <linux/uaccess.h>
+static unsigned long ex_insn_addr(const struct exception_table_entry *x)
+{
+ return (unsigned long)&x->insn + x->insn;
+}
+
+static unsigned long ex_fixup_addr(const struct exception_table_entry *x)
+{
+ return (unsigned long)&x->fixup + x->fixup;
+}
+
int fixup_exception(struct pt_regs *regs)
{
const struct exception_table_entry *fixup;
fixup = search_exception_tables(instruction_pointer(regs));
if (fixup)
- regs->pc = fixup->fixup;
+ regs->pc = ex_fixup_addr(fixup);
return fixup != NULL;
}
+
+/*
+ * Search one exception table for an entry corresponding to the
+ * given instruction address, and return the address of the entry,
+ * or NULL if none is found.
+ * We use a binary search, and thus we assume that the table is
+ * already sorted.
+ */
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value)
+{
+ while (first <= last) {
+ const struct exception_table_entry *mid;
+ unsigned long addr;
+
+ mid = ((last - first) >> 1) + first;
+ addr = ex_insn_addr(mid);
+ if (addr < value)
+ first = mid + 1;
+ else if (addr > value)
+ last = mid - 1;
+ else
+ return mid;
+ }
+ return NULL;
+}
+
+static int cmp_ex(const void *a, const void *b)
+{
+ const struct exception_table_entry *x = a, *y = b;
+
+ return x->insn - y->insn;
+}
+
+/*
+ * The exception table needs to be sorted so that the binary
+ * search that we use to find entries in it works properly.
+ * This is used both for the kernel exception table and for
+ * the exception tables of modules that get loaded.
+ *
+ */
+void sort_extable(struct exception_table_entry *start,
+ struct exception_table_entry *finish)
+{
+ struct exception_table_entry *p;
+ int i;
+
+ /* Convert all entries to being relative to the start of the section */
+ i = 0;
+ for (p = start; p < finish; p++) {
+ p->insn += i;
+ i += 4;
+ p->fixup += i;
+ i += 4;
+ }
+
+ sort(start, finish - start, sizeof(struct exception_table_entry),
+ cmp_ex, NULL);
+
+ /* Denormalize all entries */
+ i = 0;
+ for (p = start; p < finish; p++) {
+ p->insn -= i;
+ i += 4;
+ p->fixup -= i;
+ i += 4;
+ }
+}
+
+#ifdef CONFIG_MODULES
+/*
+ * If the exception table is sorted, any referring to the module init
+ * will be at the beginning or the end.
+ */
+void trim_init_extable(struct module *m)
+{
+ /* trim the beginning */
+ while (m->num_exentries && within_module_init(m->extable[0].insn, m)) {
+ m->extable++;
+ m->num_exentries--;
+ }
+ /* trim the end */
+ while (m->num_exentries &&
+ within_module_init(m->extable[m->num_exentries-1].insn, m))
+ m->num_exentries--;
+}
+#endif /* CONFIG_MODULES */
diff --git a/scripts/sortextable.c b/scripts/sortextable.c
index c2423d913b46..af247c70fb66 100644
--- a/scripts/sortextable.c
+++ b/scripts/sortextable.c
@@ -282,12 +282,12 @@ do_file(char const *const fname)
case EM_386:
case EM_X86_64:
case EM_S390:
+ case EM_AARCH64:
custom_sort = sort_relative_table;
break;
case EM_ARCOMPACT:
case EM_ARCV2:
case EM_ARM:
- case EM_AARCH64:
case EM_MICROBLAZE:
case EM_MIPS:
case EM_XTENSA:
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [kernel-hardening] [RFC PATCH 06/10] arm64: use relative references in exception tables
@ 2015-12-28 11:20 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, lkml
Cc: stuart.yoder, bhupesh.sharma, Ard Biesheuvel
Instead of using absolute addresses for both the exception location and
the fixup, use offsets relative to the exception table entry values. This
is a prerequisite for KASLR, since absolute exception table entries are
subject to dynamic relocation, which is incompatible with the sorting of
the exception table that occurs at build time.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/assembler.h | 2 +-
arch/arm64/include/asm/futex.h | 4 +-
arch/arm64/include/asm/uaccess.h | 16 +--
arch/arm64/kernel/armv8_deprecated.c | 4 +-
arch/arm64/mm/extable.c | 102 +++++++++++++++++++-
scripts/sortextable.c | 2 +-
7 files changed, 116 insertions(+), 15 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 827e78f33944..54eeab140bca 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -7,6 +7,7 @@ config ARM64
select ARCH_HAS_ELF_RANDOMIZE
select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_SG_CHAIN
+ select ARCH_HAS_SORT_EXTABLE
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_USE_CMPXCHG_LOCKREF
select ARCH_SUPPORTS_ATOMIC_RMW
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 12eff928ef8b..8094d50f05bc 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -98,7 +98,7 @@
9999: x; \
.section __ex_table,"a"; \
.align 3; \
- .quad 9999b,l; \
+ .long (9999b - .), (l - .); \
.previous
/*
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
index 007a69fc4f40..35e73e255ad3 100644
--- a/arch/arm64/include/asm/futex.h
+++ b/arch/arm64/include/asm/futex.h
@@ -44,7 +44,7 @@
" .popsection\n" \
" .pushsection __ex_table,\"a\"\n" \
" .align 3\n" \
-" .quad 1b, 4b, 2b, 4b\n" \
+" .long (1b - .), (4b - .), (2b - .), (4b - .)\n" \
" .popsection\n" \
ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \
CONFIG_ARM64_PAN) \
@@ -135,7 +135,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
" .popsection\n"
" .pushsection __ex_table,\"a\"\n"
" .align 3\n"
-" .quad 1b, 4b, 2b, 4b\n"
+" .long (1b - .), (4b - .), (2b - .), (4b - .)\n"
" .popsection\n"
: "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp)
: "r" (oldval), "r" (newval), "Ir" (-EFAULT)
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index b2ede967fe7d..064efe4b0063 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -36,11 +36,11 @@
#define VERIFY_WRITE 1
/*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue. No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
+ * The exception table consists of pairs of relative offsets: the first
+ * is the relative offset to an instruction that is allowed to fault,
+ * and the second is the relative offset at which the program should
+ * continue. No registers are modified, so it is entirely up to the
+ * continuation code to figure out what to do.
*
* All the routines below use bits of fixup code that are out of line
* with the main instruction path. This means when everything is well,
@@ -50,7 +50,7 @@
struct exception_table_entry
{
- unsigned long insn, fixup;
+ int insn, fixup;
};
extern int fixup_exception(struct pt_regs *regs);
@@ -125,7 +125,7 @@ static inline void set_fs(mm_segment_t fs)
" .previous\n" \
" .section __ex_table,\"a\"\n" \
" .align 3\n" \
- " .quad 1b, 3b\n" \
+ " .long (1b - .), (3b - .)\n" \
" .previous" \
: "+r" (err), "=&r" (x) \
: "r" (addr), "i" (-EFAULT))
@@ -192,7 +192,7 @@ do { \
" .previous\n" \
" .section __ex_table,\"a\"\n" \
" .align 3\n" \
- " .quad 1b, 3b\n" \
+ " .long (1b - .), (3b - .)\n" \
" .previous" \
: "+r" (err) \
: "r" (x), "r" (addr), "i" (-EFAULT))
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 937f5e58a4d3..8f21b1363387 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -299,8 +299,8 @@ static void register_insn_emulation_sysctl(struct ctl_table *table)
" .popsection" \
" .pushsection __ex_table,\"a\"\n" \
" .align 3\n" \
- " .quad 0b, 4b\n" \
- " .quad 1b, 4b\n" \
+ " .long (0b - .), (4b - .)\n" \
+ " .long (1b - .), (4b - .)\n" \
" .popsection\n" \
ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \
CONFIG_ARM64_PAN) \
diff --git a/arch/arm64/mm/extable.c b/arch/arm64/mm/extable.c
index 79444279ba8c..d803e3e5d3da 100644
--- a/arch/arm64/mm/extable.c
+++ b/arch/arm64/mm/extable.c
@@ -3,15 +3,115 @@
*/
#include <linux/module.h>
+#include <linux/sort.h>
#include <linux/uaccess.h>
+static unsigned long ex_insn_addr(const struct exception_table_entry *x)
+{
+ return (unsigned long)&x->insn + x->insn;
+}
+
+static unsigned long ex_fixup_addr(const struct exception_table_entry *x)
+{
+ return (unsigned long)&x->fixup + x->fixup;
+}
+
int fixup_exception(struct pt_regs *regs)
{
const struct exception_table_entry *fixup;
fixup = search_exception_tables(instruction_pointer(regs));
if (fixup)
- regs->pc = fixup->fixup;
+ regs->pc = ex_fixup_addr(fixup);
return fixup != NULL;
}
+
+/*
+ * Search one exception table for an entry corresponding to the
+ * given instruction address, and return the address of the entry,
+ * or NULL if none is found.
+ * We use a binary search, and thus we assume that the table is
+ * already sorted.
+ */
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value)
+{
+ while (first <= last) {
+ const struct exception_table_entry *mid;
+ unsigned long addr;
+
+ mid = ((last - first) >> 1) + first;
+ addr = ex_insn_addr(mid);
+ if (addr < value)
+ first = mid + 1;
+ else if (addr > value)
+ last = mid - 1;
+ else
+ return mid;
+ }
+ return NULL;
+}
+
+static int cmp_ex(const void *a, const void *b)
+{
+ const struct exception_table_entry *x = a, *y = b;
+
+ return x->insn - y->insn;
+}
+
+/*
+ * The exception table needs to be sorted so that the binary
+ * search that we use to find entries in it works properly.
+ * This is used both for the kernel exception table and for
+ * the exception tables of modules that get loaded.
+ *
+ */
+void sort_extable(struct exception_table_entry *start,
+ struct exception_table_entry *finish)
+{
+ struct exception_table_entry *p;
+ int i;
+
+ /* Convert all entries to being relative to the start of the section */
+ i = 0;
+ for (p = start; p < finish; p++) {
+ p->insn += i;
+ i += 4;
+ p->fixup += i;
+ i += 4;
+ }
+
+ sort(start, finish - start, sizeof(struct exception_table_entry),
+ cmp_ex, NULL);
+
+ /* Denormalize all entries */
+ i = 0;
+ for (p = start; p < finish; p++) {
+ p->insn -= i;
+ i += 4;
+ p->fixup -= i;
+ i += 4;
+ }
+}
+
+#ifdef CONFIG_MODULES
+/*
+ * If the exception table is sorted, any referring to the module init
+ * will be at the beginning or the end.
+ */
+void trim_init_extable(struct module *m)
+{
+ /* trim the beginning */
+ while (m->num_exentries && within_module_init(m->extable[0].insn, m)) {
+ m->extable++;
+ m->num_exentries--;
+ }
+ /* trim the end */
+ while (m->num_exentries &&
+ within_module_init(m->extable[m->num_exentries-1].insn, m))
+ m->num_exentries--;
+}
+#endif /* CONFIG_MODULES */
diff --git a/scripts/sortextable.c b/scripts/sortextable.c
index c2423d913b46..af247c70fb66 100644
--- a/scripts/sortextable.c
+++ b/scripts/sortextable.c
@@ -282,12 +282,12 @@ do_file(char const *const fname)
case EM_386:
case EM_X86_64:
case EM_S390:
+ case EM_AARCH64:
custom_sort = sort_relative_table;
break;
case EM_ARCOMPACT:
case EM_ARCV2:
case EM_ARM:
- case EM_AARCH64:
case EM_MICROBLAZE:
case EM_MIPS:
case EM_XTENSA:
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [RFC PATCH 07/10] arm64: use assembly time constants for Image header fields
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
@ 2015-12-28 11:20 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel
Unfortunately, using the linker to emit build time constants into
the Image header will no longer work once we switch to the use of
PIE executables. The reason is that such constants are emitted into
the binary using R_AARCH64_ABS64 relocations, which we will resolve
at runtime, not at build time, and the places targeted by those
relocations will contain zeroes before that.
So move back to assembly time constants. These will be emitted in the
endianness of the target binary, so we will need a post-link fixup
step to byte swap the header fields.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/boot/Makefile | 1 +
arch/arm64/kernel/head.S | 32 ++++++++++------
arch/arm64/kernel/image.h | 40 --------------------
arch/arm64/kernel/vmlinux.lds.S | 2 -
scripts/arm64fixhdr.pl | 25 ++++++++++++
5 files changed, 46 insertions(+), 54 deletions(-)
diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile
index abcbba2f01ba..b2da54b4b796 100644
--- a/arch/arm64/boot/Makefile
+++ b/arch/arm64/boot/Makefile
@@ -18,6 +18,7 @@ targets := Image Image.gz
$(obj)/Image: vmlinux FORCE
$(call if_changed,objcopy)
+ @$(srctree)/scripts/arm64fixhdr.pl $@
$(obj)/Image.bz2: $(obj)/Image FORCE
$(call if_changed,bzip2)
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 6434c844a0e4..a03ffffd84cb 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -51,6 +51,17 @@
#define KERNEL_START _text
#define KERNEL_END _end
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define __HEAD_FLAG_BE 1
+#else
+#define __HEAD_FLAG_BE 0
+#endif
+
+#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
+
+#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) | \
+ (__HEAD_FLAG_PAGE_SIZE << 1))
+
/*
* Kernel startup entry point.
* ---------------------------
@@ -67,12 +78,12 @@
* in the entry routines.
*/
__HEAD
+_head:
/*
* DO NOT MODIFY. Image header expected by Linux boot-loaders.
*/
#ifdef CONFIG_EFI
-efi_head:
/*
* This add instruction has no meaningful effect except that
* its opcode forms the magic "MZ" signature required by UEFI.
@@ -83,25 +94,22 @@ efi_head:
b stext // branch to kernel start, magic
.long 0 // reserved
#endif
- .quad _kernel_offset_le // Image load offset from start of RAM, little-endian
- .quad _kernel_size_le // Effective size of kernel image, little-endian
- .quad _kernel_flags_le // Informative flags, little-endian
+ .quad TEXT_OFFSET // Image load offset from start of RAM, little-endian
+ .quad _end - _head // Effective size of kernel image, little-endian
+ .quad __HEAD_FLAGS // Informative flags, little-endian
.quad 0 // reserved
.quad 0 // reserved
.quad 0 // reserved
- .byte 0x41 // Magic number, "ARM\x64"
- .byte 0x52
- .byte 0x4d
- .byte 0x64
+ .long 0x644d5241 // Magic number, "ARM\x64"
#ifdef CONFIG_EFI
- .long pe_header - efi_head // Offset to the PE header.
+ .long pe_header - _head // Offset to the PE header.
#else
.word 0 // reserved
#endif
#ifdef CONFIG_EFI
.globl __efistub_stext_offset
- .set __efistub_stext_offset, stext - efi_head
+ .set __efistub_stext_offset, stext - _head
.align 3
pe_header:
.ascii "PE"
@@ -124,7 +132,7 @@ optional_header:
.long _end - stext // SizeOfCode
.long 0 // SizeOfInitializedData
.long 0 // SizeOfUninitializedData
- .long __efistub_entry - efi_head // AddressOfEntryPoint
+ .long __efistub_entry - _head // AddressOfEntryPoint
.long __efistub_stext_offset // BaseOfCode
extra_header_fields:
@@ -139,7 +147,7 @@ extra_header_fields:
.short 0 // MinorSubsystemVersion
.long 0 // Win32VersionValue
- .long _end - efi_head // SizeOfImage
+ .long _end - _head // SizeOfImage
// Everything before the kernel image is considered part of the header
.long __efistub_stext_offset // SizeOfHeaders
diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h
index bc2abb8b1599..5f34770ba924 100644
--- a/arch/arm64/kernel/image.h
+++ b/arch/arm64/kernel/image.h
@@ -22,46 +22,6 @@
#error This file should only be included in vmlinux.lds.S
#endif
-/*
- * There aren't any ELF relocations we can use to endian-swap values known only
- *@link time (e.g. the subtraction of two symbol addresses), so we must get
- * the linker to endian-swap certain values before emitting them.
- */
-#ifdef CONFIG_CPU_BIG_ENDIAN
-#define DATA_LE64(data) \
- ((((data) & 0x00000000000000ff) << 56) | \
- (((data) & 0x000000000000ff00) << 40) | \
- (((data) & 0x0000000000ff0000) << 24) | \
- (((data) & 0x00000000ff000000) << 8) | \
- (((data) & 0x000000ff00000000) >> 8) | \
- (((data) & 0x0000ff0000000000) >> 24) | \
- (((data) & 0x00ff000000000000) >> 40) | \
- (((data) & 0xff00000000000000) >> 56))
-#else
-#define DATA_LE64(data) ((data) & 0xffffffffffffffff)
-#endif
-
-#ifdef CONFIG_CPU_BIG_ENDIAN
-#define __HEAD_FLAG_BE 1
-#else
-#define __HEAD_FLAG_BE 0
-#endif
-
-#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
-
-#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) | \
- (__HEAD_FLAG_PAGE_SIZE << 1))
-
-/*
- * These will output as part of the Image header, which should be little-endian
- * regardless of the endianness of the kernel. While constant values could be
- * endian swapped in head.S, all are done here for consistency.
- */
-#define HEAD_SYMBOLS \
- _kernel_size_le = DATA_LE64(_end - _text); \
- _kernel_offset_le = DATA_LE64(TEXT_OFFSET); \
- _kernel_flags_le = DATA_LE64(__HEAD_FLAGS);
-
#ifdef CONFIG_EFI
/*
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 363c2f529951..69dfa376e843 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -171,8 +171,6 @@ SECTIONS
_end = .;
STABS_DEBUG
-
- HEAD_SYMBOLS
}
/*
diff --git a/scripts/arm64fixhdr.pl b/scripts/arm64fixhdr.pl
new file mode 100755
index 000000000000..09895f412e5d
--- /dev/null
+++ b/scripts/arm64fixhdr.pl
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+
+use strict;
+
+undef $/;
+
+my $image = "arch/arm64/boot/Image";
+$image = $ARGV[0] if ($ARGV[0]);
+
+open(my $INFILE, "<", $image) or die("Failed to open $image for reading\n");
+my ($c,$to,$is,$fl,$r2,$r3,$r4,$magic,$pe) = unpack("Q<7L<2", <$INFILE>);
+close($INFILE);
+
+exit 0 if ($magic == 0x644d5241);
+die sprintf("ERROR: incorrect magic 0x%x\n",$magic) if ($magic != 0x41524d64);
+
+open(my $OUTFILE, "+<", $image) or die("Failed to open $image for writing\n");
+print $OUTFILE pack("Q<Q>6L>2",$c,$to,$is,$fl,$r2,$r3,$r4,$magic,$pe);
+close($OUTFILE);
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [kernel-hardening] [RFC PATCH 07/10] arm64: use assembly time constants for Image header fields
@ 2015-12-28 11:20 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, lkml
Cc: stuart.yoder, bhupesh.sharma, Ard Biesheuvel
Unfortunately, using the linker to emit build time constants into
the Image header will no longer work once we switch to the use of
PIE executables. The reason is that such constants are emitted into
the binary using R_AARCH64_ABS64 relocations, which we will resolve
at runtime, not at build time, and the places targeted by those
relocations will contain zeroes before that.
So move back to assembly time constants. These will be emitted in the
endianness of the target binary, so we will need a post-link fixup
step to byte swap the header fields.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/boot/Makefile | 1 +
arch/arm64/kernel/head.S | 32 ++++++++++------
arch/arm64/kernel/image.h | 40 --------------------
arch/arm64/kernel/vmlinux.lds.S | 2 -
scripts/arm64fixhdr.pl | 25 ++++++++++++
5 files changed, 46 insertions(+), 54 deletions(-)
diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile
index abcbba2f01ba..b2da54b4b796 100644
--- a/arch/arm64/boot/Makefile
+++ b/arch/arm64/boot/Makefile
@@ -18,6 +18,7 @@ targets := Image Image.gz
$(obj)/Image: vmlinux FORCE
$(call if_changed,objcopy)
+ @$(srctree)/scripts/arm64fixhdr.pl $@
$(obj)/Image.bz2: $(obj)/Image FORCE
$(call if_changed,bzip2)
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 6434c844a0e4..a03ffffd84cb 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -51,6 +51,17 @@
#define KERNEL_START _text
#define KERNEL_END _end
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define __HEAD_FLAG_BE 1
+#else
+#define __HEAD_FLAG_BE 0
+#endif
+
+#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
+
+#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) | \
+ (__HEAD_FLAG_PAGE_SIZE << 1))
+
/*
* Kernel startup entry point.
* ---------------------------
@@ -67,12 +78,12 @@
* in the entry routines.
*/
__HEAD
+_head:
/*
* DO NOT MODIFY. Image header expected by Linux boot-loaders.
*/
#ifdef CONFIG_EFI
-efi_head:
/*
* This add instruction has no meaningful effect except that
* its opcode forms the magic "MZ" signature required by UEFI.
@@ -83,25 +94,22 @@ efi_head:
b stext // branch to kernel start, magic
.long 0 // reserved
#endif
- .quad _kernel_offset_le // Image load offset from start of RAM, little-endian
- .quad _kernel_size_le // Effective size of kernel image, little-endian
- .quad _kernel_flags_le // Informative flags, little-endian
+ .quad TEXT_OFFSET // Image load offset from start of RAM, little-endian
+ .quad _end - _head // Effective size of kernel image, little-endian
+ .quad __HEAD_FLAGS // Informative flags, little-endian
.quad 0 // reserved
.quad 0 // reserved
.quad 0 // reserved
- .byte 0x41 // Magic number, "ARM\x64"
- .byte 0x52
- .byte 0x4d
- .byte 0x64
+ .long 0x644d5241 // Magic number, "ARM\x64"
#ifdef CONFIG_EFI
- .long pe_header - efi_head // Offset to the PE header.
+ .long pe_header - _head // Offset to the PE header.
#else
.word 0 // reserved
#endif
#ifdef CONFIG_EFI
.globl __efistub_stext_offset
- .set __efistub_stext_offset, stext - efi_head
+ .set __efistub_stext_offset, stext - _head
.align 3
pe_header:
.ascii "PE"
@@ -124,7 +132,7 @@ optional_header:
.long _end - stext // SizeOfCode
.long 0 // SizeOfInitializedData
.long 0 // SizeOfUninitializedData
- .long __efistub_entry - efi_head // AddressOfEntryPoint
+ .long __efistub_entry - _head // AddressOfEntryPoint
.long __efistub_stext_offset // BaseOfCode
extra_header_fields:
@@ -139,7 +147,7 @@ extra_header_fields:
.short 0 // MinorSubsystemVersion
.long 0 // Win32VersionValue
- .long _end - efi_head // SizeOfImage
+ .long _end - _head // SizeOfImage
// Everything before the kernel image is considered part of the header
.long __efistub_stext_offset // SizeOfHeaders
diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h
index bc2abb8b1599..5f34770ba924 100644
--- a/arch/arm64/kernel/image.h
+++ b/arch/arm64/kernel/image.h
@@ -22,46 +22,6 @@
#error This file should only be included in vmlinux.lds.S
#endif
-/*
- * There aren't any ELF relocations we can use to endian-swap values known only
- * at link time (e.g. the subtraction of two symbol addresses), so we must get
- * the linker to endian-swap certain values before emitting them.
- */
-#ifdef CONFIG_CPU_BIG_ENDIAN
-#define DATA_LE64(data) \
- ((((data) & 0x00000000000000ff) << 56) | \
- (((data) & 0x000000000000ff00) << 40) | \
- (((data) & 0x0000000000ff0000) << 24) | \
- (((data) & 0x00000000ff000000) << 8) | \
- (((data) & 0x000000ff00000000) >> 8) | \
- (((data) & 0x0000ff0000000000) >> 24) | \
- (((data) & 0x00ff000000000000) >> 40) | \
- (((data) & 0xff00000000000000) >> 56))
-#else
-#define DATA_LE64(data) ((data) & 0xffffffffffffffff)
-#endif
-
-#ifdef CONFIG_CPU_BIG_ENDIAN
-#define __HEAD_FLAG_BE 1
-#else
-#define __HEAD_FLAG_BE 0
-#endif
-
-#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
-
-#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) | \
- (__HEAD_FLAG_PAGE_SIZE << 1))
-
-/*
- * These will output as part of the Image header, which should be little-endian
- * regardless of the endianness of the kernel. While constant values could be
- * endian swapped in head.S, all are done here for consistency.
- */
-#define HEAD_SYMBOLS \
- _kernel_size_le = DATA_LE64(_end - _text); \
- _kernel_offset_le = DATA_LE64(TEXT_OFFSET); \
- _kernel_flags_le = DATA_LE64(__HEAD_FLAGS);
-
#ifdef CONFIG_EFI
/*
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 363c2f529951..69dfa376e843 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -171,8 +171,6 @@ SECTIONS
_end = .;
STABS_DEBUG
-
- HEAD_SYMBOLS
}
/*
diff --git a/scripts/arm64fixhdr.pl b/scripts/arm64fixhdr.pl
new file mode 100755
index 000000000000..09895f412e5d
--- /dev/null
+++ b/scripts/arm64fixhdr.pl
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+
+use strict;
+
+undef $/;
+
+my $image = "arch/arm64/boot/Image";
+$image = $ARGV[0] if ($ARGV[0]);
+
+open(my $INFILE, "<", $image) or die("Failed to open $image for reading\n");
+my ($c,$to,$is,$fl,$r2,$r3,$r4,$magic,$pe) = unpack("Q<7L<2", <$INFILE>);
+close($INFILE);
+
+exit 0 if ($magic == 0x644d5241);
+die sprintf("ERROR: incorrect magic 0x%x\n",$magic) if ($magic != 0x41524d64);
+
+open(my $OUTFILE, "+<", $image) or die("Failed to open $image for writing\n");
+print $OUTFILE pack("Q<Q>6L>2",$c,$to,$is,$fl,$r2,$r3,$r4,$magic,$pe);
+close($OUTFILE);
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [RFC PATCH 08/10] arm64: avoid dynamic relocations in early boot code
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
@ 2015-12-28 11:20 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel
Before implementing KASLR for arm64 by building a self-relocating PIE
executable, we have to ensure that values we use before the relocation
routine is executed are not subject to dynamic relocation themselves.
This applies not only to virtual addresses, but also to values that are
supplied by the linker at build time and relocated using R_AARCH64_ABS64
relocations.
So instead, use assemble time constants, or force the use of static
relocations by folding the constants into the instructions.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/kernel/efi-entry.S | 2 +-
arch/arm64/kernel/head.S | 12 +++++++++---
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
index a773db92908b..f82036e02485 100644
--- a/arch/arm64/kernel/efi-entry.S
+++ b/arch/arm64/kernel/efi-entry.S
@@ -61,7 +61,7 @@ ENTRY(entry)
*/
mov x20, x0 // DTB address
ldr x0, [sp, #16] // relocated _text address
- ldr x21, =stext_offset
+ movz x21, #:abs_g0:stext_offset
add x21, x0, x21
/*
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index a03ffffd84cb..4f086e247eea 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -227,11 +227,13 @@ ENTRY(stext)
* On return, the CPU will be ready for the MMU to be turned on and
* the TCR will have been set.
*/
- ldr x27, =__mmap_switched // address to jump to after
+ ldr x27, 0f // address to jump to after
// MMU has been enabled
adr_l lr, __enable_mmu // return (PIC) address
b __cpu_setup // initialise processor
ENDPROC(stext)
+ .align 3
+0: .quad __mmap_switched - (_head - TEXT_OFFSET) + KIMAGE_VADDR
/*
* Preserve the arguments passed by the bootloader in x0 .. x3
@@ -341,7 +343,7 @@ __create_page_tables:
cmp x0, x6
b.lo 1b
- ldr x7, =SWAPPER_MM_MMUFLAGS
+ mov x7, SWAPPER_MM_MMUFLAGS
/*
* Create the identity mapping.
@@ -399,7 +401,8 @@ __create_page_tables:
mov x0, x26 // swapper_pg_dir
ldr x5, =KIMAGE_VADDR
create_pgd_entry x0, x5, x3, x6
- ldr x6, =KERNEL_END // __va(KERNEL_END)
+ ldr w6, kernel_img_size
+ add x6, x6, x5
mov x3, x24 // phys offset
create_block_map x0, x7, x3, x5, x6
@@ -416,6 +419,9 @@ __create_page_tables:
mov lr, x27
ret
ENDPROC(__create_page_tables)
+
+kernel_img_size:
+ .long _end - (_head - TEXT_OFFSET)
.ltorg
/*
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [kernel-hardening] [RFC PATCH 08/10] arm64: avoid dynamic relocations in early boot code
@ 2015-12-28 11:20 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, lkml
Cc: stuart.yoder, bhupesh.sharma, Ard Biesheuvel
Before implementing KASLR for arm64 by building a self-relocating PIE
executable, we have to ensure that values we use before the relocation
routine is executed are not subject to dynamic relocation themselves.
This applies not only to virtual addresses, but also to values that are
supplied by the linker at build time and relocated using R_AARCH64_ABS64
relocations.
So instead, use assemble time constants, or force the use of static
relocations by folding the constants into the instructions.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/kernel/efi-entry.S | 2 +-
arch/arm64/kernel/head.S | 12 +++++++++---
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
index a773db92908b..f82036e02485 100644
--- a/arch/arm64/kernel/efi-entry.S
+++ b/arch/arm64/kernel/efi-entry.S
@@ -61,7 +61,7 @@ ENTRY(entry)
*/
mov x20, x0 // DTB address
ldr x0, [sp, #16] // relocated _text address
- ldr x21, =stext_offset
+ movz x21, #:abs_g0:stext_offset
add x21, x0, x21
/*
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index a03ffffd84cb..4f086e247eea 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -227,11 +227,13 @@ ENTRY(stext)
* On return, the CPU will be ready for the MMU to be turned on and
* the TCR will have been set.
*/
- ldr x27, =__mmap_switched // address to jump to after
+ ldr x27, 0f // address to jump to after
// MMU has been enabled
adr_l lr, __enable_mmu // return (PIC) address
b __cpu_setup // initialise processor
ENDPROC(stext)
+ .align 3
+0: .quad __mmap_switched - (_head - TEXT_OFFSET) + KIMAGE_VADDR
/*
* Preserve the arguments passed by the bootloader in x0 .. x3
@@ -341,7 +343,7 @@ __create_page_tables:
cmp x0, x6
b.lo 1b
- ldr x7, =SWAPPER_MM_MMUFLAGS
+ mov x7, SWAPPER_MM_MMUFLAGS
/*
* Create the identity mapping.
@@ -399,7 +401,8 @@ __create_page_tables:
mov x0, x26 // swapper_pg_dir
ldr x5, =KIMAGE_VADDR
create_pgd_entry x0, x5, x3, x6
- ldr x6, =KERNEL_END // __va(KERNEL_END)
+ ldr w6, kernel_img_size
+ add x6, x6, x5
mov x3, x24 // phys offset
create_block_map x0, x7, x3, x5, x6
@@ -416,6 +419,9 @@ __create_page_tables:
mov lr, x27
ret
ENDPROC(__create_page_tables)
+
+kernel_img_size:
+ .long _end - (_head - TEXT_OFFSET)
.ltorg
/*
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [RFC PATCH 09/10] arm64: add support for relocatable kernel
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
@ 2015-12-28 11:20 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel
This adds support for runtime relocation of the kernel Image, by
building it as a PIE (ET_DYN) executable and applying the dynamic
relocations in the early boot code.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
Documentation/arm64/booting.txt | 3 +-
arch/arm64/Kconfig | 13 ++++
arch/arm64/Makefile | 6 +-
arch/arm64/include/asm/memory.h | 10 ++-
arch/arm64/kernel/arm64ksyms.c | 5 ++
arch/arm64/kernel/head.S | 76 +++++++++++++++++++-
arch/arm64/kernel/setup.c | 22 +++---
arch/arm64/kernel/vmlinux.lds.S | 9 +++
scripts/sortextable.c | 4 +-
9 files changed, 130 insertions(+), 18 deletions(-)
diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
index 701d39d3171a..dcd8eee72984 100644
--- a/Documentation/arm64/booting.txt
+++ b/Documentation/arm64/booting.txt
@@ -109,7 +109,8 @@ Header notes:
1 - 4K
2 - 16K
3 - 64K
- Bits 3-63: Reserved.
+ Bit 3: Relocatable kernel.
+ Bits 4-63: Reserved.
- When image_size is zero, a bootloader should attempt to keep as much
memory as possible free for use by the kernel immediately after the
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 54eeab140bca..f458fb9e0dce 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -363,6 +363,7 @@ config ARM64_ERRATUM_843419
bool "Cortex-A53: 843419: A load or store might access an incorrect address"
depends on MODULES
default y
+ select ARM64_MODULE_CMODEL_LARGE
help
This option builds kernel modules using the large memory model in
order to avoid the use of the ADRP instruction, which can cause
@@ -709,6 +710,18 @@ config ARM64_MODULE_PLTS
bool
select HAVE_MOD_ARCH_SPECIFIC
+config ARM64_MODULE_CMODEL_LARGE
+ bool
+
+config ARM64_RELOCATABLE_KERNEL
+ bool "Kernel address space layout randomization (KASLR)"
+ select ARM64_MODULE_PLTS
+ select ARM64_MODULE_CMODEL_LARGE
+ help
+ This feature randomizes the virtual address of the kernel image, to
+ harden against exploits that rely on knowledge about the absolute
+ addresses of certain kernel data structures.
+
endmenu
menu "Boot options"
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index d4654830e536..75dc477d45f5 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -15,6 +15,10 @@ CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
GZFLAGS :=-9
+ifneq ($(CONFIG_ARM64_RELOCATABLE_KERNEL),)
+LDFLAGS_vmlinux += -pie
+endif
+
KBUILD_DEFCONFIG := defconfig
# Check for binutils support for specific extensions
@@ -41,7 +45,7 @@ endif
CHECKFLAGS += -D__aarch64__
-ifeq ($(CONFIG_ARM64_ERRATUM_843419), y)
+ifeq ($(CONFIG_ARM64_MODULE_CMODEL_LARGE), y)
KBUILD_CFLAGS_MODULE += -mcmodel=large
endif
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 1dcbf142d36c..e435423f9731 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -88,10 +88,10 @@
#define __virt_to_phys(x) ({ \
phys_addr_t __x = (phys_addr_t)(x); \
__x >= PAGE_OFFSET ? (__x - PAGE_OFFSET + PHYS_OFFSET) : \
- (__x - KIMAGE_VADDR + PHYS_OFFSET); })
+ (__x - kimage_vaddr + PHYS_OFFSET); })
#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
-#define __phys_to_kimg(x) ((unsigned long)((x) - PHYS_OFFSET + KIMAGE_VADDR))
+#define __phys_to_kimg(x) ((unsigned long)((x) - PHYS_OFFSET + kimage_vaddr))
/*
* Convert a page to/from a physical address
@@ -121,6 +121,12 @@ extern phys_addr_t memstart_addr;
/* PHYS_OFFSET - the physical address of the start of memory. */
#define PHYS_OFFSET ({ memstart_addr; })
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+extern u64 kimage_vaddr;
+#else
+#define kimage_vaddr KIMAGE_VADDR
+#endif
+
/*
* The maximum physical address that the linear direct mapping
* of system RAM can cover. (PAGE_OFFSET can be interpreted as
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
index 3b6d8cc9dfe0..4f7b7f44e2b5 100644
--- a/arch/arm64/kernel/arm64ksyms.c
+++ b/arch/arm64/kernel/arm64ksyms.c
@@ -41,6 +41,11 @@ EXPORT_SYMBOL(__copy_in_user);
/* physical memory */
EXPORT_SYMBOL(memstart_addr);
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+ /* runtime kernel virtual base address */
+EXPORT_SYMBOL(kimage_vaddr);
+#endif
+
/* string / mem functions */
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strrchr);
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 4f086e247eea..5ec779412436 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -59,8 +59,15 @@
#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+#define __HEAD_FLAG_RELOC 1
+#else
+#define __HEAD_FLAG_RELOC 0
+#endif
+
#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) | \
- (__HEAD_FLAG_PAGE_SIZE << 1))
+ (__HEAD_FLAG_PAGE_SIZE << 1) | \
+ (__HEAD_FLAG_RELOC << 3))
/*
* Kernel startup entry point.
@@ -229,6 +236,9 @@ ENTRY(stext)
*/
ldr x27, 0f // address to jump to after
// MMU has been enabled
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+ add x27, x27, x23 // add KASLR displacement
+#endif
adr_l lr, __enable_mmu // return (PIC) address
b __cpu_setup // initialise processor
ENDPROC(stext)
@@ -241,6 +251,16 @@ ENDPROC(stext)
preserve_boot_args:
mov x21, x0 // x21=FDT
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+ /*
+ * Mask off the bits of the random value supplied in x1 so it can serve
+ * as a KASLR displacement value which will move the kernel image to a
+ * random offset in the lower half of the VMALLOC area.
+ */
+ mov x23, #(1 << (VA_BITS - 2)) - 1
+ and x23, x23, x1, lsl #SWAPPER_BLOCK_SHIFT
+#endif
+
adr_l x0, boot_args // record the contents of
stp x21, x1, [x0] // x0 .. x3 at kernel entry
stp x2, x3, [x0, #16]
@@ -400,6 +420,9 @@ __create_page_tables:
*/
mov x0, x26 // swapper_pg_dir
ldr x5, =KIMAGE_VADDR
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+ add x5, x5, x23 // add KASLR displacement
+#endif
create_pgd_entry x0, x5, x3, x6
ldr w6, kernel_img_size
add x6, x6, x5
@@ -437,6 +460,51 @@ __mmap_switched:
str xzr, [x6], #8 // Clear BSS
b 1b
2:
+
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+
+#define R_AARCH64_RELATIVE 0x403
+#define R_AARCH64_ABS64 0x101
+
+ /*
+ * Iterate over each entry in the relocation table, and apply the
+ * relocations in place.
+ */
+ adr_l x8, __dynsym_start // start of symbol table
+ adr_l x9, __reloc_start // start of reloc table
+ adr_l x10, __reloc_end // end of reloc table
+
+0: cmp x9, x10
+ b.hs 2f
+ ldp x11, x12, [x9], #24
+ cmp x12, #R_AARCH64_RELATIVE
+ b.ne 1f
+ ldr x12, [x9, #-8]
+ add x12, x12, x23 // relocate
+ str x12, [x11, x23]
+ b 0b
+
+1: ubfx x13, x12, #0, #32
+ cmp x13, #R_AARCH64_ABS64
+ b.ne 0b
+ lsr x13, x12, #32 // symbol index
+ ldr x12, [x9, #-8]
+ add x13, x13, x13, lsl #1 // x 3
+ add x13, x8, x13, lsl #3 // x 8
+ ldrsh w14, [x13, #6] // Elf64_Sym::st_shndx
+ ldr x15, [x13, #8] // Elf64_Sym::st_value
+ cmp w14, #-0xf // SHN_ABS (0xfff1) ?
+ add x14, x15, x23 // relocate
+ csel x15, x14, x15, ne
+ add x15, x12, x15
+ str x15, [x11, x23]
+ b 0b
+
+2: ldr x8, =vectors // reload VBAR_EL1 with
+ msr vbar_el1, x8 // relocated address
+ isb
+#endif
+
adr_l sp, initial_sp, x4
str_l x21, __fdt_pointer, x5 // Save FDT pointer
str_l x24, memstart_addr, x6 // Save PHYS_OFFSET
@@ -452,6 +520,12 @@ ENDPROC(__mmap_switched)
* hotplug and needs to have the same protections as the text region
*/
.section ".text","ax"
+
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+ENTRY(kimage_vaddr)
+ .quad _text - TEXT_OFFSET
+#endif
+
/*
* If we're fortunate enough to boot@EL2, ensure that the world is
* sane before dropping to EL1.
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 96177a7c0f05..2faee6042e99 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -292,16 +292,15 @@ u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
void __init setup_arch(char **cmdline_p)
{
- static struct vm_struct vmlinux_vm __initdata = {
- .addr = (void *)KIMAGE_VADDR,
- .size = 0,
- .flags = VM_IOREMAP,
- .caller = setup_arch,
- };
-
- vmlinux_vm.size = round_up((unsigned long)_end - KIMAGE_VADDR,
- 1 << SWAPPER_BLOCK_SHIFT);
- vmlinux_vm.phys_addr = __pa(KIMAGE_VADDR);
+ static struct vm_struct vmlinux_vm __initdata;
+
+ vmlinux_vm.addr = (void *)kimage_vaddr;
+ vmlinux_vm.size = round_up((u64)_end - kimage_vaddr,
+ SWAPPER_BLOCK_SIZE);
+ vmlinux_vm.phys_addr = __pa(kimage_vaddr);
+ vmlinux_vm.flags = VM_IOREMAP;
+ vmlinux_vm.caller = setup_arch;
+
vm_area_add_early(&vmlinux_vm);
pr_info("Boot CPU: AArch64 Processor [%08x]\n", read_cpuid_id());
@@ -367,7 +366,8 @@ void __init setup_arch(char **cmdline_p)
conswitchp = &dummy_con;
#endif
#endif
- if (boot_args[1] || boot_args[2] || boot_args[3]) {
+ if ((!IS_ENABLED(CONFIG_ARM64_RELOCATABLE_KERNEL) && boot_args[1]) ||
+ boot_args[2] || boot_args[3]) {
pr_err("WARNING: x1-x3 nonzero in violation of boot protocol:\n"
"\tx1: %016llx\n\tx2: %016llx\n\tx3: %016llx\n"
"This indicates a broken bootloader or old kernel\n",
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 69dfa376e843..77faf85f6d46 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -148,6 +148,15 @@ SECTIONS
.altinstr_replacement : {
*(.altinstr_replacement)
}
+ .rela : ALIGN(8) {
+ __reloc_start = .;
+ *(.rela .rela*)
+ __reloc_end = .;
+ }
+ .dynsym : ALIGN(8) {
+ __dynsym_start = .;
+ *(.dynsym)
+ }
. = ALIGN(PAGE_SIZE);
__init_end = .;
diff --git a/scripts/sortextable.c b/scripts/sortextable.c
index af247c70fb66..5ecbedefdb0f 100644
--- a/scripts/sortextable.c
+++ b/scripts/sortextable.c
@@ -266,9 +266,9 @@ do_file(char const *const fname)
break;
} /* end switch */
if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
- || r2(&ehdr->e_type) != ET_EXEC
+ || (r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN)
|| ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
- fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname);
+ fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname);
fail_file();
}
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [kernel-hardening] [RFC PATCH 09/10] arm64: add support for relocatable kernel
@ 2015-12-28 11:20 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, lkml
Cc: stuart.yoder, bhupesh.sharma, Ard Biesheuvel
This adds support for runtime relocation of the kernel Image, by
building it as a PIE (ET_DYN) executable and applying the dynamic
relocations in the early boot code.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
Documentation/arm64/booting.txt | 3 +-
arch/arm64/Kconfig | 13 ++++
arch/arm64/Makefile | 6 +-
arch/arm64/include/asm/memory.h | 10 ++-
arch/arm64/kernel/arm64ksyms.c | 5 ++
arch/arm64/kernel/head.S | 76 +++++++++++++++++++-
arch/arm64/kernel/setup.c | 22 +++---
arch/arm64/kernel/vmlinux.lds.S | 9 +++
scripts/sortextable.c | 4 +-
9 files changed, 130 insertions(+), 18 deletions(-)
diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
index 701d39d3171a..dcd8eee72984 100644
--- a/Documentation/arm64/booting.txt
+++ b/Documentation/arm64/booting.txt
@@ -109,7 +109,8 @@ Header notes:
1 - 4K
2 - 16K
3 - 64K
- Bits 3-63: Reserved.
+ Bit 3: Relocatable kernel.
+ Bits 4-63: Reserved.
- When image_size is zero, a bootloader should attempt to keep as much
memory as possible free for use by the kernel immediately after the
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 54eeab140bca..f458fb9e0dce 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -363,6 +363,7 @@ config ARM64_ERRATUM_843419
bool "Cortex-A53: 843419: A load or store might access an incorrect address"
depends on MODULES
default y
+ select ARM64_MODULE_CMODEL_LARGE
help
This option builds kernel modules using the large memory model in
order to avoid the use of the ADRP instruction, which can cause
@@ -709,6 +710,18 @@ config ARM64_MODULE_PLTS
bool
select HAVE_MOD_ARCH_SPECIFIC
+config ARM64_MODULE_CMODEL_LARGE
+ bool
+
+config ARM64_RELOCATABLE_KERNEL
+ bool "Kernel address space layout randomization (KASLR)"
+ select ARM64_MODULE_PLTS
+ select ARM64_MODULE_CMODEL_LARGE
+ help
+ This feature randomizes the virtual address of the kernel image, to
+ harden against exploits that rely on knowledge about the absolute
+ addresses of certain kernel data structures.
+
endmenu
menu "Boot options"
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index d4654830e536..75dc477d45f5 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -15,6 +15,10 @@ CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
GZFLAGS :=-9
+ifneq ($(CONFIG_ARM64_RELOCATABLE_KERNEL),)
+LDFLAGS_vmlinux += -pie
+endif
+
KBUILD_DEFCONFIG := defconfig
# Check for binutils support for specific extensions
@@ -41,7 +45,7 @@ endif
CHECKFLAGS += -D__aarch64__
-ifeq ($(CONFIG_ARM64_ERRATUM_843419), y)
+ifeq ($(CONFIG_ARM64_MODULE_CMODEL_LARGE), y)
KBUILD_CFLAGS_MODULE += -mcmodel=large
endif
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 1dcbf142d36c..e435423f9731 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -88,10 +88,10 @@
#define __virt_to_phys(x) ({ \
phys_addr_t __x = (phys_addr_t)(x); \
__x >= PAGE_OFFSET ? (__x - PAGE_OFFSET + PHYS_OFFSET) : \
- (__x - KIMAGE_VADDR + PHYS_OFFSET); })
+ (__x - kimage_vaddr + PHYS_OFFSET); })
#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
-#define __phys_to_kimg(x) ((unsigned long)((x) - PHYS_OFFSET + KIMAGE_VADDR))
+#define __phys_to_kimg(x) ((unsigned long)((x) - PHYS_OFFSET + kimage_vaddr))
/*
* Convert a page to/from a physical address
@@ -121,6 +121,12 @@ extern phys_addr_t memstart_addr;
/* PHYS_OFFSET - the physical address of the start of memory. */
#define PHYS_OFFSET ({ memstart_addr; })
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+extern u64 kimage_vaddr;
+#else
+#define kimage_vaddr KIMAGE_VADDR
+#endif
+
/*
* The maximum physical address that the linear direct mapping
* of system RAM can cover. (PAGE_OFFSET can be interpreted as
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
index 3b6d8cc9dfe0..4f7b7f44e2b5 100644
--- a/arch/arm64/kernel/arm64ksyms.c
+++ b/arch/arm64/kernel/arm64ksyms.c
@@ -41,6 +41,11 @@ EXPORT_SYMBOL(__copy_in_user);
/* physical memory */
EXPORT_SYMBOL(memstart_addr);
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+ /* runtime kernel virtual base address */
+EXPORT_SYMBOL(kimage_vaddr);
+#endif
+
/* string / mem functions */
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strrchr);
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 4f086e247eea..5ec779412436 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -59,8 +59,15 @@
#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+#define __HEAD_FLAG_RELOC 1
+#else
+#define __HEAD_FLAG_RELOC 0
+#endif
+
#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) | \
- (__HEAD_FLAG_PAGE_SIZE << 1))
+ (__HEAD_FLAG_PAGE_SIZE << 1) | \
+ (__HEAD_FLAG_RELOC << 3))
/*
* Kernel startup entry point.
@@ -229,6 +236,9 @@ ENTRY(stext)
*/
ldr x27, 0f // address to jump to after
// MMU has been enabled
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+ add x27, x27, x23 // add KASLR displacement
+#endif
adr_l lr, __enable_mmu // return (PIC) address
b __cpu_setup // initialise processor
ENDPROC(stext)
@@ -241,6 +251,16 @@ ENDPROC(stext)
preserve_boot_args:
mov x21, x0 // x21=FDT
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+ /*
+ * Mask off the bits of the random value supplied in x1 so it can serve
+ * as a KASLR displacement value which will move the kernel image to a
+ * random offset in the lower half of the VMALLOC area.
+ */
+ mov x23, #(1 << (VA_BITS - 2)) - 1
+ and x23, x23, x1, lsl #SWAPPER_BLOCK_SHIFT
+#endif
+
adr_l x0, boot_args // record the contents of
stp x21, x1, [x0] // x0 .. x3 at kernel entry
stp x2, x3, [x0, #16]
@@ -400,6 +420,9 @@ __create_page_tables:
*/
mov x0, x26 // swapper_pg_dir
ldr x5, =KIMAGE_VADDR
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+ add x5, x5, x23 // add KASLR displacement
+#endif
create_pgd_entry x0, x5, x3, x6
ldr w6, kernel_img_size
add x6, x6, x5
@@ -437,6 +460,51 @@ __mmap_switched:
str xzr, [x6], #8 // Clear BSS
b 1b
2:
+
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+
+#define R_AARCH64_RELATIVE 0x403
+#define R_AARCH64_ABS64 0x101
+
+ /*
+ * Iterate over each entry in the relocation table, and apply the
+ * relocations in place.
+ */
+ adr_l x8, __dynsym_start // start of symbol table
+ adr_l x9, __reloc_start // start of reloc table
+ adr_l x10, __reloc_end // end of reloc table
+
+0: cmp x9, x10
+ b.hs 2f
+ ldp x11, x12, [x9], #24
+ cmp x12, #R_AARCH64_RELATIVE
+ b.ne 1f
+ ldr x12, [x9, #-8]
+ add x12, x12, x23 // relocate
+ str x12, [x11, x23]
+ b 0b
+
+1: ubfx x13, x12, #0, #32
+ cmp x13, #R_AARCH64_ABS64
+ b.ne 0b
+ lsr x13, x12, #32 // symbol index
+ ldr x12, [x9, #-8]
+ add x13, x13, x13, lsl #1 // x 3
+ add x13, x8, x13, lsl #3 // x 8
+ ldrsh w14, [x13, #6] // Elf64_Sym::st_shndx
+ ldr x15, [x13, #8] // Elf64_Sym::st_value
+ cmp w14, #-0xf // SHN_ABS (0xfff1) ?
+ add x14, x15, x23 // relocate
+ csel x15, x14, x15, ne
+ add x15, x12, x15
+ str x15, [x11, x23]
+ b 0b
+
+2: ldr x8, =vectors // reload VBAR_EL1 with
+ msr vbar_el1, x8 // relocated address
+ isb
+#endif
+
adr_l sp, initial_sp, x4
str_l x21, __fdt_pointer, x5 // Save FDT pointer
str_l x24, memstart_addr, x6 // Save PHYS_OFFSET
@@ -452,6 +520,12 @@ ENDPROC(__mmap_switched)
* hotplug and needs to have the same protections as the text region
*/
.section ".text","ax"
+
+#ifdef CONFIG_ARM64_RELOCATABLE_KERNEL
+ENTRY(kimage_vaddr)
+ .quad _text - TEXT_OFFSET
+#endif
+
/*
* If we're fortunate enough to boot at EL2, ensure that the world is
* sane before dropping to EL1.
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 96177a7c0f05..2faee6042e99 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -292,16 +292,15 @@ u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
void __init setup_arch(char **cmdline_p)
{
- static struct vm_struct vmlinux_vm __initdata = {
- .addr = (void *)KIMAGE_VADDR,
- .size = 0,
- .flags = VM_IOREMAP,
- .caller = setup_arch,
- };
-
- vmlinux_vm.size = round_up((unsigned long)_end - KIMAGE_VADDR,
- 1 << SWAPPER_BLOCK_SHIFT);
- vmlinux_vm.phys_addr = __pa(KIMAGE_VADDR);
+ static struct vm_struct vmlinux_vm __initdata;
+
+ vmlinux_vm.addr = (void *)kimage_vaddr;
+ vmlinux_vm.size = round_up((u64)_end - kimage_vaddr,
+ SWAPPER_BLOCK_SIZE);
+ vmlinux_vm.phys_addr = __pa(kimage_vaddr);
+ vmlinux_vm.flags = VM_IOREMAP;
+ vmlinux_vm.caller = setup_arch;
+
vm_area_add_early(&vmlinux_vm);
pr_info("Boot CPU: AArch64 Processor [%08x]\n", read_cpuid_id());
@@ -367,7 +366,8 @@ void __init setup_arch(char **cmdline_p)
conswitchp = &dummy_con;
#endif
#endif
- if (boot_args[1] || boot_args[2] || boot_args[3]) {
+ if ((!IS_ENABLED(CONFIG_ARM64_RELOCATABLE_KERNEL) && boot_args[1]) ||
+ boot_args[2] || boot_args[3]) {
pr_err("WARNING: x1-x3 nonzero in violation of boot protocol:\n"
"\tx1: %016llx\n\tx2: %016llx\n\tx3: %016llx\n"
"This indicates a broken bootloader or old kernel\n",
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 69dfa376e843..77faf85f6d46 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -148,6 +148,15 @@ SECTIONS
.altinstr_replacement : {
*(.altinstr_replacement)
}
+ .rela : ALIGN(8) {
+ __reloc_start = .;
+ *(.rela .rela*)
+ __reloc_end = .;
+ }
+ .dynsym : ALIGN(8) {
+ __dynsym_start = .;
+ *(.dynsym)
+ }
. = ALIGN(PAGE_SIZE);
__init_end = .;
diff --git a/scripts/sortextable.c b/scripts/sortextable.c
index af247c70fb66..5ecbedefdb0f 100644
--- a/scripts/sortextable.c
+++ b/scripts/sortextable.c
@@ -266,9 +266,9 @@ do_file(char const *const fname)
break;
} /* end switch */
if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
- || r2(&ehdr->e_type) != ET_EXEC
+ || (r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN)
|| ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
- fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname);
+ fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname);
fail_file();
}
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [RFC PATCH 10/10] arm64: efi: invoke EFI_RNG_PROTOCOL to supply KASLR randomness
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
@ 2015-12-28 11:20 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel
Since arm64 does not use a decompressor that supplies an execution
environment where it is feasible to some extent to provide a source of
randomness, the arm64 KASLR kernel depends on the bootloader to supply
some random bits in register x1 upon kernel entry.
On UEFI systems, we can use the EFI_RNG_PROTOCOL, if supplied, to obtain
some random bits.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/kernel/efi-entry.S | 7 +++--
drivers/firmware/efi/libstub/arm-stub.c | 31 ++++++++++++++++++++
include/linux/efi.h | 5 +++-
3 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
index f82036e02485..e9bd55de14dd 100644
--- a/arch/arm64/kernel/efi-entry.S
+++ b/arch/arm64/kernel/efi-entry.S
@@ -110,7 +110,7 @@ ENTRY(entry)
2:
/* Jump to kernel entry point */
mov x0, x20
- mov x1, xzr
+ ldr x1, efi_random_bytes
mov x2, xzr
mov x3, xzr
br x21
@@ -119,6 +119,9 @@ efi_load_fail:
mov x0, #EFI_LOAD_ERROR
ldp x29, x30, [sp], #32
ret
+ENDPROC(entry)
+
+ENTRY(efi_random_bytes)
+ .quad 0
entry_end:
-ENDPROC(entry)
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 950c87f5d279..ebdf7137fe97 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -145,6 +145,31 @@ void efi_char16_printk(efi_system_table_t *sys_table_arg,
out->output_string(out, str);
}
+struct efi_rng_protocol_t {
+ efi_status_t (*get_info)(struct efi_rng_protocol_t *, unsigned long *, efi_guid_t *);
+ efi_status_t (*get_rng)(struct efi_rng_protocol_t *, efi_guid_t *, unsigned long, u8 *out);
+};
+
+static int efi_get_random_bytes(efi_system_table_t *sys_table)
+{
+ extern u64 efi_random_bytes;
+
+ efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
+ efi_status_t status;
+ struct efi_rng_protocol_t *rng;
+
+ status = sys_table->boottime->locate_protocol(&rng_proto, NULL,
+ (void **)&rng);
+ if (status == EFI_NOT_FOUND) {
+ pr_efi(sys_table, "EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
+ return EFI_SUCCESS;
+ }
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ return rng->get_rng(rng, NULL, sizeof(u64), (u8 *)&efi_random_bytes);
+}
/*
* This function handles the architcture specific differences between arm and
@@ -267,6 +292,12 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
if (status != EFI_SUCCESS)
pr_efi_err(sys_table, "Failed initrd from command line!\n");
+ if (IS_ENABLED(CONFIG_ARM64_RELOCATABLE_KERNEL)) {
+ status = efi_get_random_bytes(sys_table);
+ if (status != EFI_SUCCESS)
+ pr_efi_err(sys_table, "efi_get_random_bytes() failed\n");
+ }
+
new_fdt_addr = fdt_addr;
status = allocate_new_fdt_and_exit_boot(sys_table, handle,
&new_fdt_addr, dram_base + MAX_FDT_OFFSET,
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 569b5a866bb1..13783fdc9bdd 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -299,7 +299,7 @@ typedef struct {
void *open_protocol_information;
void *protocols_per_handle;
void *locate_handle_buffer;
- void *locate_protocol;
+ efi_status_t (*locate_protocol)(efi_guid_t *, void *, void **);
void *install_multiple_protocol_interfaces;
void *uninstall_multiple_protocol_interfaces;
void *calculate_crc32;
@@ -599,6 +599,9 @@ void efi_native_runtime_setup(void);
#define EFI_PROPERTIES_TABLE_GUID \
EFI_GUID( 0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5 )
+#define EFI_RNG_PROTOCOL_GUID \
+ EFI_GUID( 0x3152bca5, 0xeade, 0x433d, 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 )
+
typedef struct {
efi_guid_t guid;
u64 table;
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [kernel-hardening] [RFC PATCH 10/10] arm64: efi: invoke EFI_RNG_PROTOCOL to supply KASLR randomness
@ 2015-12-28 11:20 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:20 UTC (permalink / raw)
To: linux-arm-kernel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, lkml
Cc: stuart.yoder, bhupesh.sharma, Ard Biesheuvel
Since arm64 does not use a decompressor that supplies an execution
environment where it is feasible to some extent to provide a source of
randomness, the arm64 KASLR kernel depends on the bootloader to supply
some random bits in register x1 upon kernel entry.
On UEFI systems, we can use the EFI_RNG_PROTOCOL, if supplied, to obtain
some random bits.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/kernel/efi-entry.S | 7 +++--
drivers/firmware/efi/libstub/arm-stub.c | 31 ++++++++++++++++++++
include/linux/efi.h | 5 +++-
3 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
index f82036e02485..e9bd55de14dd 100644
--- a/arch/arm64/kernel/efi-entry.S
+++ b/arch/arm64/kernel/efi-entry.S
@@ -110,7 +110,7 @@ ENTRY(entry)
2:
/* Jump to kernel entry point */
mov x0, x20
- mov x1, xzr
+ ldr x1, efi_random_bytes
mov x2, xzr
mov x3, xzr
br x21
@@ -119,6 +119,9 @@ efi_load_fail:
mov x0, #EFI_LOAD_ERROR
ldp x29, x30, [sp], #32
ret
+ENDPROC(entry)
+
+ENTRY(efi_random_bytes)
+ .quad 0
entry_end:
-ENDPROC(entry)
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 950c87f5d279..ebdf7137fe97 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -145,6 +145,31 @@ void efi_char16_printk(efi_system_table_t *sys_table_arg,
out->output_string(out, str);
}
+struct efi_rng_protocol_t {
+ efi_status_t (*get_info)(struct efi_rng_protocol_t *, unsigned long *, efi_guid_t *);
+ efi_status_t (*get_rng)(struct efi_rng_protocol_t *, efi_guid_t *, unsigned long, u8 *out);
+};
+
+static int efi_get_random_bytes(efi_system_table_t *sys_table)
+{
+ extern u64 efi_random_bytes;
+
+ efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
+ efi_status_t status;
+ struct efi_rng_protocol_t *rng;
+
+ status = sys_table->boottime->locate_protocol(&rng_proto, NULL,
+ (void **)&rng);
+ if (status == EFI_NOT_FOUND) {
+ pr_efi(sys_table, "EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
+ return EFI_SUCCESS;
+ }
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ return rng->get_rng(rng, NULL, sizeof(u64), (u8 *)&efi_random_bytes);
+}
/*
* This function handles the architcture specific differences between arm and
@@ -267,6 +292,12 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
if (status != EFI_SUCCESS)
pr_efi_err(sys_table, "Failed initrd from command line!\n");
+ if (IS_ENABLED(CONFIG_ARM64_RELOCATABLE_KERNEL)) {
+ status = efi_get_random_bytes(sys_table);
+ if (status != EFI_SUCCESS)
+ pr_efi_err(sys_table, "efi_get_random_bytes() failed\n");
+ }
+
new_fdt_addr = fdt_addr;
status = allocate_new_fdt_and_exit_boot(sys_table, handle,
&new_fdt_addr, dram_base + MAX_FDT_OFFSET,
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 569b5a866bb1..13783fdc9bdd 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -299,7 +299,7 @@ typedef struct {
void *open_protocol_information;
void *protocols_per_handle;
void *locate_handle_buffer;
- void *locate_protocol;
+ efi_status_t (*locate_protocol)(efi_guid_t *, void *, void **);
void *install_multiple_protocol_interfaces;
void *uninstall_multiple_protocol_interfaces;
void *calculate_crc32;
@@ -599,6 +599,9 @@ void efi_native_runtime_setup(void);
#define EFI_PROPERTIES_TABLE_GUID \
EFI_GUID( 0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5 )
+#define EFI_RNG_PROTOCOL_GUID \
+ EFI_GUID( 0x3152bca5, 0xeade, 0x433d, 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 )
+
typedef struct {
efi_guid_t guid;
u64 table;
--
2.5.0
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [RFC PATCH 00/10] arm64: implement support for KASLR
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
@ 2015-12-28 11:28 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:28 UTC (permalink / raw)
To: linux-arm-kernel
On 28 December 2015 at 12:20, Ard Biesheuvel <ard.biesheuvel@linaro.org>
... accidentally cc'ed this series to lkml@ rather than
linux-kernel at vger.kernel.org, so please strip it from the addressee
list before replying
Thanks,
Ard.
^ permalink raw reply [flat|nested] 45+ messages in thread
* [kernel-hardening] Re: [RFC PATCH 00/10] arm64: implement support for KASLR
@ 2015-12-28 11:28 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 11:28 UTC (permalink / raw)
To: linux-arm-kernel, kernel-hardening, Will Deacon, Catalin Marinas,
Mark Rutland, Leif Lindholm, Kees Cook, lkml
Cc: Stuart Yoder, Sharma Bhupesh, Ard Biesheuvel
On 28 December 2015 at 12:20, Ard Biesheuvel <ard.biesheuvel@linaro.org>
... accidentally cc'ed this series to lkml@ rather than
linux-kernel@vger.kernel.org, so please strip it from the addressee
list before replying
Thanks,
Ard.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
(?)
@ 2015-12-28 11:50 ` Arnd Bergmann
-1 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2015-12-28 11:50 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Ard Biesheuvel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, linux-kernel,
bhupesh.sharma, stuart.yoder
On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
> @@ -75,8 +76,13 @@
> * private definitions which should NOT be used outside memory.h
> * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
> */
> -#define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))
> +#define __virt_to_phys(x) ({ \
> + phys_addr_t __x = (phys_addr_t)(x); \
> + __x >= PAGE_OFFSET ? (__x - PAGE_OFFSET + PHYS_OFFSET) : \
> + (__x - KIMAGE_VADDR + PHYS_OFFSET); })
> +
> #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
> +#define __phys_to_kimg(x) ((unsigned long)((x) - PHYS_OFFSET + KIMAGE_VADDR))
Having a conditional here is a bit unfortunate.
IIRC KASLR means something different depending on the architecture, we either randomize
the physical address, or the virtual address, or both, and that addresses different
attack scenarios. You seem to leave the physical address unchanged, which means that
an attacker that has gained access to a DMA master device can potentially still modify
the kernel without knowing the virtual address.
Similarly, you seem to leave the kernel mapped at the original virtual address and
just add a second map (or your __phys_to_virt is wrong), so if someone has the
ability to access a kernel virtual memory address from user space, they also don't
need the relocated address because they can potentially access the kernel .text
and .data through the linear mapping.
How about a different approach that keeps the relocatable kernel, but moves it in
physical memory with the same random offset as the virtual address? That way, both
would be random, and you can keep the simple virt_to_phys() function.
I suppose the downside of that is that the number of random bits is then limited
by the size of the first memblock, which is smaller than the vmalloc area.
Arnd
^ permalink raw reply [flat|nested] 45+ messages in thread
* [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2015-12-28 11:50 ` Arnd Bergmann
0 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2015-12-28 11:50 UTC (permalink / raw)
To: linux-arm-kernel
On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
> @@ -75,8 +76,13 @@
> * private definitions which should NOT be used outside memory.h
> * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
> */
> -#define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))
> +#define __virt_to_phys(x) ({ \
> + phys_addr_t __x = (phys_addr_t)(x); \
> + __x >= PAGE_OFFSET ? (__x - PAGE_OFFSET + PHYS_OFFSET) : \
> + (__x - KIMAGE_VADDR + PHYS_OFFSET); })
> +
> #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
> +#define __phys_to_kimg(x) ((unsigned long)((x) - PHYS_OFFSET + KIMAGE_VADDR))
Having a conditional here is a bit unfortunate.
IIRC KASLR means something different depending on the architecture, we either randomize
the physical address, or the virtual address, or both, and that addresses different
attack scenarios. You seem to leave the physical address unchanged, which means that
an attacker that has gained access to a DMA master device can potentially still modify
the kernel without knowing the virtual address.
Similarly, you seem to leave the kernel mapped at the original virtual address and
just add a second map (or your __phys_to_virt is wrong), so if someone has the
ability to access a kernel virtual memory address from user space, they also don't
need the relocated address because they can potentially access the kernel .text
and .data through the linear mapping.
How about a different approach that keeps the relocatable kernel, but moves it in
physical memory with the same random offset as the virtual address? That way, both
would be random, and you can keep the simple virt_to_phys() function.
I suppose the downside of that is that the number of random bits is then limited
by the size of the first memblock, which is smaller than the vmalloc area.
Arnd
^ permalink raw reply [flat|nested] 45+ messages in thread
* [kernel-hardening] Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2015-12-28 11:50 ` Arnd Bergmann
0 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2015-12-28 11:50 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Ard Biesheuvel, kernel-hardening, will.deacon, catalin.marinas,
mark.rutland, leif.lindholm, keescook, linux-kernel,
bhupesh.sharma, stuart.yoder
On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
> @@ -75,8 +76,13 @@
> * private definitions which should NOT be used outside memory.h
> * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
> */
> -#define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))
> +#define __virt_to_phys(x) ({ \
> + phys_addr_t __x = (phys_addr_t)(x); \
> + __x >= PAGE_OFFSET ? (__x - PAGE_OFFSET + PHYS_OFFSET) : \
> + (__x - KIMAGE_VADDR + PHYS_OFFSET); })
> +
> #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
> +#define __phys_to_kimg(x) ((unsigned long)((x) - PHYS_OFFSET + KIMAGE_VADDR))
Having a conditional here is a bit unfortunate.
IIRC KASLR means something different depending on the architecture, we either randomize
the physical address, or the virtual address, or both, and that addresses different
attack scenarios. You seem to leave the physical address unchanged, which means that
an attacker that has gained access to a DMA master device can potentially still modify
the kernel without knowing the virtual address.
Similarly, you seem to leave the kernel mapped at the original virtual address and
just add a second map (or your __phys_to_virt is wrong), so if someone has the
ability to access a kernel virtual memory address from user space, they also don't
need the relocated address because they can potentially access the kernel .text
and .data through the linear mapping.
How about a different approach that keeps the relocatable kernel, but moves it in
physical memory with the same random offset as the virtual address? That way, both
would be random, and you can keep the simple virt_to_phys() function.
I suppose the downside of that is that the number of random bits is then limited
by the size of the first memblock, which is smaller than the vmalloc area.
Arnd
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
2015-12-28 11:50 ` Arnd Bergmann
(?)
@ 2015-12-28 12:07 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 12:07 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-arm-kernel, kernel-hardening, Will Deacon, Catalin Marinas,
Mark Rutland, Leif Lindholm, Kees Cook, linux-kernel,
Sharma Bhupesh, Stuart Yoder
On 28 December 2015 at 12:50, Arnd Bergmann <arnd@arndb.de> wrote:
> On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
>> @@ -75,8 +76,13 @@
>> * private definitions which should NOT be used outside memory.h
>> * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
>> */
>> -#define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))
>> +#define __virt_to_phys(x) ({ \
>> + phys_addr_t __x = (phys_addr_t)(x); \
>> + __x >= PAGE_OFFSET ? (__x - PAGE_OFFSET + PHYS_OFFSET) : \
>> + (__x - KIMAGE_VADDR + PHYS_OFFSET); })
>> +
>> #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
>> +#define __phys_to_kimg(x) ((unsigned long)((x) - PHYS_OFFSET + KIMAGE_VADDR))
>
> Having a conditional here is a bit unfortunate.
>
Yes. Unfortunately, the assumption that kernel symbols live in the
same address space as dynamic allocations in the linear mapping is
widespread throughout the code base, otherwise we could strictly
separate the two, and this would not be necessary. I played around
with adding another sparse address space for kernel addresses, but
that gives a lot of hits in generic code as well.
> IIRC KASLR means something different depending on the architecture, we either randomize
> the physical address, or the virtual address, or both, and that addresses different
> attack scenarios. You seem to leave the physical address unchanged, which means that
> an attacker that has gained access to a DMA master device can potentially still modify
> the kernel without knowing the virtual address.
Indeed. I did not mention it in the cover letter, but this work is
somewhat related to series I proposed which allows the kernel Image to
reside anywhere (i.e., at any 2 MB aligned offset + TEXT_OFFSET) in
physical memory. This is fairly straight forward once we have moved
the kernel virtual mapping out of the linear mapping, but since this
series has enough moving parts as it is, I omitted those pieces for
now.
http://thread.gmane.org/gmane.linux.ports.arm.kernel/455151
After Mark Rutland proposed his pagetable rework series, a lot of
those changes became much easier to implement, but did require rework,
and because of queries I received personally regarding KASLR, I
decided to focus on that part first.
> Similarly, you seem to leave the kernel mapped at the original virtual address and
> just add a second map (or your __phys_to_virt is wrong), so if someone has the
> ability to access a kernel virtual memory address from user space, they also don't
> need the relocated address because they can potentially access the kernel .text
> and .data through the linear mapping.
>
True. Catalin mentioned this as well in response to the series
mentioned above. Unmapping the kernel text in the linear mapping is an
important enhancement from security pov, but not essential from a
functionality pov.
> How about a different approach that keeps the relocatable kernel, but moves it in
> physical memory with the same random offset as the virtual address? That way, both
> would be random, and you can keep the simple virt_to_phys() function.
>
> I suppose the downside of that is that the number of random bits is then limited
> by the size of the first memblock, which is smaller than the vmalloc area.
>
I don't see a reason to use the same virtual and physical offset
(other than the conditional). On arm64, it would be up to the
bootloader to decide where to put the Image in physical memory, and it
would be up to the kernel to decide whether or not to virtually remap
itself.
Regards,
Ard.
^ permalink raw reply [flat|nested] 45+ messages in thread
* [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2015-12-28 12:07 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 12:07 UTC (permalink / raw)
To: linux-arm-kernel
On 28 December 2015 at 12:50, Arnd Bergmann <arnd@arndb.de> wrote:
> On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
>> @@ -75,8 +76,13 @@
>> * private definitions which should NOT be used outside memory.h
>> * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
>> */
>> -#define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))
>> +#define __virt_to_phys(x) ({ \
>> + phys_addr_t __x = (phys_addr_t)(x); \
>> + __x >= PAGE_OFFSET ? (__x - PAGE_OFFSET + PHYS_OFFSET) : \
>> + (__x - KIMAGE_VADDR + PHYS_OFFSET); })
>> +
>> #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
>> +#define __phys_to_kimg(x) ((unsigned long)((x) - PHYS_OFFSET + KIMAGE_VADDR))
>
> Having a conditional here is a bit unfortunate.
>
Yes. Unfortunately, the assumption that kernel symbols live in the
same address space as dynamic allocations in the linear mapping is
widespread throughout the code base, otherwise we could strictly
separate the two, and this would not be necessary. I played around
with adding another sparse address space for kernel addresses, but
that gives a lot of hits in generic code as well.
> IIRC KASLR means something different depending on the architecture, we either randomize
> the physical address, or the virtual address, or both, and that addresses different
> attack scenarios. You seem to leave the physical address unchanged, which means that
> an attacker that has gained access to a DMA master device can potentially still modify
> the kernel without knowing the virtual address.
Indeed. I did not mention it in the cover letter, but this work is
somewhat related to series I proposed which allows the kernel Image to
reside anywhere (i.e., at any 2 MB aligned offset + TEXT_OFFSET) in
physical memory. This is fairly straight forward once we have moved
the kernel virtual mapping out of the linear mapping, but since this
series has enough moving parts as it is, I omitted those pieces for
now.
http://thread.gmane.org/gmane.linux.ports.arm.kernel/455151
After Mark Rutland proposed his pagetable rework series, a lot of
those changes became much easier to implement, but did require rework,
and because of queries I received personally regarding KASLR, I
decided to focus on that part first.
> Similarly, you seem to leave the kernel mapped at the original virtual address and
> just add a second map (or your __phys_to_virt is wrong), so if someone has the
> ability to access a kernel virtual memory address from user space, they also don't
> need the relocated address because they can potentially access the kernel .text
> and .data through the linear mapping.
>
True. Catalin mentioned this as well in response to the series
mentioned above. Unmapping the kernel text in the linear mapping is an
important enhancement from security pov, but not essential from a
functionality pov.
> How about a different approach that keeps the relocatable kernel, but moves it in
> physical memory with the same random offset as the virtual address? That way, both
> would be random, and you can keep the simple virt_to_phys() function.
>
> I suppose the downside of that is that the number of random bits is then limited
> by the size of the first memblock, which is smaller than the vmalloc area.
>
I don't see a reason to use the same virtual and physical offset
(other than the conditional). On arm64, it would be up to the
bootloader to decide where to put the Image in physical memory, and it
would be up to the kernel to decide whether or not to virtually remap
itself.
Regards,
Ard.
^ permalink raw reply [flat|nested] 45+ messages in thread
* [kernel-hardening] Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2015-12-28 12:07 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2015-12-28 12:07 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-arm-kernel, kernel-hardening, Will Deacon, Catalin Marinas,
Mark Rutland, Leif Lindholm, Kees Cook, linux-kernel,
Sharma Bhupesh, Stuart Yoder
On 28 December 2015 at 12:50, Arnd Bergmann <arnd@arndb.de> wrote:
> On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
>> @@ -75,8 +76,13 @@
>> * private definitions which should NOT be used outside memory.h
>> * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
>> */
>> -#define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))
>> +#define __virt_to_phys(x) ({ \
>> + phys_addr_t __x = (phys_addr_t)(x); \
>> + __x >= PAGE_OFFSET ? (__x - PAGE_OFFSET + PHYS_OFFSET) : \
>> + (__x - KIMAGE_VADDR + PHYS_OFFSET); })
>> +
>> #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
>> +#define __phys_to_kimg(x) ((unsigned long)((x) - PHYS_OFFSET + KIMAGE_VADDR))
>
> Having a conditional here is a bit unfortunate.
>
Yes. Unfortunately, the assumption that kernel symbols live in the
same address space as dynamic allocations in the linear mapping is
widespread throughout the code base, otherwise we could strictly
separate the two, and this would not be necessary. I played around
with adding another sparse address space for kernel addresses, but
that gives a lot of hits in generic code as well.
> IIRC KASLR means something different depending on the architecture, we either randomize
> the physical address, or the virtual address, or both, and that addresses different
> attack scenarios. You seem to leave the physical address unchanged, which means that
> an attacker that has gained access to a DMA master device can potentially still modify
> the kernel without knowing the virtual address.
Indeed. I did not mention it in the cover letter, but this work is
somewhat related to series I proposed which allows the kernel Image to
reside anywhere (i.e., at any 2 MB aligned offset + TEXT_OFFSET) in
physical memory. This is fairly straight forward once we have moved
the kernel virtual mapping out of the linear mapping, but since this
series has enough moving parts as it is, I omitted those pieces for
now.
http://thread.gmane.org/gmane.linux.ports.arm.kernel/455151
After Mark Rutland proposed his pagetable rework series, a lot of
those changes became much easier to implement, but did require rework,
and because of queries I received personally regarding KASLR, I
decided to focus on that part first.
> Similarly, you seem to leave the kernel mapped at the original virtual address and
> just add a second map (or your __phys_to_virt is wrong), so if someone has the
> ability to access a kernel virtual memory address from user space, they also don't
> need the relocated address because they can potentially access the kernel .text
> and .data through the linear mapping.
>
True. Catalin mentioned this as well in response to the series
mentioned above. Unmapping the kernel text in the linear mapping is an
important enhancement from security pov, but not essential from a
functionality pov.
> How about a different approach that keeps the relocatable kernel, but moves it in
> physical memory with the same random offset as the virtual address? That way, both
> would be random, and you can keep the simple virt_to_phys() function.
>
> I suppose the downside of that is that the number of random bits is then limited
> by the size of the first memblock, which is smaller than the vmalloc area.
>
I don't see a reason to use the same virtual and physical offset
(other than the conditional). On arm64, it would be up to the
bootloader to decide where to put the Image in physical memory, and it
would be up to the kernel to decide whether or not to virtually remap
itself.
Regards,
Ard.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
2015-12-28 12:07 ` Ard Biesheuvel
(?)
@ 2015-12-28 14:11 ` Arnd Bergmann
-1 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2015-12-28 14:11 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-arm-kernel, kernel-hardening, Will Deacon, Catalin Marinas,
Mark Rutland, Leif Lindholm, Kees Cook, linux-kernel,
Sharma Bhupesh, Stuart Yoder
On Monday 28 December 2015 13:07:44 Ard Biesheuvel wrote:
> On 28 December 2015 at 12:50, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
> > How about a different approach that keeps the relocatable kernel, but moves it in
> > physical memory with the same random offset as the virtual address? That way, both
> > would be random, and you can keep the simple virt_to_phys() function.
> >
> > I suppose the downside of that is that the number of random bits is then limited
> > by the size of the first memblock, which is smaller than the vmalloc area.
> >
>
> I don't see a reason to use the same virtual and physical offset
> (other than the conditional). On arm64, it would be up to the
> bootloader to decide where to put the Image in physical memory, and it
> would be up to the kernel to decide whether or not to virtually remap
> itself.
I see. If we pull in the bootloader to the discussion, there are a couple
of related points that are not directly required for your series but that
we should keep in mind anyway:
- We need to implement the randomization for each boot loader separately.
This is probably easy enough for grub, as it can tap the same random
number source that you use here, but a little harder for u-boot (requiring
to implement access to hardware rng separately on each platform) and
much harder to get done consistently in UEFI for direct kernel loading
since there is no common upstream.
- once we have a random number in the bootloader, we should also pass that
through a DT property. This has been discussed multiple times in the past
and I think we had reached consensus already but don't know if we had
agreed on a specific DT property that contains the random number seed.
- For machines that don't have strong hardware RNG, or where we don't
trust that hardware enough, we may want to have a way to feed back a
random seed into the bootloader during shutdown, the equivalent of
/etc/random-seed. On real Open Firmware, we'd do this through a
nvram variable that gets copied into a /chosen DT property, but we don't
have a generic way to do the same with u-boot. On UEFI we could probably
do it through efivars, but I'm not sure if that's accessible early
enough in the kernel, so we might need help from grub again.
Arnd
^ permalink raw reply [flat|nested] 45+ messages in thread
* [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2015-12-28 14:11 ` Arnd Bergmann
0 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2015-12-28 14:11 UTC (permalink / raw)
To: linux-arm-kernel
On Monday 28 December 2015 13:07:44 Ard Biesheuvel wrote:
> On 28 December 2015 at 12:50, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
> > How about a different approach that keeps the relocatable kernel, but moves it in
> > physical memory with the same random offset as the virtual address? That way, both
> > would be random, and you can keep the simple virt_to_phys() function.
> >
> > I suppose the downside of that is that the number of random bits is then limited
> > by the size of the first memblock, which is smaller than the vmalloc area.
> >
>
> I don't see a reason to use the same virtual and physical offset
> (other than the conditional). On arm64, it would be up to the
> bootloader to decide where to put the Image in physical memory, and it
> would be up to the kernel to decide whether or not to virtually remap
> itself.
I see. If we pull in the bootloader to the discussion, there are a couple
of related points that are not directly required for your series but that
we should keep in mind anyway:
- We need to implement the randomization for each boot loader separately.
This is probably easy enough for grub, as it can tap the same random
number source that you use here, but a little harder for u-boot (requiring
to implement access to hardware rng separately on each platform) and
much harder to get done consistently in UEFI for direct kernel loading
since there is no common upstream.
- once we have a random number in the bootloader, we should also pass that
through a DT property. This has been discussed multiple times in the past
and I think we had reached consensus already but don't know if we had
agreed on a specific DT property that contains the random number seed.
- For machines that don't have strong hardware RNG, or where we don't
trust that hardware enough, we may want to have a way to feed back a
random seed into the bootloader during shutdown, the equivalent of
/etc/random-seed. On real Open Firmware, we'd do this through a
nvram variable that gets copied into a /chosen DT property, but we don't
have a generic way to do the same with u-boot. On UEFI we could probably
do it through efivars, but I'm not sure if that's accessible early
enough in the kernel, so we might need help from grub again.
Arnd
^ permalink raw reply [flat|nested] 45+ messages in thread
* [kernel-hardening] Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2015-12-28 14:11 ` Arnd Bergmann
0 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2015-12-28 14:11 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-arm-kernel, kernel-hardening, Will Deacon, Catalin Marinas,
Mark Rutland, Leif Lindholm, Kees Cook, linux-kernel,
Sharma Bhupesh, Stuart Yoder
On Monday 28 December 2015 13:07:44 Ard Biesheuvel wrote:
> On 28 December 2015 at 12:50, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
> > How about a different approach that keeps the relocatable kernel, but moves it in
> > physical memory with the same random offset as the virtual address? That way, both
> > would be random, and you can keep the simple virt_to_phys() function.
> >
> > I suppose the downside of that is that the number of random bits is then limited
> > by the size of the first memblock, which is smaller than the vmalloc area.
> >
>
> I don't see a reason to use the same virtual and physical offset
> (other than the conditional). On arm64, it would be up to the
> bootloader to decide where to put the Image in physical memory, and it
> would be up to the kernel to decide whether or not to virtually remap
> itself.
I see. If we pull in the bootloader to the discussion, there are a couple
of related points that are not directly required for your series but that
we should keep in mind anyway:
- We need to implement the randomization for each boot loader separately.
This is probably easy enough for grub, as it can tap the same random
number source that you use here, but a little harder for u-boot (requiring
to implement access to hardware rng separately on each platform) and
much harder to get done consistently in UEFI for direct kernel loading
since there is no common upstream.
- once we have a random number in the bootloader, we should also pass that
through a DT property. This has been discussed multiple times in the past
and I think we had reached consensus already but don't know if we had
agreed on a specific DT property that contains the random number seed.
- For machines that don't have strong hardware RNG, or where we don't
trust that hardware enough, we may want to have a way to feed back a
random seed into the bootloader during shutdown, the equivalent of
/etc/random-seed. On real Open Firmware, we'd do this through a
nvram variable that gets copied into a /chosen DT property, but we don't
have a generic way to do the same with u-boot. On UEFI we could probably
do it through efivars, but I'm not sure if that's accessible early
enough in the kernel, so we might need help from grub again.
Arnd
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
2015-12-28 14:11 ` Arnd Bergmann
(?)
@ 2016-01-03 14:50 ` Mark Rutland
-1 siblings, 0 replies; 45+ messages in thread
From: Mark Rutland @ 2016-01-03 14:50 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Ard Biesheuvel, linux-arm-kernel, kernel-hardening, Will Deacon,
Catalin Marinas, Leif Lindholm, Kees Cook, linux-kernel,
Sharma Bhupesh, Stuart Yoder
On Mon, Dec 28, 2015 at 03:11:25PM +0100, Arnd Bergmann wrote:
> On Monday 28 December 2015 13:07:44 Ard Biesheuvel wrote:
> > On 28 December 2015 at 12:50, Arnd Bergmann <arnd@arndb.de> wrote:
> > > On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
> > > How about a different approach that keeps the relocatable kernel, but moves it in
> > > physical memory with the same random offset as the virtual address? That way, both
> > > would be random, and you can keep the simple virt_to_phys() function.
> > >
> > > I suppose the downside of that is that the number of random bits is then limited
> > > by the size of the first memblock, which is smaller than the vmalloc area.
> > >
> >
> > I don't see a reason to use the same virtual and physical offset
> > (other than the conditional). On arm64, it would be up to the
> > bootloader to decide where to put the Image in physical memory, and it
> > would be up to the kernel to decide whether or not to virtually remap
> > itself.
>
> I see. If we pull in the bootloader to the discussion, there are a couple
> of related points that are not directly required for your series but that
> we should keep in mind anyway:
>
> - We need to implement the randomization for each boot loader separately.
> This is probably easy enough for grub, as it can tap the same random
> number source that you use here, but a little harder for u-boot (requiring
> to implement access to hardware rng separately on each platform) and
> much harder to get done consistently in UEFI for direct kernel loading
> since there is no common upstream.
In the GRUB case the kernel is loaded as an EFI application -- as far as I am
aware, GRUB for arm64 doesn't know anything about the Linux kernel Image
binary.
When loaded as an EFI application the EFI stub can perform the relocation,
which it already does if the kernel was laoded at an address it cannot execute
from. It looks like Ard's implemented that for v2.
Being (cold) booted from EFI is likely to be the most consistent case as we
have complete control over where the kernel is placed, bar some limitations
imposed by prior EFI applications or EFI itself.
> - once we have a random number in the bootloader, we should also pass that
> through a DT property. This has been discussed multiple times in the past
> and I think we had reached consensus already but don't know if we had
> agreed on a specific DT property that contains the random number seed.
Any links for this? I don't recall spotting this discussion.
Thanks,
Mark.
^ permalink raw reply [flat|nested] 45+ messages in thread
* [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2016-01-03 14:50 ` Mark Rutland
0 siblings, 0 replies; 45+ messages in thread
From: Mark Rutland @ 2016-01-03 14:50 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Dec 28, 2015 at 03:11:25PM +0100, Arnd Bergmann wrote:
> On Monday 28 December 2015 13:07:44 Ard Biesheuvel wrote:
> > On 28 December 2015 at 12:50, Arnd Bergmann <arnd@arndb.de> wrote:
> > > On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
> > > How about a different approach that keeps the relocatable kernel, but moves it in
> > > physical memory with the same random offset as the virtual address? That way, both
> > > would be random, and you can keep the simple virt_to_phys() function.
> > >
> > > I suppose the downside of that is that the number of random bits is then limited
> > > by the size of the first memblock, which is smaller than the vmalloc area.
> > >
> >
> > I don't see a reason to use the same virtual and physical offset
> > (other than the conditional). On arm64, it would be up to the
> > bootloader to decide where to put the Image in physical memory, and it
> > would be up to the kernel to decide whether or not to virtually remap
> > itself.
>
> I see. If we pull in the bootloader to the discussion, there are a couple
> of related points that are not directly required for your series but that
> we should keep in mind anyway:
>
> - We need to implement the randomization for each boot loader separately.
> This is probably easy enough for grub, as it can tap the same random
> number source that you use here, but a little harder for u-boot (requiring
> to implement access to hardware rng separately on each platform) and
> much harder to get done consistently in UEFI for direct kernel loading
> since there is no common upstream.
In the GRUB case the kernel is loaded as an EFI application -- as far as I am
aware, GRUB for arm64 doesn't know anything about the Linux kernel Image
binary.
When loaded as an EFI application the EFI stub can perform the relocation,
which it already does if the kernel was laoded at an address it cannot execute
from. It looks like Ard's implemented that for v2.
Being (cold) booted from EFI is likely to be the most consistent case as we
have complete control over where the kernel is placed, bar some limitations
imposed by prior EFI applications or EFI itself.
> - once we have a random number in the bootloader, we should also pass that
> through a DT property. This has been discussed multiple times in the past
> and I think we had reached consensus already but don't know if we had
> agreed on a specific DT property that contains the random number seed.
Any links for this? I don't recall spotting this discussion.
Thanks,
Mark.
^ permalink raw reply [flat|nested] 45+ messages in thread
* [kernel-hardening] Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2016-01-03 14:50 ` Mark Rutland
0 siblings, 0 replies; 45+ messages in thread
From: Mark Rutland @ 2016-01-03 14:50 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Ard Biesheuvel, linux-arm-kernel, kernel-hardening, Will Deacon,
Catalin Marinas, Leif Lindholm, Kees Cook, linux-kernel,
Sharma Bhupesh, Stuart Yoder
On Mon, Dec 28, 2015 at 03:11:25PM +0100, Arnd Bergmann wrote:
> On Monday 28 December 2015 13:07:44 Ard Biesheuvel wrote:
> > On 28 December 2015 at 12:50, Arnd Bergmann <arnd@arndb.de> wrote:
> > > On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
> > > How about a different approach that keeps the relocatable kernel, but moves it in
> > > physical memory with the same random offset as the virtual address? That way, both
> > > would be random, and you can keep the simple virt_to_phys() function.
> > >
> > > I suppose the downside of that is that the number of random bits is then limited
> > > by the size of the first memblock, which is smaller than the vmalloc area.
> > >
> >
> > I don't see a reason to use the same virtual and physical offset
> > (other than the conditional). On arm64, it would be up to the
> > bootloader to decide where to put the Image in physical memory, and it
> > would be up to the kernel to decide whether or not to virtually remap
> > itself.
>
> I see. If we pull in the bootloader to the discussion, there are a couple
> of related points that are not directly required for your series but that
> we should keep in mind anyway:
>
> - We need to implement the randomization for each boot loader separately.
> This is probably easy enough for grub, as it can tap the same random
> number source that you use here, but a little harder for u-boot (requiring
> to implement access to hardware rng separately on each platform) and
> much harder to get done consistently in UEFI for direct kernel loading
> since there is no common upstream.
In the GRUB case the kernel is loaded as an EFI application -- as far as I am
aware, GRUB for arm64 doesn't know anything about the Linux kernel Image
binary.
When loaded as an EFI application the EFI stub can perform the relocation,
which it already does if the kernel was laoded at an address it cannot execute
from. It looks like Ard's implemented that for v2.
Being (cold) booted from EFI is likely to be the most consistent case as we
have complete control over where the kernel is placed, bar some limitations
imposed by prior EFI applications or EFI itself.
> - once we have a random number in the bootloader, we should also pass that
> through a DT property. This has been discussed multiple times in the past
> and I think we had reached consensus already but don't know if we had
> agreed on a specific DT property that contains the random number seed.
Any links for this? I don't recall spotting this discussion.
Thanks,
Mark.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
2016-01-03 14:50 ` Mark Rutland
(?)
@ 2016-01-03 15:23 ` Ard Biesheuvel
-1 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2016-01-03 15:23 UTC (permalink / raw)
To: Mark Rutland
Cc: Arnd Bergmann, linux-arm-kernel, kernel-hardening, Will Deacon,
Catalin Marinas, Leif Lindholm, Kees Cook, linux-kernel,
Sharma Bhupesh, Stuart Yoder
On 3 January 2016 at 15:50, Mark Rutland <mark.rutland@arm.com> wrote:
> On Mon, Dec 28, 2015 at 03:11:25PM +0100, Arnd Bergmann wrote:
>> On Monday 28 December 2015 13:07:44 Ard Biesheuvel wrote:
>> > On 28 December 2015 at 12:50, Arnd Bergmann <arnd@arndb.de> wrote:
>> > > On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
>> > > How about a different approach that keeps the relocatable kernel, but moves it in
>> > > physical memory with the same random offset as the virtual address? That way, both
>> > > would be random, and you can keep the simple virt_to_phys() function.
>> > >
>> > > I suppose the downside of that is that the number of random bits is then limited
>> > > by the size of the first memblock, which is smaller than the vmalloc area.
>> > >
>> >
>> > I don't see a reason to use the same virtual and physical offset
>> > (other than the conditional). On arm64, it would be up to the
>> > bootloader to decide where to put the Image in physical memory, and it
>> > would be up to the kernel to decide whether or not to virtually remap
>> > itself.
>>
>> I see. If we pull in the bootloader to the discussion, there are a couple
>> of related points that are not directly required for your series but that
>> we should keep in mind anyway:
>>
>> - We need to implement the randomization for each boot loader separately.
>> This is probably easy enough for grub, as it can tap the same random
>> number source that you use here, but a little harder for u-boot (requiring
>> to implement access to hardware rng separately on each platform) and
>> much harder to get done consistently in UEFI for direct kernel loading
>> since there is no common upstream.
>
> In the GRUB case the kernel is loaded as an EFI application -- as far as I am
> aware, GRUB for arm64 doesn't know anything about the Linux kernel Image
> binary.
>
No, it doesn't. Alexander Graf is even proposing a EFI compatible
runtime in U-boot so it can run EFI-GRUB as well, so it is unlikely
that something like that will get added soon. If he includes a
EFI_RNG_PROTOCOL implementation, we can run these patches on U-Boot as
well.
> When loaded as an EFI application the EFI stub can perform the relocation,
> which it already does if the kernel was laoded at an address it cannot execute
> from. It looks like Ard's implemented that for v2.
>
Indeed.
> Being (cold) booted from EFI is likely to be the most consistent case as we
> have complete control over where the kernel is placed, bar some limitations
> imposed by prior EFI applications or EFI itself.
>
>> - once we have a random number in the bootloader, we should also pass that
>> through a DT property. This has been discussed multiple times in the past
>> and I think we had reached consensus already but don't know if we had
>> agreed on a specific DT property that contains the random number seed.
>
> Any links for this? I don't recall spotting this discussion.
>
> Thanks,
> Mark.
^ permalink raw reply [flat|nested] 45+ messages in thread
* [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2016-01-03 15:23 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2016-01-03 15:23 UTC (permalink / raw)
To: linux-arm-kernel
On 3 January 2016 at 15:50, Mark Rutland <mark.rutland@arm.com> wrote:
> On Mon, Dec 28, 2015 at 03:11:25PM +0100, Arnd Bergmann wrote:
>> On Monday 28 December 2015 13:07:44 Ard Biesheuvel wrote:
>> > On 28 December 2015 at 12:50, Arnd Bergmann <arnd@arndb.de> wrote:
>> > > On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
>> > > How about a different approach that keeps the relocatable kernel, but moves it in
>> > > physical memory with the same random offset as the virtual address? That way, both
>> > > would be random, and you can keep the simple virt_to_phys() function.
>> > >
>> > > I suppose the downside of that is that the number of random bits is then limited
>> > > by the size of the first memblock, which is smaller than the vmalloc area.
>> > >
>> >
>> > I don't see a reason to use the same virtual and physical offset
>> > (other than the conditional). On arm64, it would be up to the
>> > bootloader to decide where to put the Image in physical memory, and it
>> > would be up to the kernel to decide whether or not to virtually remap
>> > itself.
>>
>> I see. If we pull in the bootloader to the discussion, there are a couple
>> of related points that are not directly required for your series but that
>> we should keep in mind anyway:
>>
>> - We need to implement the randomization for each boot loader separately.
>> This is probably easy enough for grub, as it can tap the same random
>> number source that you use here, but a little harder for u-boot (requiring
>> to implement access to hardware rng separately on each platform) and
>> much harder to get done consistently in UEFI for direct kernel loading
>> since there is no common upstream.
>
> In the GRUB case the kernel is loaded as an EFI application -- as far as I am
> aware, GRUB for arm64 doesn't know anything about the Linux kernel Image
> binary.
>
No, it doesn't. Alexander Graf is even proposing a EFI compatible
runtime in U-boot so it can run EFI-GRUB as well, so it is unlikely
that something like that will get added soon. If he includes a
EFI_RNG_PROTOCOL implementation, we can run these patches on U-Boot as
well.
> When loaded as an EFI application the EFI stub can perform the relocation,
> which it already does if the kernel was laoded at an address it cannot execute
> from. It looks like Ard's implemented that for v2.
>
Indeed.
> Being (cold) booted from EFI is likely to be the most consistent case as we
> have complete control over where the kernel is placed, bar some limitations
> imposed by prior EFI applications or EFI itself.
>
>> - once we have a random number in the bootloader, we should also pass that
>> through a DT property. This has been discussed multiple times in the past
>> and I think we had reached consensus already but don't know if we had
>> agreed on a specific DT property that contains the random number seed.
>
> Any links for this? I don't recall spotting this discussion.
>
> Thanks,
> Mark.
^ permalink raw reply [flat|nested] 45+ messages in thread
* [kernel-hardening] Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2016-01-03 15:23 ` Ard Biesheuvel
0 siblings, 0 replies; 45+ messages in thread
From: Ard Biesheuvel @ 2016-01-03 15:23 UTC (permalink / raw)
To: Mark Rutland
Cc: Arnd Bergmann, linux-arm-kernel, kernel-hardening, Will Deacon,
Catalin Marinas, Leif Lindholm, Kees Cook, linux-kernel,
Sharma Bhupesh, Stuart Yoder
On 3 January 2016 at 15:50, Mark Rutland <mark.rutland@arm.com> wrote:
> On Mon, Dec 28, 2015 at 03:11:25PM +0100, Arnd Bergmann wrote:
>> On Monday 28 December 2015 13:07:44 Ard Biesheuvel wrote:
>> > On 28 December 2015 at 12:50, Arnd Bergmann <arnd@arndb.de> wrote:
>> > > On Monday 28 December 2015 12:20:45 Ard Biesheuvel wrote:
>> > > How about a different approach that keeps the relocatable kernel, but moves it in
>> > > physical memory with the same random offset as the virtual address? That way, both
>> > > would be random, and you can keep the simple virt_to_phys() function.
>> > >
>> > > I suppose the downside of that is that the number of random bits is then limited
>> > > by the size of the first memblock, which is smaller than the vmalloc area.
>> > >
>> >
>> > I don't see a reason to use the same virtual and physical offset
>> > (other than the conditional). On arm64, it would be up to the
>> > bootloader to decide where to put the Image in physical memory, and it
>> > would be up to the kernel to decide whether or not to virtually remap
>> > itself.
>>
>> I see. If we pull in the bootloader to the discussion, there are a couple
>> of related points that are not directly required for your series but that
>> we should keep in mind anyway:
>>
>> - We need to implement the randomization for each boot loader separately.
>> This is probably easy enough for grub, as it can tap the same random
>> number source that you use here, but a little harder for u-boot (requiring
>> to implement access to hardware rng separately on each platform) and
>> much harder to get done consistently in UEFI for direct kernel loading
>> since there is no common upstream.
>
> In the GRUB case the kernel is loaded as an EFI application -- as far as I am
> aware, GRUB for arm64 doesn't know anything about the Linux kernel Image
> binary.
>
No, it doesn't. Alexander Graf is even proposing a EFI compatible
runtime in U-boot so it can run EFI-GRUB as well, so it is unlikely
that something like that will get added soon. If he includes a
EFI_RNG_PROTOCOL implementation, we can run these patches on U-Boot as
well.
> When loaded as an EFI application the EFI stub can perform the relocation,
> which it already does if the kernel was laoded at an address it cannot execute
> from. It looks like Ard's implemented that for v2.
>
Indeed.
> Being (cold) booted from EFI is likely to be the most consistent case as we
> have complete control over where the kernel is placed, bar some limitations
> imposed by prior EFI applications or EFI itself.
>
>> - once we have a random number in the bootloader, we should also pass that
>> through a DT property. This has been discussed multiple times in the past
>> and I think we had reached consensus already but don't know if we had
>> agreed on a specific DT property that contains the random number seed.
>
> Any links for this? I don't recall spotting this discussion.
>
> Thanks,
> Mark.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
2016-01-03 14:50 ` Mark Rutland
(?)
@ 2016-01-04 12:21 ` Arnd Bergmann
-1 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2016-01-04 12:21 UTC (permalink / raw)
To: Mark Rutland
Cc: Ard Biesheuvel, linux-arm-kernel, kernel-hardening, Will Deacon,
Catalin Marinas, Leif Lindholm, Kees Cook, linux-kernel,
Sharma Bhupesh, Stuart Yoder
On Sunday 03 January 2016 14:50:10 Mark Rutland wrote:
>
> > - once we have a random number in the bootloader, we should also pass that
> > through a DT property. This has been discussed multiple times in the past
> > and I think we had reached consensus already but don't know if we had
> > agreed on a specific DT property that contains the random number seed.
>
> Any links for this? I don't recall spotting this discussion.
One discussion I found in the mail archives is in this thread
https://lkml.org/lkml/2014/2/12/518, I also remember discussing it in person
at some conference, obviously no archive of that.
Arnd
^ permalink raw reply [flat|nested] 45+ messages in thread
* [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2016-01-04 12:21 ` Arnd Bergmann
0 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2016-01-04 12:21 UTC (permalink / raw)
To: linux-arm-kernel
On Sunday 03 January 2016 14:50:10 Mark Rutland wrote:
>
> > - once we have a random number in the bootloader, we should also pass that
> > through a DT property. This has been discussed multiple times in the past
> > and I think we had reached consensus already but don't know if we had
> > agreed on a specific DT property that contains the random number seed.
>
> Any links for this? I don't recall spotting this discussion.
One discussion I found in the mail archives is in this thread
https://lkml.org/lkml/2014/2/12/518, I also remember discussing it in person
at some conference, obviously no archive of that.
Arnd
^ permalink raw reply [flat|nested] 45+ messages in thread
* [kernel-hardening] Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2016-01-04 12:21 ` Arnd Bergmann
0 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2016-01-04 12:21 UTC (permalink / raw)
To: Mark Rutland
Cc: Ard Biesheuvel, linux-arm-kernel, kernel-hardening, Will Deacon,
Catalin Marinas, Leif Lindholm, Kees Cook, linux-kernel,
Sharma Bhupesh, Stuart Yoder
On Sunday 03 January 2016 14:50:10 Mark Rutland wrote:
>
> > - once we have a random number in the bootloader, we should also pass that
> > through a DT property. This has been discussed multiple times in the past
> > and I think we had reached consensus already but don't know if we had
> > agreed on a specific DT property that contains the random number seed.
>
> Any links for this? I don't recall spotting this discussion.
One discussion I found in the mail archives is in this thread
https://lkml.org/lkml/2014/2/12/518, I also remember discussing it in person
at some conference, obviously no archive of that.
Arnd
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
2016-01-04 12:21 ` Arnd Bergmann
(?)
@ 2016-01-04 12:31 ` Mark Rutland
-1 siblings, 0 replies; 45+ messages in thread
From: Mark Rutland @ 2016-01-04 12:31 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Ard Biesheuvel, linux-arm-kernel, kernel-hardening, Will Deacon,
Catalin Marinas, Leif Lindholm, Kees Cook, linux-kernel,
Sharma Bhupesh, Stuart Yoder
On Mon, Jan 04, 2016 at 01:21:05PM +0100, Arnd Bergmann wrote:
> On Sunday 03 January 2016 14:50:10 Mark Rutland wrote:
> >
> > > - once we have a random number in the bootloader, we should also pass that
> > > through a DT property. This has been discussed multiple times in the past
> > > and I think we had reached consensus already but don't know if we had
> > > agreed on a specific DT property that contains the random number seed.
> >
> > Any links for this? I don't recall spotting this discussion.
>
> One discussion I found in the mail archives is in this thread
> https://lkml.org/lkml/2014/2/12/518, I also remember discussing it in person
> at some conference, obviously no archive of that.
Thanks for the pointer!
Mark.
^ permalink raw reply [flat|nested] 45+ messages in thread
* [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2016-01-04 12:31 ` Mark Rutland
0 siblings, 0 replies; 45+ messages in thread
From: Mark Rutland @ 2016-01-04 12:31 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Jan 04, 2016 at 01:21:05PM +0100, Arnd Bergmann wrote:
> On Sunday 03 January 2016 14:50:10 Mark Rutland wrote:
> >
> > > - once we have a random number in the bootloader, we should also pass that
> > > through a DT property. This has been discussed multiple times in the past
> > > and I think we had reached consensus already but don't know if we had
> > > agreed on a specific DT property that contains the random number seed.
> >
> > Any links for this? I don't recall spotting this discussion.
>
> One discussion I found in the mail archives is in this thread
> https://lkml.org/lkml/2014/2/12/518, I also remember discussing it in person
> at some conference, obviously no archive of that.
Thanks for the pointer!
Mark.
^ permalink raw reply [flat|nested] 45+ messages in thread
* [kernel-hardening] Re: [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
@ 2016-01-04 12:31 ` Mark Rutland
0 siblings, 0 replies; 45+ messages in thread
From: Mark Rutland @ 2016-01-04 12:31 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Ard Biesheuvel, linux-arm-kernel, kernel-hardening, Will Deacon,
Catalin Marinas, Leif Lindholm, Kees Cook, linux-kernel,
Sharma Bhupesh, Stuart Yoder
On Mon, Jan 04, 2016 at 01:21:05PM +0100, Arnd Bergmann wrote:
> On Sunday 03 January 2016 14:50:10 Mark Rutland wrote:
> >
> > > - once we have a random number in the bootloader, we should also pass that
> > > through a DT property. This has been discussed multiple times in the past
> > > and I think we had reached consensus already but don't know if we had
> > > agreed on a specific DT property that contains the random number seed.
> >
> > Any links for this? I don't recall spotting this discussion.
>
> One discussion I found in the mail archives is in this thread
> https://lkml.org/lkml/2014/2/12/518, I also remember discussing it in person
> at some conference, obviously no archive of that.
Thanks for the pointer!
Mark.
^ permalink raw reply [flat|nested] 45+ messages in thread
end of thread, other threads:[~2016-01-04 12:31 UTC | newest]
Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-28 11:20 [RFC PATCH 00/10] arm64: implement support for KASLR Ard Biesheuvel
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
2015-12-28 11:20 ` [RFC PATCH 01/10] arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region Ard Biesheuvel
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
2015-12-28 11:50 ` Arnd Bergmann
2015-12-28 11:50 ` [kernel-hardening] " Arnd Bergmann
2015-12-28 11:50 ` Arnd Bergmann
2015-12-28 12:07 ` Ard Biesheuvel
2015-12-28 12:07 ` [kernel-hardening] " Ard Biesheuvel
2015-12-28 12:07 ` Ard Biesheuvel
2015-12-28 14:11 ` Arnd Bergmann
2015-12-28 14:11 ` [kernel-hardening] " Arnd Bergmann
2015-12-28 14:11 ` Arnd Bergmann
2016-01-03 14:50 ` Mark Rutland
2016-01-03 14:50 ` [kernel-hardening] " Mark Rutland
2016-01-03 14:50 ` Mark Rutland
2016-01-03 15:23 ` Ard Biesheuvel
2016-01-03 15:23 ` [kernel-hardening] " Ard Biesheuvel
2016-01-03 15:23 ` Ard Biesheuvel
2016-01-04 12:21 ` Arnd Bergmann
2016-01-04 12:21 ` [kernel-hardening] " Arnd Bergmann
2016-01-04 12:21 ` Arnd Bergmann
2016-01-04 12:31 ` Mark Rutland
2016-01-04 12:31 ` [kernel-hardening] " Mark Rutland
2016-01-04 12:31 ` Mark Rutland
2015-12-28 11:20 ` [RFC PATCH 02/10] arm64: use more granular reservations for static page table allocations Ard Biesheuvel
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
2015-12-28 11:20 ` [RFC PATCH 03/10] arm64: decouple early fixmap init from linear mapping Ard Biesheuvel
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
2015-12-28 11:20 ` [RFC PATCH 04/10] arm64: move kernel image to base of vmalloc area Ard Biesheuvel
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
2015-12-28 11:20 ` [RFC PATCH 05/10] arm64: add support for module PLTs Ard Biesheuvel
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
2015-12-28 11:20 ` [RFC PATCH 06/10] arm64: use relative references in exception tables Ard Biesheuvel
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
2015-12-28 11:20 ` [RFC PATCH 07/10] arm64: use assembly time constants for Image header fields Ard Biesheuvel
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
2015-12-28 11:20 ` [RFC PATCH 08/10] arm64: avoid dynamic relocations in early boot code Ard Biesheuvel
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
2015-12-28 11:20 ` [RFC PATCH 09/10] arm64: add support for relocatable kernel Ard Biesheuvel
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
2015-12-28 11:20 ` [RFC PATCH 10/10] arm64: efi: invoke EFI_RNG_PROTOCOL to supply KASLR randomness Ard Biesheuvel
2015-12-28 11:20 ` [kernel-hardening] " Ard Biesheuvel
2015-12-28 11:28 ` [RFC PATCH 00/10] arm64: implement support for KASLR Ard Biesheuvel
2015-12-28 11:28 ` [kernel-hardening] " Ard Biesheuvel
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.