1 From b9a4b9d084d978f80eb9210727c81804588b42ff Mon Sep 17 00:00:00 2001
2 From: Will Deacon <will.deacon@arm.com>
3 Date: Fri, 1 Mar 2019 13:28:00 +0000
4 Subject: arm64: debug: Don't propagate UNKNOWN FAR into si_code for debug signals
6 From: Will Deacon <will.deacon@arm.com>
8 commit b9a4b9d084d978f80eb9210727c81804588b42ff upstream.
10 FAR_EL1 is UNKNOWN for all debug exceptions other than those caused by
11 taking a hardware watchpoint. Unfortunately, if a debug handler returns
12 a non-zero value, then we will propagate the UNKNOWN FAR value to
13 userspace via the si_addr field of the SIGTRAP siginfo_t.
15 Instead, let's set si_addr to take on the PC of the faulting instruction,
16 which we have available in the current pt_regs.
18 Cc: <stable@vger.kernel.org>
19 Reviewed-by: Mark Rutland <mark.rutland@arm.com>
20 Signed-off-by: Will Deacon <will.deacon@arm.com>
21 Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
22 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
26 arch/arm64/mm/fault.c | 9 +++++----
27 1 file changed, 5 insertions(+), 4 deletions(-)
29 --- a/arch/arm64/mm/fault.c
30 +++ b/arch/arm64/mm/fault.c
31 @@ -827,11 +827,12 @@ void __init hook_debug_fault_code(int nr
32 debug_fault_info[nr].name = name;
35 -asmlinkage int __exception do_debug_exception(unsigned long addr,
36 +asmlinkage int __exception do_debug_exception(unsigned long addr_if_watchpoint,
40 const struct fault_info *inf = debug_fault_info + DBG_ESR_EVT(esr);
41 + unsigned long pc = instruction_pointer(regs);
45 @@ -841,10 +842,10 @@ asmlinkage int __exception do_debug_exce
46 if (interrupts_enabled(regs))
49 - if (user_mode(regs) && instruction_pointer(regs) > TASK_SIZE)
50 + if (user_mode(regs) && pc > TASK_SIZE)
51 arm64_apply_bp_hardening();
53 - if (!inf->fn(addr, esr, regs)) {
54 + if (!inf->fn(addr_if_watchpoint, esr, regs)) {
58 @@ -853,7 +854,7 @@ asmlinkage int __exception do_debug_exce
59 info.si_signo = inf->sig;
61 info.si_code = inf->code;
62 - info.si_addr = (void __user *)addr;
63 + info.si_addr = (void __user *)pc;
64 arm64_notify_die(inf->name, regs, &info, esr);