Skip to content

Commit 73f9b91

Browse files
mhiramatAlexei Starovoitov
authored andcommitted
kprobes: Use rethook for kretprobe if possible
Use rethook for kretprobe function return hooking if the arch sets CONFIG_HAVE_RETHOOK=y. In this case, CONFIG_KRETPROBE_ON_RETHOOK is set to 'y' automatically, and the kretprobe internal data fields switches to use rethook. If not, it continues to use kretprobe specific function return hooks. Suggested-by: Peter Zijlstra <[email protected]> Signed-off-by: Masami Hiramatsu <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/164826162556.2455864.12255833167233452047.stgit@devnote2
1 parent ef8a257 commit 73f9b91

File tree

5 files changed

+163
-25
lines changed

5 files changed

+163
-25
lines changed

arch/Kconfig

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,13 @@ config ARCH_USE_BUILTIN_BSWAP
164164

165165
config KRETPROBES
166166
def_bool y
167-
depends on KPROBES && HAVE_KRETPROBES
167+
depends on KPROBES && (HAVE_KRETPROBES || HAVE_RETHOOK)
168+
169+
config KRETPROBE_ON_RETHOOK
170+
def_bool y
171+
depends on HAVE_RETHOOK
172+
depends on KRETPROBES
173+
select RETHOOK
168174

169175
config USER_RETURN_NOTIFIER
170176
bool

include/linux/kprobes.h

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <linux/ftrace.h>
2929
#include <linux/refcount.h>
3030
#include <linux/freelist.h>
31+
#include <linux/rethook.h>
3132
#include <asm/kprobes.h>
3233

3334
#ifdef CONFIG_KPROBES
@@ -149,13 +150,20 @@ struct kretprobe {
149150
int maxactive;
150151
int nmissed;
151152
size_t data_size;
153+
#ifdef CONFIG_KRETPROBE_ON_RETHOOK
154+
struct rethook *rh;
155+
#else
152156
struct freelist_head freelist;
153157
struct kretprobe_holder *rph;
158+
#endif
154159
};
155160

156161
#define KRETPROBE_MAX_DATA_SIZE 4096
157162

