kprobes: Remove kprobe::fault_handler
The reason for kprobe::fault_handler(), as given by their comment: * We come here because instructions in the pre/post * handler caused the page_fault, this could happen * if handler tries to access user space by * copy_from_user(), get_user() etc. Let the * user-specified handler try to fix it first. Is just plain bad. Those other handlers are ran from non-preemptible context and had better use _nofault() functions. Also, there is no upstream usage of this. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Acked-by: Masami Hiramatsu <mhiramat@kernel.org> Link: https://lore.kernel.org/r/20210525073213.561116662@infradead.org
This commit is contained in:
parent
9ce4d216fe
commit
ec6aba3d2b
|
@ -362,14 +362,11 @@ register_kprobe
|
||||||
#include <linux/kprobes.h>
|
#include <linux/kprobes.h>
|
||||||
int register_kprobe(struct kprobe *kp);
|
int register_kprobe(struct kprobe *kp);
|
||||||
|
|
||||||
Sets a breakpoint at the address kp->addr. When the breakpoint is
|
Sets a breakpoint at the address kp->addr. When the breakpoint is hit, Kprobes
|
||||||
hit, Kprobes calls kp->pre_handler. After the probed instruction
|
calls kp->pre_handler. After the probed instruction is single-stepped, Kprobe
|
||||||
is single-stepped, Kprobe calls kp->post_handler. If a fault
|
calls kp->post_handler. Any or all handlers can be NULL. If kp->flags is set
|
||||||
occurs during execution of kp->pre_handler or kp->post_handler,
|
KPROBE_FLAG_DISABLED, that kp will be registered but disabled, so, its handlers
|
||||||
or during single-stepping of the probed instruction, Kprobes calls
|
aren't hit until calling enable_kprobe(kp).
|
||||||
kp->fault_handler. Any or all handlers can be NULL. If kp->flags
|
|
||||||
is set KPROBE_FLAG_DISABLED, that kp will be registered but disabled,
|
|
||||||
so, its handlers aren't hit until calling enable_kprobe(kp).
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -415,17 +412,6 @@ User's post-handler (kp->post_handler)::
|
||||||
p and regs are as described for the pre_handler. flags always seems
|
p and regs are as described for the pre_handler. flags always seems
|
||||||
to be zero.
|
to be zero.
|
||||||
|
|
||||||
User's fault-handler (kp->fault_handler)::
|
|
||||||
|
|
||||||
#include <linux/kprobes.h>
|
|
||||||
#include <linux/ptrace.h>
|
|
||||||
int fault_handler(struct kprobe *p, struct pt_regs *regs, int trapnr);
|
|
||||||
|
|
||||||
p and regs are as described for the pre_handler. trapnr is the
|
|
||||||
architecture-specific trap number associated with the fault (e.g.,
|
|
||||||
on i386, 13 for a general protection fault or 14 for a page fault).
|
|
||||||
Returns 1 if it successfully handled the exception.
|
|
||||||
|
|
||||||
register_kretprobe
|
register_kretprobe
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -323,16 +323,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned long trapnr)
|
||||||
*/
|
*/
|
||||||
kprobes_inc_nmissed_count(cur);
|
kprobes_inc_nmissed_count(cur);
|
||||||
|
|
||||||
/*
|
|
||||||
* We come here because instructions in the pre/post
|
|
||||||
* handler caused the page_fault, this could happen
|
|
||||||
* if handler tries to access user space by
|
|
||||||
* copy_from_user(), get_user() etc. Let the
|
|
||||||
* user-specified handler try to fix it first.
|
|
||||||
*/
|
|
||||||
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case the user-specified fault handler returned zero,
|
* In case the user-specified fault handler returned zero,
|
||||||
* try to fix up.
|
* try to fix up.
|
||||||
|
|
|
@ -358,15 +358,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
|
||||||
*/
|
*/
|
||||||
kprobes_inc_nmissed_count(cur);
|
kprobes_inc_nmissed_count(cur);
|
||||||
|
|
||||||
/*
|
|
||||||
* We come here because instructions in the pre/post
|
|
||||||
* handler caused the page_fault, this could happen
|
|
||||||
* if handler tries to access user space by
|
|
||||||
* copy_from_user(), get_user() etc. Let the
|
|
||||||
* user-specified handler try to fix it.
|
|
||||||
*/
|
|
||||||
if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
|
|
||||||
return 1;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -283,16 +283,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
|
||||||
*/
|
*/
|
||||||
kprobes_inc_nmissed_count(cur);
|
kprobes_inc_nmissed_count(cur);
|
||||||
|
|
||||||
/*
|
|
||||||
* We come here because instructions in the pre/post
|
|
||||||
* handler caused the page_fault, this could happen
|
|
||||||
* if handler tries to access user space by
|
|
||||||
* copy_from_user(), get_user() etc. Let the
|
|
||||||
* user-specified handler try to fix it first.
|
|
||||||
*/
|
|
||||||
if (cur->fault_handler && cur->fault_handler(cur, regs, fsr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case the user-specified fault handler returned
|
* In case the user-specified fault handler returned
|
||||||
* zero, try to fix up.
|
* zero, try to fix up.
|
||||||
|
|
|
@ -301,16 +301,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr)
|
||||||
*/
|
*/
|
||||||
kprobes_inc_nmissed_count(cur);
|
kprobes_inc_nmissed_count(cur);
|
||||||
|
|
||||||
/*
|
|
||||||
* We come here because instructions in the pre/post
|
|
||||||
* handler caused the page_fault, this could happen
|
|
||||||
* if handler tries to access user space by
|
|
||||||
* copy_from_user(), get_user() etc. Let the
|
|
||||||
* user-specified handler try to fix it first.
|
|
||||||
*/
|
|
||||||
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case the user-specified fault handler returned
|
* In case the user-specified fault handler returned
|
||||||
* zero, try to fix up.
|
* zero, try to fix up.
|
||||||
|
|
|
@ -850,15 +850,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
||||||
*/
|
*/
|
||||||
kprobes_inc_nmissed_count(cur);
|
kprobes_inc_nmissed_count(cur);
|
||||||
|
|
||||||
/*
|
|
||||||
* We come here because instructions in the pre/post
|
|
||||||
* handler caused the page_fault, this could happen
|
|
||||||
* if handler tries to access user space by
|
|
||||||
* copy_from_user(), get_user() etc. Let the
|
|
||||||
* user-specified handler try to fix it first.
|
|
||||||
*/
|
|
||||||
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
|
|
||||||
return 1;
|
|
||||||
/*
|
/*
|
||||||
* In case the user-specified fault handler returned
|
* In case the user-specified fault handler returned
|
||||||
* zero, try to fix up.
|
* zero, try to fix up.
|
||||||
|
|
|
@ -403,9 +403,6 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
||||||
struct kprobe *cur = kprobe_running();
|
struct kprobe *cur = kprobe_running();
|
||||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||||
|
|
||||||
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (kcb->kprobe_status & KPROBE_HIT_SS) {
|
if (kcb->kprobe_status & KPROBE_HIT_SS) {
|
||||||
resume_execution(cur, regs, kcb);
|
resume_execution(cur, regs, kcb);
|
||||||
regs->cp0_status |= kcb->kprobe_old_SR;
|
regs->cp0_status |= kcb->kprobe_old_SR;
|
||||||
|
|
|
@ -508,16 +508,6 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
||||||
*/
|
*/
|
||||||
kprobes_inc_nmissed_count(cur);
|
kprobes_inc_nmissed_count(cur);
|
||||||
|
|
||||||
/*
|
|
||||||
* We come here because instructions in the pre/post
|
|
||||||
* handler caused the page_fault, this could happen
|
|
||||||
* if handler tries to access user space by
|
|
||||||
* copy_from_user(), get_user() etc. Let the
|
|
||||||
* user-specified handler try to fix it first.
|
|
||||||
*/
|
|
||||||
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case the user-specified fault handler returned
|
* In case the user-specified fault handler returned
|
||||||
* zero, try to fix up.
|
* zero, try to fix up.
|
||||||
|
|
|
@ -283,16 +283,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr)
|
||||||
*/
|
*/
|
||||||
kprobes_inc_nmissed_count(cur);
|
kprobes_inc_nmissed_count(cur);
|
||||||
|
|
||||||
/*
|
|
||||||
* We come here because instructions in the pre/post
|
|
||||||
* handler caused the page_fault, this could happen
|
|
||||||
* if handler tries to access user space by
|
|
||||||
* copy_from_user(), get_user() etc. Let the
|
|
||||||
* user-specified handler try to fix it first.
|
|
||||||
*/
|
|
||||||
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case the user-specified fault handler returned
|
* In case the user-specified fault handler returned
|
||||||
* zero, try to fix up.
|
* zero, try to fix up.
|
||||||
|
|
|
@ -452,16 +452,6 @@ static int kprobe_trap_handler(struct pt_regs *regs, int trapnr)
|
||||||
*/
|
*/
|
||||||
kprobes_inc_nmissed_count(p);
|
kprobes_inc_nmissed_count(p);
|
||||||
|
|
||||||
/*
|
|
||||||
* We come here because instructions in the pre/post
|
|
||||||
* handler caused the page_fault, this could happen
|
|
||||||
* if handler tries to access user space by
|
|
||||||
* copy_from_user(), get_user() etc. Let the
|
|
||||||
* user-specified handler try to fix it first.
|
|
||||||
*/
|
|
||||||
if (p->fault_handler && p->fault_handler(p, regs, trapnr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case the user-specified fault handler returned
|
* In case the user-specified fault handler returned
|
||||||
* zero, try to fix up.
|
* zero, try to fix up.
|
||||||
|
|
|
@ -389,16 +389,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
||||||
*/
|
*/
|
||||||
kprobes_inc_nmissed_count(cur);
|
kprobes_inc_nmissed_count(cur);
|
||||||
|
|
||||||
/*
|
|
||||||
* We come here because instructions in the pre/post
|
|
||||||
* handler caused the page_fault, this could happen
|
|
||||||
* if handler tries to access user space by
|
|
||||||
* copy_from_user(), get_user() etc. Let the
|
|
||||||
* user-specified handler try to fix it first.
|
|
||||||
*/
|
|
||||||
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case the user-specified fault handler returned
|
* In case the user-specified fault handler returned
|
||||||
* zero, try to fix up.
|
* zero, try to fix up.
|
||||||
|
|
|
@ -352,16 +352,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
||||||
*/
|
*/
|
||||||
kprobes_inc_nmissed_count(cur);
|
kprobes_inc_nmissed_count(cur);
|
||||||
|
|
||||||
/*
|
|
||||||
* We come here because instructions in the pre/post
|
|
||||||
* handler caused the page_fault, this could happen
|
|
||||||
* if handler tries to access user space by
|
|
||||||
* copy_from_user(), get_user() etc. Let the
|
|
||||||
* user-specified handler try to fix it first.
|
|
||||||
*/
|
|
||||||
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In case the user-specified fault handler returned
|
* In case the user-specified fault handler returned
|
||||||
* zero, try to fix up.
|
* zero, try to fix up.
|
||||||
|
|
|
@ -1110,16 +1110,6 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
||||||
* these specific fault cases.
|
* these specific fault cases.
|
||||||
*/
|
*/
|
||||||
kprobes_inc_nmissed_count(cur);
|
kprobes_inc_nmissed_count(cur);
|
||||||
|
|
||||||
/*
|
|
||||||
* We come here because instructions in the pre/post
|
|
||||||
* handler caused the page_fault, this could happen
|
|
||||||
* if handler tries to access user space by
|
|
||||||
* copy_from_user(), get_user() etc. Let the
|
|
||||||
* user-specified handler try to fix it first.
|
|
||||||
*/
|
|
||||||
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -54,8 +54,6 @@ struct kretprobe_instance;
|
||||||
typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *);
|
typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *);
|
||||||
typedef void (*kprobe_post_handler_t) (struct kprobe *, struct pt_regs *,
|
typedef void (*kprobe_post_handler_t) (struct kprobe *, struct pt_regs *,
|
||||||
unsigned long flags);
|
unsigned long flags);
|
||||||
typedef int (*kprobe_fault_handler_t) (struct kprobe *, struct pt_regs *,
|
|
||||||
int trapnr);
|
|
||||||
typedef int (*kretprobe_handler_t) (struct kretprobe_instance *,
|
typedef int (*kretprobe_handler_t) (struct kretprobe_instance *,
|
||||||
struct pt_regs *);
|
struct pt_regs *);
|
||||||
|
|
||||||
|
@ -83,12 +81,6 @@ struct kprobe {
|
||||||
/* Called after addr is executed, unless... */
|
/* Called after addr is executed, unless... */
|
||||||
kprobe_post_handler_t post_handler;
|
kprobe_post_handler_t post_handler;
|
||||||
|
|
||||||
/*
|
|
||||||
* ... called if executing addr causes a fault (eg. page fault).
|
|
||||||
* Return 1 if it handled fault, otherwise kernel will see it.
|
|
||||||
*/
|
|
||||||
kprobe_fault_handler_t fault_handler;
|
|
||||||
|
|
||||||
/* Saved opcode (which has been replaced with breakpoint) */
|
/* Saved opcode (which has been replaced with breakpoint) */
|
||||||
kprobe_opcode_t opcode;
|
kprobe_opcode_t opcode;
|
||||||
|
|
||||||
|
|
|
@ -1183,23 +1183,6 @@ static void aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
|
||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(aggr_post_handler);
|
NOKPROBE_SYMBOL(aggr_post_handler);
|
||||||
|
|
||||||
static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
|
|
||||||
int trapnr)
|
|
||||||
{
|
|
||||||
struct kprobe *cur = __this_cpu_read(kprobe_instance);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if we faulted "during" the execution of a user specified
|
|
||||||
* probe handler, invoke just that probe's fault handler
|
|
||||||
*/
|
|
||||||
if (cur && cur->fault_handler) {
|
|
||||||
if (cur->fault_handler(cur, regs, trapnr))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
NOKPROBE_SYMBOL(aggr_fault_handler);
|
|
||||||
|
|
||||||
/* Walks the list and increments nmissed count for multiprobe case */
|
/* Walks the list and increments nmissed count for multiprobe case */
|
||||||
void kprobes_inc_nmissed_count(struct kprobe *p)
|
void kprobes_inc_nmissed_count(struct kprobe *p)
|
||||||
{
|
{
|
||||||
|
@ -1330,7 +1313,6 @@ static void init_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
|
||||||
ap->addr = p->addr;
|
ap->addr = p->addr;
|
||||||
ap->flags = p->flags & ~KPROBE_FLAG_OPTIMIZED;
|
ap->flags = p->flags & ~KPROBE_FLAG_OPTIMIZED;
|
||||||
ap->pre_handler = aggr_pre_handler;
|
ap->pre_handler = aggr_pre_handler;
|
||||||
ap->fault_handler = aggr_fault_handler;
|
|
||||||
/* We don't care the kprobe which has gone. */
|
/* We don't care the kprobe which has gone. */
|
||||||
if (p->post_handler && !kprobe_gone(p))
|
if (p->post_handler && !kprobe_gone(p))
|
||||||
ap->post_handler = aggr_post_handler;
|
ap->post_handler = aggr_post_handler;
|
||||||
|
@ -2014,7 +1996,6 @@ int register_kretprobe(struct kretprobe *rp)
|
||||||
|
|
||||||
rp->kp.pre_handler = pre_handler_kretprobe;
|
rp->kp.pre_handler = pre_handler_kretprobe;
|
||||||
rp->kp.post_handler = NULL;
|
rp->kp.post_handler = NULL;
|
||||||
rp->kp.fault_handler = NULL;
|
|
||||||
|
|
||||||
/* Pre-allocate memory for max kretprobe instances */
|
/* Pre-allocate memory for max kretprobe instances */
|
||||||
if (rp->maxactive <= 0) {
|
if (rp->maxactive <= 0) {
|
||||||
|
|
|
@ -94,26 +94,11 @@ static void __kprobes handler_post(struct kprobe *p, struct pt_regs *regs,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* fault_handler: this is called if an exception is generated for any
|
|
||||||
* instruction within the pre- or post-handler, or when Kprobes
|
|
||||||
* single-steps the probed instruction.
|
|
||||||
*/
|
|
||||||
static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
|
|
||||||
{
|
|
||||||
pr_info("fault_handler: p->addr = 0x%p, trap #%dn", p->addr, trapnr);
|
|
||||||
/* Return 0 because we don't handle the fault. */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* NOKPROBE_SYMBOL() is also available */
|
|
||||||
NOKPROBE_SYMBOL(handler_fault);
|
|
||||||
|
|
||||||
static int __init kprobe_init(void)
|
static int __init kprobe_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
kp.pre_handler = handler_pre;
|
kp.pre_handler = handler_pre;
|
||||||
kp.post_handler = handler_post;
|
kp.post_handler = handler_post;
|
||||||
kp.fault_handler = handler_fault;
|
|
||||||
|
|
||||||
ret = register_kprobe(&kp);
|
ret = register_kprobe(&kp);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
Loading…
Reference in New Issue