[RFC PATCH bpf-next 2/2] bpf: Get fentry func addr from user when BTF info invalid

Tao Chen posted 2 patches 9 months, 1 week ago
[RFC PATCH bpf-next 2/2] bpf: Get fentry func addr from user when BTF info invalid
Posted by Tao Chen 9 months, 1 week ago
If kernel function optimized by the compiler, the function name in
kallsyms will have suffix like ".isra.0" or others. And fentry uses
function name from BTF to find the function address in kallsyms, in this
situation, it will fail due to the inconsistency of function names.
If so, try to use the function address passed from the user.

Signed-off-by: Tao Chen <chen.dylane@linux.dev>
---
 include/linux/bpf.h      | 1 +
 include/uapi/linux/bpf.h | 1 +
 kernel/bpf/syscall.c     | 1 +
 kernel/bpf/verifier.c    | 9 +++++++++
 4 files changed, 12 insertions(+)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 3f0cc89c06..fd53d1817f 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1626,6 +1626,7 @@ struct bpf_prog_aux {
 		struct work_struct work;
 		struct rcu_head	rcu;
 	};
+	u64 fentry_func;
 };
 
 struct bpf_prog {
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 07ee73cdf9..7016e47a70 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1577,6 +1577,7 @@ union bpf_attr {
 		 * If provided, prog_flags should have BPF_F_TOKEN_FD flag set.
 		 */
 		__s32		prog_token_fd;
+		__aligned_u64	fentry_func;
 		/* The fd_array_cnt can be used to pass the length of the
 		 * fd_array array. In this case all the [map] file descriptors
 		 * passed in this array will be bound to the program, even if
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 9794446bc8..6c1e3572cc 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2892,6 +2892,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
 	prog->sleepable = !!(attr->prog_flags & BPF_F_SLEEPABLE);
 	prog->aux->attach_btf = attach_btf;
 	prog->aux->attach_btf_id = attr->attach_btf_id;
+	prog->aux->fentry_func = attr->fentry_func;
 	prog->aux->dst_prog = dst_prog;
 	prog->aux->dev_bound = !!attr->prog_ifindex;
 	prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 54c6953a8b..507c281ddc 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -23304,6 +23304,15 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
 			} else {
 				addr = kallsyms_lookup_name(tname);
 			}
+
+			if (!addr && (prog->expected_attach_type == BPF_TRACE_FENTRY ||
+					prog->expected_attach_type == BPF_TRACE_FEXIT)) {
+				fname = kallsyms_lookup((unsigned long)prog->aux->fentry_func,
+							NULL, NULL, NULL, trace_symbol);
+				if (fname)
+					addr = (long)prog->aux->fentry_func;
+			}
+
 			if (!addr) {
 				module_put(mod);
 				bpf_log(log,
-- 
2.43.0
Re: [RFC PATCH bpf-next 2/2] bpf: Get fentry func addr from user when BTF info invalid
Posted by Alan Maguire 9 months, 1 week ago
On 30/04/2025 17:46, Tao Chen wrote:
> If kernel function optimized by the compiler, the function name in
> kallsyms will have suffix like ".isra.0" or others. And fentry uses
> function name from BTF to find the function address in kallsyms, in this
> situation, it will fail due to the inconsistency of function names.
> If so, try to use the function address passed from the user.
> 
> Signed-off-by: Tao Chen <chen.dylane@linux.dev>
> ---
>  include/linux/bpf.h      | 1 +
>  include/uapi/linux/bpf.h | 1 +
>  kernel/bpf/syscall.c     | 1 +
>  kernel/bpf/verifier.c    | 9 +++++++++
>  4 files changed, 12 insertions(+)
> 
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 3f0cc89c06..fd53d1817f 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -1626,6 +1626,7 @@ struct bpf_prog_aux {
>  		struct work_struct work;
>  		struct rcu_head	rcu;
>  	};
> +	u64 fentry_func;
>  };
>  
>  struct bpf_prog {
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index 07ee73cdf9..7016e47a70 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -1577,6 +1577,7 @@ union bpf_attr {
>  		 * If provided, prog_flags should have BPF_F_TOKEN_FD flag set.
>  		 */
>  		__s32		prog_token_fd;
> +		__aligned_u64	fentry_func;

since it can be used for fentry/fexit (I think from below?) might be
clearer to call it attach_func_addr or similar.

>  		/* The fd_array_cnt can be used to pass the length of the
>  		 * fd_array array. In this case all the [map] file descriptors
>  		 * passed in this array will be bound to the program, even if
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 9794446bc8..6c1e3572cc 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -2892,6 +2892,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
>  	prog->sleepable = !!(attr->prog_flags & BPF_F_SLEEPABLE);
>  	prog->aux->attach_btf = attach_btf;
>  	prog->aux->attach_btf_id = attr->attach_btf_id;
> +	prog->aux->fentry_func = attr->fentry_func;
>  	prog->aux->dst_prog = dst_prog;
>  	prog->aux->dev_bound = !!attr->prog_ifindex;
>  	prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS;
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 54c6953a8b..507c281ddc 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -23304,6 +23304,15 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
>  			} else {
>  				addr = kallsyms_lookup_name(tname);
>  			}
> +
> +			if (!addr && (prog->expected_attach_type == BPF_TRACE_FENTRY ||
> +					prog->expected_attach_type == BPF_TRACE_FEXIT)) {
> +				fname = kallsyms_lookup((unsigned long)prog->aux->fentry_func,
> +							NULL, NULL, NULL, trace_symbol);
> +				if (fname)
> +					addr = (long)prog->aux->fentry_func;


We should do some validation that the fname we get back matches the BTF
func name prefix (fname "foo.isra.0" matches "foo") I think?

> +			}
> +
>  			if (!addr) {
>  				module_put(mod);
>  				bpf_log(log,
Re: [RFC PATCH bpf-next 2/2] bpf: Get fentry func addr from user when BTF info invalid
Posted by Alexei Starovoitov 9 months, 1 week ago
On Wed, Apr 30, 2025 at 10:57 AM Alan Maguire <alan.maguire@oracle.com> wrote:
> > +
> > +                     if (!addr && (prog->expected_attach_type == BPF_TRACE_FENTRY ||
> > +                                     prog->expected_attach_type == BPF_TRACE_FEXIT)) {
> > +                             fname = kallsyms_lookup((unsigned long)prog->aux->fentry_func,
> > +                                                     NULL, NULL, NULL, trace_symbol);
> > +                             if (fname)
> > +                                     addr = (long)prog->aux->fentry_func;
>
>
> We should do some validation that the fname we get back matches the BTF
> func name prefix (fname "foo.isra.0" matches "foo") I think?

I don't think that will be enough.
User space should not be able to pass a random kernel address
and convince the kernel that it matches a particular btf_id.
As discussed in the other thread matching based on name is
breaking apart.
pahole does all the safety check to make sure name/addr/btf_id
are consistent.
We shouldn't be adding workarounds like this because
pahole/btf/kernel build is not smart enough.

pw-bot: cr
Re: [RFC PATCH bpf-next 2/2] bpf: Get fentry func addr from user when BTF info invalid
Posted by Tao Chen 9 months, 1 week ago
在 2025/5/1 06:23, Alexei Starovoitov 写道:
> On Wed, Apr 30, 2025 at 10:57 AM Alan Maguire <alan.maguire@oracle.com> wrote:
>>> +
>>> +                     if (!addr && (prog->expected_attach_type == BPF_TRACE_FENTRY ||
>>> +                                     prog->expected_attach_type == BPF_TRACE_FEXIT)) {
>>> +                             fname = kallsyms_lookup((unsigned long)prog->aux->fentry_func,
>>> +                                                     NULL, NULL, NULL, trace_symbol);
>>> +                             if (fname)
>>> +                                     addr = (long)prog->aux->fentry_func;
>>
>>
>> We should do some validation that the fname we get back matches the BTF
>> func name prefix (fname "foo.isra.0" matches "foo") I think?
> 
> I don't think that will be enough.
> User space should not be able to pass a random kernel address
> and convince the kernel that it matches a particular btf_id.
> As discussed in the other thread matching based on name is
> breaking apart.
> pahole does all the safety check to make sure name/addr/btf_id
> are consistent.
> We shouldn't be adding workarounds like this because
> pahole/btf/kernel build is not smart enough.
> 

Got it thanks for your reply, it is hoped that pahole/btf can have a 
better way to solve such problems.

> pw-bot: cr


-- 
Best Regards
Tao Chen