On 6/4/26 4:10 AM, [email protected] wrote:
> From: Yuan Chen <[email protected]>
> 
> probe_fd() converts BPF syscall failures to return value 0,
> which feat_supported() interprets as 'feature absent' (ret==0),
> even when the probe failed due to a BPF token's restricted
> program/map type mask.
> 
> In a user namespace with an implicit BPF token, the sequence is:
>   1. bpf_object_open() -> no feat_cache yet -> global cache used
>   2. bpf_object_prepare_token() -> creates token, sets feat_cache->token_fd
>   3. bpf_object__create_maps() -> feat_supported() runs probe
>      -> bpf_prog_load(SOCKET_FILTER) with token -> -EPERM
>      -> probe_fd(-EPERM) -> returns 0
>      -> feat_supported sees ret==0 -> FEAT_MISSING
>      -> internal maps (global data) skipped -> verifier EINVAL
> 
> Fix by making probe_fd() return the negative error on failure
> instead of 0, so feat_supported() enters the ret<0 path.
> 
> Additionally add a token_fd rescue in feat_supported() for the
> ret<0 case: when a BPF token is present, a failed feature probe
> is treated as 'feature supported' because token creation itself
> proves the kernel BPF subsystem works.  Real BPF issues will
> be caught during actual program/map loading.
> 
> Signed-off-by: Yuan Chen <[email protected]>
> ---

It looks wrong to say that any feature is supported just because there is
token_fd present. In patch 1 we only checked that BPF is available, so
it was ok skipping probing. This one looks a bit more risky.
Is the reason this code fails because of BPF_PROG_TYPE_SOCKET_FILTER not enabled
in the token? I suggest fetch the first supported program type from the token 
and
pass it down to bpf_prog_load().

>  tools/lib/bpf/features.c | 23 +++++++++++++++++++++--
>  1 file changed, 21 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/lib/bpf/features.c b/tools/lib/bpf/features.c
> index b7e388f99d0b..f934452e52f0 100644
> --- a/tools/lib/bpf/features.c
> +++ b/tools/lib/bpf/features.c
> @@ -16,7 +16,14 @@ int probe_fd(int fd)
>  {
>       if (fd >= 0)
>               close(fd);
> -     return fd >= 0;
> +     /* Return 1 on success, negative error on failure, so
> +      * feat_supported() can distinguish probe errors from
> +      * genuine feature absence.  When a BPF token is present,
> +      * a negative return triggers the rescue path that marks
> +      * the feature as SUPPORTED (token creation itself proves
> +      * the kernel BPF subsystem works).
> +      */
> +     return fd >= 0 ? 1 : fd;
>  }
>  
>  static int probe_kern_prog_name(int token_fd)
> @@ -725,9 +732,21 @@ bool feat_supported(struct kern_feature_cache *cache, 
> enum kern_feature_id feat_
>               } else if (ret == 0) {
>                       WRITE_ONCE(cache->res[feat_id], FEAT_MISSING);
>               } else {
> +                     /*
> +                      * A BPF token may restrict which program/map types
> +                      * are permitted, causing the probe to fail even
> +                      * though the kernel supports the feature.  When a
> +                      * token is present the probe is best-effort: BPF
> +                      * token creation itself proves the kernel has a
> +                      * working BPF subsystem.  Real BPF issues will be
> +                      * caught during actual program/map loading.
> +                      */
> +                     if (cache->token_fd)
> +                             WRITE_ONCE(cache->res[feat_id], FEAT_SUPPORTED);
> +                     else
> +                             WRITE_ONCE(cache->res[feat_id], FEAT_MISSING);
>                       pr_warn("Detection of kernel %s support failed: %s\n",
>                               feat->desc, errstr(ret));
> -                     WRITE_ONCE(cache->res[feat_id], FEAT_MISSING);
>               }
>       }
>  


Reply via email to