BACKPORT: arm64: Add CNTFRQ_EL0 trap handler
Marc Zyngier [Wed, 20 Dec 2017 09:34:10 +0000 (14:34 +0530)]
We now trap accesses to CNTVCT_EL0 when the counter is broken
enough to require the kernel to mediate the access. But it
turns out that some existing userspace (such as OpenMPI) do
probe for the counter frequency, leading to an UNDEF exception
as CNTVCT_EL0 and CNTFRQ_EL0 share the same control bit.

The fix is to handle the exception the same way we do for CNTVCT_EL0.

Bug 2031796
CVE-2017-13218

Fixes: a86bd139f2ae ("arm64: arch_timer: Enable CNTVCT_EL0 trap if workaround is enabled")
Reported-by: Hanjun Guo <guohanjun@huawei.com>
Tested-by: Hanjun Guo <guohanjun@huawei.com>
Reviewed-by: Hanjun Guo <guohanjun@huawei.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
(cherry picked from commit 9842119a238bfb92cbab63258dabb54f0e7b111b)
Change-Id: Ie5a9a93fcca238d6097ecacd6df0e540be90220b
Signed-off-by: Gagan Grover <ggrover@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1623696
(cherry picked from commit b7437af000c530e53cedce73a942571405766245)
Reviewed-on: https://git-master.nvidia.com/r/1648568
Reviewed-by: Jeetesh Burman <jburman@nvidia.com>
Tested-by: Jeetesh Burman <jburman@nvidia.com>
Reviewed-by: Bibek Basu <bbasu@nvidia.com>
GVS: Gerrit_Virtual_Submit

arch/arm64/include/asm/esr.h
arch/arm64/kernel/traps.c

index 422ec15..3146d0c 100644 (file)
@@ -89,4 +89,7 @@
 #define ESR_ELx_SYS64_ISS_SYS_CNTVCT   (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 2, 14, 0) | \
                                         ESR_ELx_SYS64_ISS_DIR_READ)
 
+#define ESR_ELx_SYS64_ISS_SYS_CNTFRQ   (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 0, 14, 0) | \
+                                        ESR_ELx_SYS64_ISS_DIR_READ)
+
 #endif /* __ASM_ESR_H */
index c227247..3c97aab 100644 (file)
@@ -336,11 +336,23 @@ static void cntvct_read_handler(unsigned int esr, struct pt_regs *regs)
        regs->pc += 4;
 }
 
+static void cntfrq_read_handler(unsigned int esr, struct pt_regs *regs)
+{
+       int rt = (esr & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT;
+
+       if (rt != 31)
+               asm volatile("mrs %0, cntfrq_el0" : "=r" (regs->regs[rt]));
+       regs->pc += 4;
+}
+
 asmlinkage void __exception do_sysinstr(unsigned int esr, struct pt_regs *regs)
 {
        if ((esr & ESR_ELx_SYS64_ISS_SYS_OP_MASK) == ESR_ELx_SYS64_ISS_SYS_CNTVCT) {
                cntvct_read_handler(esr, regs);
                return;
+       } else if ((esr & ESR_ELx_SYS64_ISS_SYS_OP_MASK) == ESR_ELx_SYS64_ISS_SYS_CNTFRQ) {
+               cntfrq_read_handler(esr, regs);
+               return;
        }
 
        do_undefinstr(regs);