158163
struct kretprobe_instance {
164+
#ifdef CONFIG_KRETPROBE_ON_RETHOOK
165+
struct rethook_node node;
166+
#else
159167
union {
160168
struct freelist_node freelist;
161169
struct rcu_head rcu;
@@ -164,6 +172,7 @@ struct kretprobe_instance {
164172
struct kretprobe_holder *rph;
165173
kprobe_opcode_t *ret_addr;
166174
void *fp;
175+
#endif
167176
char data[];
168177
};
169178

@@ -186,10 +195,24 @@ extern void kprobe_busy_begin(void);
186195
extern void kprobe_busy_end(void);
187196

188197
#ifdef CONFIG_KRETPROBES
189-
extern void arch_prepare_kretprobe(struct kretprobe_instance *ri,
190-
struct pt_regs *regs);
198+
/* Check whether @p is used for implementing a trampoline. */
191199
extern int arch_trampoline_kprobe(struct kprobe *p);
192200

201+
#ifdef CONFIG_KRETPROBE_ON_RETHOOK
202+
static nokprobe_inline struct kretprobe *get_kretprobe(struct kretprobe_instance *ri)
203+
{
204+
RCU_LOCKDEP_WARN(!rcu_read_lock_any_held(),
205+
"Kretprobe is accessed from instance under preemptive context");
206+
207+
return (struct kretprobe *)READ_ONCE(ri->node.rethook->data);
208+
}
209+
static nokprobe_inline unsigned long get_kretprobe_retaddr(struct kretprobe_instance *ri)
210+
{
211+
return ri->node.ret_addr;
212+
}
213+
#else
214+
extern void arch_prepare_kretprobe(struct kretprobe_instance *ri,
215+
struct pt_regs *regs);
193216
void arch_kretprobe_fixup_return(struct pt_regs *regs,
194217
kprobe_opcode_t *correct_ret_addr);
195218

@@ -232,6 +255,12 @@ static nokprobe_inline struct kretprobe *get_kretprobe(struct kretprobe_instance
232255
return READ_ONCE(ri->rph->rp);
233256
}
234257

258+
static nokprobe_inline unsigned long get_kretprobe_retaddr(struct kretprobe_instance *ri)
259+
{
260+
return (unsigned long)ri->ret_addr;
261+
}
262+
#endif /* CONFIG_KRETPROBE_ON_RETHOOK */
263+
235264
#else /* !CONFIG_KRETPROBES */
236265
static inline void arch_prepare_kretprobe(struct kretprobe *rp,
237266
struct pt_regs *regs)
@@ -395,7 +424,11 @@ void unregister_kretprobe(struct kretprobe *rp);
395424
int register_kretprobes(struct kretprobe **rps, int num);
396425
void unregister_kretprobes(struct kretprobe **rps, int num);
397426

427+
#ifdef CONFIG_KRETPROBE_ON_RETHOOK
428+
#define kprobe_flush_task(tk) do {} while (0)
429+
#else
398430
void kprobe_flush_task(struct task_struct *tk);
431+
#endif
399432

400433
void kprobe_free_init_mem(void);
401434

@@ -509,13 +542,27 @@ static inline bool is_kprobe_optinsn_slot(unsigned long addr)
509542
#endif /* !CONFIG_OPTPROBES */
510543

511544
#ifdef CONFIG_KRETPROBES
545+
#ifdef CONFIG_KRETPROBE_ON_RETHOOK
546+
static nokprobe_inline bool is_kretprobe_trampoline(unsigned long addr)
547+
{
548+
return is_rethook_trampoline(addr);
549+
}
550+
551+
static nokprobe_inline
552+
unsigned long kretprobe_find_ret_addr(struct task_struct *tsk, void *fp,
553+
struct llist_node **cur)
554+
{
555+
return rethook_find_ret_addr(tsk, (unsigned long)fp, cur);
556+
}
557+
#else
512558
static nokprobe_inline bool is_kretprobe_trampoline(unsigned long addr)
513559
{
514560
return (void *)addr == kretprobe_trampoline_addr();
515561
}
516562

517563
unsigned long kretprobe_find_ret_addr(struct task_struct *tsk, void *fp,
518564
struct llist_node **cur);
565+
#endif
519566
#else
520567
static nokprobe_inline bool is_kretprobe_trampoline(unsigned long addr)
521568
{

kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ obj-$(CONFIG_TRACING) += trace/
108108
obj-$(CONFIG_TRACE_CLOCK) += trace/
109109
obj-$(CONFIG_RING_BUFFER) += trace/
110110
obj-$(CONFIG_TRACEPOINTS) += trace/
111+
obj-$(CONFIG_RETHOOK) += trace/
111112
obj-$(CONFIG_IRQ_WORK) += irq_work.o
112113
obj-$(CONFIG_CPU_PM) += cpu_pm.o
113114
obj-$(CONFIG_BPF) += bpf/

kernel/kprobes.c

Lines changed: 104 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,27 @@ void kprobes_inc_nmissed_count(struct kprobe *p)
12371237
}
12381238
NOKPROBE_SYMBOL(kprobes_inc_nmissed_count);
12391239

1240+
static struct kprobe kprobe_busy = {
1241+
.addr = (void *) get_kprobe,
1242+
};
1243+
1244+
void kprobe_busy_begin(void)
1245+
{
1246+
struct kprobe_ctlblk *kcb;
1247+
1248+
preempt_disable();
1249+
__this_cpu_write(current_kprobe, &kprobe_busy);
1250+
kcb = get_kprobe_ctlblk();
1251+
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
1252+
}
1253+
1254+
void kprobe_busy_end(void)
1255+
{
1256+
__this_cpu_write(current_kprobe, NULL);
1257+
preempt_enable();
1258+
}
1259+
1260+
#if !defined(CONFIG_KRETPROBE_ON_RETHOOK)
12401261
static void free_rp_inst_rcu(struct rcu_head *head)
12411262
{
12421263
struct kretprobe_instance *ri = container_of(head, struct kretprobe_instance, rcu);
@@ -1258,26 +1279,6 @@ static void recycle_rp_inst(struct kretprobe_instance *ri)
12581279
}
12591280
NOKPROBE_SYMBOL(recycle_rp_inst);
12601281

1261-
static struct kprobe kprobe_busy = {
1262-
.addr = (void *) get_kprobe,
1263-
};
1264-
1265-
void kprobe_busy_begin(void)
1266-
{
1267-
struct kprobe_ctlblk *kcb;
1268-
1269-
preempt_disable();
1270-
__this_cpu_write(current_kprobe, &kprobe_busy);
1271-
kcb = get_kprobe_ctlblk();
1272-
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
1273-
}
1274-
1275-
void kprobe_busy_end(void)
1276-
{
1277-
__this_cpu_write(current_kprobe, NULL);
1278-
preempt_enable();
1279-
}
1280-
12811282
/*
12821283
* This function is called from delayed_put_task_struct() when a task is
12831284
* dead and cleaned up to recycle any kretprobe instances associated with
@@ -1327,6 +1328,7 @@ static inline void free_rp_inst(struct kretprobe *rp)
13271328
rp->rph = NULL;
13281329
}
13291330
}
1331+
#endif /* !CONFIG_KRETPROBE_ON_RETHOOK */
13301332

13311333
/* Add the new probe to 'ap->list'. */
13321334
static int add_new_kprobe(struct kprobe *ap, struct kprobe *p)
@@ -1925,6 +1927,7 @@ static struct notifier_block kprobe_exceptions_nb = {
19251927

19261928
#ifdef CONFIG_KRETPROBES
19271929

1930+
#if !defined(CONFIG_KRETPROBE_ON_RETHOOK)
19281931
/* This assumes the 'tsk' is the current task or the is not running. */
19291932
static kprobe_opcode_t *__kretprobe_find_ret_addr(struct task_struct *tsk,
19301933
struct llist_node **cur)
@@ -2087,6 +2090,57 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
20872090
return 0;
20882091
}
20892092
NOKPROBE_SYMBOL(pre_handler_kretprobe);
2093+
#else /* CONFIG_KRETPROBE_ON_RETHOOK */
2094+
/*
2095+
* This kprobe pre_handler is registered with every kretprobe. When probe
2096+
* hits it will set up the return probe.
2097+
*/
2098+
static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
2099+
{
2100+
struct kretprobe *rp = container_of(p, struct kretprobe, kp);
2101+
struct kretprobe_instance *ri;
2102+
struct rethook_node *rhn;
2103+
2104+
rhn = rethook_try_get(rp->rh);
2105+
if (!rhn) {
2106+
rp->nmissed++;
2107+
return 0;
2108+
}
2109+
2110+
ri = container_of(rhn, struct kretprobe_instance, node);
2111+
2112+
if (rp->entry_handler && rp->entry_handler(ri, regs))
2113+
rethook_recycle(rhn);
2114+
else
2115+
rethook_hook(rhn, regs, kprobe_ftrace(p));
2116+
2117+
return 0;
2118+
}
2119+
NOKPROBE_SYMBOL(pre_handler_kretprobe);
2120+
2121+
static void kretprobe_rethook_handler(struct rethook_node *rh, void *data,
2122+
struct pt_regs *regs)
2123+
{
2124+
struct kretprobe *rp = (struct kretprobe *)data;
2125+
struct kretprobe_instance *ri;
2126+
struct kprobe_ctlblk *kcb;
2127+
2128+
/* The data must NOT be null. This means rethook data structure is broken. */
2129+
if (WARN_ON_ONCE(!data))
2130+
return;
2131+
2132+
__this_cpu_write(current_kprobe, &rp->kp);
2133+
kcb = get_kprobe_ctlblk();
2134+
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
2135+
2136+
ri = container_of(rh, struct kretprobe_instance, node);
2137+
rp->handler(ri, regs);
2138+
2139+
__this_cpu_write(current_kprobe, NULL);
2140+
}
2141+
NOKPROBE_SYMBOL(kretprobe_rethook_handler);
2142+
2143+
#endif /* !CONFIG_KRETPROBE_ON_RETHOOK */
20902144

20912145
/**
20922146
* kprobe_on_func_entry() -- check whether given address is function entry
@@ -2155,6 +2209,29 @@ int register_kretprobe(struct kretprobe *rp)
21552209
rp->maxactive = num_possible_cpus();
21562210
#endif
21572211
}
2212+
#ifdef CONFIG_KRETPROBE_ON_RETHOOK
2213+
rp->rh = rethook_alloc((void *)rp, kretprobe_rethook_handler);
2214+
if (!rp->rh)
2215+
return -ENOMEM;
2216+
2217+
for (i = 0; i < rp->maxactive; i++) {
2218+
inst = kzalloc(sizeof(struct kretprobe_instance) +
2219+
rp->data_size, GFP_KERNEL);
2220+
if (inst == NULL) {
2221+
rethook_free(rp->rh);
2222+
rp->rh = NULL;
2223+
return -ENOMEM;
2224+
}
2225+
rethook_add_node(rp->rh, &inst->node);
2226+
}
2227+
rp->nmissed = 0;
2228+
/* Establish function entry probe point */
2229+
ret = register_kprobe(&rp->kp);
2230+
if (ret != 0) {
2231+
rethook_free(rp->rh);
2232+
rp->rh = NULL;
2233+
}
2234+
#else /* !CONFIG_KRETPROBE_ON_RETHOOK */
21582235
rp->freelist.head = NULL;
21592236
rp->rph = kzalloc(sizeof(struct kretprobe_holder), GFP_KERNEL);
21602237
if (!rp->rph)
@@ -2179,6 +2256,7 @@ int register_kretprobe(struct kretprobe *rp)
21792256
ret = register_kprobe(&rp->kp);
21802257
if (ret != 0)
21812258
free_rp_inst(rp);
2259+
#endif
21822260
return ret;
21832261
}
21842262
EXPORT_SYMBOL_GPL(register_kretprobe);
@@ -2217,15 +2295,21 @@ void unregister_kretprobes(struct kretprobe **rps, int num)
22172295
for (i = 0; i < num; i++) {
22182296
if (__unregister_kprobe_top(&rps[i]->kp) < 0)
22192297
rps[i]->kp.addr = NULL;
2298+
#ifdef CONFIG_KRETPROBE_ON_RETHOOK
2299+
rethook_free(rps[i]->rh);
2300+
#else
22202301
rps[i]->rph->rp = NULL;
2302+
#endif
22212303
}
22222304
mutex_unlock(&kprobe_mutex);
22232305

22242306
synchronize_rcu();
22252307
for (i = 0; i < num; i++) {
22262308
if (rps[i]->kp.addr) {
22272309
__unregister_kprobe_bottom(&rps[i]->kp);
2310+
#ifndef CONFIG_KRETPROBE_ON_RETHOOK
22282311
free_rp_inst(rps[i]);
2312+
#endif
22292313
}
22302314
}
22312315
}

kernel/trace/trace_kprobe.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,7 +1433,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
14331433
fbuffer.regs = regs;
14341434
entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event);
14351435
entry->func = (unsigned long)tk->rp.kp.addr;
1436-
entry->ret_ip = (unsigned long)ri->ret_addr;
1436+
entry->ret_ip = get_kretprobe_retaddr(ri);
14371437
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
14381438

14391439
trace_event_buffer_commit(&fbuffer);
@@ -1628,7 +1628,7 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri,
16281628
return;
16291629

16301630
entry->func = (unsigned long)tk->rp.kp.addr;
1631-
entry->ret_ip = (unsigned long)ri->ret_addr;
1631+
entry->ret_ip = get_kretprobe_retaddr(ri);
16321632
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize);
16331633
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
16341634
head, NULL);

0 commit comments

Comments
 (0)