arm64: implement virtual KASLR
Subsystems (3)
cover arm64: implement virtual KASLR
At the request of Catalin, this series has been split off from my series 'arm64: implement support for KASLR v4' [1]. This sub-series deals with creating a relocatable binary, and randomizing the virtual placement of the kernel itself, the modules and the linear region based on entropy supplied by the bootloader in the /chosen/kaslr-seed DT property.
Changes since v4:
- add randomization of the linear region, i.e., if the linear region is substantially larger than the space spanned by RAM, the mapping of RAM is moved to a random offset inside the linear region.
- dropped the CRC check in kaslr_early_init(), since the only code that may modify .data through __fixmap_remap_fdt() is instrumentation that should deal with that correctly (For instance, the branch profiling records taken branches in structs allocated in .data, and these counts will not be reset to 0 between the first and the second call to __mmap_switched())
- add Mark's ack to patch #4
Patch #1 adds support for resolving cross-module branches via veneers if the module is located too far from the target. This should not be necessary in the common case even with KASRL enabled, but since the space around the kernel image will no longer be strictly reserved for modules, there is a slight chance that the region may be exhausted, in which case modules will be moved further away from the kernel (and each other)
Patches #2 and #3 deal with the fact that relocations of 64-bit values are deferred to runtime when building a PIE executable, and some values are required before the relocation routine executes (either in the code, or as an externally visible constant in the Image header)
Patch #4 rehuffles asm/elf.h so we can use its preprocessor constants in head.S
Patch #5 and #6 implement building vmlinux as a PIE (Position Independent Executable) binary, which is emitted with relocation information that is processed by the program itself in the early boot code.
Patch #7 implements KASLR, i.e., CONFIG_RANDOMIZE_BASE for the core kernel and for the module region.
Patch #8 implements KASLR for the linear region.
[1] http://thread.gmane.org/gmane.linux.kernel/2135931
Ard Biesheuvel (8):
arm64: add support for module PLTs
arm64: avoid R_AARCH64_ABS64 relocations for Image header fields
arm64: avoid dynamic relocations in early boot code
arm64: make asm/elf.h available to asm files scripts/sortextable: add support for ET_DYN binaries
arm64: add support for building vmlinux as a relocatable PIE binary
arm64: add support for kernel ASLR
arm64: kaslr: randomize the linear region
arch/arm64/Kconfig | 34 ++++ arch/arm64/Makefile | 10 +- arch/arm64/include/asm/assembler.h | 11 ++ arch/arm64/include/asm/elf.h | 24 ++- arch/arm64/include/asm/memory.h | 5 +- arch/arm64/include/asm/module.h | 11 ++ arch/arm64/kernel/Makefile | 2 + arch/arm64/kernel/efi-entry.S | 2 +- arch/arm64/kernel/head.S | 128 +++++++++++-- arch/arm64/kernel/image.h | 32 ++-- arch/arm64/kernel/kaslr.c | 143 ++++++++++++++ arch/arm64/kernel/module-plts.c | 201 ++++++++++++++++++++ arch/arm64/kernel/module.c | 20 +- arch/arm64/kernel/module.lds | 3 + arch/arm64/kernel/setup.c | 29 +++ arch/arm64/kernel/vmlinux.lds.S | 16 ++ arch/arm64/mm/init.c | 22 ++- arch/arm64/mm/mmu.c | 33 +++- scripts/sortextable.c | 8 +- 19 files changed, 672 insertions(+), 62 deletions(-) create mode 100644 arch/arm64/kernel/kaslr.c create mode 100644 arch/arm64/kernel/module-plts.c create mode 100644 arch/arm64/kernel/module.lds
Signature · 1 line
2.5.0
PATCH 1/8 arm64: add support for module PLTs
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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
---
In this version, I removed the distinction between relocations against .init executable sections and ordinary executable sections. The reason is that it is hardly worth the trouble, given that .init.text usually does not contain that many far branches, and this version now only reserves PLT entry space for jump and call relocations against undefined symbols (since symbols defined in the same module can be assumed to be within +/- 128 MB)
For example, the mac80211.ko module (which is fairly sizable at ~400 KB) built with -mcmodel=large gives the following relocation counts:
relocs branches unique !local
.text 3925 3347 518 219
.init.text 11 8 7 1 .exit.text 4 4 4 1
.text.unlikely 81 67 36 17
('unique' means branches to unique type/symbol/addend combos, of which !local is the subset referring to undefined symbols)
IOW, we are only emitting a single PLT entry for the .init sections, and we are better off just adding it to the core PLT section instead.
--- arch/arm64/Kconfig | 9 + arch/arm64/Makefile | 6 +- arch/arm64/include/asm/module.h | 11 ++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/module-plts.c | 201 ++++++++++++++++++++ arch/arm64/kernel/module.c | 12 ++ arch/arm64/kernel/module.lds | 3 + 7 files changed, 242 insertions(+), 1 deletion(-)
arch/arm64/Kconfig +9 -0
@@ -394,6 +394,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
@@ -753,6 +754,14 @@ config ARM64_LSE_ATOMICS endmenu +config ARM64_MODULE_CMODEL_LARGE + bool + +config ARM64_MODULE_PLTS + bool + select ARM64_MODULE_CMODEL_LARGE + select HAVE_MOD_ARCH_SPECIFIC + endmenu menu "Boot options"
arch/arm64/Makefile +5 -1
@@ -43,10 +43,14 @@ endif CHECKFLAGS += -D__aarch64__ -ifeq ($(CONFIG_ARM64_ERRATUM_843419), y) +ifeq ($(CONFIG_ARM64_MODULE_CMODEL_LARGE), 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
arch/arm64/include/asm/module.h +11 -0
@@ -20,4 +20,15 @@#define MODULE_ARCH_VERMAGIC "aarch64" +#ifdef CONFIG_ARM64_MODULE_PLTS +struct mod_arch_specific { +struct elf64_shdr *plt; +int plt_num_entries; +int plt_max_entries; +}; +#endif + +u64 module_emit_plt_entry (struct module *mod,const Elf64_Rela *rela, +Elf64_Sym *sym); +#endif /* __ASM_MODULE_H */
arch/arm64/kernel/Makefile +1 -0
@@ -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
arch/arm64/kernel/module-plts.c new file +201 -0
201 lines not on this page · raw message
arch/arm64/kernel/module.c +12 -0
@@ -38,6 +38,11 @@ void *module_alloc(unsigned long size)GFP_KERNEL ,PAGE_KERNEL_EXEC ,0 , NUMA_NO_NODE, __builtin_return_address(0)); +if (!p &&IS_ENABLED (CONFIG_ARM64_MODULE_PLTS )) + p =__vmalloc_node_range (size,MODULE_ALIGN ,VMALLOC_START , +VMALLOC_END ,GFP_KERNEL ,PAGE_KERNEL_EXEC ,0 , +NUMA_NO_NODE ,__builtin_return_address (0 )); +if (p && (kasan_module_alloc (p, size) <0 )) {vfree (p);return NULL ;
@@ -361,6 +366,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 =module_emit_plt_entry (me, &rel[i], sym); + ovf =reloc_insn_imm (RELOC_OP_PREL , loc, val,2 , +26 ,AARCH64_INSN_IMM_26 ); + }break ;default :
arch/arm64/kernel/module.lds new file +3 -0
@@ -0,0 +1,3 @@ +SECTIONS { + .plt (NOLOAD) : { BYTE(0) } +}
Signature · 1 line
2.5.0
Catalin Marinas
maintainerPATCH 1/8 arm64: add support for module PLTs
Quoted 5 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Any downside to trying to keep the kernel+modules coupled together so that we avoid the PLT?
Signature · 1 line
Catalin
PATCH 1/8 arm64: add support for module PLTs
Quoted 10 lines · Catalin Marinas
Quoted 5 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Any downside to trying to keep the kernel+modules coupled together so that we avoid the PLT?
First of all, note that it is unlikely that the PLTs are ever required in practice, considering that either
a) the kernel is loaded at the default location right at the base of the vmalloc range, and in this case, the module space is reserved for modules only, or
b) the kernel is loaded at some random offset in the 240+ GB vmalloc space, and it is unlikely that all VMA space around the kernel happens to be given out to non-randomized vmalloc/ioremap allocations
So while this patch was a requirement at first (since in the first version of the series, the modules always remained below the vmalloc area so they would always be out of range when KASLR was enabled), in the current series, it is simply a last resort (although still required) to make sure that modules can be loaded far away from the kernel in the unlikely event that all VMA space in close proximity is given to another user.
Reserving a dedicated module region around the kernel while it is loaded at a random offset is not straight forward, since it affects all other users of the vmalloc area. So generic vmalloc/vmap/ioremap code would need to be updated to disregard the area around the kernel, since simply reserving the VMA area for the modules would make it inaccessible to module_alloc() as well (unless we reserve the whole region and manage the module allocations separately)
So the bottom line is that it may be possible, but it is unlikely to be worth the effort imo
Signature · 1 line
Ard.
Catalin Marinas
maintainerPATCH 1/8 arm64: add support for module PLTs
Quoted 11 lines · Ard Biesheuvel
Quoted 9 lines · Catalin Marinas
Quoted 5 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Any downside to trying to keep the kernel+modules coupled together so that we avoid the PLT?
Quoted 8 lines
First of all, note that it is unlikely that the PLTs are ever required in practice, considering that either
a) the kernel is loaded at the default location right at the base of the vmalloc range, and in this case, the module space is reserved for modules only, or
b) the kernel is loaded at some random offset in the 240+ GB vmalloc space, and it is unlikely that all VMA space around the kernel happens to be given out to non-randomized vmalloc/ioremap allocations
My worry is that we merge some code that's rarely tested.
Quoted 2 lines
So the bottom line is that it may be possible, but it is unlikely to be worth the effort imo
The alternative of having our own allocator for modules isn't that appealing either, so let's stick with the PLTs.
Signature · 1 line
Catalin
PATCH 1/8 arm64: add support for module PLTs
Quoted 21 lines · Catalin Marinas
Quoted 11 lines · Ard Biesheuvel
Quoted 9 lines · Catalin Marinas
Quoted 5 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Any downside to trying to keep the kernel+modules coupled together so that we avoid the PLT?
Quoted 8 lines
First of all, note that it is unlikely that the PLTs are ever required in practice, considering that either
a) the kernel is loaded at the default location right at the base of the vmalloc range, and in this case, the module space is reserved for modules only, or
b) the kernel is loaded at some random offset in the 240+ GB vmalloc space, and it is unlikely that all VMA space around the kernel happens to be given out to non-randomized vmalloc/ioremap allocations
Quoted 2 lines
My worry is that we merge some code that's rarely tested.
I understand. But unfortunately, having corner cases that are unlikely but not impossible comes with the territory of randomization.
Alternatively, we could take the performance hit if KASLR is in effect and allocate each module completely randomly as well. This way, the code is always exercised (for now), and we can always backpedal later if the performance is measurably worse.
Quoted 8 lines
Quoted 2 lines
So the bottom line is that it may be possible, but it is unlikely to be worth the effort imo
The alternative of having our own allocator for modules isn't that appealing either, so let's stick with the PLTs.
--
Catalin
Catalin Marinas
maintainerPATCH 1/8 arm64: add support for module PLTs
Quoted 24 lines · Ard Biesheuvel
Quoted 21 lines · Catalin Marinas
Quoted 11 lines · Ard Biesheuvel
Quoted 9 lines · Catalin Marinas
Quoted 5 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Any downside to trying to keep the kernel+modules coupled together so that we avoid the PLT?
Quoted 8 lines
First of all, note that it is unlikely that the PLTs are ever required in practice, considering that either
a) the kernel is loaded at the default location right at the base of the vmalloc range, and in this case, the module space is reserved for modules only, or
b) the kernel is loaded at some random offset in the 240+ GB vmalloc space, and it is unlikely that all VMA space around the kernel happens to be given out to non-randomized vmalloc/ioremap allocationsQuoted 1 line
My worry is that we merge some code that's rarely tested.
Quoted 7 lines
I understand. But unfortunately, having corner cases that are unlikely but not impossible comes with the territory of randomization.
Alternatively, we could take the performance hit if KASLR is in effect and allocate each module completely randomly as well. This way, the code is always exercised (for now), and we can always backpedal later if the performance is measurably worse.
I'm fine with this. You can post it as a separate patch that we can easily revert/modify later (like turning it into a config option).
Signature · 1 line
Catalin
PATCH 1/8 arm64: add support for module PLTs
Quoted 28 lines · Catalin Marinas
Quoted 27 lines · Ard Biesheuvel
Quoted 21 lines · Catalin Marinas
Quoted 11 lines · Ard Biesheuvel
Quoted 9 lines · Catalin Marinas
Quoted 5 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Any downside to trying to keep the kernel+modules coupled together so that we avoid the PLT?
Quoted 8 lines
First of all, note that it is unlikely that the PLTs are ever required in practice, considering that either
a) the kernel is loaded at the default location right at the base of the vmalloc range, and in this case, the module space is reserved for modules only, or
b) the kernel is loaded at some random offset in the 240+ GB vmalloc space, and it is unlikely that all VMA space around the kernel happens to be given out to non-randomized vmalloc/ioremap allocationsQuoted 1 line
My worry is that we merge some code that's rarely tested.
I understand. But unfortunately, having corner cases that are unlikely but not impossible comes with the territory of randomization.
Quoted 8 lines
Quoted 4 lines
Alternatively, we could take the performance hit if KASLR is in effect and allocate each module completely randomly as well. This way, the code is always exercised (for now), and we can always backpedal later if the performance is measurably worse.
I'm fine with this. You can post it as a separate patch that we can easily revert/modify later (like turning it into a config option).
OK, I will hack something up
Catalin Marinas
maintainerPATCH 1/8 arm64: add support for module PLTs
Quoted 34 lines · Ard Biesheuvel
Quoted 33 lines · Catalin Marinas
Quoted 31 lines · Ard Biesheuvel
Quoted 21 lines · Catalin Marinas
Quoted 11 lines · Ard Biesheuvel
Quoted 9 lines · Catalin Marinas
Quoted 5 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Any downside to trying to keep the kernel+modules coupled together so that we avoid the PLT?
Quoted 8 lines
First of all, note that it is unlikely that the PLTs are ever required in practice, considering that either
a) the kernel is loaded at the default location right at the base of the vmalloc range, and in this case, the module space is reserved for modules only, or
b) the kernel is loaded at some random offset in the 240+ GB vmalloc space, and it is unlikely that all VMA space around the kernel happens to be given out to non-randomized vmalloc/ioremap allocationsQuoted 1 line
My worry is that we merge some code that's rarely tested.
I understand. But unfortunately, having corner cases that are unlikely but not impossible comes with the territory of randomization.
Alternatively, we could take the performance hit if KASLR is in effect and allocate each module completely randomly as well. This way, the code is always exercised (for now), and we can always backpedal later if the performance is measurably worse.
Quoted 4 lines
Quoted 2 lines
I'm fine with this. You can post it as a separate patch that we can easily revert/modify later (like turning it into a config option).
OK, I will hack something up
If it's simpler, you can just add a config option but defaulting to the full vmalloc space for modules.
Signature · 1 line
Catalin
PATCH 1/8 arm64: add support for module PLTs
Quoted 35 lines · Catalin Marinas
Quoted 34 lines · Ard Biesheuvel
Quoted 33 lines · Catalin Marinas
Quoted 31 lines · Ard Biesheuvel
Quoted 21 lines · Catalin Marinas
Quoted 11 lines · Ard Biesheuvel
Quoted 9 lines · Catalin Marinas
Quoted 5 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Any downside to trying to keep the kernel+modules coupled together so that we avoid the PLT?
Quoted 8 lines
First of all, note that it is unlikely that the PLTs are ever required in practice, considering that either
a) the kernel is loaded at the default location right at the base of the vmalloc range, and in this case, the module space is reserved for modules only, or
b) the kernel is loaded at some random offset in the 240+ GB vmalloc space, and it is unlikely that all VMA space around the kernel happens to be given out to non-randomized vmalloc/ioremap allocationsQuoted 1 line
My worry is that we merge some code that's rarely tested.
I understand. But unfortunately, having corner cases that are unlikely but not impossible comes with the territory of randomization.
Alternatively, we could take the performance hit if KASLR is in effect and allocate each module completely randomly as well. This way, the code is always exercised (for now), and we can always backpedal later if the performance is measurably worse.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
I'm fine with this. You can post it as a separate patch that we can easily revert/modify later (like turning it into a config option).
OK, I will hack something up
If it's simpler, you can just add a config option but defaulting to the full vmalloc space for modules.
What would be the simplest is to randomize the 128 MB module region as a whole, and either put it close to the kernel (which is what I am doing now), or put it at a random offset inside the vmalloc space, in which case all branches will be resolved via PLTs. My suggestion to randomize each module_alloc() call separately is actually not that straight-forward.
So what I propose now is to keep a single module_load_offset that randomizes the base of the region, and add a default-n config option that shrinks the interval it is chosen from so that PLTs are usually not needed.
Signature · 1 line
Ard.
Catalin Marinas
maintainerPATCH 1/8 arm64: add support for module PLTs
Quoted 51 lines · Ard Biesheuvel
Quoted 35 lines · Catalin Marinas
Quoted 34 lines · Ard Biesheuvel
Quoted 33 lines · Catalin Marinas
Quoted 31 lines · Ard Biesheuvel
Quoted 21 lines · Catalin Marinas
Quoted 11 lines · Ard Biesheuvel
Quoted 9 lines · Catalin Marinas
Quoted 5 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Any downside to trying to keep the kernel+modules coupled together so that we avoid the PLT?
Quoted 8 lines
First of all, note that it is unlikely that the PLTs are ever required in practice, considering that either
a) the kernel is loaded at the default location right at the base of the vmalloc range, and in this case, the module space is reserved for modules only, or
b) the kernel is loaded at some random offset in the 240+ GB vmalloc space, and it is unlikely that all VMA space around the kernel happens to be given out to non-randomized vmalloc/ioremap allocationsQuoted 1 line
My worry is that we merge some code that's rarely tested.
I understand. But unfortunately, having corner cases that are unlikely but not impossible comes with the territory of randomization.
Alternatively, we could take the performance hit if KASLR is in effect and allocate each module completely randomly as well. This way, the code is always exercised (for now), and we can always backpedal later if the performance is measurably worse.
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
I'm fine with this. You can post it as a separate patch that we can easily revert/modify later (like turning it into a config option).
OK, I will hack something up
If it's simpler, you can just add a config option but defaulting to the full vmalloc space for modules.
What would be the simplest is to randomize the 128 MB module region as a whole, and either put it close to the kernel (which is what I am doing now), or put it at a random offset inside the vmalloc space, in which case all branches will be resolved via PLTs. My suggestion to randomize each
module_alloc()call separately is actually not that straight-forward.
Quoted 4 lines
So what I propose now is to keep a single
module_load_offsetthat randomizes the base of the region, and add a default-n config option that shrinks the interval it is chosen from so that PLTs are usually not needed.
Sounds fine.
Signature · 1 line
Catalin
PATCH 1/8 arm64: add support for module PLTs
In reply to Ard BiesheuvelQuoted 45 lines · Ard Biesheuvel
Quoted 35 lines · Catalin Marinas
Quoted 34 lines · Ard Biesheuvel
Quoted 33 lines · Catalin Marinas
Quoted 31 lines · Ard Biesheuvel
Quoted 21 lines · Catalin Marinas
Quoted 11 lines · Ard Biesheuvel
Quoted 9 lines · Catalin Marinas
Quoted 5 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Any downside to trying to keep the kernel+modules coupled together so that we avoid the PLT?
Quoted 8 lines
First of all, note that it is unlikely that the PLTs are ever required in practice, considering that either
a) the kernel is loaded at the default location right at the base of the vmalloc range, and in this case, the module space is reserved for modules only, or
b) the kernel is loaded at some random offset in the 240+ GB vmalloc space, and it is unlikely that all VMA space around the kernel happens to be given out to non-randomized vmalloc/ioremap allocationsQuoted 1 line
My worry is that we merge some code that's rarely tested.
I understand. But unfortunately, having corner cases that are unlikely but not impossible comes with the territory of randomization.
Alternatively, we could take the performance hit if KASLR is in effect and allocate each module completely randomly as well. This way, the code is always exercised (for now), and we can always backpedal later if the performance is measurably worse.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
I'm fine with this. You can post it as a separate patch that we can easily revert/modify later (like turning it into a config option).
OK, I will hack something up
If it's simpler, you can just add a config option but defaulting to the full vmalloc space for modules.
Quoted 6 lines
What would be the simplest is to randomize the 128 MB module region as a whole, and either put it close to the kernel (which is what I am doing now), or put it at a random offset inside the vmalloc space, in which case all branches will be resolved via PLTs. My suggestion to randomize each
module_alloc()call separately is actually not that straight-forward.
FWIW, it also turns out that this ends up not being very random in a limited address range. It ends up turning into a greedy-allocation hole-filling routine, and for a given system ends up being pretty deterministic.
-Kees
Signature · 2 lines
Kees Cook Chrome OS & Brillo Security
PATCH 1/1 arm64: allow the module region to be randomized independently
This patch applies directly onto '[PATCH v5sub2 7/8] arm64: add support for kernel ASLR' so it can be folded in or applied separately, as desired.
As pointed out by Kees, fully randomizing each module allocation does not add anything in terms of security, and only hurts performance even more, since it would cause all inter-module branches to be resolved via veneers as well.
----------8<--------------
This adds the option to randomize the module region independently from the core kernel, and enables it by default. This makes it less likely that the location of core kernel data structures can be determined by an adversary, but causes all function calls from modules into the core kernel to be resolved via entries in the module PLTs.
--- arch/arm64/Kconfig | 15 ++++++++ arch/arm64/include/asm/module.h | 6 ++++ arch/arm64/kernel/kaslr.c | 36 +++++++++++++++----- arch/arm64/kernel/module.c | 9 ++--- 4 files changed, 50 insertions(+), 16 deletions(-)
arch/arm64/Kconfig +15 -0
@@ -787,6 +787,21 @@ config RANDOMIZE_BASE If unsure, say N. +config RANDOMIZE_MODULE_REGION_FULL + bool "Randomize the module region independently from the core kernel" + depends on RANDOMIZE_BASE + default y + help + Randomizes the location of the module region without considering the + location of the core kernel. This way, it is impossible for modules + to leak information about the location of core kernel data structures + but it does imply that function calls between modules and the core + kernel will need to be resolved via veneers in the module PLT. + + When this option is not set, the module region will be randomized over + a limited range that contains the [_stext, _etext] interval of the + core kernel, so branch relocations are always in range. + endmenu menu "Boot options"
arch/arm64/include/asm/module.h +6 -0
@@ -31,4 +31,10 @@ struct mod_arch_specific {u64 module_emit_plt_entry (struct module *mod,const Elf64_Rela *rela,Elf64_Sym *sym); +#ifdef CONFIG_RANDOMIZE_BASE +extern u64 module_alloc_base; +#else +#define module_alloc_base ((u64)_etext - MODULES_VSIZE) +#endif +#endif /* __ASM_MODULE_H */
arch/arm64/kernel/kaslr.c +27 -9
@@ -20,7 +20,7 @@#include <asm/pgtable.h> #include <asm/sections.h> -u32 __read_mostly module_load_offset; +u64 __read_mostly module_alloc_base;static __init u64 get_kaslr_seed (void *fdt) {
@@ -126,14 +126,32 @@ u64 __init kaslr_early_init(u64 dt_phys) (((u64)_end + offset) >> SWAPPER_TABLE_SHIFT)) offset = (offset + (u64)(_end - _text)) & mask; -/* -* Randomize the module region, by setting module_load_offset to -* a PAGE_SIZE multiple in the interval [0, module_range). This -* ensures that the resulting region still covers [_stext, _etext], -* and that all relative branches can be resolved without veneers. -*/ - module_range =MODULES_VSIZE - (u64)(_etext - _stext); - module_load_offset = ((module_range * (u16 )seed) >>16 ) &PAGE_MASK ; +if (IS_ENABLED (CONFIG_RANDOMIZE_MODULE_REGION_FULL )) { +/* +* Randomize the module region independently from the core +* kernel. This prevents modules from leaking any information +* about the address of the kernel itself, but results in +* branches between modules and the core kernel that are +* resolved via PLTs. (Branches between modules will be +* resolved normally.) +*/ + module_range =VMALLOC_END -VMALLOC_START -MODULES_VSIZE ; + module_alloc_base =VMALLOC_START ; + }else { +/* +* Randomize the module region by setting module_alloc_base to +* a PAGE_SIZE multiple in the range [_etext - MODULES_VSIZE, +* _stext) . This guarantees that the resulting region still +* covers [_stext, _etext], and that all relative branches can +* be resolved without veneers. +*/ + module_range =MODULES_VSIZE - (u64)(_etext - _stext); + module_alloc_base = (u64 )_etext + offset -MODULES_VSIZE ; + } + +/* use the lower 21 bits to randomize the base of the module region */ + module_alloc_base += (module_range * (seed & ((1 <<21 ) -1 ))) >>21 ; + module_alloc_base &=PAGE_MASK ;return offset; }
arch/arm64/kernel/module.c +2 -7
@@ -33,14 +33,9 @@void *module_alloc (unsigned long size) {void *p; -u64 base = (u64 )_etext -MODULES_VSIZE ; -if (IS_ENABLED (CONFIG_RANDOMIZE_BASE )) { -extern u32 module_load_offset; - base += module_load_offset; - } - - p =__vmalloc_node_range (size,MODULE_ALIGN , base, base +MODULES_VSIZE , + p =__vmalloc_node_range (size,MODULE_ALIGN , module_alloc_base, + module_alloc_base +MODULES_VSIZE ,GFP_KERNEL ,PAGE_KERNEL_EXEC ,0 ,NUMA_NO_NODE ,__builtin_return_address (0 ));
Signature · 1 line
2.5.0
Catalin Marinas
maintainerPATCH 1/1 arm64: allow the module region to be randomized independently
Quoted 6 lines · Ard Biesheuvel
This adds the option to randomize the module region independently from the core kernel, and enables it by default. This makes it less likely that the location of core kernel data structures can be determined by an adversary, but causes all function calls from modules into the core kernel to be resolved via entries in the module PLTs.
Quoted 7 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/Kconfig | 15 ++++++++ arch/arm64/include/asm/module.h | 6 ++++ arch/arm64/kernel/kaslr.c | 36 +++++++++++++++----- arch/arm64/kernel/module.c | 9 ++--- 4 files changed, 50 insertions(+), 16 deletions(-)
With this patch I get an unhandled paging request, coming from kernel/module.c:2982 (the memset). The PC is wrongly attributed but it's in arch/arm64/lib/memset.S:
[ 7.140606] Unable to handle kernel paging request at virtual address 00004000 [ 7.147794] pgd = ffffffc060171000 [ 7.151190] [00004000] *pgd=0000000000000000, *pud=0000000000000000 [ 7.157447] Internal error: Oops: 96000045 [#1] PREEMPT SMP [ 7.162962] Modules linked in: [ 7.165995] CPU: 1 PID: 875 Comm: systemd-modules Not tainted 4.5.0-rc1+ #95 [ 7.172976] Hardware name: Juno (DT) [ 7.176520] task: ffffffc9760bb000 ti: ffffffc079538000 task.ti: ffffffc079538000 [ 7.183939] PC is at __efistub_memset+0x1ac/0x200 [ 7.188601] LR is at load_module+0xfc8/0x1df8 [ 7.192912] pc : [<ffffff8008336fac>] lr : [<ffffff8008120d88>] pstate: 40000145 [ 7.200233] sp : ffffffc07953bd40 [ 7.203514] x29: ffffffc07953bd40 x28: 0000000000002361 [ 7.208791] x27: ffffff80086bb000 x26: ffffff8008f84aa0 [ 7.214054] x25: 0000000000000111 x24: 000000000000006e [ 7.219317] x23: 0000007f7bc01918 x22: ffffff8008f0e100 [ 7.224580] x21: ffffff8008f4d2c0 x20: 0000000000004000 [ 7.229855] x19: ffffffc07953be70 x18: 0000000000000000 [ 7.235127] x17: 0000000000000000 x16: 0000000000000002 [ 7.240398] x15: ffffffffffffffff x14: ffffff0000000000 [ 7.245667] x13: ffffffbdc3e55340 x12: 0000000000006fff [ 7.250934] x11: ffffffc97fed46a8 x10: 0000000000000010 [ 7.256198] x9 : 0000000000000000 x8 : 0000000000004000 [ 7.261462] x7 : 0000000000000000 x6 : 000000000000003f [ 7.266823] x5 : 0000000000000040 x4 : 0000000000000000 [ 7.271219] systemd-journald[864]: Received request to flush runtime journal from PID 1
[ 7.279835] [ 7.281487] x3 : 0000000000000004 x2 : 000000000000229e [ 7.286758] x1 : 0000000000000000 x0 : 0000000000004000 [ 7.292019] [ 7.293495] Process systemd-modules (pid: 875, stack limit = 0xffffffc079538020) [ 7.300822] Stack: (0xffffffc07953bd40 to 0xffffffc07953c000) [ 7.306522] bd40: ffffffc07953be40 ffffff8008121de0 0000000000000000 0000000000000005 [ 7.314276] bd60: 0000007f7bc01918 0000007f7bb24ad4 0000000080000000 0000000000000015 [ 7.322029] bd80: 000000000000011e 0000000000000111 ffffff80086b0000 ffffffc079538000 [ 7.329781] bda0: 0000000000000000 0000000000000005 0000007f7bc01918 0000007f7bb24ad4 [ 7.337536] bdc0: ffffff8008f0e288 ffffff8008f84ae0 ffffff8008f0e2d8 ffffff8008f0d000 [ 7.345288] bde0: ffff81a40000000f 0000000000000001 0000000000000000 0000000000077b20 [ 7.353041] be00: 0000000056b8d7f8 00000000134c2b98 0000000056b8d7f8 000000001163e398 [ 7.360793] be20: 0000000056b8d7f8 000000001163e398 0000000000001000 00000000000003c0 [ 7.368545] be40: 0000000000000000 ffffff8008085d30 0000000000000000 0000000000000000 [ 7.376298] be60: ffffffffffffffff 0000005571c2aa60 ffffff8008f0d000 0000000000077b20 [ 7.384051] be80: ffffff8008f84120 ffffff8008f4b7af ffffff8008f4d2c0 0000000000001388 [ 7.391803] bea0: 0000000000001dd8 0000000000000000 0000000000000000 0000002700000026 [ 7.399555] bec0: 0000000000000011 000000000000000b 0000000000000005 0000007f7bc01918 [ 7.407307] bee0: 0000000000000000 0000000000000005 0000000000000000 60ceffffffffffff [ 7.415060] bf00: ffffffffffffffff ffffffffffffffff 0000000000000111 0000000000000038 [ 7.422812] bf20: 0101010101010101 0000000000000001 0000000000000000 ffffffffffff0000 [ 7.430565] bf40: 0000007f7bc43000 0000007f7ba626b8 0000007f7bb24ab0 0000007f7bc132d8 [ 7.438317] bf60: 0000005565850710 0000005571c2a8a0 0000000000000000 0000007f7bc01918 [ 7.446069] bf80: 0000005571c2a920 0000000000020000 0000000000000000 0000000000000000 [ 7.453821] bfa0: 0000005571c29330 0000000000000000 0000000000000000 0000007ff3bc1e80 [ 7.461575] bfc0: 0000007f7bbfa1ac 0000007ff3bc1e80 0000007f7bb24ad4 0000000080000000 [ 7.469327] bfe0: 0000000000000005 0000000000000111 f712e45f3fdb5baf 5d70fcf3d73b5fa3 [ 7.477075] Call trace: [ 7.479494] Exception stack(0xffffffc07953bb80 to 0xffffffc07953bca0) [ 7.485871] bb80: ffffffc07953be70 0000000000004000 ffffffc07953bd40 ffffff8008336fac [ 7.493624] bba0: 0000000000400000 00000000024000c0 ffffffc975853300 00c8000000000713 [ 7.501376] bbc0: ffffff80086bb000 0000000000002361 0000000000004000 0000000000000000 [ 7.509128] bbe0: ffffffc07953bc60 ffffff80081885d8 ffffffc07953bca0 ffffff8008187fb8 [ 7.516880] bc00: 0000000000000003 ffffffc975853480 00000000ffffffff 00000000024002c0 [ 7.524631] bc20: 0000000000004000 0000000000000000 000000000000229e 0000000000000004 [ 7.532383] bc40: 0000000000000000 0000000000000040 000000000000003f 0000000000000000 [ 7.540135] bc60: 0000000000004000 0000000000000000 0000000000000010 ffffffc97fed46a8 [ 7.547888] bc80: 0000000000006fff ffffffbdc3e55340 ffffff0000000000 ffffffffffffffff [ 7.555646] [<ffffff8008336fac>] __efistub_memset+0x1ac/0x200 [ 7.561334] [<ffffff8008121de0>] SyS_finit_module+0xb0/0xc0 [ 7.566852] [<ffffff8008085d30>] el0_svc_naked+0x24/0x28 [ 7.572112] Code: 91010108 54ffff4a 8b040108 cb050042 (d50b7428) [ 7.578196] ---[ end trace 13bd770b734da68a ]---
Signature · 1 line
Catalin
PATCH 1/1 arm64: allow the module region to be randomized independently
Quoted 15 lines · Catalin Marinas
Quoted 6 lines · Ard Biesheuvel
This adds the option to randomize the module region independently from the core kernel, and enables it by default. This makes it less likely that the location of core kernel data structures can be determined by an adversary, but causes all function calls from modules into the core kernel to be resolved via entries in the module PLTs.
Quoted 7 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/Kconfig | 15 ++++++++ arch/arm64/include/asm/module.h | 6 ++++ arch/arm64/kernel/kaslr.c | 36 +++++++++++++++----- arch/arm64/kernel/module.c | 9 ++--- 4 files changed, 50 insertions(+), 16 deletions(-)
Quoted 4 lines
With this patch I get an unhandled paging request, coming from
kernel/module.c:2982(the memset). The PC is wrongly attributed but it's inarch/arm64/lib/memset.S:
That is quite surprising tbh. The only thing that is supposed to happen here is that the low and high limits of the __vmalloc_node_range() call in module_alloc() are modified. I don't see how a successful __vmalloc_node_range() call should end up here.
I will try to reproduce tomorrow.
Signature · 1 line
Ard.
Quoted 73 lines
[ 7.140606] Unable to handle kernel paging request at virtual address 00004000 [ 7.147794] pgd = ffffffc060171000 [ 7.151190] [00004000] *pgd=0000000000000000, *pud=0000000000000000 [ 7.157447] Internal error: Oops: 96000045 [#1] PREEMPT SMP [ 7.162962] Modules linked in: [ 7.165995] CPU: 1 PID: 875 Comm: systemd-modules Not tainted 4.5.0-rc1+ #95 [ 7.172976] Hardware name: Juno (DT) [ 7.176520] task: ffffffc9760bb000 ti: ffffffc079538000 task.ti: ffffffc079538000 [ 7.183939] PC is at __efistub_memset+0x1ac/0x200 [ 7.188601] LR is at load_module+0xfc8/0x1df8 [ 7.192912] pc : [<ffffff8008336fac>] lr : [<ffffff8008120d88>] pstate: 40000145 [ 7.200233] sp : ffffffc07953bd40 [ 7.203514] x29: ffffffc07953bd40 x28: 0000000000002361 [ 7.208791] x27: ffffff80086bb000 x26: ffffff8008f84aa0 [ 7.214054] x25: 0000000000000111 x24: 000000000000006e [ 7.219317] x23: 0000007f7bc01918 x22: ffffff8008f0e100 [ 7.224580] x21: ffffff8008f4d2c0 x20: 0000000000004000 [ 7.229855] x19: ffffffc07953be70 x18: 0000000000000000 [ 7.235127] x17: 0000000000000000 x16: 0000000000000002 [ 7.240398] x15: ffffffffffffffff x14: ffffff0000000000 [ 7.245667] x13: ffffffbdc3e55340 x12: 0000000000006fff [ 7.250934] x11: ffffffc97fed46a8 x10: 0000000000000010 [ 7.256198] x9 : 0000000000000000 x8 : 0000000000004000 [ 7.261462] x7 : 0000000000000000 x6 : 000000000000003f [ 7.266823] x5 : 0000000000000040 x4 : 0000000000000000 [ 7.271219] systemd-journald[864]: Received request to flush runtime journal from PID 1[ 7.279835] [ 7.281487] x3 : 0000000000000004 x2 : 000000000000229e [ 7.286758] x1 : 0000000000000000 x0 : 0000000000004000 [ 7.292019] [ 7.293495] Process systemd-modules (pid: 875, stack limit = 0xffffffc079538020) [ 7.300822] Stack: (0xffffffc07953bd40 to 0xffffffc07953c000) [ 7.306522] bd40: ffffffc07953be40 ffffff8008121de0 0000000000000000 0000000000000005 [ 7.314276] bd60: 0000007f7bc01918 0000007f7bb24ad4 0000000080000000 0000000000000015 [ 7.322029] bd80: 000000000000011e 0000000000000111 ffffff80086b0000 ffffffc079538000 [ 7.329781] bda0: 0000000000000000 0000000000000005 0000007f7bc01918 0000007f7bb24ad4 [ 7.337536] bdc0: ffffff8008f0e288 ffffff8008f84ae0 ffffff8008f0e2d8 ffffff8008f0d000 [ 7.345288] bde0: ffff81a40000000f 0000000000000001 0000000000000000 0000000000077b20 [ 7.353041] be00: 0000000056b8d7f8 00000000134c2b98 0000000056b8d7f8 000000001163e398 [ 7.360793] be20: 0000000056b8d7f8 000000001163e398 0000000000001000 00000000000003c0 [ 7.368545] be40: 0000000000000000 ffffff8008085d30 0000000000000000 0000000000000000 [ 7.376298] be60: ffffffffffffffff 0000005571c2aa60 ffffff8008f0d000 0000000000077b20 [ 7.384051] be80: ffffff8008f84120 ffffff8008f4b7af ffffff8008f4d2c0 0000000000001388 [ 7.391803] bea0: 0000000000001dd8 0000000000000000 0000000000000000 0000002700000026 [ 7.399555] bec0: 0000000000000011 000000000000000b 0000000000000005 0000007f7bc01918 [ 7.407307] bee0: 0000000000000000 0000000000000005 0000000000000000 60ceffffffffffff [ 7.415060] bf00: ffffffffffffffff ffffffffffffffff 0000000000000111 0000000000000038 [ 7.422812] bf20: 0101010101010101 0000000000000001 0000000000000000 ffffffffffff0000 [ 7.430565] bf40: 0000007f7bc43000 0000007f7ba626b8 0000007f7bb24ab0 0000007f7bc132d8 [ 7.438317] bf60: 0000005565850710 0000005571c2a8a0 0000000000000000 0000007f7bc01918 [ 7.446069] bf80: 0000005571c2a920 0000000000020000 0000000000000000 0000000000000000 [ 7.453821] bfa0: 0000005571c29330 0000000000000000 0000000000000000 0000007ff3bc1e80 [ 7.461575] bfc0: 0000007f7bbfa1ac 0000007ff3bc1e80 0000007f7bb24ad4 0000000080000000 [ 7.469327] bfe0: 0000000000000005 0000000000000111 f712e45f3fdb5baf 5d70fcf3d73b5fa3 [ 7.477075] Call trace: [ 7.479494] Exception stack(0xffffffc07953bb80 to 0xffffffc07953bca0) [ 7.485871] bb80: ffffffc07953be70 0000000000004000 ffffffc07953bd40 ffffff8008336fac [ 7.493624] bba0: 0000000000400000 00000000024000c0 ffffffc975853300 00c8000000000713 [ 7.501376] bbc0: ffffff80086bb000 0000000000002361 0000000000004000 0000000000000000 [ 7.509128] bbe0: ffffffc07953bc60 ffffff80081885d8 ffffffc07953bca0 ffffff8008187fb8 [ 7.516880] bc00: 0000000000000003 ffffffc975853480 00000000ffffffff 00000000024002c0 [ 7.524631] bc20: 0000000000004000 0000000000000000 000000000000229e 0000000000000004 [ 7.532383] bc40: 0000000000000000 0000000000000040 000000000000003f 0000000000000000 [ 7.540135] bc60: 0000000000004000 0000000000000000 0000000000000010 ffffffc97fed46a8 [ 7.547888] bc80: 0000000000006fff ffffffbdc3e55340 ffffff0000000000 ffffffffffffffff [ 7.555646] [<ffffff8008336fac>] __efistub_memset+0x1ac/0x200 [ 7.561334] [<ffffff8008121de0>] SyS_finit_module+0xb0/0xc0 [ 7.566852] [<ffffff8008085d30>] el0_svc_naked+0x24/0x28 [ 7.572112] Code: 91010108 54ffff4a 8b040108 cb050042 (d50b7428) [ 7.578196] ---[ end trace 13bd770b734da68a ]-----
Catalin
PATCH 1/1 arm64: allow the module region to be randomized independently
In reply to Catalin MarinasQuoted 15 lines · Catalin Marinas
Quoted 6 lines · Ard Biesheuvel
This adds the option to randomize the module region independently from the core kernel, and enables it by default. This makes it less likely that the location of core kernel data structures can be determined by an adversary, but causes all function calls from modules into the core kernel to be resolved via entries in the module PLTs.
Quoted 7 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/Kconfig | 15 ++++++++ arch/arm64/include/asm/module.h | 6 ++++ arch/arm64/kernel/kaslr.c | 36 +++++++++++++++----- arch/arm64/kernel/module.c | 9 ++--- 4 files changed, 50 insertions(+), 16 deletions(-)
Quoted 4 lines
With this patch I get an unhandled paging request, coming from
kernel/module.c:2982(the memset). The PC is wrongly attributed but it's inarch/arm64/lib/memset.S:
This was due to a thinko in kaslr_early_init(). Folding the following hunk will fix it (or I can resend the patch if you prefer)
-------8<----------
arch/arm64/kernel/kaslr.c +6 -0
@@ -82,6 +82,12 @@ u64 __init kaslr_early_init(u64 dt_phys)int size;/* +* Set a reasonable default for module_alloc_base in case +* we end up running with KASLR disabled. +*/ + module_alloc_base = (u64 )_etext -MODULES_VSIZE ; + +/* * Try to map the FDT early. If this fails, we simply bail, * and proceed with KASLR disabled. We will make another * attempt@mapping the FDT in setup_machine()
-------8<----------
Catalin Marinas
maintainerPATCH 1/1 arm64: allow the module region to be randomized independently
Quoted 33 lines · Ard Biesheuvel
Quoted 15 lines · Catalin Marinas
Quoted 6 lines · Ard Biesheuvel
This adds the option to randomize the module region independently from the core kernel, and enables it by default. This makes it less likely that the location of core kernel data structures can be determined by an adversary, but causes all function calls from modules into the core kernel to be resolved via entries in the module PLTs.
Quoted 7 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/Kconfig | 15 ++++++++ arch/arm64/include/asm/module.h | 6 ++++ arch/arm64/kernel/kaslr.c | 36 +++++++++++++++----- arch/arm64/kernel/module.c | 9 ++--- 4 files changed, 50 insertions(+), 16 deletions(-)Quoted 4 lines
With this patch I get an unhandled paging request, coming from
kernel/module.c:2982(the memset). The PC is wrongly attributed but it's inarch/arm64/lib/memset.S:This was due to a thinko in
kaslr_early_init(). Folding the following hunk will fix it (or I can resend the patch if you prefer)-------8<----------
arch/arm64/kernel/kaslr.c +0
-0@@ -82,6 +82,12 @@ u64 __init kaslr_early_init(u64 dt_phys)int size;/*
arch/arm64/kernel/kaslr.c u64 __init kaslr_early_init(u64 dt_phys)
Quoted 10 lines
arch/arm64/kernel/kaslr.c +6
-1+* Set a reasonable default for module_alloc_base in case +* we end up running with KASLR disabled. +*/ + module_alloc_base = (u64 )_etext -MODULES_VSIZE ; + +/* * Try to map the FDT early. If this fails, we simply bail, * and proceed with KASLR disabled. We will make another * attempt at mapping the FDT in setup_machine() -------8<----------
I'll fold the hunk in and give it a try. Thanks.
Signature · 1 line
Catalin
PATCH 1/8 arm64: add support for module PLTs
In reply to Ard BiesheuvelHi Ard,
Quoted 40 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Signed-off-by Ard Biesheuvel <[email protected]>---
In this version, I removed the distinction between relocations against .init executable sections and ordinary executable sections. The reason is that it is hardly worth the trouble, given that .init.text usually does not contain that many far branches, and this version now only reserves PLT entry space for jump and call relocations against undefined symbols (since symbols defined in the same module can be assumed to be within +/- 128 MB)
For example, the mac80211.ko module (which is fairly sizable at ~400 KB) built with -mcmodel=large gives the following relocation counts:
relocs branches unique !local
.text 3925 3347 518 219.init.text 11 8 7 1 .exit.text 4 4 4 1.text.unlikely 81 67 36 17
('unique' means branches to unique type/symbol/addend combos, of which !local is the subset referring to undefined symbols)
IOW, we are only emitting a single PLT entry for the .init sections, and we are better off just adding it to the core PLT section instead.
--- arch/arm64/Kconfig | 9 + arch/arm64/Makefile | 6 +- arch/arm64/include/asm/module.h | 11 ++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/module-plts.c | 201 ++++++++++++++++++++ arch/arm64/kernel/module.c | 12 ++ arch/arm64/kernel/module.lds | 3 + 7 files changed, 242 insertions(+), 1 deletion(-)
[...]
Quoted 4 lines
arch/arm64/kernel/module-plts.c new file +4
-0+struct plt_entry { +/* +* A program that conforms to the AArch64 Procedure Call Standard +* (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or
arch/arm64/kernel/module-plts.c line 27
Quoted 10 lines
arch/arm64/kernel/module-plts.c new file +10
-0+* IP1 (x17) may be inserted at any branch instruction that is +* exposed to a relocation that supports long branches. Since that +* is exactly what we are dealing with here, we are free to use x16 +* as a scratch register in the PLT veneers. +*/ +__le32 mov0;/* movn x16, #0x.... */ +__le32 mov1;/* movk x16, #0x...., lsl #16 */ +__le32 mov2;/* movk x16, #0x...., lsl #32 */ +__le32 br;/* br x16 */ +};
I'm worried about this code when CONFIG_ARM64_LSE_ATOMICS=y, but we don't detect them on the CPU at runtime. In this case, all atomic operations are moved out-of-line and called using a bl instruction from inline asm.
The out-of-line code is compiled with magic GCC options to force the explicit save/restore of all used registers (see arch/arm64/lib/Makefile), otherwise we'd have to clutter the inline asm with constraints that wouldn't be needed had we managed to patch the bl with an LSE atomic instruction.
If you're emitting a PLT, couldn't we end up with silent corruption of x16 for modules using out-of-line atomics like this?
Will
PATCH 1/8 arm64: add support for module PLTs
Quoted 65 lines · Will Deacon
Hi Ard,
Quoted 40 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Signed-off-by Ard Biesheuvel <[email protected]>---
In this version, I removed the distinction between relocations against .init executable sections and ordinary executable sections. The reason is that it is hardly worth the trouble, given that .init.text usually does not contain that many far branches, and this version now only reserves PLT entry space for jump and call relocations against undefined symbols (since symbols defined in the same module can be assumed to be within +/- 128 MB)
For example, the mac80211.ko module (which is fairly sizable at ~400 KB) built with -mcmodel=large gives the following relocation counts:
relocs branches unique !local
.text 3925 3347 518 219.init.text 11 8 7 1 .exit.text 4 4 4 1.text.unlikely 81 67 36 17
('unique' means branches to unique type/symbol/addend combos, of which !local is the subset referring to undefined symbols)
IOW, we are only emitting a single PLT entry for the .init sections, and we are better off just adding it to the core PLT section instead.
--- arch/arm64/Kconfig | 9 + arch/arm64/Makefile | 6 +- arch/arm64/include/asm/module.h | 11 ++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/module-plts.c | 201 ++++++++++++++++++++ arch/arm64/kernel/module.c | 12 ++ arch/arm64/kernel/module.lds | 3 + 7 files changed, 242 insertions(+), 1 deletion(-)[...]
Quoted 4 lines
arch/arm64/kernel/module-plts.c new file +4
-0+struct plt_entry { +/* +* A program that conforms to the AArch64 Procedure Call Standard +* (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or arch/arm64/kernel/module-plts.c line 27
Quoted 10 lines
arch/arm64/kernel/module-plts.c new file +10
-0+* IP1 (x17) may be inserted at any branch instruction that is +* exposed to a relocation that supports long branches. Since that +* is exactly what we are dealing with here, we are free to use x16 +* as a scratch register in the PLT veneers. +*/ +__le32 mov0;/* movn x16, #0x.... */ +__le32 mov1;/* movk x16, #0x...., lsl #16 */ +__le32 mov2;/* movk x16, #0x...., lsl #32 */ +__le32 br;/* br x16 */ +};I'm worried about this code when
CONFIG_ARM64_LSE_ATOMICS=y, but we don't detect them on the CPU at runtime. In this case, all atomic operations are moved out-of-line and called using a bl instruction from inline asm.
Quoted 1 line
The out-of-line code is compiled with magic GCC options
Which options are those exactly?
Quoted 9 lines
to force the
explicit save/restore of all used registers (seearch/arm64/lib/Makefile), otherwise we'd have to clutter the inline asm with constraints that wouldn't be needed had we managed to patch the bl with an LSE atomic instruction.If you're emitting a PLT, couldn't we end up with silent corruption of x16 for modules using out-of-line atomics like this?
If you violate the AAPCS64 ABI, then obviously the claim above does not hold.
PATCH 1/8 arm64: add support for module PLTs
Quoted 76 lines · Ard Biesheuvel
Quoted 65 lines · Will Deacon
Hi Ard,
Quoted 40 lines · 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 more likely that branch target offsets exceed the maximum range of +/- 128 MB.
Signed-off-by Ard Biesheuvel <[email protected]>---
In this version, I removed the distinction between relocations against .init executable sections and ordinary executable sections. The reason is that it is hardly worth the trouble, given that .init.text usually does not contain that many far branches, and this version now only reserves PLT entry space for jump and call relocations against undefined symbols (since symbols defined in the same module can be assumed to be within +/- 128 MB)
For example, the mac80211.ko module (which is fairly sizable at ~400 KB) built with -mcmodel=large gives the following relocation counts:
relocs branches unique !local
.text 3925 3347 518 219.init.text 11 8 7 1 .exit.text 4 4 4 1.text.unlikely 81 67 36 17
('unique' means branches to unique type/symbol/addend combos, of which !local is the subset referring to undefined symbols)
IOW, we are only emitting a single PLT entry for the .init sections, and we are better off just adding it to the core PLT section instead.
--- arch/arm64/Kconfig | 9 + arch/arm64/Makefile | 6 +- arch/arm64/include/asm/module.h | 11 ++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/module-plts.c | 201 ++++++++++++++++++++ arch/arm64/kernel/module.c | 12 ++ arch/arm64/kernel/module.lds | 3 + 7 files changed, 242 insertions(+), 1 deletion(-)[...]
Quoted 4 lines
arch/arm64/kernel/module-plts.c new file +4
-0+struct plt_entry { +/* +* A program that conforms to the AArch64 Procedure Call Standard +* (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or arch/arm64/kernel/module-plts.c line 27
Quoted 10 lines
arch/arm64/kernel/module-plts.c new file +10
-0+* IP1 (x17) may be inserted at any branch instruction that is +* exposed to a relocation that supports long branches. Since that +* is exactly what we are dealing with here, we are free to use x16 +* as a scratch register in the PLT veneers. +*/ +__le32 mov0;/* movn x16, #0x.... */ +__le32 mov1;/* movk x16, #0x...., lsl #16 */ +__le32 mov2;/* movk x16, #0x...., lsl #32 */ +__le32 br;/* br x16 */ +};I'm worried about this code when
CONFIG_ARM64_LSE_ATOMICS=y, but we don't detect them on the CPU at runtime. In this case, all atomic operations are moved out-of-line and called using a bl instruction from inline asm.Quoted 1 line
The out-of-line code is compiled with magic GCC options
Which options are those exactly?
Quoted 6 lines
to force the
explicit save/restore of all used registers (seearch/arm64/lib/Makefile), otherwise we'd have to clutter the inline asm with constraints that wouldn't be needed had we managed to patch the bl with an LSE atomic instruction.
Quoted 5 lines
Quoted 3 lines
If you're emitting a PLT, couldn't we end up with silent corruption of x16 for modules using out-of-line atomics like this?
If you violate the AAPCS64 ABI, then obviously the claim above does not hold.
IOW, yes, x16 will be corrupted unexpectedly if it you are expecting it to be preserved across a bl or b instruction that is exposed to a jump/call relocation
PATCH 1/8 arm64: add support for module PLTs
In reply to Ard BiesheuvelQuoted 21 lines · Ard Biesheuvel
Quoted 20 lines · Will Deacon
Quoted 4 lines · Ard Biesheuvel
arch/arm64/kernel/module-plts.c new file +4
-0+struct plt_entry { +/* +* A program that conforms to the AArch64 Procedure Call Standard +* (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or arch/arm64/kernel/module-plts.c line 27
Quoted 10 lines
arch/arm64/kernel/module-plts.c new file +10
-0+* IP1 (x17) may be inserted at any branch instruction that is +* exposed to a relocation that supports long branches. Since that +* is exactly what we are dealing with here, we are free to use x16 +* as a scratch register in the PLT veneers. +*/ +__le32 mov0;/* movn x16, #0x.... */ +__le32 mov1;/* movk x16, #0x...., lsl #16 */ +__le32 mov2;/* movk x16, #0x...., lsl #32 */ +__le32 br;/* br x16 */ +};I'm worried about this code when
CONFIG_ARM64_LSE_ATOMICS=y, but we don't detect them on the CPU at runtime. In this case, all atomic operations are moved out-of-line and called using a bl instruction from inline asm.
Quoted 3 lines
Quoted 1 line
The out-of-line code is compiled with magic GCC options
Which options are those exactly?
# Tell the compiler to treat all general purpose registers as # callee-saved, which allows for efficient runtime patching of the bl
# instruction in the caller with an atomic instruction when supported by # the CPU. Result and argument registers are handled correctly, based on # the function prototype. lib-$(CONFIG_ARM64_LSE_ATOMICS) += atomic_ll_sc.o CFLAGS_atomic_ll_sc.o := -fcall-used-x0 -ffixed-x1 -ffixed-x2 \ -ffixed-x3 -ffixed-x4 -ffixed-x5 -ffixed-x6 \ -ffixed-x7 -fcall-saved-x8 -fcall-saved-x9 \ -fcall-saved-x10 -fcall-saved-x11 -fcall-saved-x12 \ -fcall-saved-x13 -fcall-saved-x14 -fcall-saved-x15 \ -fcall-saved-x16 -fcall-saved-x17 -fcall-saved-x18
Quoted 11 lines
Quoted 9 lines
to force the
explicit save/restore of all used registers (seearch/arm64/lib/Makefile), otherwise we'd have to clutter the inline asm with constraints that wouldn't be needed had we managed to patch the bl with an LSE atomic instruction.If you're emitting a PLT, couldn't we end up with silent corruption of x16 for modules using out-of-line atomics like this?
If you violate the AAPCS64 ABI, then obviously the claim above does not hold.
Indeed, but this is what mainline is doing today and I'm not keen on breaking it. One way to fix it would be to generate a different type of plt for branches to the atomic functions that would use the stack instead of x16.
Will
PATCH 1/8 arm64: add support for module PLTs
Quoted 28 lines · Will Deacon
Quoted 21 lines · Ard Biesheuvel
Quoted 20 lines · Will Deacon
Quoted 4 lines · Ard Biesheuvel
arch/arm64/kernel/module-plts.c new file +4
-0+struct plt_entry { +/* +* A program that conforms to the AArch64 Procedure Call Standard +* (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or arch/arm64/kernel/module-plts.c line 27
Quoted 10 lines
arch/arm64/kernel/module-plts.c new file +10
-0+* IP1 (x17) may be inserted at any branch instruction that is +* exposed to a relocation that supports long branches. Since that +* is exactly what we are dealing with here, we are free to use x16 +* as a scratch register in the PLT veneers. +*/ +__le32 mov0;/* movn x16, #0x.... */ +__le32 mov1;/* movk x16, #0x...., lsl #16 */ +__le32 mov2;/* movk x16, #0x...., lsl #32 */ +__le32 br;/* br x16 */ +};I'm worried about this code when
CONFIG_ARM64_LSE_ATOMICS=y, but we don't detect them on the CPU at runtime. In this case, all atomic operations are moved out-of-line and called using a bl instruction from inline asm.Quoted 3 lines
Quoted 1 line
The out-of-line code is compiled with magic GCC options
Which options are those exactly?
# Tell the compiler to treat all general purpose registers as # callee-saved, which allows for efficient runtime patching of the bl
Quoted 11 lines
# instruction in the caller with an atomic instruction when supported by
# the CPU. Result and argument registers are handled correctly, based on
# the function prototype.
lib-$(CONFIG_ARM64_LSE_ATOMICS) += atomic_ll_sc.o
CFLAGS_atomic_ll_sc.o := -fcall-used-x0 -ffixed-x1 -ffixed-x2 \
-ffixed-x3 -ffixed-x4 -ffixed-x5 -ffixed-x6 \
-ffixed-x7 -fcall-saved-x8 -fcall-saved-x9 \
-fcall-saved-x10 -fcall-saved-x11 -fcall-saved-x12 \
-fcall-saved-x13 -fcall-saved-x14 -fcall-saved-x15 \
-fcall-saved-x16 -fcall-saved-x17 -fcall-saved-x18Yikes. Is that safe?
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
to force the
explicit save/restore of all used registers (seearch/arm64/lib/Makefile), otherwise we'd have to clutter the inline asm with constraints that wouldn't be needed had we managed to patch the bl with an LSE atomic instruction.If you're emitting a PLT, couldn't we end up with silent corruption of x16 for modules using out-of-line atomics like this?
Quoted 7 lines
Quoted 1 line
If you violate the AAPCS64 ABI, then obviously the claim above does not hold.
Indeed, but this is what mainline is doing today and I'm not keen on breaking it. One way to fix it would be to generate a different type of plt for branches to the atomic functions that would use the stack instead of x16.
AFAIK, gcc never uses x18 (the platform register) so we may be able to use that instead. We'd need confirmation from the toolchain guys, though ...
PATCH 1/8 arm64: add support for module PLTs
Quoted 41 lines · Ard Biesheuvel
Quoted 28 lines · Will Deacon
Quoted 21 lines · Ard Biesheuvel
Quoted 20 lines · Will Deacon
Quoted 4 lines · Ard Biesheuvel
arch/arm64/kernel/module-plts.c new file +4
-0+struct plt_entry { +/* +* A program that conforms to the AArch64 Procedure Call Standard +* (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or arch/arm64/kernel/module-plts.c line 27
Quoted 10 lines
arch/arm64/kernel/module-plts.c new file +10
-0+* IP1 (x17) may be inserted at any branch instruction that is +* exposed to a relocation that supports long branches. Since that +* is exactly what we are dealing with here, we are free to use x16 +* as a scratch register in the PLT veneers. +*/ +__le32 mov0;/* movn x16, #0x.... */ +__le32 mov1;/* movk x16, #0x...., lsl #16 */ +__le32 mov2;/* movk x16, #0x...., lsl #32 */ +__le32 br;/* br x16 */ +};I'm worried about this code when
CONFIG_ARM64_LSE_ATOMICS=y, but we don't detect them on the CPU at runtime. In this case, all atomic operations are moved out-of-line and called using a bl instruction from inline asm.Quoted 3 lines
Quoted 1 line
The out-of-line code is compiled with magic GCC options
Which options are those exactly?
# Tell the compiler to treat all general purpose registers as # callee-saved, which allows for efficient runtime patching of the bl
Quoted 11 lines
# instruction in the caller with an atomic instruction when supported by # the CPU. Result and argument registers are handled correctly, based on # the function prototype. lib-$(CONFIG_ARM64_LSE_ATOMICS) += atomic_ll_sc.o CFLAGS_atomic_ll_sc.o := -fcall-used-x0 -ffixed-x1 -ffixed-x2 \ -ffixed-x3 -ffixed-x4 -ffixed-x5 -ffixed-x6 \ -ffixed-x7 -fcall-saved-x8 -fcall-saved-x9 \ -fcall-saved-x10 -fcall-saved-x11 -fcall-saved-x12 \ -fcall-saved-x13 -fcall-saved-x14 -fcall-saved-x15 \ -fcall-saved-x16 -fcall-saved-x17 -fcall-saved-x18
Quoted 1 line
Yikes. Is that safe?
It seems to work, and x86 uses a similar trick for it's hweight code.
Quoted 18 lines
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
to force the
explicit save/restore of all used registers (seearch/arm64/lib/Makefile), otherwise we'd have to clutter the inline asm with constraints that wouldn't be needed had we managed to patch the bl with an LSE atomic instruction.If you're emitting a PLT, couldn't we end up with silent corruption of x16 for modules using out-of-line atomics like this?
Quoted 7 lines
Quoted 1 line
If you violate the AAPCS64 ABI, then obviously the claim above does not hold.
Indeed, but this is what mainline is doing today and I'm not keen on breaking it. One way to fix it would be to generate a different type of plt for branches to the atomic functions that would use the stack instead of x16.
Quoted 3 lines
AFAIK, gcc never uses x18 (the platform register) so we may be able to use that instead. We'd need confirmation from the toolchain guys, though ...
In fact, a better thing to do is probably for the atomic code to save/restore those register explicitly and then remove them from the cflags above.
I'll try hacking something together...
Will
PATCH 1/8 arm64: add support for module PLTs
Quoted 68 lines · Will Deacon
Quoted 41 lines · Ard Biesheuvel
Quoted 28 lines · Will Deacon
Quoted 21 lines · Ard Biesheuvel
Quoted 20 lines · Will Deacon
Quoted 4 lines · Ard Biesheuvel
arch/arm64/kernel/module-plts.c new file +4
-0+struct plt_entry { +/* +* A program that conforms to the AArch64 Procedure Call Standard +* (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or arch/arm64/kernel/module-plts.c line 27
Quoted 10 lines
arch/arm64/kernel/module-plts.c new file +10
-0+* IP1 (x17) may be inserted at any branch instruction that is +* exposed to a relocation that supports long branches. Since that +* is exactly what we are dealing with here, we are free to use x16 +* as a scratch register in the PLT veneers. +*/ +__le32 mov0;/* movn x16, #0x.... */ +__le32 mov1;/* movk x16, #0x...., lsl #16 */ +__le32 mov2;/* movk x16, #0x...., lsl #32 */ +__le32 br;/* br x16 */ +};I'm worried about this code when
CONFIG_ARM64_LSE_ATOMICS=y, but we don't detect them on the CPU at runtime. In this case, all atomic operations are moved out-of-line and called using a bl instruction from inline asm.Quoted 3 lines
Quoted 1 line
The out-of-line code is compiled with magic GCC options
Which options are those exactly?
# Tell the compiler to treat all general purpose registers as # callee-saved, which allows for efficient runtime patching of the bl
Quoted 11 lines
# instruction in the caller with an atomic instruction when supported by # the CPU. Result and argument registers are handled correctly, based on # the function prototype. lib-$(CONFIG_ARM64_LSE_ATOMICS) += atomic_ll_sc.o CFLAGS_atomic_ll_sc.o := -fcall-used-x0 -ffixed-x1 -ffixed-x2 \ -ffixed-x3 -ffixed-x4 -ffixed-x5 -ffixed-x6 \ -ffixed-x7 -fcall-saved-x8 -fcall-saved-x9 \ -fcall-saved-x10 -fcall-saved-x11 -fcall-saved-x12 \ -fcall-saved-x13 -fcall-saved-x14 -fcall-saved-x15 \ -fcall-saved-x16 -fcall-saved-x17 -fcall-saved-x18Quoted 1 line
Yikes. Is that safe?
It seems to work, and x86 uses a similar trick for it's hweight code.
Quoted 18 lines
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
to force the
explicit save/restore of all used registers (seearch/arm64/lib/Makefile), otherwise we'd have to clutter the inline asm with constraints that wouldn't be needed had we managed to patch the bl with an LSE atomic instruction.If you're emitting a PLT, couldn't we end up with silent corruption of x16 for modules using out-of-line atomics like this?
Quoted 7 lines
Quoted 1 line
If you violate the AAPCS64 ABI, then obviously the claim above does not hold.
Indeed, but this is what mainline is doing today and I'm not keen on breaking it. One way to fix it would be to generate a different type of plt for branches to the atomic functions that would use the stack instead of x16.
Quoted 3 lines
AFAIK, gcc never uses x18 (the platform register) so we may be able to use that instead. We'd need confirmation from the toolchain guys, though ...
Quoted 6 lines
In fact, a better thing to do is probably for the atomic code to save/restore those register explicitly and then remove them from the cflags above.
I'll try hacking something together...
That would be more correct, indeed. Also, the PLT can only use br <reg> so it will always enter the callee with the preserved value stacked, and so the callee needs to be modified in any case.
PATCH 1/8 arm64: add support for module PLTs
Quoted 10 lines · Ard Biesheuvel
Quoted 9 lines · Will Deacon
Quoted 3 lines · Ard Biesheuvel
AFAIK, gcc never uses x18 (the platform register) so we may be able to use that instead. We'd need confirmation from the toolchain guys, though ...
In fact, a better thing to do is probably for the atomic code to save/restore those register explicitly and then remove them from the cflags above.
Quoted 6 lines
Quoted 2 lines
I'll try hacking something together...
That would be more correct, indeed. Also, the PLT can only use br <reg> so it will always enter the callee with the preserved value stacked, and so the callee needs to be modified in any case.
Wait -- why does the callee need to be modified here? It has no idea about whether or not it was invoked via a PLT.
Also, can I rely on the PLT not clobbering the condition code?
Will
PATCH 1/8 arm64: add support for module PLTs
Quoted 14 lines · Will Deacon
Quoted 13 lines · Ard Biesheuvel
Quoted 11 lines · Will Deacon
Quoted 3 lines · Ard Biesheuvel
AFAIK, gcc never uses x18 (the platform register) so we may be able to use that instead. We'd need confirmation from the toolchain guys, though ...
In fact, a better thing to do is probably for the atomic code to save/restore those register explicitly and then remove them from the cflags above.
I'll try hacking something together...
Quoted 7 lines
Quoted 3 lines
That would be more correct, indeed. Also, the PLT can only use br <reg> so it will always enter the callee with the preserved value stacked, and so the callee needs to be modified in any case.
Wait -- why does the callee need to be modified here? It has no idea about whether or not it was invoked via a PLT.
No, it doesn't, and that is exactly the problem: the PLT must end in a br <reg> instruction because that is the only branch instruction with unlimited range. That means you will always enter the callee with its address in some register rather than the value that should have been preserved. I don't see a way to manage that from the callee
Quoted 2 lines
Also, can I rely on the PLT not clobbering the condition code?
For my particular implementation, yes.
PATCH 1/8 arm64: add support for module PLTs
Quoted 23 lines · Ard Biesheuvel
Quoted 14 lines · Will Deacon
Quoted 13 lines · Ard Biesheuvel
Quoted 11 lines · Will Deacon
Quoted 3 lines · Ard Biesheuvel
AFAIK, gcc never uses x18 (the platform register) so we may be able to use that instead. We'd need confirmation from the toolchain guys, though ...
In fact, a better thing to do is probably for the atomic code to save/restore those register explicitly and then remove them from the cflags above.
I'll try hacking something together...
Quoted 7 lines
Quoted 3 lines
That would be more correct, indeed. Also, the PLT can only use br <reg> so it will always enter the callee with the preserved value stacked, and so the callee needs to be modified in any case.
Wait -- why does the callee need to be modified here? It has no idea about whether or not it was invoked via a PLT.
Quoted 6 lines
No, it doesn't, and that is exactly the problem: the PLT must end in a br <reg> instruction because that is the only branch instruction with unlimited range. That means you will always enter the callee with its address in some register rather than the value that should have been preserved. I don't see a way to manage that from the callee
*caller! dammit
Quoted 4 lines
Quoted 2 lines
Also, can I rely on the PLT not clobbering the condition code?
For my particular implementation, yes.
PATCH 1/8 arm64: add support for module PLTs
Quoted 24 lines · Ard Biesheuvel
Quoted 23 lines · Ard Biesheuvel
Quoted 21 lines · Will Deacon
Quoted 10 lines · Ard Biesheuvel
Quoted 9 lines · Will Deacon
Quoted 3 lines · Ard Biesheuvel
AFAIK, gcc never uses x18 (the platform register) so we may be able to use that instead. We'd need confirmation from the toolchain guys, though ...
In fact, a better thing to do is probably for the atomic code to save/restore those register explicitly and then remove them from the cflags above.
Quoted 6 lines
Quoted 2 lines
I'll try hacking something together...
That would be more correct, indeed. Also, the PLT can only use br <reg> so it will always enter the callee with the preserved value stacked, and so the callee needs to be modified in any case.
Wait -- why does the callee need to be modified here? It has no idea about whether or not it was invoked via a PLT.
Quoted 8 lines
Quoted 6 lines
No, it doesn't, and that is exactly the problem: the PLT must end in a br <reg> instruction because that is the only branch instruction with unlimited range. That means you will always enter the callee with its address in some register rather than the value that should have been preserved. I don't see a way to manage that from the callee
*caller! dammit
The caller can do:
save x16, 17
bl plt
restore x16, x17
the plt will do:
get_addr_of_callee_into_x16_and_clobber_x17_or_something br callee
then the callee will be compiled with all those weird options, but *not* the ones specifying x16 and x17. That means it can happily use those guys as scratch, because the caller will take care of them.
Will
PATCH 1/8 arm64: add support for module PLTs
Quoted 32 lines · Will Deacon
Quoted 31 lines · Ard Biesheuvel
Quoted 29 lines · Ard Biesheuvel
Quoted 14 lines · Will Deacon
Quoted 13 lines · Ard Biesheuvel
Quoted 11 lines · Will Deacon
Quoted 3 lines · Ard Biesheuvel
AFAIK, gcc never uses x18 (the platform register) so we may be able to use that instead. We'd need confirmation from the toolchain guys, though ...
In fact, a better thing to do is probably for the atomic code to save/restore those register explicitly and then remove them from the cflags above.
I'll try hacking something together...
Quoted 7 lines
Quoted 3 lines
That would be more correct, indeed. Also, the PLT can only use br <reg> so it will always enter the callee with the preserved value stacked, and so the callee needs to be modified in any case.
Wait -- why does the callee need to be modified here? It has no idea about whether or not it was invoked via a PLT.
No, it doesn't, and that is exactly the problem: the PLT must end in a br <reg> instruction because that is the only branch instruction with unlimited range. That means you will always enter the callee with its address in some register rather than the value that should have been preserved. I don't see a way to manage that from the callee
Quoted 8 lines
Quoted 1 line
*caller! dammit
The caller can do:
save x16, 17
bl plt
restore x16, x17
This is __LL_SC_CALL, right? So you just fold a stp/ldp in there?
Quoted 9 lines
the plt will do:
get_addr_of_callee_into_x16_and_clobber_x17_or_somethingbr calleethen the callee will be compiled with all those weird options, but *not* the ones specifying x16 and x17. That means it can happily use those guys as scratch, because the caller will take care of them.
Yes, that makes sense. But if you don't relax that restriction, you only need the alternative __LL_SC_CALL for modules.
PATCH 1/8 arm64: add support for module PLTs
Quoted 6 lines · Ard Biesheuvel
Quoted 5 lines · Will Deacon
the plt will do:
get_addr_of_callee_into_x16_and_clobber_x17_or_somethingbr callee
Quoted 7 lines
Quoted 4 lines
then the callee will be compiled with all those weird options, but *not* the ones specifying x16 and x17. That means it can happily use those guys as scratch, because the caller will take care of them.
Yes, that makes sense. But if you don't relax that restriction, you only need the alternative
__LL_SC_CALLfor modules.
Totally untested patch below, but I'll give it a whirl tomorrow.
It looks a bit mental.
Will
--->8
arch/arm64/include/asm/atomic_lse.h +25 -19
@@ -33,6 +33,8 @@ static inline void atomic_andnot(int i, atomic_t *v) register atomic_t *x1 asm ("x1") = v; asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(andnot), +" nop\n" +" nop\n" " stclr %w[i], %[v]\n" ) : [i] "+r" (w0), [v] "+Q" (v->counter) : "r" (x1)
@@ -45,6 +47,8 @@ static inline void atomic_or(int i, atomic_t *v) register atomic_t *x1 asm ("x1") = v; asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(or), +" nop\n" +" nop\n" " stset %w[i], %[v]\n" ) : [i] "+r" (w0), [v] "+Q" (v->counter) : "r" (x1)
@@ -57,6 +61,8 @@ static inline void atomic_xor(int i, atomic_t *v) register atomic_t *x1 asm ("x1") = v; asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(xor), +" nop\n" +" nop\n" " steor %w[i], %[v]\n" ) : [i] "+r" (w0), [v] "+Q" (v->counter) : "r" (x1)
@@ -69,6 +75,8 @@ static inline void atomic_add(int i, atomic_t *v) register atomic_t *x1 asm ("x1") = v; asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(add), +" nop\n" +" nop\n" " stadd %w[i], %[v]\n" ) : [i] "+r" (w0), [v] "+Q" (v->counter) : "r" (x1)
@@ -83,9 +91,9 @@ static inline int atomic_add_return##name(int i, atomic_t *v) \ \ asm volatile(ARM64_LSE_ATOMIC_INSN( \ /* LL/SC */ \ -" nop\n" \ __LL_SC_ATOMIC(add_return##name), \ /* LSE atomics */ \ + " nop\n" \ " ldadd" #mb " %w[i], w30, %[v]\n" \ " add %w[i], %w[i], w30") \ : [i] "+r" (w0), [v] "+Q" (v->counter) \
@@ -109,9 +117,9 @@ static inline void atomic_and(int i, atomic_t *v) asm volatile(ARM64_LSE_ATOMIC_INSN(/* LL/SC */ - " nop\n" __LL_SC_ATOMIC(and),/* LSE atomics */ +" nop\n" " mvn %w[i], %w[i]\n" " stclr %w[i], %[v]" ) : [i] "+r" (w0), [v] "+Q" (v->counter)
@@ -126,9 +134,9 @@ static inline void atomic_sub(int i, atomic_t *v) asm volatile(ARM64_LSE_ATOMIC_INSN(/* LL/SC */ - " nop\n" __LL_SC_ATOMIC(sub),/* LSE atomics */ +" nop\n" " neg %w[i], %w[i]\n" " stadd %w[i], %[v]" ) : [i] "+r" (w0), [v] "+Q" (v->counter)
@@ -144,9 +152,7 @@ static inline int atomic_sub_return##name(int i, atomic_t *v) \ \ asm volatile(ARM64_LSE_ATOMIC_INSN( \ /* LL/SC */ \ - " nop\n" \ - __LL_SC_ATOMIC(sub_return##name) \ - " nop", \ + __LL_SC_ATOMIC(sub_return##name), \ /* LSE atomics */ \ " neg %w[i], %w[i]\n" \ " ldadd" #mb " %w[i], w30, %[v]\n" \
@@ -174,6 +180,8 @@ static inline void atomic64_andnot(long i, atomic64_t *v) register atomic64_t *x1 asm ("x1") = v; asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(andnot), +" nop\n" +" nop\n" " stclr %[i], %[v]\n" ) : [i] "+r" (x0), [v] "+Q" (v->counter) : "r" (x1)
@@ -186,6 +194,8 @@ static inline void atomic64_or(long i, atomic64_t *v) register atomic64_t *x1 asm ("x1") = v; asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(or), +" nop\n" +" nop\n" " stset %[i], %[v]\n" ) : [i] "+r" (x0), [v] "+Q" (v->counter) : "r" (x1)
@@ -198,6 +208,8 @@ static inline void atomic64_xor(long i, atomic64_t *v) register atomic64_t *x1 asm ("x1") = v; asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(xor), +" nop\n" +" nop\n" " steor %[i], %[v]\n" ) : [i] "+r" (x0), [v] "+Q" (v->counter) : "r" (x1)
@@ -210,6 +222,8 @@ static inline void atomic64_add(long i, atomic64_t *v) register atomic64_t *x1 asm ("x1") = v; asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(add), +" nop\n" +" nop\n" " stadd %[i], %[v]\n" ) : [i] "+r" (x0), [v] "+Q" (v->counter) : "r" (x1)
@@ -224,9 +238,9 @@ static inline long atomic64_add_return##name(long i, atomic64_t *v) \ \ asm volatile(ARM64_LSE_ATOMIC_INSN( \ /* LL/SC */ \ -" nop\n" \ __LL_SC_ATOMIC64(add_return##name), \ /* LSE atomics */ \ + " nop\n" \ " ldadd" #mb " %[i], x30, %[v]\n" \ " add %[i], %[i], x30") \ : [i] "+r" (x0), [v] "+Q" (v->counter) \
@@ -250,9 +264,9 @@ static inline void atomic64_and(long i, atomic64_t *v) asm volatile(ARM64_LSE_ATOMIC_INSN(/* LL/SC */ - " nop\n" __LL_SC_ATOMIC64(and),/* LSE atomics */ +" nop\n" " mvn %[i], %[i]\n" " stclr %[i], %[v]" ) : [i] "+r" (x0), [v] "+Q" (v->counter)
@@ -267,9 +281,9 @@ static inline void atomic64_sub(long i, atomic64_t *v) asm volatile(ARM64_LSE_ATOMIC_INSN(/* LL/SC */ - " nop\n" __LL_SC_ATOMIC64(sub),/* LSE atomics */ +" nop\n" " neg %[i], %[i]\n" " stadd %[i], %[v]" ) : [i] "+r" (x0), [v] "+Q" (v->counter)
@@ -285,9 +299,7 @@ static inline long atomic64_sub_return##name(long i, atomic64_t *v) \ \ asm volatile(ARM64_LSE_ATOMIC_INSN( \ /* LL/SC */ \ - " nop\n" \ - __LL_SC_ATOMIC64(sub_return##name) \ - " nop", \ + __LL_SC_ATOMIC64(sub_return##name), \ /* LSE atomics */ \ " neg %[i], %[i]\n" \ " ldadd" #mb " %[i], x30, %[v]\n" \
@@ -312,12 +324,10 @@ static inline long atomic64_dec_if_positive(atomic64_t *v) asm volatile(ARM64_LSE_ATOMIC_INSN(/* LL/SC */ -" nop\n" __LL_SC_ATOMIC64(dec_if_positive)" nop\n" " nop\n" " nop\n" -" nop\n" " nop",/* LSE atomics */ "1: ldr x30, %[v]\n"
@@ -350,9 +360,7 @@ static inline unsigned long __cmpxchg_case_##name(volatile void *ptr, \ \ asm volatile(ARM64_LSE_ATOMIC_INSN( \ /* LL/SC */ \ -" nop\n" \ - __LL_SC_CMPXCHG(name) \ -" nop" , \ + __LL_SC_CMPXCHG(name), \ /* LSE atomics */ \ " mov " #w "30, %" #w "[old]\n" \ " cas" #mb #sz "\t" #w "30, %" #w "[new], %[v]\n" \
@@ -404,8 +412,6 @@ static inline long __cmpxchg_double##name(unsigned long old1, \ asm volatile(ARM64_LSE_ATOMIC_INSN( \/* LL/SC */ \" nop\n" \ -" nop\n" \ -" nop\n" \ __LL_SC_CMPXCHG_DBL(name), \/* LSE atomics */ \ " casp" #mb "\t%[old1], %[old2], %[new1], %[new2], %[v]\n"\
arch/arm64/include/asm/lse.h +4 -1
@@ -25,7 +25,10 @@ __asm__(".arch_extension lse");#define __LL_SC_EXPORT (x) EXPORT_SYMBOL(__LL_SC_PREFIX(x))/* Macro for constructing calls to out-of-line ll/sc atomics */ -#define __LL_SC_CALL (op) "bl\t" __stringify(__LL_SC_PREFIX(op)) "\n" +#define __LL_SC_CALL (op) \ + "stp x16, x17, [sp, #-16]!\n" \ + "bl\t" __stringify(__LL_SC_PREFIX(op)) "\n" \ + "ldp x16, x17, [sp], #16\n"/* In-line patching at runtime */ #define ARM64_LSE_ATOMIC_INSN (llsc, lse) \
arch/arm64/lib/Makefile +7 -6
@@ -4,15 +4,16 @@ lib-y := bitops.o clear_user.o delay.o copy_from_user.o \ memcmp.o strcmp.o strncmp.o strlen.o strnlen.o \ strchr.o strrchr.o -# Tell the compiler to treat all general purpose registers as -# callee-saved, which allows for efficient runtime patching of the bl -# instruction in the caller with an atomic instruction when supported by -# the CPU. Result and argument registers are handled correctly, based on -# the function prototype. +# Tell the compiler to treat all general purpose registers (with the +# exception of the IP registers, which are already handled by the caller +# in case of a PLT) as callee-saved, which allows for efficient runtime +# patching of the bl instruction in the caller with an atomic instruction +# when supported by the CPU. Result and argument registers are handled +# correctly, based on the function prototype. lib-$(CONFIG_ARM64_LSE_ATOMICS) += atomic_ll_sc.o CFLAGS_atomic_ll_sc.o := -fcall-used-x0 -ffixed-x1 -ffixed-x2 \ -ffixed-x3 -ffixed-x4 -ffixed-x5 -ffixed-x6 \ -ffixed-x7 -fcall-saved-x8 -fcall-saved-x9 \ -fcall-saved-x10 -fcall-saved-x11 -fcall-saved-x12 \ -fcall-saved-x13 -fcall-saved-x14 -fcall-saved-x15 \ - -fcall-saved-x16 -fcall-saved-x17 -fcall-saved-x18 + -fcall-saved-x18
PATCH 2/8 arm64: avoid R_AARCH64_ABS64 relocations for Image header fields
In reply to Ard BiesheuvelUnfortunately, the current way of 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 are resolved at runtime, not at build time, and the places targeted by those relocations will contain zeroes before that.
So refactor the endian swapping linker script constant generation code so that it emits the upper and lower 32-bit words separately.
--- arch/arm64/include/asm/assembler.h | 11 +++++++ arch/arm64/kernel/head.S | 6 ++-- arch/arm64/kernel/image.h | 32 ++++++++++++-------- 3 files changed, 33 insertions(+), 16 deletions(-)
arch/arm64/include/asm/assembler.h +11 -0
@@ -222,4 +222,15 @@ lr .req x30 // link register .size __pi_##x, . - x; \ ENDPROC(x) +/* +* Emit a 64-bit absolute little endian symbol reference in a way that +* ensures that it will be resolved at build time, even when building a +* PIE binary. This requires cooperation from the linker script, which +* must emit the lo32/hi32 halves individually. +*/ + .macro le64sym, sym + .long \sym\()_lo32 + .long \sym\()_hi32 + .endm +#endif /* __ASM_ASSEMBLER_H */
arch/arm64/kernel/head.S +3 -3
@@ -83,9 +83,9 @@ 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 + le64sym _kernel_offset_le // Image load offset from start of RAM, little-endian + le64sym _kernel_size_le // Effective size of kernel image, little-endian + le64sym _kernel_flags_le // Informative flags, little-endian .quad 0 // reserved .quad 0 // reserved .quad 0 // reserved
arch/arm64/kernel/image.h +19 -13
@@ -26,21 +26,27 @@* 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. +* +* Note that, in order for this to work when building the ELF64 PIE executable +* (for KASLR), these values should not be referenced via R_AARCH64_ABS64 +* relocations, since these are fixed up at runtime rather than at build time +* when PIE is in effect. So we need to split them up in 32-bit high and low +* words. */ #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)) +#define DATA_LE32 (data) \ + ((((data) & 0x000000ff) << 24) | \ + (((data) & 0x0000ff00) << 8) | \ + (((data) & 0x00ff0000) >> 8) | \ + (((data) & 0xff000000) >> 24))#else -#define DATA_LE64 (data) ((data) & 0xffffffffffffffff) +#define DATA_LE32 (data) ((data) & 0xffffffff)#endif +#define DEFINE_IMAGE_LE64 (sym, data) \ + sym##_lo32 = DATA_LE32((data) & 0xffffffff); \ + sym##_hi32 = DATA_LE32((data) >> 32) +#ifdef CONFIG_CPU_BIG_ENDIAN #define __HEAD_FLAG_BE 1#else
@@ -61,9 +67,9 @@* 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); + DEFINE_IMAGE_LE64(_kernel_size_le, _end - _text); \ + DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET); \ + DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS);#ifdef CONFIG_EFI
Signature · 1 line
2.5.0
PATCH 3/8 arm64: avoid dynamic relocations in early boot code
In reply to Ard BiesheuvelBefore 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.
--- arch/arm64/kernel/efi-entry.S | 2 +- arch/arm64/kernel/head.S | 39 +++++++++++++------- 2 files changed, 27 insertions(+), 14 deletions(-)
arch/arm64/kernel/efi-entry.S +1 -1
@@ -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 /*
arch/arm64/kernel/head.S +26 -13
@@ -67,12 +67,11 @@ * 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.
@@ -94,14 +93,14 @@ efi_head: .byte 0x4d .byte 0x64 #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 +123,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 +138,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
@@ -219,11 +218,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
@@ -391,7 +392,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
@@ -408,6 +410,9 @@ __create_page_tables: mov lr, x27 ret ENDPROC(__create_page_tables) + +kernel_img_size: + .long _end - (_head - TEXT_OFFSET) .ltorg /*
@@ -415,6 +420,10 @@ ENDPROC(__create_page_tables) */ .set initial_sp, init_thread_union + THREAD_START_SP __mmap_switched: + adr_l x8, vectors // load VBAR_EL1 with virtual + msr vbar_el1, x8 // vector table address + isb + // Clear BSS adr_l x0, __bss_start mov x1, xzr
@@ -610,13 +619,19 @@ ENTRY(secondary_startup) adrp x26, swapper_pg_dir bl __cpu_setup // initialise processor - ldr x21, =secondary_data - ldr x27, =__secondary_switched // address to jump to after enabling the MMU + ldr x8, =KIMAGE_VADDR + ldr w9, 0f + sub x27, x8, w9, sxtw // address to jump to after enabling the MMU b __enable_mmu ENDPROC(secondary_startup) +0: .long (_text - TEXT_OFFSET) - __secondary_switched ENTRY(__secondary_switched) - ldr x0, [x21] // get secondary_data.stack + adr_l x5, vectors + msr vbar_el1, x5 + isb + + ldr_l x0, secondary_data // get secondary_data.stack mov sp, x0 and x0, x0, #~(THREAD_SIZE - 1) msr sp_el0, x0 // save thread_info
@@ -641,8 +656,6 @@ __enable_mmu: ubfx x2, x1, #ID_AA64MMFR0_TGRAN_SHIFT, 4 cmp x2, #ID_AA64MMFR0_TGRAN_SUPPORTED b.ne __no_granule_support - ldr x5, =vectors - msr vbar_el1, x5 msr ttbr0_el1, x25 // load TTBR0 msr ttbr1_el1, x26 // load TTBR1 isb
Signature · 1 line
2.5.0
PATCH 4/8 arm64: make asm/elf.h available to asm files
In reply to Ard BiesheuvelThis reshuffles some code in asm/elf.h and puts a #ifndef __ASSEMBLY__ around its C definitions so that the CPP defines can be used in asm source files as well.
--- arch/arm64/include/asm/elf.h | 22 ++++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-)
arch/arm64/include/asm/elf.h +13 -9
@@ -24,15 +24,6 @@#include <asm/ptrace.h> #include <asm/user.h> -typedef unsigned long elf_greg_t ; - -#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t)) -#define ELF_CORE_COPY_REGS (dest, regs) \ - *(struct user_pt_regs *)&(dest) = (regs)->user_regs; - -typedef elf_greg_t elf_gregset_t [ELF_NGREG ]; -typedef struct user_fpsimd_state elf_fpregset_t ; -/* * AArch64 static relocation types. */
@@ -127,6 +118,17 @@ typedef struct user_fpsimd_state elf_fpregset_t;*/ #define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3) +#ifndef __ASSEMBLY__ + +typedef unsigned long elf_greg_t ; + +#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t)) +#define ELF_CORE_COPY_REGS (dest, regs) \ + *(struct user_pt_regs *)&(dest) = (regs)->user_regs; + +typedef elf_greg_t elf_gregset_t [ELF_NGREG ]; +typedef struct user_fpsimd_state elf_fpregset_t ; +/* * When the program starts, a1 contains a pointer to a function to be * registered with atexit, as per the SVR4 ABI. A value of 0 means we have no
@@ -186,4 +188,6 @@ extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,#endif /* CONFIG_COMPAT */ +#endif /* !__ASSEMBLY__ */ +#endif
Signature · 1 line
2.5.0
PATCH 5/8 scripts/sortextable: add support for ET_DYN binaries
In reply to Ard BiesheuvelAdd support to scripts/sortextable for handling relocatable (PIE) executables, whose ELF type is ET_DYN, not ET_EXEC. Other than adding support for the new type, no changes are needed.
--- scripts/sortextable.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
scripts/sortextable.c +4 -4
@@ -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 (); }
@@ -304,7 +304,7 @@ do_file(char const *const fname)if (r2 (&ehdr->e_ehsize) !=sizeof (Elf32_Ehdr) ||r2 (&ehdr->e_shentsize) !=sizeof (Elf32_Shdr)) {fprintf (stderr, -"unrecognized ET_EXEC file: %s\n" , fname); +"unrecognized ET_EXEC/ET_DYN file: %s\n" , fname);fail_file (); }do32 (ehdr, fname, custom_sort);
@@ -314,7 +314,7 @@ do_file(char const *const fname)if (r2 (&ghdr->e_ehsize) !=sizeof (Elf64_Ehdr) ||r2 (&ghdr->e_shentsize) !=sizeof (Elf64_Shdr)) {fprintf (stderr, -"unrecognized ET_EXEC file: %s\n" , fname); +"unrecognized ET_EXEC/ET_DYN file: %s\n" , fname);fail_file (); }do64 (ghdr, fname, custom_sort);
Signature · 1 line
2.5.0
PATCH 6/8 arm64: add support for building vmlinux as a relocatable PIE binary
In reply to Ard BiesheuvelThis implements CONFIG_RELOCATABLE, which links the final vmlinux image with a dynamic relocation section, allowing the early boot code to perform a relocation to a different virtual address at runtime.
This is a prerequisite for KASLR (CONFIG_RANDOMIZE_BASE).
--- arch/arm64/Kconfig | 11 +++++++ arch/arm64/Makefile | 4 +++ arch/arm64/include/asm/elf.h | 2 ++ arch/arm64/kernel/head.S | 32 ++++++++++++++++++++ arch/arm64/kernel/vmlinux.lds.S | 16 ++++++++++ 5 files changed, 65 insertions(+)
arch/arm64/Kconfig +11 -0
@@ -762,6 +762,17 @@ config ARM64_MODULE_PLTS select ARM64_MODULE_CMODEL_LARGE select HAVE_MOD_ARCH_SPECIFIC +config RELOCATABLE + bool + help + This builds the kernel as a Position Independent Executable (PIE), + which retains all relocation metadata required to relocate the + kernel binary at runtime to a different virtual address than the + address it was linked at. + Since AArch64 uses the RELA relocation format, this requires a + relocation pass at runtime even if the kernel is loaded at the + same address it was linked at. + endmenu menu "Boot options"
arch/arm64/Makefile +4 -0
@@ -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_RELOCATABLE),) +LDFLAGS_vmlinux += -pie +endif + KBUILD_DEFCONFIG := defconfig # Check for binutils support for specific extensions
arch/arm64/include/asm/elf.h +2 -0
@@ -77,6 +77,8 @@#define R_AARCH64_MOVW_PREL_G2_NC 292#define R_AARCH64_MOVW_PREL_G3 293 +#define R_AARCH64_RELATIVE 1027 +/* * These are used to set parameters in the core dumps. */
arch/arm64/kernel/head.S +32 -0
@@ -29,6 +29,7 @@ #include <asm/asm-offsets.h> #include <asm/cache.h> #include <asm/cputype.h> +#include <asm/elf.h> #include <asm/kernel-pgtable.h> #include <asm/memory.h> #include <asm/pgtable-hwdef.h>
@@ -432,6 +433,37 @@ __mmap_switched: bl __pi_memset dsb ishst // Make zero page visible to PTW +#ifdef CONFIG_RELOCATABLE + + /* + * 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 + ldr x13, [x9, #-8] + cmp w12, #R_AARCH64_RELATIVE + b.ne 1f + str x13, [x11] + b 0b + +1: cmp w12, #R_AARCH64_ABS64 + b.ne 0b + add x12, x12, x12, lsl #1 // symtab offset: 24x top word + add x12, x8, x12, lsr #(32 - 3) // ... shifted into bottom word + ldr x15, [x12, #8] // Elf64_Sym::st_value + add x15, x13, x15 + str x15, [x11] + b 0b + +2: +#endif + adr_l sp, initial_sp, x4 mov x4, sp and x4, x4, #~(THREAD_SIZE - 1)
arch/arm64/kernel/vmlinux.lds.S +16 -0
@@ -87,6 +87,7 @@ SECTIONS EXIT_CALL *(.discard) *(.discard.*) + *(.interp .dynamic) } . = KIMAGE_VADDR + TEXT_OFFSET;
@@ -149,6 +150,21 @@ SECTIONS .altinstr_replacement : { *(.altinstr_replacement) } + .rela : ALIGN(8) { + __reloc_start = .; + *(.rela .rela*) + __reloc_end = .; + } + .dynsym : ALIGN(8) { + __dynsym_start = .; + *(.dynsym) + } + .dynstr : { + *(.dynstr) + } + .hash : { + *(.hash) + } . = ALIGN(PAGE_SIZE); __init_end = .;
Signature · 1 line
2.5.0
PATCH 7/8 arm64: add support for kernel ASLR
In reply to Ard BiesheuvelThis adds support for KASLR is implemented, based on entropy provided by the bootloader in the /chosen/kaslr-seed DT property. Depending on the size of the address space (VA_BITS) and the page size, the entropy in the virtual displacement is up to 13 bits (16k/2 levels) and up to 25 bits (all 4 levels), with the sidenote that displacements that result in the kernel image straddling a 1GB/32MB/512MB alignment boundary (for 4KB/16KB/64KB granule kernels, respectively) are not allowed, and will be rounded up to an acceptable value.
The module region is randomized by choosing a page aligned 128 MB region inside the interval [_etext - 128 MB, _stext + 128 MB). This gives between 10 and 14 bits of entropy (depending on page size), independently of the kernel randomization, but still guarantees that modules are within the range of relative branch and jump instructions (with the caveat that, since the module region is shared with other uses of the vmalloc area, modules may need to be loaded further away if the module region is exhausted)
--- arch/arm64/Kconfig | 14 ++ arch/arm64/include/asm/memory.h | 5 +- arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/head.S | 59 +++++++-- arch/arm64/kernel/kaslr.c | 139 ++++++++++++++++++++ arch/arm64/kernel/module.c | 8 +- arch/arm64/kernel/setup.c | 29 ++++ arch/arm64/mm/mmu.c | 33 +++-- 8 files changed, 268 insertions(+), 20 deletions(-)
arch/arm64/Kconfig +14 -0
@@ -773,6 +773,20 @@ config RELOCATABLE relocation pass at runtime even if the kernel is loaded at the same address it was linked at. +config RANDOMIZE_BASE + bool "Randomize the address of the kernel image" + select ARM64_MODULE_PLTS + select RELOCATABLE + help + Randomizes the virtual address at which the kernel image is + loaded, as a security feature that deters exploit attempts + relying on knowledge of the location of kernel internals. + + It is the bootloader's job to provide entropy, by passing a + random u64 value in /chosen/kaslr-seed at kernel entry. + + If unsure, say N. + endmenu menu "Boot options"
arch/arm64/include/asm/memory.h +4 -1
@@ -52,7 +52,7 @@#define KIMAGE_VADDR (MODULES_END)#define MODULES_END (MODULES_VADDR + MODULES_VSIZE)#define MODULES_VADDR (VA_START + KASAN_SHADOW_SIZE) -#define MODULES_VSIZE (SZ_64M) +#define MODULES_VSIZE (SZ_128M)#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)
@@ -127,6 +127,9 @@ extern phys_addr_t memstart_addr;/* PHYS_OFFSET - the physical address of the start of memory. */ #define PHYS_OFFSET ({ memstart_addr; }) +/* the virtual base of the kernel image (minus TEXT_OFFSET) */ +extern u64 kimage_vaddr; +/* the offset between the kernel virtual and physical mappings */ extern u64 kimage_voffset;
arch/arm64/kernel/Makefile +1 -0
@@ -43,6 +43,7 @@ arm64-obj-$(CONFIG_PCI) += pci.o arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o arm64-obj-$(CONFIG_ACPI) += acpi.o arm64-obj-$(CONFIG_PARAVIRT) += paravirt.o +arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m)
arch/arm64/kernel/head.S +51 -8
141 lines not on this page · raw message
arch/arm64/kernel/kaslr.c new file +139 -0
139 lines not on this page · raw message
arch/arm64/kernel/module.c +7 -1
@@ -33,8 +33,14 @@void *module_alloc (unsigned long size) {void *p; +u64 base = (u64 )_etext -MODULES_VSIZE ; - p =__vmalloc_node_range (size,MODULE_ALIGN ,MODULES_VADDR ,MODULES_END , +if (IS_ENABLED (CONFIG_RANDOMIZE_BASE )) { +extern u32 module_load_offset; + base += module_load_offset; + } + + p =__vmalloc_node_range (size,MODULE_ALIGN , base, base +MODULES_VSIZE ,GFP_KERNEL ,PAGE_KERNEL_EXEC ,0 ,NUMA_NO_NODE ,__builtin_return_address (0 ));
arch/arm64/kernel/setup.c +29 -0
@@ -388,3 +388,32 @@ static int __init topology_init(void)return 0 ; }subsys_initcall (topology_init); + +/* +* Dump out kernel offset information on panic. +*/ +static int dump_kernel_offset (struct notifier_block *self,unsigned long v, +void *p) +{ +u64 const kaslr_offset = kimage_vaddr -KIMAGE_VADDR ; + +if (IS_ENABLED (CONFIG_RANDOMIZE_BASE ) && kaslr_offset >0 ) { +pr_emerg ("Kernel Offset: 0x%llx from 0x%lx\n" , + kaslr_offset,KIMAGE_VADDR ); + }else { +pr_emerg ("Kernel Offset: disabled\n" ); + } +return 0 ; +} + +static struct notifier_block kernel_offset_notifier = { + .notifier_call = dump_kernel_offset +}; + +static int __init register_kernel_offset_dumper (void ) +{ +atomic_notifier_chain_register (&panic_notifier_list, + &kernel_offset_notifier); +return 0 ; +} +__initcall (register_kernel_offset_dumper);
arch/arm64/mm/mmu.c +23 -10
@@ -636,7 +636,8 @@ void __init early_fixmap_init(void)unsigned long addr =FIXADDR_START ; pgd =pgd_offset_k (addr); -if (CONFIG_PGTABLE_LEVELS >3 && !pgd_none (*pgd)) { +if (CONFIG_PGTABLE_LEVELS >3 && + !(pgd_none (*pgd) ||pgd_page_paddr (*pgd) ==__pa (bm_pud))) {/* * We only end up here if the kernel mapping and the fixmap * share the top level pgd entry, which should only happen on
@@ -693,11 +694,10 @@ void __set_fixmap(enum fixed_addresses idx, } } -void *__init fixmap_remap_fdt (phys_addr_t dt_phys) +void *__init __fixmap_remap_fdt (phys_addr_t dt_phys,int *size,pgprot_t prot) {const u64 dt_virt_base =__fix_to_virt (FIX_FDT ); -pgprot_t prot =PAGE_KERNEL_RO ; -int size, offset; +int offset;void *dt_virt;/*
@@ -736,16 +736,29 @@ void *__init fixmap_remap_fdt(phys_addr_t dt_phys)if (fdt_check_header (dt_virt) !=0 )return NULL ; - size =fdt_totalsize (dt_virt); -if (size >MAX_FDT_SIZE ) + *size =fdt_totalsize (dt_virt); +if (*size >MAX_FDT_SIZE )return NULL ; -if (offset + size >SWAPPER_BLOCK_SIZE ) -create_mapping (round_down (dt_phys,SWAPPER_BLOCK_SIZE ), dt_virt_base, -round_up (offset + size,SWAPPER_BLOCK_SIZE ), prot); +if (offset + *size >SWAPPER_BLOCK_SIZE ) +create_mapping (round_down (dt_phys,SWAPPER_BLOCK_SIZE ), + dt_virt_base, +round_up (offset + *size,SWAPPER_BLOCK_SIZE ), + prot); -memblock_reserve (dt_phys, size); +return dt_virt; +} +void *__init fixmap_remap_fdt (phys_addr_t dt_phys) +{ +void *dt_virt; +int size; + + dt_virt =__fixmap_remap_fdt (dt_phys, &size,PAGE_KERNEL_RO ); +if (!dt_virt) +return NULL ; + +memblock_reserve (dt_phys, size);return dt_virt; }
Signature · 1 line
2.5.0
PATCH 8/8 arm64: kaslr: randomize the linear region
In reply to Ard BiesheuvelWhen KASLR is enabled (CONFIG_RANDOMIZE_BASE=y), and entropy has been provided by the bootloader, randomize the placement of RAM inside the linear region if sufficient space is available. For instance, on a 4KB granule/3 levels kernel, the linear region is 256 GB in size, and we can choose any 1 GB aligned offset that is far enough from the top of the address space to fit the distance between the start of the lowest memblock and the top of the highest memblock.
--- arch/arm64/kernel/kaslr.c | 4 ++++ arch/arm64/mm/init.c | 22 ++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-)
arch/arm64/kernel/kaslr.c +4 -0
@@ -21,6 +21,7 @@#include <asm/sections.h> u32 __read_mostly module_load_offset; +u16 __initdata memstart_offset_seed;static __init u64 get_kaslr_seed (void *fdt) {
@@ -135,5 +136,8 @@ u64 __init kaslr_early_init(u64 dt_phys) module_range =MODULES_VSIZE - (u64)(_etext - _stext); module_load_offset = ((module_range * (u16 )seed) >>16 ) &PAGE_MASK ; +/* use the top 16 bits to randomize the linear region */ + memstart_offset_seed = seed >>48 ; +return offset; }
arch/arm64/mm/init.c +20 -2
@@ -215,6 +215,23 @@ void __init arm64_memblock_init(void)if (memblock_end_of_DRAM () > linear_region_size)memblock_remove (0 ,memblock_end_of_DRAM () - linear_region_size); +if (IS_ENABLED (CONFIG_RANDOMIZE_BASE )) { +extern u16 memstart_offset_seed; +u64 range = linear_region_size - + (memblock_end_of_DRAM () -memblock_start_of_DRAM ()); + +/* +* If the size of the linear region exceeds, by a sufficient +* margin, the size of the region that the available physical +* memory spans, randomize the linear region as well. +*/ +if (memstart_offset_seed >0 && range >=ARM64_MEMSTART_ALIGN ) { + range = range /ARM64_MEMSTART_ALIGN +1 ; + memstart_addr -=ARM64_MEMSTART_ALIGN * + ((range * memstart_offset_seed) >>16 ); + } + } +if (memory_limit != (phys_addr_t )ULLONG_MAX ) {u64 kbase =round_down (__pa (_text),MIN_KIMG_ALIGN );u64 kend =PAGE_ALIGN (__pa (_end));
@@ -399,12 +416,13 @@ void __init mem_init(void)#ifdef CONFIG_SPARSEMEM_VMEMMAP MLG ((unsigned long )vmemmap, (unsigned long )vmemmap +VMEMMAP_SIZE ), -MLM ((unsigned long )virt_to_page (PAGE_OFFSET ), +MLM ((unsigned long )phys_to_page (memblock_start_of_DRAM ()), (unsigned long )virt_to_page (high_memory)), #endifMLK (FIXADDR_START ,FIXADDR_TOP ),MLM (PCI_IO_START ,PCI_IO_END ), - MLM(PAGE_OFFSET, (unsigned long)high_memory)); +MLM (__phys_to_virt (memblock_start_of_DRAM ()), + (unsigned long)high_memory));#undef MLK#undef MLM
Signature · 1 line
2.5.0
cover arm64: implement virtual KASLR
In reply to Ard BiesheuvelQuoted 6 lines · Ard Biesheuvel
At the request of Catalin, this series has been split off from my series 'arm64: implement support for KASLR v4' [1]. This sub-series deals with creating a relocatable binary, and randomizing the virtual placement of the kernel itself, the modules and the linear region based on entropy supplied by the bootloader in the /chosen/kaslr-seed DT property.
Quoted 11 lines
Changes since v4:
- add randomization of the linear region, i.e., if the linear region is substantially larger than the space spanned by RAM, the mapping of RAM is moved to a random offset inside the linear region.
- dropped the CRC check inkaslr_early_init(), since the only code that may modify .data through__fixmap_remap_fdt()is instrumentation that should deal with that correctly (For instance, the branch profiling records taken branches in structs allocated in .data, and these counts will not be reset to 0 between the first and the second call to__mmap_switched())
- add Mark's ack to patch #4
NOTE: I have omitted the relative kallsyms and relative extable patches, since they already queued in akpm's tree. However, while the kallsyms patch is merely an optimization, the extable patches are in fact required for correct operation, since the build time sorting does not work on absolute extables (this is due to the fact that the resolution of the relocations is deferred until runtime, and so the extable addresses are all zero at sorting time)
http://ozlabs.org/~akpm/mmotm/broken-out/extable-add-support-for-relative-extables-to-search-and-sort-routines.patch
http://ozlabs.org/~akpm/mmotm/broken-out/arm64-switch-to-relative-exception-tables.patch
Quoted 62 lines
Patch #1 adds support for resolving cross-module branches via veneers if the module is located too far from the target. This should not be necessary in the common case even with KASRL enabled, but since the space around the kernel image will no longer be strictly reserved for modules, there is a slight chance that the region may be exhausted, in which case modules will be moved further away from the kernel (and each other)
Patches #2 and #3 deal with the fact that relocations of 64-bit values are deferred to runtime when building a PIE executable, and some values are required before the relocation routine executes (either in the code, or as an externally visible constant in the Image header)
Patch #4 rehuffles
asm/elf.hso we can use its preprocessor constants inhead.SPatch #5 and #6 implement building vmlinux as a PIE (Position Independent Executable) binary, which is emitted with relocation information that is processed by the program itself in the early boot code.
Patch #7 implements KASLR, i.e.,
CONFIG_RANDOMIZE_BASEfor the core kernel and for the module region.Patch #8 implements KASLR for the linear region.
[1] http://thread.gmane.org/gmane.linux.kernel/2135931
Ard Biesheuvel (8):
arm64: add support for module PLTs
arm64: avoidR_AARCH64_ABS64relocations for Image header fields
arm64: avoid dynamic relocations in early boot code
arm64: makeasm/elf.havailable to asm filesscripts/sortextable: add support forET_DYNbinaries
arm64: add support for building vmlinux as a relocatable PIE binary
arm64: add support for kernel ASLR
arm64: kaslr: randomize the linear regionarch/arm64/Kconfig | 34 ++++ arch/arm64/Makefile | 10 +- arch/arm64/include/asm/assembler.h | 11 ++ arch/arm64/include/asm/elf.h | 24 ++- arch/arm64/include/asm/memory.h | 5 +- arch/arm64/include/asm/module.h | 11 ++ arch/arm64/kernel/Makefile | 2 + arch/arm64/kernel/efi-entry.S | 2 +- arch/arm64/kernel/head.S | 128 +++++++++++-- arch/arm64/kernel/image.h | 32 ++-- arch/arm64/kernel/kaslr.c | 143 ++++++++++++++ arch/arm64/kernel/module-plts.c | 201 ++++++++++++++++++++ arch/arm64/kernel/module.c | 20 +- arch/arm64/kernel/module.lds | 3 + arch/arm64/kernel/setup.c | 29 +++ arch/arm64/kernel/vmlinux.lds.S | 16 ++ arch/arm64/mm/init.c | 22 ++- arch/arm64/mm/mmu.c | 33 +++- scripts/sortextable.c | 8 +- 19 files changed, 672 insertions(+), 62 deletions(-) create mode 100644 arch/arm64/kernel/kaslr.c create mode 100644 arch/arm64/kernel/module-plts.c create mode 100644 arch/arm64/kernel/module.lds--
2.5.0
Catalin Marinas
maintainercover arm64: implement virtual KASLR
Quoted 27 lines · Ard Biesheuvel
Quoted 6 lines · Ard Biesheuvel
At the request of Catalin, this series has been split off from my series 'arm64: implement support for KASLR v4' [1]. This sub-series deals with creating a relocatable binary, and randomizing the virtual placement of the kernel itself, the modules and the linear region based on entropy supplied by the bootloader in the /chosen/kaslr-seed DT property.
Quoted 11 lines
Changes since v4:
- add randomization of the linear region, i.e., if the linear region is substantially larger than the space spanned by RAM, the mapping of RAM is moved to a random offset inside the linear region.
- dropped the CRC check inkaslr_early_init(), since the only code that may modify .data through__fixmap_remap_fdt()is instrumentation that should deal with that correctly (For instance, the branch profiling records taken branches in structs allocated in .data, and these counts will not be reset to 0 between the first and the second call to__mmap_switched())
- add Mark's ack to patch #4NOTE: I have omitted the relative kallsyms and relative extable patches, since they already queued in akpm's tree. However, while the kallsyms patch is merely an optimization, the extable patches are in fact required for correct operation, since the build time sorting does not work on absolute extables (this is due to the fact that the resolution of the relocations is deferred until runtime, and so the extable addresses are all zero at sorting time)
Quoted 2 lines
http://ozlabs.org/~akpm/mmotm/broken-out/extable-add-support-for-relative-extables-to-search-and-sort-routines.patch
http://ozlabs.org/~akpm/mmotm/broken-out/arm64-switch-to-relative-exception-tables.patch
I'm still trying to get my head around how we merge those. Since I assume akpm will push them during the merging window, part of your code cannot be tested before.
Can we deselect CONFIG_BUILDTIME_EXTABLE_SORT temporarily while we use absolute extable addresses? We patch them at boot-time and sort them at run-time. Once the above patches go in, we can revert to build-time extable sorting.
Signature · 1 line
Catalin
cover arm64: implement virtual KASLR
Quoted 28 lines · Catalin Marinas
Quoted 27 lines · Ard Biesheuvel
Quoted 6 lines · Ard Biesheuvel
At the request of Catalin, this series has been split off from my series 'arm64: implement support for KASLR v4' [1]. This sub-series deals with creating a relocatable binary, and randomizing the virtual placement of the kernel itself, the modules and the linear region based on entropy supplied by the bootloader in the /chosen/kaslr-seed DT property.
Quoted 11 lines
Changes since v4:
- add randomization of the linear region, i.e., if the linear region is substantially larger than the space spanned by RAM, the mapping of RAM is moved to a random offset inside the linear region.
- dropped the CRC check inkaslr_early_init(), since the only code that may modify .data through__fixmap_remap_fdt()is instrumentation that should deal with that correctly (For instance, the branch profiling records taken branches in structs allocated in .data, and these counts will not be reset to 0 between the first and the second call to__mmap_switched())
- add Mark's ack to patch #4NOTE: I have omitted the relative kallsyms and relative extable patches, since they already queued in akpm's tree. However, while the kallsyms patch is merely an optimization, the extable patches are in fact required for correct operation, since the build time sorting does not work on absolute extables (this is due to the fact that the resolution of the relocations is deferred until runtime, and so the extable addresses are all zero at sorting time)
Quoted 7 lines
Quoted 2 lines
http://ozlabs.org/~akpm/mmotm/broken-out/extable-add-support-for-relative-extables-to-search-and-sort-routines.patch
http://ozlabs.org/~akpm/mmotm/broken-out/arm64-switch-to-relative-exception-tables.patchI'm still trying to get my head around how we merge those. Since I assume akpm will push them during the merging window, part of your code cannot be tested before.
Actually, my original idea was for akpm to take them as a late merge after rebasing to -rc1, since they touch a variety of architectures, but I am not sure if that came across.
You could always take the series through your tree instead, I guess?
Quoted 5 lines
Can we deselect
CONFIG_BUILDTIME_EXTABLE_SORTtemporarily while we use absolute extable addresses? We patch them at boot-time and sort them at run-time. Once the above patches go in, we can revert to build-time extable sorting.
I suppose that would be possible, but I simply haven't tried. I noticed that ppc does not use build time extable sorting, that is why they don't need to scripts/extable patch while they do use PIE binaries.
Catalin Marinas
maintainercover arm64: implement virtual KASLR
Quoted 36 lines · Ard Biesheuvel
Quoted 28 lines · Catalin Marinas
Quoted 27 lines · Ard Biesheuvel
Quoted 6 lines · Ard Biesheuvel
At the request of Catalin, this series has been split off from my series 'arm64: implement support for KASLR v4' [1]. This sub-series deals with creating a relocatable binary, and randomizing the virtual placement of the kernel itself, the modules and the linear region based on entropy supplied by the bootloader in the /chosen/kaslr-seed DT property.
Quoted 11 lines
Changes since v4:
- add randomization of the linear region, i.e., if the linear region is substantially larger than the space spanned by RAM, the mapping of RAM is moved to a random offset inside the linear region.
- dropped the CRC check inkaslr_early_init(), since the only code that may modify .data through__fixmap_remap_fdt()is instrumentation that should deal with that correctly (For instance, the branch profiling records taken branches in structs allocated in .data, and these counts will not be reset to 0 between the first and the second call to__mmap_switched())
- add Mark's ack to patch #4NOTE: I have omitted the relative kallsyms and relative extable patches, since they already queued in akpm's tree. However, while the kallsyms patch is merely an optimization, the extable patches are in fact required for correct operation, since the build time sorting does not work on absolute extables (this is due to the fact that the resolution of the relocations is deferred until runtime, and so the extable addresses are all zero at sorting time)
Quoted 6 lines
Quoted 2 lines
http://ozlabs.org/~akpm/mmotm/broken-out/extable-add-support-for-relative-extables-to-search-and-sort-routines.patch
http://ozlabs.org/~akpm/mmotm/broken-out/arm64-switch-to-relative-exception-tables.patchI'm still trying to get my head around how we merge those. Since I assume akpm will push them during the merging window, part of your code cannot be tested before.
Quoted 5 lines
Actually, my original idea was for akpm to take them as a late merge after rebasing to -rc1, since they touch a variety of architectures, but I am not sure if that came across.
You could always take the series through your tree instead, I guess?
They all have acks from maintainers, so that's an option.
Quoted 9 lines
Quoted 4 lines
Can we deselect
CONFIG_BUILDTIME_EXTABLE_SORTtemporarily while we use absolute extable addresses? We patch them at boot-time and sort them at run-time. Once the above patches go in, we can revert to build-time extable sorting.I suppose that would be possible, but I simply haven't tried. I noticed that ppc does not use build time extable sorting, that is why they don't need to
scripts/extablepatch while they do use PIE binaries.
I did a quick check with:
arch/arm64/Kconfig +1 -1
@@ -22,7 +22,7 @@ config ARM64 select ARM_GIC_V3 select ARM_GIC_V3_ITS if PCI_MSI select ARM_PSCI_FW - select BUILDTIME_EXTABLE_SORT + select BUILDTIME_EXTABLE_SORT if !RELOCATABLE select CLONE_BACKWARDS select COMMON_CLK select CPU_PM if (SUSPEND || CPU_IDLE)
and it seems that extable entries end up in the relocation symbols but I haven't fully checked the patching/sorting yet (it will probably be on Monday).
Signature · 1 line
Catalin
cover arm64: implement virtual KASLR
In reply to Ard BiesheuvelQuoted 10 lines · Ard Biesheuvel
Quoted 3 lines · Catalin Marinas
I'm still trying to get my head around how we merge those. Since I assume akpm will push them during the merging window, part of your code cannot be tested before.
Actually, my original idea was for akpm to take them as a late merge after rebasing to -rc1, since they touch a variety of architectures, but I am not sure if that came across.
You could always take the series through your tree instead, I guess?
Traditionally akpm will de-duplicate patches he's carrying that appear in another tree. I think it should be okay to carry them in both places. (Though I'm CCing akpm just to see if I'm talking crazy.)
-Kees
Signature · 2 lines
Kees Cook Chrome OS & Brillo Security
Catalin Marinas
maintainercover arm64: implement virtual KASLR
Quoted 11 lines · Kees Cook
Quoted 9 lines · Ard Biesheuvel
Quoted 3 lines · Catalin Marinas
I'm still trying to get my head around how we merge those. Since I assume akpm will push them during the merging window, part of your code cannot be tested before.
Actually, my original idea was for akpm to take them as a late merge after rebasing to -rc1, since they touch a variety of architectures, but I am not sure if that came across.
Quoted 5 lines
Quoted 1 line
You could always take the series through your tree instead, I guess?
Traditionally akpm will de-duplicate patches he's carrying that appear in another tree. I think it should be okay to carry them in both places. (Though I'm CCing akpm just to see if I'm talking crazy.)
For now, I'll merge this series in the arm64 tree and push it to next:
http://lkml.kernel.org/r/1452007180-27411-1-git-send-email-ard.biesheuvel at linaro.org
If there are any objections, I can drop the patches and do the BUILDTIME_EXTABLE_SORT disabling trick until they end up in mainline.
Signature · 1 line
Catalin
cover arm64: implement virtual KASLR
Quoted 18 lines · Catalin Marinas
Quoted 11 lines · Kees Cook
Quoted 9 lines · Ard Biesheuvel
Quoted 3 lines · Catalin Marinas
I'm still trying to get my head around how we merge those. Since I assume akpm will push them during the merging window, part of your code cannot be tested before.
Actually, my original idea was for akpm to take them as a late merge after rebasing to -rc1, since they touch a variety of architectures, but I am not sure if that came across.
Quoted 5 lines
Quoted 1 line
You could always take the series through your tree instead, I guess?
Traditionally akpm will de-duplicate patches he's carrying that appear in another tree. I think it should be okay to carry them in both places. (Though I'm CCing akpm just to see if I'm talking crazy.)
Quoted 7 lines
For now, I'll merge this series in the arm64 tree and push it to next:
http://lkml.kernel.org/r/1452007180-27411-1-git-send-email-ard.biesheuvel at linaro.org
If there are any objections, I can drop the patches and do the
BUILDTIME_EXTABLE_SORTdisabling trick until they end up in mainline.
Latest version is here:
http://lkml.kernel.org/r/1453892123-17973-1-git-send-email-ard.biesheuvel at linaro.org (only difference is an ack from that Alpha maintainter/supporter to patches #1 and #2)
However, the arm64 patch (#6) now conflicts with futex.h in -rc3 after the PAN fix, not sure how to best address that ...
Signature · 1 line
Ard.
cover arm64: implement virtual KASLR
Quoted 23 lines · Ard Biesheuvel
Quoted 22 lines · Catalin Marinas
Quoted 11 lines · Kees Cook
Quoted 9 lines · Ard Biesheuvel
Quoted 3 lines · Catalin Marinas
I'm still trying to get my head around how we merge those. Since I assume akpm will push them during the merging window, part of your code cannot be tested before.
Actually, my original idea was for akpm to take them as a late merge after rebasing to -rc1, since they touch a variety of architectures, but I am not sure if that came across.
Quoted 5 lines
Quoted 1 line
You could always take the series through your tree instead, I guess?
Traditionally akpm will de-duplicate patches he's carrying that appear in another tree. I think it should be okay to carry them in both places. (Though I'm CCing akpm just to see if I'm talking crazy.)
For now, I'll merge this series in the arm64 tree and push it to next:
http://lkml.kernel.org/r/1452007180-27411-1-git-send-email-ard.biesheuvel at linaro.org
Quoted 7 lines
Quoted 2 lines
If there are any objections, I can drop the patches and do the
BUILDTIME_EXTABLE_SORTdisabling trick until they end up in mainline.Latest version is here:
http://lkml.kernel.org/r/1453892123-17973-1-git-send-email-ard.biesheuvel at linaro.org (only difference is an ack from that Alpha maintainter/supporter to patches #1 and #2)
I applied the acks manually but I'll double-check to make sure I haven't missed anything.
Quoted 2 lines
However, the arm64 patch (#6) now conflicts with
futex.hin -rc3 after the PAN fix, not sure how to best address that ...
I'll have a look.
Signature · 1 line
Catalin
cover arm64: implement virtual KASLR
Quoted 32 lines · Catalin Marinas
Quoted 23 lines · Ard Biesheuvel
Quoted 22 lines · Catalin Marinas
Quoted 11 lines · Kees Cook
Quoted 9 lines · Ard Biesheuvel
Quoted 3 lines · Catalin Marinas
I'm still trying to get my head around how we merge those. Since I assume akpm will push them during the merging window, part of your code cannot be tested before.
Actually, my original idea was for akpm to take them as a late merge after rebasing to -rc1, since they touch a variety of architectures, but I am not sure if that came across.
Quoted 5 lines
Quoted 1 line
You could always take the series through your tree instead, I guess?
Traditionally akpm will de-duplicate patches he's carrying that appear in another tree. I think it should be okay to carry them in both places. (Though I'm CCing akpm just to see if I'm talking crazy.)
For now, I'll merge this series in the arm64 tree and push it to next:
http://lkml.kernel.org/r/1452007180-27411-1-git-send-email-ard.biesheuvel at linaro.org
Quoted 7 lines
Quoted 2 lines
If there are any objections, I can drop the patches and do the
BUILDTIME_EXTABLE_SORTdisabling trick until they end up in mainline.Latest version is here:
http://lkml.kernel.org/r/1453892123-17973-1-git-send-email-ard.biesheuvel at linaro.org (only difference is an ack from that Alpha maintainter/supporter to patches #1 and #2)
Quoted 8 lines
I applied the acks manually but I'll double-check to make sure I haven't missed anything.
Quoted 2 lines
However, the arm64 patch (#6) now conflicts with
futex.hin -rc3 after the PAN fix, not sure how to best address that ...I'll have a look.
Note that the fix is trivial, but I don't know who should be carrying the fix is all
Catalin Marinas
maintainercover arm64: implement virtual KASLR
Quoted 9 lines · Ard Biesheuvel
Quoted 5 lines · Catalin Marinas
Quoted 2 lines · Ard Biesheuvel
However, the arm64 patch (#6) now conflicts with
futex.hin -rc3 after the PAN fix, not sure how to best address that ...I'll have a look.
Note that the fix is trivial, but I don't know who should be carrying the fix is all
I'll push the arm64 for-next/core branch (including your series) out against 4.5-rc3, so there won't be any conflict.
Signature · 1 line
Catalin