Skip to content

Commit f709869

Browse files
olsajiriborkmann
authored andcommitted
bpf: Fix kprobe_multi return probe backtrace
Andrii reported that backtraces from kprobe_multi program attached as return probes are not complete and showing just initial entry [1]. It's caused by changing registers to have original function ip address as instruction pointer even for return probe, which will screw backtrace from return probe. This change keeps registers intact and store original entry ip and link address on the stack in bpf_kprobe_multi_run_ctx struct, where bpf_get_func_ip and bpf_get_attach_cookie helpers for kprobe_multi programs can find it. [1] https://lore.kernel.org/bpf/CAEf4BzZDDqK24rSKwXNp7XL3ErGD4bZa1M6c_c4EvDSt3jrZcg@mail.gmail.com/T/#m8d1301c0ea0892ddf9dc6fba57a57b8cf11b8c51 Fixes: ca74823 ("bpf: Add cookie support to programs attached with kprobe multi link") Reported-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Jiri Olsa <jolsa@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20220321070113.1449167-3-jolsa@kernel.org
1 parent f705ec7 commit f709869

File tree

1 file changed

+37
-30
lines changed

1 file changed

+37
-30
lines changed

kernel/trace/bpf_trace.c

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ u64 bpf_get_stack(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
8080
static int bpf_btf_printf_prepare(struct btf_ptr *ptr, u32 btf_ptr_size,
8181
u64 flags, const struct btf **btf,
8282
s32 *btf_id);
83-
static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx, u64 ip);
83+
static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx);
84+
static u64 bpf_kprobe_multi_entry_ip(struct bpf_run_ctx *ctx);
8485

8586
/**
8687
* trace_call_bpf - invoke BPF program
@@ -1042,7 +1043,7 @@ static const struct bpf_func_proto bpf_get_func_ip_proto_kprobe = {
10421043

10431044
BPF_CALL_1(bpf_get_func_ip_kprobe_multi, struct pt_regs *, regs)
10441045
{
1045-
return instruction_pointer(regs);
1046+
return bpf_kprobe_multi_entry_ip(current->bpf_ctx);
10461047
}
10471048

10481049
static const struct bpf_func_proto bpf_get_func_ip_proto_kprobe_multi = {
@@ -1054,7 +1055,7 @@ static const struct bpf_func_proto bpf_get_func_ip_proto_kprobe_multi = {
10541055

10551056
BPF_CALL_1(bpf_get_attach_cookie_kprobe_multi, struct pt_regs *, regs)
10561057
{
1057-
return bpf_kprobe_multi_cookie(current->bpf_ctx, instruction_pointer(regs));
1058+
return bpf_kprobe_multi_cookie(current->bpf_ctx);
10581059
}
10591060

10601061
static const struct bpf_func_proto bpf_get_attach_cookie_proto_kmulti = {
@@ -2219,15 +2220,16 @@ struct bpf_kprobe_multi_link {
22192220
struct bpf_link link;
22202221
struct fprobe fp;
22212222
unsigned long *addrs;
2222-
/*
2223-
* The run_ctx here is used to get struct bpf_kprobe_multi_link in
2224-
* get_attach_cookie helper, so it can't be used to store data.
2225-
*/
2226-
struct bpf_run_ctx run_ctx;
22272223
u64 *cookies;
22282224
u32 cnt;
22292225
};
22302226

