| From foo@baz Sun 27 Oct 2019 09:50:54 AM CET |
| From: Ard Biesheuvel <ard.biesheuvel@linaro.org> |
| Date: Thu, 24 Oct 2019 14:48:07 +0200 |
| Subject: arm64: capabilities: Restrict KPTI detection to boot-time CPUs |
| To: stable@vger.kernel.org |
| Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>, Will Deacon <will@kernel.org>, Catalin Marinas <catalin.marinas@arm.com>, Marc Zyngier <maz@kernel.org>, Mark Rutland <mark.rutland@arm.com>, Suzuki K Poulose <suzuki.poulose@arm.com>, Jeremy Linton <jeremy.linton@arm.com>, Andre Przywara <andre.przywara@arm.com>, Alexandru Elisei <alexandru.elisei@arm.com>, Will Deacon <will.deacon@arm.com>, Dave Martin <dave.martin@arm.com> |
| Message-ID: <20191024124833.4158-23-ard.biesheuvel@linaro.org> |
| |
| From: Suzuki K Poulose <suzuki.poulose@arm.com> |
| |
| [ Upstream commit d3aec8a28be3b88bf75442e7c24fd9da8d69a6df ] |
| |
| KPTI is treated as a system wide feature and is only detected if all |
| the CPUs in the sysetm needs the defense, unless it is forced via kernel |
| command line. This leaves a system with a mix of CPUs with and without |
| the defense vulnerable. Also, if a late CPU needs KPTI but KPTI was not |
| activated at boot time, the CPU is currently allowed to boot, which is a |
| potential security vulnerability. |
| This patch ensures that the KPTI is turned on if at least one CPU detects |
| the capability (i.e, change scope to SCOPE_LOCAL_CPU). Also rejetcs a late |
| CPU, if it requires the defense, when the system hasn't enabled it, |
| |
| Cc: Will Deacon <will.deacon@arm.com> |
| Reviewed-by: Dave Martin <dave.martin@arm.com> |
| Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> |
| Signed-off-by: Will Deacon <will.deacon@arm.com> |
| Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/arm64/include/asm/cpufeature.h | 9 +++++++++ |
| arch/arm64/kernel/cpufeature.c | 16 +++++++++++----- |
| 2 files changed, 20 insertions(+), 5 deletions(-) |
| |
| --- a/arch/arm64/include/asm/cpufeature.h |
| +++ b/arch/arm64/include/asm/cpufeature.h |
| @@ -244,6 +244,15 @@ extern struct arm64_ftr_reg arm64_ftr_re |
| ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU | \ |
| ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU) |
| |
| +/* |
| + * CPU feature detected at boot time, on one or more CPUs. A late CPU |
| + * is not allowed to have the capability when the system doesn't have it. |
| + * It is Ok for a late CPU to miss the feature. |
| + */ |
| +#define ARM64_CPUCAP_BOOT_RESTRICTED_CPU_LOCAL_FEATURE \ |
| + (ARM64_CPUCAP_SCOPE_LOCAL_CPU | \ |
| + ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU) |
| + |
| struct arm64_cpu_capabilities { |
| const char *desc; |
| u16 capability; |
| --- a/arch/arm64/kernel/cpufeature.c |
| +++ b/arch/arm64/kernel/cpufeature.c |
| @@ -824,10 +824,9 @@ static bool has_no_fpsimd(const struct a |
| static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */ |
| |
| static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, |
| - int __unused) |
| + int scope) |
| { |
| char const *str = "command line option"; |
| - u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); |
| |
| /* |
| * For reasons that aren't entirely clear, enabling KPTI on Cavium |
| @@ -863,8 +862,7 @@ static bool unmap_kernel_at_el0(const st |
| } |
| |
| /* Defer to CPU feature registers */ |
| - return !cpuid_feature_extract_unsigned_field(pfr0, |
| - ID_AA64PFR0_CSV3_SHIFT); |
| + return !has_cpuid_feature(entry, scope); |
| } |
| |
| static void |
| @@ -1011,7 +1009,15 @@ static const struct arm64_cpu_capabiliti |
| { |
| .desc = "Kernel page table isolation (KPTI)", |
| .capability = ARM64_UNMAP_KERNEL_AT_EL0, |
| - .type = ARM64_CPUCAP_SYSTEM_FEATURE, |
| + .type = ARM64_CPUCAP_BOOT_RESTRICTED_CPU_LOCAL_FEATURE, |
| + /* |
| + * The ID feature fields below are used to indicate that |
| + * the CPU doesn't need KPTI. See unmap_kernel_at_el0 for |
| + * more details. |
| + */ |
| + .sys_reg = SYS_ID_AA64PFR0_EL1, |
| + .field_pos = ID_AA64PFR0_CSV3_SHIFT, |
| + .min_field_value = 1, |
| .matches = unmap_kernel_at_el0, |
| .cpu_enable = kpti_install_ng_mappings, |
| }, |