summaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2018-10-01 12:19:43 +0100
committerCatalin Marinas <catalin.marinas@arm.com>2018-10-01 16:52:24 +0100
commitc219bc4e920518feb025749bdf9623aa57e94b64 (patch)
treebf2043211dbd9423e10005d6872d348065fb40cb /arch/arm64/kernel
parentee91176120bd584aa10c564e7e9fdcaf397190a1 (diff)
downloadlinux-stable-c219bc4e920518feb025749bdf9623aa57e94b64.tar.gz
linux-stable-c219bc4e920518feb025749bdf9623aa57e94b64.tar.bz2
linux-stable-c219bc4e920518feb025749bdf9623aa57e94b64.zip
arm64: Trap WFI executed in userspace
It recently came to light that userspace can execute WFI, and that the arm64 kernel doesn't trap this event. This sounds rather benign, but the kernel should decide when it wants to wait for an interrupt, and not userspace. Let's trap WFI and immediately return after having skipped the instruction. This effectively makes WFI a rather expensive NOP. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64/kernel')
-rw-r--r--arch/arm64/kernel/entry.S1
-rw-r--r--arch/arm64/kernel/traps.c11
2 files changed, 12 insertions, 0 deletions
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index f0a0464d4809..039144ecbcb2 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -665,6 +665,7 @@ el0_sync:
cmp x24, #ESR_ELx_EC_FP_EXC64 // FP/ASIMD exception
b.eq el0_fpsimd_exc
cmp x24, #ESR_ELx_EC_SYS64 // configurable trap
+ ccmp x24, #ESR_ELx_EC_WFx, #4, ne
b.eq el0_sys
cmp x24, #ESR_ELx_EC_SP_ALIGN // stack alignment exception
b.eq el0_sp_pc
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 58134a97928f..4066da7f1e5e 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -508,6 +508,11 @@ static void mrs_handler(unsigned int esr, struct pt_regs *regs)
force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc);
}
+static void wfi_handler(unsigned int esr, struct pt_regs *regs)
+{
+ arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
+}
+
struct sys64_hook {
unsigned int esr_mask;
unsigned int esr_val;
@@ -544,6 +549,12 @@ static struct sys64_hook sys64_hooks[] = {
.esr_val = ESR_ELx_SYS64_ISS_SYS_MRS_OP_VAL,
.handler = mrs_handler,
},
+ {
+ /* Trap WFI instructions executed in userspace */
+ .esr_mask = ESR_ELx_WFx_MASK,
+ .esr_val = ESR_ELx_WFx_WFI_VAL,
+ .handler = wfi_handler,
+ },
{},
};