[RFC PATCH] powerpc/uprobes: Fixup si_addr if we took an exception while single stepping

Christophe Leroy christophe.leroy at csgroup.eu
Sat Mar 12 03:49:19 AEDT 2022



Le 13/09/2017 à 22:03, Naveen N. Rao a écrit :
> If the single-stepped instruction causes an exception, we may end up
> setting siginfo.si_addr to the address of the uprobe xol area. This is
> not desirable since the address won't make sense for the process if it
> wants to handle the exception. Fixup the si_addr field in such cases.
> 
> Reported-by: Anton Blanchard <anton at samba.org>
> Signed-off-by: Naveen N. Rao <naveen.n.rao at linux.vnet.ibm.com>


Nowadays _exception() calls force_sig_fault_to_task() so if the change 
is still required I guess it must be done there ?

Christophe


> ---
>   arch/powerpc/include/asm/uprobes.h |  7 +++++++
>   arch/powerpc/kernel/traps.c        |  4 ++++
>   arch/powerpc/kernel/uprobes.c      | 17 +++++++++++++++++
>   3 files changed, 28 insertions(+)
> 
> diff --git a/arch/powerpc/include/asm/uprobes.h b/arch/powerpc/include/asm/uprobes.h
> index 7422a999a39a..13fc6af3c1fd 100644
> --- a/arch/powerpc/include/asm/uprobes.h
> +++ b/arch/powerpc/include/asm/uprobes.h
> @@ -23,6 +23,7 @@
>    */
>   
>   #include <linux/notifier.h>
> +#include <asm/siginfo.h>
>   #include <asm/probes.h>
>   
>   typedef ppc_opcode_t uprobe_opcode_t;
> @@ -45,4 +46,10 @@ struct arch_uprobe_task {
>   	unsigned long	saved_trap_nr;
>   };
>   
> +#ifdef CONFIG_UPROBES
> +extern void uprobe_fixup_exception(struct pt_regs *regs, siginfo_t *info);
> +#else
> +static inline void uprobe_fixup_exception(struct pt_regs *regs, siginfo_t *info) { }
> +#endif
> +
>   #endif	/* _ASM_UPROBES_H */
> diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
> index ec74e203ee04..1bb858a37029 100644
> --- a/arch/powerpc/kernel/traps.c
> +++ b/arch/powerpc/kernel/traps.c
> @@ -66,6 +66,7 @@
>   #include <asm/hmi.h>
>   #include <sysdev/fsl_pci.h>
>   #include <asm/kprobes.h>
> +#include <asm/uprobes.h>
>   
>   #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC_CORE)
>   int (*__debugger)(struct pt_regs *regs) __read_mostly;
> @@ -292,6 +293,9 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
>   	info.si_signo = signr;
>   	info.si_code = code;
>   	info.si_addr = (void __user *) addr;
> +
> +	uprobe_fixup_exception(regs, &info);
> +
>   	force_sig_info(signr, &info, current);
>   }
>   
> diff --git a/arch/powerpc/kernel/uprobes.c b/arch/powerpc/kernel/uprobes.c
> index 5d105b8eeece..a361a56e6210 100644
> --- a/arch/powerpc/kernel/uprobes.c
> +++ b/arch/powerpc/kernel/uprobes.c
> @@ -25,6 +25,7 @@
>   #include <linux/uprobes.h>
>   #include <linux/uaccess.h>
>   #include <linux/kdebug.h>
> +#include <linux/signal.h>
>   
>   #include <asm/sstep.h>
>   
> @@ -214,3 +215,19 @@ bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
>   	else
>   		return regs->gpr[1] < ret->stack;
>   }
> +
> +void uprobe_fixup_exception(struct pt_regs *regs, siginfo_t *info)
> +{
> +	struct task_struct *t = current;
> +	struct uprobe_task *utask = t->utask;
> +
> +	if (likely(!utask || !utask->active_uprobe))
> +		return;
> +
> +	/*
> +	 * We reset si_addr here.
> +	 * regs->nip is reset during our way back through uprobe_deny_signal()
> +	 */
> +	if (info->si_addr == (void __user *) utask->xol_vaddr)
> +		info->si_addr = (void __user *) utask->vaddr;
> +}


More information about the Linuxppc-dev mailing list