> commit acd0d2042870d7613c0c27932c41262d1c41b4e1
> Author: Leon Hwang <[email protected]>
> Commit: Kernel Patches Daemon <[email protected]>
>
> bpf: Check tail zero of bpf_prog_info
>
> Since there're 4 bytes padding at the end of struct bpf_prog_info, they
> won't be checked by bpf_check_uarg_tail_zero().
>
> pahole -C bpf_prog_info ./vmlinux
> struct bpf_prog_info {
> ...
> __u32 attach_btf_obj_id; /* 220 4 */
> __u32 attach_btf_id; /* 224 4 */
>
> /* size: 232, cachelines: 4, members: 38 */
> /* sum members: 224 */
> /* sum bitfield members: 1 bits, bit holes: 1, sum bit holes: 31
> bits */
> /* padding: 4 */
> /* forced alignments: 9 */
> /* last cacheline: 40 bytes */
> } __attribute__((__aligned__(8)));
>
> If a future kernel extension adds a new 4-byte field, older userspace
> programs allocating this structure on the stack might inadvertently pass
> uninitialized stack garbage into the new field, permanently breaking
> backward compatibility. -- sashiko [1]
>
> Fix it by changing sizeof(info) to
> offsetofend(struct bpf_prog_info, attach_btf_id).
>
> And, add "__u32 :32" to the tail of struct bpf_prog_info.
>
> [1]
> https://lore.kernel.org/bpf/[email protected]/
>
> Fixes: aba64c7da983 ("bpf: Add verified_insns to bpf_prog_info and
> fdinfo")
Is the Fixes: tag pointing to the right commit? The padding bug was
actually introduced by commit b79c9fc9551b ("bpf: implement BPF_PROG_QUERY
for BPF_LSM_CGROUP"), which added attach_btf_obj_id and attach_btf_id after
verified_insns, creating the 4 bytes of padding at the end of the structure.
Commit aba64c7da983 added verified_insns as the last field but did not
create padding.
Suggested: Fixes: b79c9fc9551b ("bpf: implement BPF_PROG_QUERY for
BPF_LSM_CGROUP")
> Acked-by: Mykyta Yatsenko <[email protected]>
> Signed-off-by: Leon Hwang <[email protected]>
[ ... ]
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index 89f020a44fc9..c5d4ae957e87 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -5121,10 +5121,11 @@ static int bpf_prog_get_info_by_fd(struct file *file,
> u32 info_len = attr->info.info_len;
> struct bpf_prog_kstats stats;
> char __user *uinsns;
> - u32 ulen;
> + u32 ulen, len;
> int err;
>
> - err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info),
> info_len);
> + len = offsetofend(struct bpf_prog_info, attach_btf_id);
> + err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), len, info_len);
> if (err)
> return err;
> info_len = min_t(u32, sizeof(info), info_len);
Does this change break the ABI for existing deployed binaries?
Previously, expected_size was 232 (sizeof(info)). If an existing binary
passes info_len = 232 with uninitialized stack garbage in the 4-byte
padding, bpf_check_uarg_tail_zero() would see actual_size <= expected_size
(232 <= 232) and immediately return 0.
By reducing expected_size to 228, actual_size > expected_size (232 > 228),
so bpf_check_uarg_tail_zero() will actively check the 4 padding bytes and
return -E2BIG if they contain garbage. This rejects previously working
applications.
sashiko-bot and bot+bpf-ci raised this concern in v1 and v2:
https://lore.kernel.org/bpf/[email protected]/
While v3 adds '__u32 :32;' to prevent future field additions in the
padding space (addressing forward compatibility), the backward
compatibility concern about breaking existing binaries remains unresolved.
[ ... ]
---
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/27025811732