4.11-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Kristina Martsenko <[email protected]>

commit 81cddd65b5c82758ea5571a25e31ff6f1f89ff02 upstream.

When we emulate userspace cache maintenance in the kernel, we can
currently send the task a SIGSEGV even though the maintenance was done
on a valid address. This happens if the address has a non-zero address
tag, and happens to not be mapped in.

When we get the address from a user register, we don't currently remove
the address tag before performing cache maintenance on it. If the
maintenance faults, we end up in either __do_page_fault, where find_vma
can't find the VMA if the address has a tag, or in do_translation_fault,
where the tagged address will appear to be above TASK_SIZE. In both
cases, the address is not mapped in, and the task is sent a SIGSEGV.

This patch removes the tag from the address before using it. With this
patch, the fault is handled correctly, the address gets mapped in, and
the cache maintenance succeeds.

As a second bug, if cache maintenance (correctly) fails on an invalid
tagged address, the address gets passed into arm64_notify_segfault,
where find_vma fails to find the VMA due to the tag, and the wrong
si_code may be sent as part of the siginfo_t of the segfault. With this
patch, the correct si_code is sent.

Fixes: 7dd01aef0557 ("arm64: trap userspace "dc cvau" cache operation on 
errata-affected core")
Acked-by: Will Deacon <[email protected]>
Signed-off-by: Kristina Martsenko <[email protected]>
Signed-off-by: Catalin Marinas <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
 arch/arm64/kernel/traps.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -443,7 +443,7 @@ int cpu_enable_cache_maint_trap(void *__
 }
 
 #define __user_cache_maint(insn, address, res)                 \
-       if (untagged_addr(address) >= user_addr_max()) {        \
+       if (address >= user_addr_max()) {                       \
                res = -EFAULT;                                  \
        } else {                                                \
                uaccess_ttbr0_enable();                         \
@@ -469,7 +469,7 @@ static void user_cache_maint_handler(uns
        int crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> 
ESR_ELx_SYS64_ISS_CRM_SHIFT;
        int ret = 0;
 
-       address = pt_regs_read_reg(regs, rt);
+       address = untagged_addr(pt_regs_read_reg(regs, rt));
 
        switch (crm) {
        case ESR_ELx_SYS64_ISS_CRM_DC_CVAU:     /* DC CVAU, gets promoted */


Reply via email to