Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fprobe: Pass return address to the handlers

Pass return address as 'ret_ip' to the fprobe entry and return handlers
so that the fprobe user handler can get the reutrn address without
analyzing arch-dependent pt_regs.

Link: https://lore.kernel.org/all/168507467664.913472.11642316698862778600.stgit@mhiramat.roam.corp.google.com/

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>

+26 -14
+4 -2
include/linux/fprobe.h
··· 35 35 int nr_maxactive; 36 36 37 37 int (*entry_handler)(struct fprobe *fp, unsigned long entry_ip, 38 - struct pt_regs *regs, void *entry_data); 38 + unsigned long ret_ip, struct pt_regs *regs, 39 + void *entry_data); 39 40 void (*exit_handler)(struct fprobe *fp, unsigned long entry_ip, 40 - struct pt_regs *regs, void *entry_data); 41 + unsigned long ret_ip, struct pt_regs *regs, 42 + void *entry_data); 41 43 }; 42 44 43 45 /* This fprobe is soft-disabled. */
+1 -1
include/linux/rethook.h
··· 14 14 15 15 struct rethook_node; 16 16 17 - typedef void (*rethook_handler_t) (struct rethook_node *, void *, struct pt_regs *); 17 + typedef void (*rethook_handler_t) (struct rethook_node *, void *, unsigned long, struct pt_regs *); 18 18 19 19 /** 20 20 * struct rethook - The rethook management data structure.
+1
kernel/kprobes.c
··· 2127 2127 NOKPROBE_SYMBOL(pre_handler_kretprobe); 2128 2128 2129 2129 static void kretprobe_rethook_handler(struct rethook_node *rh, void *data, 2130 + unsigned long ret_addr, 2130 2131 struct pt_regs *regs) 2131 2132 { 2132 2133 struct kretprobe *rp = (struct kretprobe *)data;
+4 -2
kernel/trace/bpf_trace.c
··· 2642 2642 2643 2643 static int 2644 2644 kprobe_multi_link_handler(struct fprobe *fp, unsigned long fentry_ip, 2645 - struct pt_regs *regs, void *data) 2645 + unsigned long ret_ip, struct pt_regs *regs, 2646 + void *data) 2646 2647 { 2647 2648 struct bpf_kprobe_multi_link *link; 2648 2649 ··· 2654 2653 2655 2654 static void 2656 2655 kprobe_multi_link_exit_handler(struct fprobe *fp, unsigned long fentry_ip, 2657 - struct pt_regs *regs, void *data) 2656 + unsigned long ret_ip, struct pt_regs *regs, 2657 + void *data) 2658 2658 { 2659 2659 struct bpf_kprobe_multi_link *link; 2660 2660
+3 -3
kernel/trace/fprobe.c
··· 46 46 } 47 47 48 48 if (fp->entry_handler) 49 - ret = fp->entry_handler(fp, ip, ftrace_get_regs(fregs), entry_data); 49 + ret = fp->entry_handler(fp, ip, parent_ip, ftrace_get_regs(fregs), entry_data); 50 50 51 51 /* If entry_handler returns !0, nmissed is not counted. */ 52 52 if (rh) { ··· 112 112 } 113 113 114 114 static void fprobe_exit_handler(struct rethook_node *rh, void *data, 115 - struct pt_regs *regs) 115 + unsigned long ret_ip, struct pt_regs *regs) 116 116 { 117 117 struct fprobe *fp = (struct fprobe *)data; 118 118 struct fprobe_rethook_node *fpr; ··· 133 133 return; 134 134 } 135 135 136 - fp->exit_handler(fp, fpr->entry_ip, regs, 136 + fp->exit_handler(fp, fpr->entry_ip, ret_ip, regs, 137 137 fp->entry_data_size ? (void *)fpr->data : NULL); 138 138 ftrace_test_recursion_unlock(bit); 139 139 }
+2 -1
kernel/trace/rethook.c
··· 301 301 break; 302 302 handler = READ_ONCE(rhn->rethook->handler); 303 303 if (handler) 304 - handler(rhn, rhn->rethook->data, regs); 304 + handler(rhn, rhn->rethook->data, 305 + correct_ret_addr, regs); 305 306 306 307 if (first == node) 307 308 break;
+7 -3
lib/test_fprobe.c
··· 39 39 } 40 40 41 41 static notrace int fp_entry_handler(struct fprobe *fp, unsigned long ip, 42 - struct pt_regs *regs, void *data) 42 + unsigned long ret_ip, 43 + struct pt_regs *regs, void *data) 43 44 { 44 45 KUNIT_EXPECT_FALSE(current_test, preemptible()); 45 46 /* This can be called on the fprobe_selftest_target and the fprobe_selftest_target2 */ ··· 58 57 } 59 58 60 59 static notrace void fp_exit_handler(struct fprobe *fp, unsigned long ip, 60 + unsigned long ret_ip, 61 61 struct pt_regs *regs, void *data) 62 62 { 63 63 unsigned long ret = regs_return_value(regs); ··· 80 78 } 81 79 82 80 static notrace int nest_entry_handler(struct fprobe *fp, unsigned long ip, 83 - struct pt_regs *regs, void *data) 81 + unsigned long ret_ip, 82 + struct pt_regs *regs, void *data) 84 83 { 85 84 KUNIT_EXPECT_FALSE(current_test, preemptible()); 86 85 return 0; 87 86 } 88 87 89 88 static notrace void nest_exit_handler(struct fprobe *fp, unsigned long ip, 90 - struct pt_regs *regs, void *data) 89 + unsigned long ret_ip, 90 + struct pt_regs *regs, void *data) 91 91 { 92 92 KUNIT_EXPECT_FALSE(current_test, preemptible()); 93 93 KUNIT_EXPECT_EQ(current_test, ip, target_nest_ip);
+4 -2
samples/fprobe/fprobe_example.c
··· 49 49 } 50 50 51 51 static int sample_entry_handler(struct fprobe *fp, unsigned long ip, 52 + unsigned long ret_ip, 52 53 struct pt_regs *regs, void *data) 53 54 { 54 55 if (use_trace) ··· 66 65 return 0; 67 66 } 68 67 69 - static void sample_exit_handler(struct fprobe *fp, unsigned long ip, struct pt_regs *regs, 68 + static void sample_exit_handler(struct fprobe *fp, unsigned long ip, 69 + unsigned long ret_ip, struct pt_regs *regs, 70 70 void *data) 71 71 { 72 - unsigned long rip = instruction_pointer(regs); 72 + unsigned long rip = ret_ip; 73 73 74 74 if (use_trace) 75 75 /*