fprobe: Skip exit_handler if entry_handler returns !0
authorMasami Hiramatsu (Google) <mhiramat@kernel.org>
Wed, 1 Feb 2023 15:56:38 +0000 (00:56 +0900)
committerSteven Rostedt (Google) <rostedt@goodmis.org>
Tue, 28 Mar 2023 22:52:22 +0000 (18:52 -0400)
Skip hooking function return and calling exit_handler if the
entry_handler() returns !0.

Link: https://lkml.kernel.org/r/167526699798.433354.10998365726830117303.stgit@mhiramat.roam.corp.google.com
Cc: Florent Revest <revest@chromium.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
include/linux/fprobe.h
kernel/trace/bpf_trace.c
kernel/trace/fprobe.c
lib/test_fprobe.c
samples/fprobe/fprobe_example.c

index 678f741..47fefc7 100644 (file)
@@ -34,8 +34,8 @@ struct fprobe {
        size_t                  entry_data_size;
        int                     nr_maxactive;
 
-       void (*entry_handler)(struct fprobe *fp, unsigned long entry_ip,
-                             struct pt_regs *regs, void *entry_data);
+       int (*entry_handler)(struct fprobe *fp, unsigned long entry_ip,
+                            struct pt_regs *regs, void *entry_data);
        void (*exit_handler)(struct fprobe *fp, unsigned long entry_ip,
                             struct pt_regs *regs, void *entry_data);
 };
index fa403c3..d804172 100644 (file)
@@ -2644,7 +2644,7 @@ kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link,
        return err;
 }
 
-static void
+static int
 kprobe_multi_link_handler(struct fprobe *fp, unsigned long fentry_ip,
                          struct pt_regs *regs, void *data)
 {
@@ -2652,6 +2652,17 @@ kprobe_multi_link_handler(struct fprobe *fp, unsigned long fentry_ip,
 
        link = container_of(fp, struct bpf_kprobe_multi_link, fp);
        kprobe_multi_link_prog_run(link, get_entry_ip(fentry_ip), regs);
+       return 0;
+}
+
+static void
+kprobe_multi_link_exit_handler(struct fprobe *fp, unsigned long fentry_ip,
+                              struct pt_regs *regs, void *data)
+{
+       struct bpf_kprobe_multi_link *link;
+
+       link = container_of(fp, struct bpf_kprobe_multi_link, fp);
+       kprobe_multi_link_prog_run(link, get_entry_ip(fentry_ip), regs);
 }
 
 static int symbols_cmp_r(const void *a, const void *b, const void *priv)
@@ -2848,7 +2859,7 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
                goto error;
 
        if (flags & BPF_F_KPROBE_MULTI_RETURN)
-               link->fp.exit_handler = kprobe_multi_link_handler;
+               link->fp.exit_handler = kprobe_multi_link_exit_handler;
        else
                link->fp.entry_handler = kprobe_multi_link_handler;
 
index f222848..9abb390 100644 (file)
@@ -27,7 +27,7 @@ static void fprobe_handler(unsigned long ip, unsigned long parent_ip,
        struct rethook_node *rh = NULL;
        struct fprobe *fp;
        void *entry_data = NULL;
-       int bit;
+       int bit, ret;
 
        fp = container_of(ops, struct fprobe, ops);
        if (fprobe_disabled(fp))
@@ -52,11 +52,15 @@ static void fprobe_handler(unsigned long ip, unsigned long parent_ip,
        }
 
        if (fp->entry_handler)
-               fp->entry_handler(fp, ip, ftrace_get_regs(fregs), entry_data);
-
-       if (rh)
-               rethook_hook(rh, ftrace_get_regs(fregs), true);
+               ret = fp->entry_handler(fp, ip, ftrace_get_regs(fregs), entry_data);
 
+       /* If entry_handler returns !0, nmissed is not counted. */
+       if (rh) {
+               if (ret)
+                       rethook_recycle(rh);
+               else
+                       rethook_hook(rh, ftrace_get_regs(fregs), true);
+       }
 out:
        ftrace_test_recursion_unlock(bit);
 }
index 4b37d70..9fa2ac9 100644 (file)
@@ -37,7 +37,7 @@ static noinline u32 fprobe_selftest_nest_target(u32 value, u32 (*nest)(u32))
        return nest(value + 2);
 }
 
-static notrace void fp_entry_handler(struct fprobe *fp, unsigned long ip,
+static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip,
                                     struct pt_regs *regs, void *data)
 {
        KUNIT_EXPECT_FALSE(current_test, preemptible());
@@ -51,6 +51,8 @@ static notrace void fp_entry_handler(struct fprobe *fp, unsigned long ip,
                        *(u32 *)data = entry_val;
        } else
                KUNIT_EXPECT_NULL(current_test, data);
+
+       return 0;
 }
 
 static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip,
@@ -74,10 +76,11 @@ static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip,
                KUNIT_EXPECT_NULL(current_test, data);
 }
 
-static notrace void nest_entry_handler(struct fprobe *fp, unsigned long ip,
+static notrace int nest_entry_handler(struct fprobe *fp, unsigned long ip,
                                     struct pt_regs *regs, void *data)
 {
        KUNIT_EXPECT_FALSE(current_test, preemptible());
+       return 0;
 }
 
 static notrace void nest_exit_handler(struct fprobe *fp, unsigned long ip,
index dd79499..4efc8fe 100644 (file)
@@ -48,8 +48,8 @@ static void show_backtrace(void)
        stack_trace_print(stacks, len, 24);
 }
 
-static void sample_entry_handler(struct fprobe *fp, unsigned long ip,
-                                struct pt_regs *regs, void *data)
+static int sample_entry_handler(struct fprobe *fp, unsigned long ip,
+                               struct pt_regs *regs, void *data)
 {
        if (use_trace)
                /*
@@ -62,6 +62,7 @@ static void sample_entry_handler(struct fprobe *fp, unsigned long ip,
        nhit++;
        if (stackdump)
                show_backtrace();
+       return 0;
 }
 
 static void sample_exit_handler(struct fprobe *fp, unsigned long ip, struct pt_regs *regs,