2227+
struct bpf_kprobe_multi_run_ctx {
2228+
struct bpf_run_ctx run_ctx;
2229+
struct bpf_kprobe_multi_link *link;
2230+
unsigned long entry_ip;
2231+
};
2232+
22312233
static void bpf_kprobe_multi_link_release(struct bpf_link *link)
22322234
{
22332235
struct bpf_kprobe_multi_link *kmulti_link;
@@ -2281,29 +2283,44 @@ static int bpf_kprobe_multi_cookie_cmp(const void *a, const void *b, const void
22812283
return __bpf_kprobe_multi_cookie_cmp(a, b);
22822284
}
22832285

2284-
static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx, u64 ip)
2286+
static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx)
22852287
{
2288+
struct bpf_kprobe_multi_run_ctx *run_ctx;
22862289
struct bpf_kprobe_multi_link *link;
2290+
u64 *cookie, entry_ip;
22872291
unsigned long *addr;
2288-
u64 *cookie;
22892292

22902293
if (WARN_ON_ONCE(!ctx))
22912294
return 0;
2292-
link = container_of(ctx, struct bpf_kprobe_multi_link, run_ctx);
2295+
run_ctx = container_of(current->bpf_ctx, struct bpf_kprobe_multi_run_ctx, run_ctx);
2296+
link = run_ctx->link;
22932297
if (!link->cookies)
22942298
return 0;
2295-
addr = bsearch(&ip, link->addrs, link->cnt, sizeof(ip),
2299+
entry_ip = run_ctx->entry_ip;
2300+
addr = bsearch(&entry_ip, link->addrs, link->cnt, sizeof(entry_ip),
22962301
__bpf_kprobe_multi_cookie_cmp);
22972302
if (!addr)
22982303
return 0;
22992304
cookie = link->cookies + (addr - link->addrs);
23002305
return *cookie;
23012306
}
23022307

2308+
static u64 bpf_kprobe_multi_entry_ip(struct bpf_run_ctx *ctx)
2309+
{
2310+
struct bpf_kprobe_multi_run_ctx *run_ctx;
2311+
2312+
run_ctx = container_of(current->bpf_ctx, struct bpf_kprobe_multi_run_ctx, run_ctx);
2313+
return run_ctx->entry_ip;
2314+
}
2315+
23032316
static int
23042317
kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link,
2305-
struct pt_regs *regs)
2318+
unsigned long entry_ip, struct pt_regs *regs)
23062319
{
2320+
struct bpf_kprobe_multi_run_ctx run_ctx = {
2321+
.link = link,
2322+
.entry_ip = entry_ip,
2323+
};
23072324
struct bpf_run_ctx *old_run_ctx;
23082325
int err;
23092326

@@ -2314,7 +2331,7 @@ kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link,
23142331

23152332
migrate_disable();
23162333
rcu_read_lock();
2317-
old_run_ctx = bpf_set_run_ctx(&link->run_ctx);
2334+
old_run_ctx = bpf_set_run_ctx(&run_ctx.run_ctx);
23182335
err = bpf_prog_run(link->link.prog, regs);
23192336
bpf_reset_run_ctx(old_run_ctx);
23202337
rcu_read_unlock();
@@ -2329,24 +2346,10 @@ static void
23292346
kprobe_multi_link_handler(struct fprobe *fp, unsigned long entry_ip,
23302347
struct pt_regs *regs)
23312348
{
2332-
unsigned long saved_ip = instruction_pointer(regs);
23332349
struct bpf_kprobe_multi_link *link;
23342350

2335-
/*
2336-
* Because fprobe's regs->ip is set to the next instruction of
2337-
* dynamic-ftrace instruction, correct entry ip must be set, so
2338-
* that the bpf program can access entry address via regs as same
2339-
* as kprobes.
2340-
*
2341-
* Both kprobe and kretprobe see the entry ip of traced function
2342-
* as instruction pointer.
2343-
*/
2344-
instruction_pointer_set(regs, entry_ip);
2345-
23462351
link = container_of(fp, struct bpf_kprobe_multi_link, fp);
2347-
kprobe_multi_link_prog_run(link, regs);
2348-
2349-
instruction_pointer_set(regs, saved_ip);
2352+
kprobe_multi_link_prog_run(link, entry_ip, regs);
23502353
}
23512354

23522355
static int
@@ -2513,7 +2516,11 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
25132516
{
25142517
return -EOPNOTSUPP;
25152518
}
2516-
static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx, u64 ip)
2519+
static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx)
2520+
{
2521+
return 0;
2522+
}
2523+
static u64 bpf_kprobe_multi_entry_ip(struct bpf_run_ctx *ctx)
25172524
{
25182525
return 0;
25192526
}

0 commit comments

Comments
 (0)