[PATCH] arm: Make kprobes unregistration SMP safe
Nicolas Pitre
nico at fluxnic.net
Thu Sep 17 20:40:10 EDT 2009
On Wed, 16 Sep 2009, Frédéric RISS wrote:
> ARM kprobes use an illegal instruction to trigger kprobes. In the
> current implementation, there's a race between the unregistration of a
> kprobe and the illegal instruction exception handler if they run at the
> same time on different cores.
>
> When reading the value of the undefined instruction, the exception
> handler might get the original legal instruction as just patched
> concurrently by arch_disarm_kprobe(). When this happen the kprobe
> handler won't run, and thus the exception handler will oops because it
> believe it just hit an undefined instruction in kernel space.
>
> The following patch synchronizes the code patching in the kprobes
> unregistration using stop_machine and thus avoids the above race.
>
> Signed-off-by: Frederic RISS <frederic.riss at gmail.com>
Acked-by: Nicolas Pitre <nico at fluxnic.net>
> ---
>
> diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
> index d28513f..6ada87d 100644
> --- a/arch/arm/kernel/kprobes.c
> +++ b/arch/arm/kernel/kprobes.c
> @@ -22,6 +22,7 @@
> #include <linux/kernel.h>
> #include <linux/kprobes.h>
> #include <linux/module.h>
> +#include <linux/stop_machine.h>
> #include <linux/stringify.h>
> #include <asm/traps.h>
> #include <asm/cacheflush.h>
> @@ -83,10 +84,24 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
> flush_insns(p->addr, 1);
> }
>
> +/*
> + * The actual disarming is done here on each CPU and synchronized using
> + * stop_machine. This synchronization is necessary on SMP to avoid removing
> + * a probe between the moment the 'Undefined Instruction' exception is raised
> + * and the moment the exception handler reads the faulting instruction from
> + * memory.
> + */
> +int __kprobes __arch_disarm_kprobe(void *p)
> +{
> + struct kprobe *kp = p;
> + *kp->addr = kp->opcode;
> + flush_insns(kp->addr, 1);
> + return 0;
> +}
> +
> void __kprobes arch_disarm_kprobe(struct kprobe *p)
> {
> - *p->addr = p->opcode;
> - flush_insns(p->addr, 1);
> + stop_machine(__arch_disarm_kprobe, p, &cpu_online_map);
> }
>
> void __kprobes arch_remove_kprobe(struct kprobe *p)
>
>
More information about the linux-arm-kernel
mailing list