From: Jiri Olsa <hidden> Date: 2021-07-14 09:44:08
hi,
adding bpf_get_func_ip helper that returns IP address of the
caller function for trampoline and krobe programs.
There're 2 specific implementation of the bpf_get_func_ip
helper, one for trampoline progs and one for kprobe/kretprobe
progs.
The trampoline helper call is replaced/inlined by verifier
with simple move instruction. The kprobe/kretprobe is actual
helper call that returns prepared caller address.
Also available at:
https://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
bpf/get_func_ip
v4 changes:
- dropped jit/x86 check for get_func_ip tracing check [Alexei]
- added code to bpf_get_func_ip_tracing [Alexei]
and tested that it works without inlining [Alexei]
- changed has_get_func_ip to check_get_func_ip [Andrii]
- replaced test assert loop with explicit asserts [Andrii]
- adde bpf_program__attach_kprobe_opts function
and use it for offset setup [Andrii]
- used bpf_program__set_autoload(false) for test6 [Andrii]
- added Masami's ack
v3 changes:
- resend with Masami in cc and v3 in each patch subject
v2 changes:
- use kprobe_running to get kprobe instead of cpu var [Masami]
- added support to add kprobe on function+offset
and test for that [Alan]
thanks,
jirka
---
Alan Maguire (1):
libbpf: Allow specification of "kprobe/function+offset"
Jiri Olsa (7):
bpf, x86: Store caller's ip in trampoline stack
bpf: Enable BPF_TRAMP_F_IP_ARG for trampolines with call_get_func_ip
bpf: Add bpf_get_func_ip helper for tracing programs
bpf: Add bpf_get_func_ip helper for kprobe programs
selftests/bpf: Add test for bpf_get_func_ip helper
libbpf: Add bpf_program__attach_kprobe_opts function
selftests/bpf: Add test for bpf_get_func_ip in kprobe+offset probe
arch/x86/net/bpf_jit_comp.c | 19 +++++++++++++++++++
include/linux/bpf.h | 5 +++++
include/linux/filter.h | 3 ++-
include/uapi/linux/bpf.h | 7 +++++++
kernel/bpf/trampoline.c | 12 +++++++++---
kernel/bpf/verifier.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
kernel/trace/bpf_trace.c | 31 +++++++++++++++++++++++++++++++
tools/include/uapi/linux/bpf.h | 7 +++++++
tools/lib/bpf/libbpf.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++----------
tools/testing/selftests/bpf/prog_tests/get_func_ip_test.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/testing/selftests/bpf/progs/get_func_ip_test.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 297 insertions(+), 14 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/get_func_ip_test.c
create mode 100644 tools/testing/selftests/bpf/progs/get_func_ip_test.c
From: Jiri Olsa <hidden> Date: 2021-07-14 09:44:15
Storing caller's ip in trampoline's stack. Trampoline programs
can reach the IP in (ctx - 8) address, so there's no change in
program's arguments interface.
The IP address is takes from [fp + 8], which is return address
from the initial 'call fentry' call to trampoline.
This IP address will be returned via bpf_get_func_ip helper
helper, which is added in following patches.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
arch/x86/net/bpf_jit_comp.c | 19 +++++++++++++++++++
include/linux/bpf.h | 5 +++++
2 files changed, 24 insertions(+)
@@ -1951,6 +1951,9 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *iif(flags&BPF_TRAMP_F_CALL_ORIG)stack_size+=8;/* room for return value of orig_call */+if(flags&BPF_TRAMP_F_IP_ARG)+stack_size+=8;/* room for IP address argument */+if(flags&BPF_TRAMP_F_SKIP_FRAME)/* skip patched call instruction and point orig_call to actual*bodyofthekernelfunction.
@@ -1964,6 +1967,22 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *iEMIT4(0x48,0x83,0xEC,stack_size);/* sub rsp, stack_size */EMIT1(0x53);/* push rbx */+if(flags&BPF_TRAMP_F_IP_ARG){+/* Store IP address of the traced function:+*movrax,QWORDPTR[rbp+8]+*subrax,X86_PATCH_SIZE+*movQWORDPTR[rbp-stack_size],rax+*/+emit_ldx(&prog,BPF_DW,BPF_REG_0,BPF_REG_FP,8);+EMIT4(0x48,0x83,0xe8,X86_PATCH_SIZE);+emit_stx(&prog,BPF_DW,BPF_REG_FP,BPF_REG_0,-stack_size);++/* Continue with stack_size for regs storage, stack will+*becorrectlyrestoredwith'leave'instruction.+*/+stack_size-=8;+}+save_regs(m,&prog,nr_args,stack_size);if(flags&BPF_TRAMP_F_CALL_ORIG){
@@ -554,6 +554,11 @@ struct btf_func_model {*/#define BPF_TRAMP_F_SKIP_FRAME BIT(2)+/* Store IP address of the caller on the trampoline stack,+*soit'savailablefortrampoline'sprograms.+*/+#define BPF_TRAMP_F_IP_ARG BIT(3)+/* Each call __bpf_prog_enter + call bpf_func + call __bpf_prog_exit is ~50*bytesonx86.PickanumbertofitintoBPF_IMAGE_SIZE/2*/
From: Jiri Olsa <hidden> Date: 2021-07-14 09:44:22
Enabling BPF_TRAMP_F_IP_ARG for trampolines that actually need it.
The BPF_TRAMP_F_IP_ARG adds extra 3 instructions to trampoline code
and is used only by programs with bpf_get_func_ip helper, which is
added in following patch and sets call_get_func_ip bit.
This patch ensures that BPF_TRAMP_F_IP_ARG flag is used only for
trampolines that have programs with call_get_func_ip set.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
include/linux/filter.h | 3 ++-
kernel/bpf/trampoline.c | 12 +++++++++---
2 files changed, 11 insertions(+), 4 deletions(-)
@@ -559,7 +559,8 @@ struct bpf_prog {kprobe_override:1,/* Do we override a kprobe? */has_callchain_buf:1,/* callchain buffer allocated? */enforce_expected_attach_type:1,/* Enforce expected_attach_type checking at attach time */-call_get_stack:1;/* Do we call bpf_get_stack() or bpf_get_stackid() */+call_get_stack:1,/* Do we call bpf_get_stack() or bpf_get_stackid() */+call_get_func_ip:1;/* Do we call get_func_ip() */enumbpf_prog_typetype;/* Type of BPF program */enumbpf_attach_typeexpected_attach_type;/* For some prog types */u32len;/* Number of filter blocks */
From: Jiri Olsa <hidden> Date: 2021-07-14 09:44:32
Adding bpf_get_func_ip helper for BPF_PROG_TYPE_TRACING programs,
specifically for all trampoline attach types.
The trampoline's caller IP address is stored in (ctx - 8) address.
so there's no reason to actually call the helper, but rather fixup
the call instruction and return [ctx - 8] value directly (suggested
by Alexei).
[fixed has_get_func_ip wrong return type]
Reported-by: kernel test robot <redacted>
Reported-by: Dan Carpenter <redacted>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
include/uapi/linux/bpf.h | 7 ++++++
kernel/bpf/verifier.c | 43 ++++++++++++++++++++++++++++++++++
kernel/trace/bpf_trace.c | 15 ++++++++++++
tools/include/uapi/linux/bpf.h | 7 ++++++
4 files changed, 72 insertions(+)
@@ -4777,6 +4777,12 @@ union bpf_attr {*ExecuteclosesyscallforgivenFD.*Return*Asyscallresult.+*+*u64bpf_get_func_ip(void*ctx)+*Description+*Getaddressofthetracedfunction(fortracingprograms).+*Return+*Addressofthetracedfunction.*/#define __BPF_FUNC_MAPPER(FN) \FN(unspec),\
@@ -4948,6 +4954,7 @@ union bpf_attr {FN(sys_bpf),\FN(btf_find_by_name_kind),\FN(sys_close),\+FN(get_func_ip),\/* *//* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -5955,6 +5955,27 @@ static int check_bpf_snprintf_call(struct bpf_verifier_env *env,returnerr;}+staticintcheck_get_func_ip(structbpf_verifier_env*env)+{+enumbpf_attach_typeeatype=env->prog->expected_attach_type;+enumbpf_prog_typetype=resolve_prog_type(env->prog);+intfunc_id=BPF_FUNC_get_func_ip;++if(type==BPF_PROG_TYPE_TRACING){+if(eatype!=BPF_TRACE_FENTRY&&eatype!=BPF_TRACE_FEXIT&&+eatype!=BPF_MODIFY_RETURN){+verbose(env,"func %s#%d supported only for fentry/fexit/fmod_ret programs\n",+func_id_name(func_id),func_id);+return-ENOTSUPP;+}+return0;+}++verbose(env,"func %s#%d not supported for program type %d\n",+func_id_name(func_id),func_id,type);+return-ENOTSUPP;+}+staticintcheck_helper_call(structbpf_verifier_env*env,structbpf_insn*insn,int*insn_idx_p){
@@ -12369,6 +12396,7 @@ static int do_misc_fixups(struct bpf_verifier_env *env){structbpf_prog*prog=env->prog;boolexpect_blinding=bpf_jit_blinding_enabled(prog);+enumbpf_prog_typeprog_type=resolve_prog_type(prog);structbpf_insn*insn=prog->insnsi;conststructbpf_func_proto*fn;constintinsn_cnt=prog->len;
@@ -12702,6 +12730,21 @@ static int do_misc_fixups(struct bpf_verifier_env *env)continue;}+/* Implement bpf_get_func_ip inline. */+if(prog_type==BPF_PROG_TYPE_TRACING&&+insn->imm==BPF_FUNC_get_func_ip){+/* Load IP address from ctx - 8 */+insn_buf[0]=BPF_LDX_MEM(BPF_DW,BPF_REG_0,BPF_REG_1,-8);++new_prog=bpf_patch_insn_data(env,i+delta,insn_buf,1);+if(!new_prog)+return-ENOMEM;++env->prog=prog=new_prog;+insn=new_prog->insnsi+i+delta;+continue;+}+patch_call_imm:fn=env->ops->get_func_proto(insn->imm,env->prog);/* all functions that have prototype and verifier allowed
@@ -4780,6 +4780,12 @@ union bpf_attr {*ExecuteclosesyscallforgivenFD.*Return*Asyscallresult.+*+*u64bpf_get_func_ip(void*ctx)+*Description+*Getaddressofthetracedfunction(fortracingprograms).+*Return+*Addressofthetracedfunction.*/#define __BPF_FUNC_MAPPER(FN) \FN(unspec),\
@@ -4951,6 +4957,7 @@ union bpf_attr {FN(sys_bpf),\FN(btf_find_by_name_kind),\FN(sys_close),\+FN(get_func_ip),\/* *//* integer value in 'imm' field of BPF_CALL instruction selects which helper
From: Jiri Olsa <hidden> Date: 2021-07-14 09:44:45
Adding bpf_get_func_ip helper for BPF_PROG_TYPE_KPROBE programs,
so it's now possible to call bpf_get_func_ip from both kprobe and
kretprobe programs.
Taking the caller's address from 'struct kprobe::addr', which is
defined for both kprobe and kretprobe.
[removed duplicate include]
Reported-by: kernel test robot <redacted>
Reviewed-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
include/uapi/linux/bpf.h | 2 +-
kernel/bpf/verifier.c | 2 ++
kernel/trace/bpf_trace.c | 16 ++++++++++++++++
tools/include/uapi/linux/bpf.h | 2 +-
4 files changed, 20 insertions(+), 2 deletions(-)
@@ -5969,6 +5969,8 @@ static int check_get_func_ip(struct bpf_verifier_env *env)return-ENOTSUPP;}return0;+}elseif(type==BPF_PROG_TYPE_KPROBE){+return0;}verbose(env,"func %s#%d not supported for program type %d\n",
From: Jiri Olsa <hidden> Date: 2021-07-14 09:44:56
Adding bpf_program__attach_kprobe_opts that does the same
as bpf_program__attach_kprobe, but takes opts argument.
Currently opts struct holds just retprobe bool, but we will
add new field in following patch.
The function is not exported, so there's no need to add
size to the struct bpf_program_attach_kprobe_opts for now.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
tools/lib/bpf/libbpf.c | 34 +++++++++++++++++++++++++---------
1 file changed, 25 insertions(+), 9 deletions(-)
From: Jiri Olsa <hidden> Date: 2021-07-14 09:45:04
From: Alan Maguire <redacted>
kprobes can be placed on most instructions in a function, not
just entry, and ftrace and bpftrace support the function+offset
notification for probe placement. Adding parsing of func_name
into func+offset to bpf_program__attach_kprobe() allows the
user to specify
SEC("kprobe/bpf_fentry_test5+0x6")
...for example, and the offset can be passed to perf_event_open_probe()
to support kprobe attachment.
[jolsa: changed original code to use bpf_program__attach_kprobe_opts
and use dynamic allocation in sscanf]
Signed-off-by: Alan Maguire <redacted>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
tools/lib/bpf/libbpf.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
@@ -10394,12 +10395,31 @@ static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec,structbpf_program*prog){structbpf_program_attach_kprobe_optsopts;+unsignedlongoffset=0;+structbpf_link*link;constchar*func_name;+char*func;+intn,err;func_name=prog->sec_name+sec->len;opts.retprobe=strcmp(sec->sec,"kretprobe/")==0;-returnbpf_program__attach_kprobe_opts(prog,func_name,&opts);+n=sscanf(func_name,"%m[a-zA-Z0-9_.]+%lx",&func,&offset);+if(n<1){+err=-EINVAL;+pr_warn("kprobe name is invalid: %s\n",func_name);+returnlibbpf_err_ptr(err);+}+if(opts.retprobe&&offset!=0){+err=-EINVAL;+pr_warn("kretprobes do not support offset specification\n");+returnlibbpf_err_ptr(err);+}++opts.offset=offset;+link=bpf_program__attach_kprobe_opts(prog,func,&opts);+free(func);+returnlink;}structbpf_link*bpf_program__attach_uprobe(structbpf_program*prog,
From: Jiri Olsa <hidden> Date: 2021-07-14 09:45:12
Adding test for bpf_get_func_ip in kprobe+ofset probe.
Because of the offset value it's arch specific, enabling
the new test only for x86_64 architecture.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
.../bpf/prog_tests/get_func_ip_test.c | 18 ++++++++++++++++--
.../selftests/bpf/progs/get_func_ip_test.c | 11 +++++++++++
2 files changed, 27 insertions(+), 2 deletions(-)
@@ -8,10 +8,21 @@ void test_get_func_ip_test(void)__u32duration=0,retval;interr,prog_fd;-skel=get_func_ip_test__open_and_load();-if(!ASSERT_OK_PTR(skel,"get_func_ip_test__open_and_load"))+skel=get_func_ip_test__open();+if(!ASSERT_OK_PTR(skel,"get_func_ip_test__open"))return;+/* test6 is x86_64 specifc because of the instruction+*offset,disablingitforallotherarchs+*/+#ifndef __x86_64__+bpf_program__set_autoload(skel->progs.test6,false);+#endif++err=get_func_ip_test__load(skel);+if(!ASSERT_OK(err,"get_func_ip_test__load"))+gotocleanup;+err=get_func_ip_test__attach(skel);if(!ASSERT_OK(err,"get_func_ip_test__attach"))gotocleanup;
@@ -60,3 +61,13 @@ int BPF_PROG(test5, int a, int *b, int ret)test5_result=(constvoid*)addr==&bpf_modify_return_test;returnret;}++__u64test6_result=0;+SEC("kprobe/bpf_fentry_test6+0x5")+inttest6(structpt_regs*ctx)+{+__u64addr=bpf_get_func_ip(ctx);++test6_result=(constvoid*)addr==&bpf_fentry_test6+5;+return0;+}
On Wed, Jul 14, 2021 at 2:44 AM Jiri Olsa [off-list ref] wrote:
Adding bpf_get_func_ip helper for BPF_PROG_TYPE_TRACING programs,
specifically for all trampoline attach types.
The trampoline's caller IP address is stored in (ctx - 8) address.
so there's no reason to actually call the helper, but rather fixup
the call instruction and return [ctx - 8] value directly (suggested
by Alexei).
[fixed has_get_func_ip wrong return type]
Reported-by: kernel test robot <redacted>
Reported-by: Dan Carpenter <redacted>
I removed these tags, since they don't correspond to any real commit in the git.
Otherwise all patches would have been full of such things when patch series
go through iterations. Also fixed a few typos here and there,
manually rebased and applied.
Thanks!
On Wed, Jul 14, 2021 at 2:45 AM Jiri Olsa [off-list ref] wrote:
Adding bpf_program__attach_kprobe_opts that does the same
as bpf_program__attach_kprobe, but takes opts argument.
Currently opts struct holds just retprobe bool, but we will
add new field in following patch.
The function is not exported, so there's no need to add
size to the struct bpf_program_attach_kprobe_opts for now.
Why not exported? Please use a proper _opts struct just like others
(e.g., bpf_object_open_opts) and add is as a public API, it's a useful
addition. We are going to have a similar structure for attach_uprobe,
btw. Please send a follow up patch.
when you make it part of libbpf API, let's call it something shorter,
like bpf_kprobe_opts, maybe? And later we'll have bpf_uprobe_opts for
uprobes. Short and unambiguous.
On Wed, Jul 14, 2021 at 2:45 AM Jiri Olsa [off-list ref] wrote:
quoted hunk
From: Alan Maguire <redacted>
kprobes can be placed on most instructions in a function, not
just entry, and ftrace and bpftrace support the function+offset
notification for probe placement. Adding parsing of func_name
into func+offset to bpf_program__attach_kprobe() allows the
user to specify
SEC("kprobe/bpf_fentry_test5+0x6")
...for example, and the offset can be passed to perf_event_open_probe()
to support kprobe attachment.
[jolsa: changed original code to use bpf_program__attach_kprobe_opts
and use dynamic allocation in sscanf]
Signed-off-by: Alan Maguire <redacted>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
tools/lib/bpf/libbpf.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
From: Jiri Olsa <hidden> Date: 2021-07-18 19:30:54
On Thu, Jul 15, 2021 at 06:09:22PM -0700, Alexei Starovoitov wrote:
On Wed, Jul 14, 2021 at 2:44 AM Jiri Olsa [off-list ref] wrote:
quoted
Adding bpf_get_func_ip helper for BPF_PROG_TYPE_TRACING programs,
specifically for all trampoline attach types.
The trampoline's caller IP address is stored in (ctx - 8) address.
so there's no reason to actually call the helper, but rather fixup
the call instruction and return [ctx - 8] value directly (suggested
by Alexei).
[fixed has_get_func_ip wrong return type]
Reported-by: kernel test robot <redacted>
Reported-by: Dan Carpenter <redacted>
I removed these tags, since they don't correspond to any real commit in the git.
Otherwise all patches would have been full of such things when patch series
go through iterations. Also fixed a few typos here and there,
manually rebased and applied.
Thanks!
From: Jiri Olsa <hidden> Date: 2021-07-18 19:32:09
On Fri, Jul 16, 2021 at 06:41:59PM -0700, Andrii Nakryiko wrote:
On Wed, Jul 14, 2021 at 2:45 AM Jiri Olsa [off-list ref] wrote:
quoted
Adding bpf_program__attach_kprobe_opts that does the same
as bpf_program__attach_kprobe, but takes opts argument.
Currently opts struct holds just retprobe bool, but we will
add new field in following patch.
The function is not exported, so there's no need to add
size to the struct bpf_program_attach_kprobe_opts for now.
Why not exported? Please use a proper _opts struct just like others
(e.g., bpf_object_open_opts) and add is as a public API, it's a useful
addition. We are going to have a similar structure for attach_uprobe,
btw. Please send a follow up patch.
when you make it part of libbpf API, let's call it something shorter,
like bpf_kprobe_opts, maybe? And later we'll have bpf_uprobe_opts for
uprobes. Short and unambiguous.
From: Jiri Olsa <hidden> Date: 2021-07-18 19:33:12
On Fri, Jul 16, 2021 at 06:42:05PM -0700, Andrii Nakryiko wrote:
On Wed, Jul 14, 2021 at 2:45 AM Jiri Olsa [off-list ref] wrote:
quoted
From: Alan Maguire <redacted>
kprobes can be placed on most instructions in a function, not
just entry, and ftrace and bpftrace support the function+offset
notification for probe placement. Adding parsing of func_name
into func+offset to bpf_program__attach_kprobe() allows the
user to specify
SEC("kprobe/bpf_fentry_test5+0x6")
...for example, and the offset can be passed to perf_event_open_probe()
to support kprobe attachment.
[jolsa: changed original code to use bpf_program__attach_kprobe_opts
and use dynamic allocation in sscanf]
Signed-off-by: Alan Maguire <redacted>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
tools/lib/bpf/libbpf.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
On Sun, Jul 18, 2021 at 12:32 PM Jiri Olsa [off-list ref] wrote:
On Fri, Jul 16, 2021 at 06:41:59PM -0700, Andrii Nakryiko wrote:
quoted
On Wed, Jul 14, 2021 at 2:45 AM Jiri Olsa [off-list ref] wrote:
quoted
Adding bpf_program__attach_kprobe_opts that does the same
as bpf_program__attach_kprobe, but takes opts argument.
Currently opts struct holds just retprobe bool, but we will
add new field in following patch.
The function is not exported, so there's no need to add
size to the struct bpf_program_attach_kprobe_opts for now.
Why not exported? Please use a proper _opts struct just like others
(e.g., bpf_object_open_opts) and add is as a public API, it's a useful
addition. We are going to have a similar structure for attach_uprobe,
btw. Please send a follow up patch.
there's no outside user.. ok
because there is no API :) I've seen people asking about the ability
to attach to kprobe+offset in some PRs.
when you make it part of libbpf API, let's call it something shorter,
like bpf_kprobe_opts, maybe? And later we'll have bpf_uprobe_opts for
uprobes. Short and unambiguous.