All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.