[01/10] arm64: debug: Don't propagate UNKNOWN FAR into si_code for debug signals

Message ID 20190301132809.24653-2-will.deacon@arm.com
State Accepted
Commit b9a4b9d084d978f80eb9210727c81804588b42ff
Headers show
Series
  • [01/10] arm64: debug: Don't propagate UNKNOWN FAR into si_code for debug signals
Related show

Commit Message

Will Deacon March 1, 2019, 1:28 p.m.
FAR_EL1 is UNKNOWN for all debug exceptions other than those caused by
taking a hardware watchpoint. Unfortunately, if a debug handler returns
a non-zero value, then we will propagate the UNKNOWN FAR value to
userspace via the si_addr field of the SIGTRAP siginfo_t.

Instead, let's set si_addr to take on the PC of the faulting instruction,
which we have available in the current pt_regs.

Cc: <stable@vger.kernel.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>

---
 arch/arm64/mm/fault.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

-- 
2.11.0

Comments

Mark Rutland March 1, 2019, 1:45 p.m. | #1
On Fri, Mar 01, 2019 at 01:28:00PM +0000, Will Deacon wrote:
> FAR_EL1 is UNKNOWN for all debug exceptions other than those caused by

> taking a hardware watchpoint. Unfortunately, if a debug handler returns

> a non-zero value, then we will propagate the UNKNOWN FAR value to

> userspace via the si_addr field of the SIGTRAP siginfo_t.

> 

> Instead, let's set si_addr to take on the PC of the faulting instruction,

> which we have available in the current pt_regs.

> 

> Cc: <stable@vger.kernel.org>

> Signed-off-by: Will Deacon <will.deacon@arm.com>


Reviewed-by: Mark Rutland <mark.rutland@arm.com>


Mark.

> ---

>  arch/arm64/mm/fault.c | 9 +++++----

>  1 file changed, 5 insertions(+), 4 deletions(-)

> 

> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c

> index efb7b2cbead5..ef46925096f0 100644

> --- a/arch/arm64/mm/fault.c

> +++ b/arch/arm64/mm/fault.c

> @@ -824,11 +824,12 @@ void __init hook_debug_fault_code(int nr,

>  	debug_fault_info[nr].name	= name;

>  }

>  

> -asmlinkage int __exception do_debug_exception(unsigned long addr,

> +asmlinkage int __exception do_debug_exception(unsigned long addr_if_watchpoint,

>  					      unsigned int esr,

>  					      struct pt_regs *regs)

>  {

>  	const struct fault_info *inf = esr_to_debug_fault_info(esr);

> +	unsigned long pc = instruction_pointer(regs);

>  	int rv;

>  

>  	/*

> @@ -838,14 +839,14 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,

>  	if (interrupts_enabled(regs))

>  		trace_hardirqs_off();

>  

> -	if (user_mode(regs) && !is_ttbr0_addr(instruction_pointer(regs)))

> +	if (user_mode(regs) && !is_ttbr0_addr(pc))

>  		arm64_apply_bp_hardening();

>  

> -	if (!inf->fn(addr, esr, regs)) {

> +	if (!inf->fn(addr_if_watchpoint, esr, regs)) {

>  		rv = 1;

>  	} else {

>  		arm64_notify_die(inf->name, regs,

> -				 inf->sig, inf->code, (void __user *)addr, esr);

> +				 inf->sig, inf->code, (void __user *)pc, esr);

>  		rv = 0;

>  	}

>  

> -- 

> 2.11.0

>

Patch

diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index efb7b2cbead5..ef46925096f0 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -824,11 +824,12 @@  void __init hook_debug_fault_code(int nr,
 	debug_fault_info[nr].name	= name;
 }
 
-asmlinkage int __exception do_debug_exception(unsigned long addr,
+asmlinkage int __exception do_debug_exception(unsigned long addr_if_watchpoint,
 					      unsigned int esr,
 					      struct pt_regs *regs)
 {
 	const struct fault_info *inf = esr_to_debug_fault_info(esr);
+	unsigned long pc = instruction_pointer(regs);
 	int rv;
 
 	/*
@@ -838,14 +839,14 @@  asmlinkage int __exception do_debug_exception(unsigned long addr,
 	if (interrupts_enabled(regs))
 		trace_hardirqs_off();
 
-	if (user_mode(regs) && !is_ttbr0_addr(instruction_pointer(regs)))
+	if (user_mode(regs) && !is_ttbr0_addr(pc))
 		arm64_apply_bp_hardening();
 
-	if (!inf->fn(addr, esr, regs)) {
+	if (!inf->fn(addr_if_watchpoint, esr, regs)) {
 		rv = 1;
 	} else {
 		arm64_notify_die(inf->name, regs,
-				 inf->sig, inf->code, (void __user *)addr, esr);
+				 inf->sig, inf->code, (void __user *)pc, esr);
 		rv = 0;
 	}