From 4b7a6ce71e033666d6f5a577deb7f1f5126ed889 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Tue, 13 Oct 2020 22:24:30 -0700 Subject: arm64: reject prctl(PR_PAC_RESET_KEYS) on compat tasks It doesn't make sense to issue prctl(PR_PAC_RESET_KEYS) on a compat task because the 32-bit instruction set does not offer PAuth instructions. For consistency with other 64-bit only prctls such as {SET,GET}_TAGGED_ADDR_CTRL, reject the prctl on compat tasks. Although this is a userspace-visible change, maybe it isn't too late to make this change given that the hardware isn't available yet and it's very unlikely that anyone has 32-bit software that actually depends on this succeeding. Signed-off-by: Peter Collingbourne Link: https://linux-review.googlesource.com/id/Ie885a1ff84ab498cc9f62d6451e9f2cfd4b1d06a Link: https://lore.kernel.org/r/20201014052430.11630-1-pcc@google.com [will: Do the same for the SVE prctl()s] Signed-off-by: Will Deacon --- arch/arm64/kernel/fpsimd.c | 4 ++-- arch/arm64/kernel/pointer_auth.c | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'arch/arm64') diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index a6d688c10745..062b21f30f94 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -678,7 +678,7 @@ int sve_set_current_vl(unsigned long arg) vl = arg & PR_SVE_VL_LEN_MASK; flags = arg & ~vl; - if (!system_supports_sve()) + if (!system_supports_sve() || is_compat_task()) return -EINVAL; ret = sve_set_vector_length(current, vl, flags); @@ -691,7 +691,7 @@ int sve_set_current_vl(unsigned long arg) /* PR_SVE_GET_VL */ int sve_get_current_vl(void) { - if (!system_supports_sve()) + if (!system_supports_sve() || is_compat_task()) return -EINVAL; return sve_prctl_status(0); diff --git a/arch/arm64/kernel/pointer_auth.c b/arch/arm64/kernel/pointer_auth.c index 1e77736a4f66..adb955fd9bdd 100644 --- a/arch/arm64/kernel/pointer_auth.c +++ b/arch/arm64/kernel/pointer_auth.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include #include #include @@ -17,6 +18,9 @@ int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg) if (!system_supports_address_auth() && !system_supports_generic_auth()) return -EINVAL; + if (is_compat_thread(task_thread_info(tsk))) + return -EINVAL; + if (!arg) { ptrauth_keys_init_user(keys); return 0; -- cgit v1.2.3-58-ga151 From 7bc1a0f9e1765830e945669c99c59c35cf9bca82 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 8 Oct 2020 17:35:59 +0200 Subject: arm64: mm: use single quantity to represent the PA to VA translation On arm64, the global variable memstart_addr represents the physical address of PAGE_OFFSET, and so physical to virtual translations or vice versa used to come down to simple additions or subtractions involving the values of PAGE_OFFSET and memstart_addr. When support for 52-bit virtual addressing was introduced, we had to deal with PAGE_OFFSET potentially being outside of the region that can be covered by the virtual range (as the 52-bit VA capable build needs to be able to run on systems that are only 48-bit VA capable), and for this reason, another translation was introduced, and recorded in the global variable physvirt_offset. However, if we go back to the original definition of memstart_addr, i.e., the physical address of PAGE_OFFSET, it turns out that there is no need for two separate translations: instead, we can simply subtract the size of the unaddressable VA space from memstart_addr to make the available physical memory appear in the 48-bit addressable VA region. This simplifies things, but also fixes a bug on KASLR builds, which may update memstart_addr later on in arm64_memblock_init(), but fails to update vmemmap and physvirt_offset accordingly. Fixes: 5383cc6efed1 ("arm64: mm: Introduce vabits_actual") Signed-off-by: Ard Biesheuvel Reviewed-by: Steve Capper Link: https://lore.kernel.org/r/20201008153602.9467-2-ardb@kernel.org Signed-off-by: Will Deacon --- arch/arm64/include/asm/memory.h | 5 ++--- arch/arm64/include/asm/pgtable.h | 4 ++-- arch/arm64/mm/init.c | 30 ++++++++++-------------------- 3 files changed, 14 insertions(+), 25 deletions(-) (limited to 'arch/arm64') diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 43640d797455..cd61239bae8c 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -169,7 +169,6 @@ extern u64 vabits_actual; #define PAGE_END (_PAGE_END(vabits_actual)) -extern s64 physvirt_offset; extern s64 memstart_addr; /* PHYS_OFFSET - the physical address of the start of memory. */ #define PHYS_OFFSET ({ VM_BUG_ON(memstart_addr & 1); memstart_addr; }) @@ -245,7 +244,7 @@ static inline const void *__tag_set(const void *addr, u8 tag) */ #define __is_lm_address(addr) (!(((u64)addr) & BIT(vabits_actual - 1))) -#define __lm_to_phys(addr) (((addr) + physvirt_offset)) +#define __lm_to_phys(addr) (((addr) & ~PAGE_OFFSET) + PHYS_OFFSET) #define __kimg_to_phys(addr) ((addr) - kimage_voffset) #define __virt_to_phys_nodebug(x) ({ \ @@ -263,7 +262,7 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x); #define __phys_addr_symbol(x) __pa_symbol_nodebug(x) #endif /* CONFIG_DEBUG_VIRTUAL */ -#define __phys_to_virt(x) ((unsigned long)((x) - physvirt_offset)) +#define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET) #define __phys_to_kimg(x) ((unsigned long)((x) + kimage_voffset)) /* diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index a11bf52e0c38..4ff12a7adcfd 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -24,6 +24,8 @@ #define VMALLOC_START (MODULES_END) #define VMALLOC_END (- PUD_SIZE - VMEMMAP_SIZE - SZ_64K) +#define vmemmap ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT)) + #define FIRST_USER_ADDRESS 0UL #ifndef __ASSEMBLY__ @@ -34,8 +36,6 @@ #include #include -extern struct page *vmemmap; - #ifdef CONFIG_TRANSPARENT_HUGEPAGE #define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 481d22c32a2e..324f0e0894f6 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -54,12 +54,6 @@ s64 memstart_addr __ro_after_init = -1; EXPORT_SYMBOL(memstart_addr); -s64 physvirt_offset __ro_after_init; -EXPORT_SYMBOL(physvirt_offset); - -struct page *vmemmap __ro_after_init; -EXPORT_SYMBOL(vmemmap); - /* * We create both ZONE_DMA and ZONE_DMA32. ZONE_DMA covers the first 1G of * memory as some devices, namely the Raspberry Pi 4, have peripherals with @@ -290,20 +284,6 @@ void __init arm64_memblock_init(void) memstart_addr = round_down(memblock_start_of_DRAM(), ARM64_MEMSTART_ALIGN); - physvirt_offset = PHYS_OFFSET - PAGE_OFFSET; - - vmemmap = ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT)); - - /* - * If we are running with a 52-bit kernel VA config on a system that - * does not support it, we have to offset our vmemmap and physvirt_offset - * s.t. we avoid the 52-bit portion of the direct linear map - */ - if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52) && (vabits_actual != 52)) { - vmemmap += (_PAGE_OFFSET(48) - _PAGE_OFFSET(52)) >> PAGE_SHIFT; - physvirt_offset = PHYS_OFFSET - _PAGE_OFFSET(48); - } - /* * Remove the memory that we will not be able to cover with the * linear mapping. Take care not to clip the kernel which may be @@ -318,6 +298,16 @@ void __init arm64_memblock_init(void) memblock_remove(0, memstart_addr); } + /* + * If we are running with a 52-bit kernel VA config on a system that + * does not support it, we have to place the available physical + * memory in the 48-bit addressable part of the linear region, i.e., + * we have to move it upward. Since memstart_addr represents the + * physical address of PAGE_OFFSET, we have to *subtract* from it. + */ + if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52) && (vabits_actual != 52)) + memstart_addr -= _PAGE_OFFSET(48) - _PAGE_OFFSET(52); + /* * Apply the memory limit if it was set. Since the kernel may be loaded * high up in memory, add back the kernel region that must be accessible -- cgit v1.2.3-58-ga151 From 45544eee96065cf183fbb937fe1f45a172b06f4e Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Wed, 14 Oct 2020 00:53:07 +0000 Subject: arm64: mremap speedup - Enable HAVE_MOVE_PMD HAVE_MOVE_PMD enables remapping pages at the PMD level if both the source and destination addresses are PMD-aligned. HAVE_MOVE_PMD is already enabled on x86. The original patch [1] that introduced this config did not enable it on arm64 at the time because of performance issues with flushing the TLB on every PMD move. These issues have since been addressed in more recent releases with improvements to the arm64 TLB invalidation and core mmu_gather code as Will Deacon mentioned in [2]. >From the data below, it can be inferred that there is approximately 8x improvement in performance when HAVE_MOVE_PMD is enabled on arm64. --------- Test Results ---------- The following results were obtained on an arm64 device running a 5.4 kernel, by remapping a PMD-aligned, 1GB sized region to a PMD-aligned destination. The results from 10 iterations of the test are given below. All times are in nanoseconds. Control HAVE_MOVE_PMD 9220833 1247761 9002552 1219896 9254115 1094792 8725885 1227760 9308646 1043698 9001667 1101771 8793385 1159896 8774636 1143594 9553125 1025833 9374010 1078125 9100885.4 1134312.6 <-- Mean Time in nanoseconds Total mremap time for a 1GB sized PMD-aligned region drops from ~9.1 milliseconds to ~1.1 milliseconds. (~8x speedup). [1] https://lore.kernel.org/r/20181108181201.88826-3-joelaf@google.com [2] https://www.mail-archive.com/linuxppc-dev@lists.ozlabs.org/msg140837.html Signed-off-by: Kalesh Singh Acked-by: Kirill A. Shutemov Cc: Catalin Marinas Cc: Will Deacon Cc: Andrew Morton Link: https://lore.kernel.org/r/20201014005320.2233162-3-kaleshsingh@google.com Link: https://lore.kernel.org/kvmarm/20181029102840.GC13965@arm.com/ Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm64') diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 43091f439e4e..02e1a868d570 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -122,6 +122,7 @@ config ARM64 select GENERIC_VDSO_TIME_NS select HANDLE_DOMAIN_IRQ select HARDIRQS_SW_RESEND + select HAVE_MOVE_PMD select HAVE_PCI select HAVE_ACPI_APEI if (ACPI && EFI) select HAVE_ALIGNED_STRUCT_PAGE if SLUB -- cgit v1.2.3-58-ga151 From 7bdf468a5b40bbf1776e17eb1313d145d3e3ce28 Mon Sep 17 00:00:00 2001 From: Palmer Dabbelt Date: Fri, 16 Oct 2020 17:26:37 -0700 Subject: arm64: Fix a broken copyright header in gen_vdso_offsets.sh I was going to copy this but I didn't want to chase around the build system stuff so I did it a different way. Signed-off-by: Palmer Dabbelt Link: https://lore.kernel.org/r/20201017002637.503579-1-palmer@dabbelt.com Signed-off-by: Will Deacon --- arch/arm64/kernel/vdso/gen_vdso_offsets.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm64') diff --git a/arch/arm64/kernel/vdso/gen_vdso_offsets.sh b/arch/arm64/kernel/vdso/gen_vdso_offsets.sh index 0664acaf61ff..8b806eacd0a6 100755 --- a/arch/arm64/kernel/vdso/gen_vdso_offsets.sh +++ b/arch/arm64/kernel/vdso/gen_vdso_offsets.sh @@ -8,7 +8,7 @@ # Doing this inside the Makefile will break the $(filter-out) function, # causing Kbuild to rebuild the vdso-offsets header file every time. # -# Author: Will Deacon # LC_ALL=C -- cgit v1.2.3-58-ga151 From 3b92fa7485eba16b05166fddf38ab42f2ff6ab95 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Fri, 16 Oct 2020 10:53:39 -0700 Subject: arm64: link with -z norelro regardless of CONFIG_RELOCATABLE With CONFIG_EXPERT=y, CONFIG_KASAN=y, CONFIG_RANDOMIZE_BASE=n, CONFIG_RELOCATABLE=n, we observe the following failure when trying to link the kernel image with LD=ld.lld: error: section: .exit.data is not contiguous with other relro sections ld.lld defaults to -z relro while ld.bfd defaults to -z norelro. This was previously fixed, but only for CONFIG_RELOCATABLE=y. Fixes: 3bbd3db86470 ("arm64: relocatable: fix inconsistencies in linker script and options") Signed-off-by: Nick Desaulniers Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20201016175339.2429280-1-ndesaulniers@google.com Signed-off-by: Will Deacon --- arch/arm64/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm64') diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 0fd4c1be4f64..1245274dacf9 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -10,13 +10,13 @@ # # Copyright (C) 1995-2001 by Russell King -LDFLAGS_vmlinux :=--no-undefined -X +LDFLAGS_vmlinux :=--no-undefined -X -z norelro ifeq ($(CONFIG_RELOCATABLE), y) # Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour # for relative relocs, since this leads to better Image compression # with the relocation offsets always being zero. -LDFLAGS_vmlinux += -shared -Bsymbolic -z notext -z norelro \ +LDFLAGS_vmlinux += -shared -Bsymbolic -z notext \ $(call ld-option, --no-apply-dynamic-relocs) endif -- cgit v1.2.3-58-ga151 From ea8f8c99a28199f6e067581b8626d192b07750f2 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 20 Oct 2020 16:01:57 +0100 Subject: arm64: spectre-v2: Favour CPU-specific mitigation at EL2 Spectre-v2 can be mitigated on Falkor CPUs either by calling into firmware or by issuing a magic, CPU-specific sequence of branches. Although the latter is faster, the size of the code sequence means that it cannot be used in the EL2 vectors, and so there is a need for both mitigations to co-exist in order to achieve optimal performance. Change the mitigation selection logic for Spectre-v2 so that the CPU-specific mitigation is used only when the firmware mitigation is also available, rather than when a firmware mitigation is unavailable. Cc: Marc Zyngier Signed-off-by: Will Deacon --- arch/arm64/kernel/proton-pack.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'arch/arm64') diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c index 68b710f1b43f..5029ef14fb27 100644 --- a/arch/arm64/kernel/proton-pack.c +++ b/arch/arm64/kernel/proton-pack.c @@ -67,7 +67,8 @@ ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, * - Mitigated in hardware and advertised by ID_AA64PFR0_EL1.CSV2. * - Mitigated in hardware and listed in our "safe list". * - Mitigated in software by firmware. - * - Mitigated in software by a CPU-specific dance in the kernel. + * - Mitigated in software by a CPU-specific dance in the kernel and a + * firmware call at EL2. * - Vulnerable. * * It's not unlikely for different CPUs in a big.LITTLE system to fall into @@ -259,6 +260,16 @@ static void qcom_link_stack_sanitisation(void) : "=&r" (tmp)); } +static bp_hardening_cb_t spectre_v2_get_sw_mitigation_cb(void) +{ + u32 midr = read_cpuid_id(); + if (((midr & MIDR_CPU_MODEL_MASK) != MIDR_QCOM_FALKOR) && + ((midr & MIDR_CPU_MODEL_MASK) != MIDR_QCOM_FALKOR_V1)) + return NULL; + + return qcom_link_stack_sanitisation; +} + static enum mitigation_state spectre_v2_enable_fw_mitigation(void) { bp_hardening_cb_t cb; @@ -284,26 +295,15 @@ static enum mitigation_state spectre_v2_enable_fw_mitigation(void) return SPECTRE_VULNERABLE; } + /* + * Prefer a CPU-specific workaround if it exists. Note that we + * still rely on firmware for the mitigation at EL2. + */ + cb = spectre_v2_get_sw_mitigation_cb() ?: cb; install_bp_hardening_cb(cb); return SPECTRE_MITIGATED; } -static enum mitigation_state spectre_v2_enable_sw_mitigation(void) -{ - u32 midr; - - if (spectre_v2_mitigations_off()) - return SPECTRE_VULNERABLE; - - midr = read_cpuid_id(); - if (((midr & MIDR_CPU_MODEL_MASK) != MIDR_QCOM_FALKOR) && - ((midr & MIDR_CPU_MODEL_MASK) != MIDR_QCOM_FALKOR_V1)) - return SPECTRE_VULNERABLE; - - install_bp_hardening_cb(qcom_link_stack_sanitisation); - return SPECTRE_MITIGATED; -} - void spectre_v2_enable_mitigation(const struct arm64_cpu_capabilities *__unused) { enum mitigation_state state; @@ -313,8 +313,6 @@ void spectre_v2_enable_mitigation(const struct arm64_cpu_capabilities *__unused) state = spectre_v2_get_cpu_hw_mitigation_state(); if (state == SPECTRE_VULNERABLE) state = spectre_v2_enable_fw_mitigation(); - if (state == SPECTRE_VULNERABLE) - state = spectre_v2_enable_sw_mitigation(); update_mitigation_state(&spectre_v2_state, state); } -- cgit v1.2.3-58-ga151 From 66dd3474702aa98d5844367e1577cdad78ef7c65 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 20 Oct 2020 14:45:44 -0700 Subject: arm64: proton-pack: Update comment to reflect new function name The function detect_harden_bp_fw() is gone after commit d4647f0a2ad7 ("arm64: Rewrite Spectre-v2 mitigation code"). Update this comment to reflect the new state of affairs. Fixes: d4647f0a2ad7 ("arm64: Rewrite Spectre-v2 mitigation code") Signed-off-by: Stephen Boyd Cc: Marc Zyngier Link: https://lore.kernel.org/r/20201020214544.3206838-3-swboyd@chromium.org Signed-off-by: Will Deacon --- arch/arm64/kernel/proton-pack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm64') diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c index 5029ef14fb27..25f3c80b5ffe 100644 --- a/arch/arm64/kernel/proton-pack.c +++ b/arch/arm64/kernel/proton-pack.c @@ -205,8 +205,8 @@ static void install_bp_hardening_cb(bp_hardening_cb_t fn) __SMCCC_WORKAROUND_1_SMC_SZ; /* - * detect_harden_bp_fw() passes NULL for the hyp_vecs start/end if - * we're a guest. Skip the hyp-vectors work. + * Vinz Clortho takes the hyp_vecs start/end "keys" at + * the door when we're a guest. Skip the hyp-vectors work. */ if (!is_hyp_mode_available()) { __this_cpu_write(bp_hardening_data.fn, fn); -- cgit v1.2.3-58-ga151