> diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> index 5846de364209..84a53c594f48 100644
> --- a/tools/lib/bpf/bpf.c
> +++ b/tools/lib/bpf/bpf.c
> @@ -884,6 +884,14 @@ int bpf_link_create(int prog_fd, int target_fd,
>               if (!OPTS_ZEROED(opts, cgroup))
>                       return libbpf_err(-EINVAL);
>               break;
> +     case BPF_STRUCT_OPS:
> +             relative_fd = OPTS_GET(opts, cgroup.relative_fd, 0);
> +             attr.link_create.cgroup.relative_fd = relative_fd;
> +             attr.link_create.cgroup.expected_revision =
> +                     OPTS_GET(opts, cgroup.expected_revision, 0);

The bpf_link_create() BPF_STRUCT_OPS case reads expected_revision from
the opts, but looking at bpf_map__attach_struct_ops_opts() below...

> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 0c8bf0b5cce4..70a00da54ff5 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c

[ ... ]

> @@ -13503,7 +13510,9 @@ struct bpf_link *bpf_map__attach_struct_ops(const 
> struct bpf_map *map)
>               return &link->link;
>       }
>
> -     fd = bpf_link_create(map->fd, 0, BPF_STRUCT_OPS, NULL);
> +     link_opts.cgroup.relative_fd = OPTS_GET(opts, relative_fd, 0);
> +
> +     fd = bpf_link_create(map->fd, 0, BPF_STRUCT_OPS, &link_opts);

Should there also be a line here to forward expected_revision? The
bpf_struct_ops_opts struct defines expected_revision and the BPF_STRUCT_OPS
case in bpf_link_create() reads it, but this function only sets relative_fd.
If a user passes expected_revision in their opts, it appears to be silently
ignored.

> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index dfc37a615578..5aef44bcfcc2 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h

[ ... ]

> +struct bpf_struct_ops_opts {
> +     /* size of this struct, for forward/backward compatibility */
> +     size_t sz;
> +     __u32 flags;
> +     __u32 relative_fd;
> +     __u64 expected_revision;
                ^^^^^^^^^^^^^^^^
> +     size_t :0;
> +};
> +#define bpf_struct_ops_opts__last_field expected_revision

The expected_revision field is declared here and is even the __last_field,
but it does not appear to be forwarded to bpf_link_create_opts in
bpf_map__attach_struct_ops_opts(). Is this intentional, or was the
forwarding line missed?


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/21392729810

AI-authorship-score: low
AI-authorship-explanation: Commit message and code follow standard 
kernel/libbpf conventions without unusual patterns typically associated with 
AI-generated content.
issues-found: 1
issue-severity-score: low
issue-severity-explanation: The expected_revision field in bpf_struct_ops_opts 
is defined but silently ignored, which could cause unexpected behavior for 
users relying on revision checking, but does not cause crashes or security 
issues.

Reply via email to