diff mbox

[3/5] arm64: Handle TRAP_HWBRKPT for user mode as well

Message ID ebc25cc4a2ea95cace064aa1c3a2407885623d16.1470114993.git.panand@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Pratyush Anand Aug. 2, 2016, 5:30 a.m. UTC
uprobe registers a handler at step_hook. So, single_step_handler now
checks for user mode as well if there is a valid hook.

Signed-off-by: Pratyush Anand <panand@redhat.com>
---
 arch/arm64/kernel/debug-monitors.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

Comments

Catalin Marinas Sept. 6, 2016, 4:11 p.m. UTC | #1
On Tue, Aug 02, 2016 at 11:00:07AM +0530, Pratyush Anand wrote:
> --- a/arch/arm64/kernel/debug-monitors.c
> +++ b/arch/arm64/kernel/debug-monitors.c
> @@ -246,6 +246,8 @@ static void send_user_sigtrap(int si_code)
>  static int single_step_handler(unsigned long addr, unsigned int esr,
>  			       struct pt_regs *regs)
>  {
> +	bool handler_found = false;
> +
>  	/*
>  	 * If we are stepping a pending breakpoint, call the hw_breakpoint
>  	 * handler first.
> @@ -253,7 +255,14 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
>  	if (!reinstall_suspended_bps(regs))
>  		return 0;
>  
> -	if (user_mode(regs)) {
> +#ifdef	CONFIG_KPROBES
> +	if (kprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED)
> +		handler_found = true;
> +#endif
> +	if (!handler_found && call_step_hook(regs, esr) == DBG_HOOK_HANDLED)
> +		handler_found = true;
> +
> +	if (!handler_found && user_mode(regs)) {
>  		send_user_sigtrap(TRAP_HWBKPT);

Could we register kprobe_single_step_handler() via register_set_hook()
and only invoke call_step_hook() above?
David Long Sept. 6, 2016, 9:36 p.m. UTC | #2
On 09/06/2016 12:11 PM, Catalin Marinas wrote:
> On Tue, Aug 02, 2016 at 11:00:07AM +0530, Pratyush Anand wrote:
>> --- a/arch/arm64/kernel/debug-monitors.c
>> +++ b/arch/arm64/kernel/debug-monitors.c
>> @@ -246,6 +246,8 @@ static void send_user_sigtrap(int si_code)
>>   static int single_step_handler(unsigned long addr, unsigned int esr,
>>   			       struct pt_regs *regs)
>>   {
>> +	bool handler_found = false;
>> +
>>   	/*
>>   	 * If we are stepping a pending breakpoint, call the hw_breakpoint
>>   	 * handler first.
>> @@ -253,7 +255,14 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
>>   	if (!reinstall_suspended_bps(regs))
>>   		return 0;
>>
>> -	if (user_mode(regs)) {
>> +#ifdef	CONFIG_KPROBES
>> +	if (kprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED)
>> +		handler_found = true;
>> +#endif
>> +	if (!handler_found && call_step_hook(regs, esr) == DBG_HOOK_HANDLED)
>> +		handler_found = true;
>> +
>> +	if (!handler_found && user_mode(regs)) {
>>   		send_user_sigtrap(TRAP_HWBKPT);
>
> Could we register kprobe_single_step_handler() via register_set_hook()
> and only invoke call_step_hook() above?
>

I seem to recall a criticism of doing that in a much earlier kprobes64 
patch of mine.  The concern was that it would cause unnecessarily more 
kernel functions to be kprobes-blacklisted.  Hence the hardcoded check 
and call.

-dl
Pratyush Anand Sept. 7, 2016, 4:47 a.m. UTC | #3
On 06/09/2016:05:36:18 PM, David Long wrote:
> On 09/06/2016 12:11 PM, Catalin Marinas wrote:
> > On Tue, Aug 02, 2016 at 11:00:07AM +0530, Pratyush Anand wrote:
> > > --- a/arch/arm64/kernel/debug-monitors.c
> > > +++ b/arch/arm64/kernel/debug-monitors.c
> > > @@ -246,6 +246,8 @@ static void send_user_sigtrap(int si_code)
> > >   static int single_step_handler(unsigned long addr, unsigned int esr,
> > >   			       struct pt_regs *regs)
> > >   {
> > > +	bool handler_found = false;
> > > +
> > >   	/*
> > >   	 * If we are stepping a pending breakpoint, call the hw_breakpoint
> > >   	 * handler first.
> > > @@ -253,7 +255,14 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
> > >   	if (!reinstall_suspended_bps(regs))
> > >   		return 0;
> > > 
> > > -	if (user_mode(regs)) {
> > > +#ifdef	CONFIG_KPROBES
> > > +	if (kprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED)
> > > +		handler_found = true;
> > > +#endif
> > > +	if (!handler_found && call_step_hook(regs, esr) == DBG_HOOK_HANDLED)
> > > +		handler_found = true;
> > > +
> > > +	if (!handler_found && user_mode(regs)) {
> > >   		send_user_sigtrap(TRAP_HWBKPT);
> > 
> > Could we register kprobe_single_step_handler() via register_set_hook()
> > and only invoke call_step_hook() above?
> > 
> 
> I seem to recall a criticism of doing that in a much earlier kprobes64 patch
> of mine.  The concern was that it would cause unnecessarily more kernel
> functions to be kprobes-blacklisted.  Hence the hardcoded check and call.

Yes, all the code regions are kprobe unsafe which lie within the moment we
receive a break/single step exception to the point where it is handled for
kprobe. Therefore we must call kprobe_single_step/breakpoint_handler() before
other handlers. Otherwise, we would not be able to trace other handlers and the
functions called from those handlers.

~Pratyush
Catalin Marinas Sept. 7, 2016, 1:41 p.m. UTC | #4
On Tue, Sep 06, 2016 at 05:36:18PM -0400, David Long wrote:
> On 09/06/2016 12:11 PM, Catalin Marinas wrote:
> > On Tue, Aug 02, 2016 at 11:00:07AM +0530, Pratyush Anand wrote:
> > > --- a/arch/arm64/kernel/debug-monitors.c
> > > +++ b/arch/arm64/kernel/debug-monitors.c
> > > @@ -246,6 +246,8 @@ static void send_user_sigtrap(int si_code)
> > >   static int single_step_handler(unsigned long addr, unsigned int esr,
> > >   			       struct pt_regs *regs)
> > >   {
> > > +	bool handler_found = false;
> > > +
> > >   	/*
> > >   	 * If we are stepping a pending breakpoint, call the hw_breakpoint
> > >   	 * handler first.
> > > @@ -253,7 +255,14 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
> > >   	if (!reinstall_suspended_bps(regs))
> > >   		return 0;
> > > 
> > > -	if (user_mode(regs)) {
> > > +#ifdef	CONFIG_KPROBES
> > > +	if (kprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED)
> > > +		handler_found = true;
> > > +#endif
> > > +	if (!handler_found && call_step_hook(regs, esr) == DBG_HOOK_HANDLED)
> > > +		handler_found = true;
> > > +
> > > +	if (!handler_found && user_mode(regs)) {
> > >   		send_user_sigtrap(TRAP_HWBKPT);
> > 
> > Could we register kprobe_single_step_handler() via register_set_hook()
> > and only invoke call_step_hook() above?
> 
> I seem to recall a criticism of doing that in a much earlier kprobes64 patch
> of mine.  The concern was that it would cause unnecessarily more kernel
> functions to be kprobes-blacklisted.  Hence the hardcoded check and call.

Ah, ok. I missed this aspect.
diff mbox

Patch

diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index 91fff48d0f57..fae2f57a92b7 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -246,6 +246,8 @@  static void send_user_sigtrap(int si_code)
 static int single_step_handler(unsigned long addr, unsigned int esr,
 			       struct pt_regs *regs)
 {
+	bool handler_found = false;
+
 	/*
 	 * If we are stepping a pending breakpoint, call the hw_breakpoint
 	 * handler first.
@@ -253,7 +255,14 @@  static int single_step_handler(unsigned long addr, unsigned int esr,
 	if (!reinstall_suspended_bps(regs))
 		return 0;
 
-	if (user_mode(regs)) {
+#ifdef	CONFIG_KPROBES
+	if (kprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED)
+		handler_found = true;
+#endif
+	if (!handler_found && call_step_hook(regs, esr) == DBG_HOOK_HANDLED)
+		handler_found = true;
+
+	if (!handler_found && user_mode(regs)) {
 		send_user_sigtrap(TRAP_HWBKPT);
 
 		/*
@@ -263,15 +272,8 @@  static int single_step_handler(unsigned long addr, unsigned int esr,
 		 * to the active-not-pending state).
 		 */
 		user_rewind_single_step(current);
-	} else {
-#ifdef	CONFIG_KPROBES
-		if (kprobe_single_step_handler(regs, esr) == DBG_HOOK_HANDLED)
-			return 0;
-#endif
-		if (call_step_hook(regs, esr) == DBG_HOOK_HANDLED)
-			return 0;
-
-		pr_warning("Unexpected kernel single-step exception at EL1\n");
+	} else if (!handler_found) {
+		pr_warn("Unexpected kernel single-step exception at EL1\n");
 		/*
 		 * Re-enable stepping since we know that we will be
 		 * returning to regs.