From 961b8946acb482b6d7a39c266d623e5f9c4e873f Mon Sep 17 00:00:00 2001 From: Mingpei CAO Date: Tue, 15 Sep 2026 16:22:36 +0000 Subject: [PATCH] libbpf: Reject local struct_ops bitfields before data access A local struct_ops type can contain a bitfield absent from the corresponding kernel BTF type. bpf_map__init_kern_struct_ops() checks whether data for an absent local member is zero. For a bitfield, member->offset contains the bit offset and field width. bpf_map__init_kern_struct_ops() used the encoded value to calculate the member data pointer before rejecting the bitfield. The zero-data check could therefore read outside st_ops->data and crash libbpf. Reject local bitfields before calculating the member data pointer. Keep the existing rejection for bitfields in the kernel type. Fixes: c911fc61a7ce ("libbpf: Skip zeroed or null fields if not found in the kernel type.") Signed-off-by: Mingpei CAO Signed-off-by: Andrii Nakryiko Reviewed-by: Amery Hung Link: https://lore.kernel.org/bpf/20260915162252.473044-2-caomingpei@gmail.com --- tools/lib/bpf/libbpf.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index f7a0517d8fa8..33ff61b151f3 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1223,6 +1223,12 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map) const char *mname; mname = btf__name_by_offset(btf, member->name_off); + if (btf_member_bitfield_size(type, i)) { + pr_warn("struct_ops init_kern %s: local bitfield %s is not supported\n", + map->name, mname); + return -ENOTSUP; + } + moff = member->offset / 8; mdata = data + moff; msize = btf__resolve_size(btf, member->type); @@ -1259,8 +1265,7 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map) } kern_member_idx = kern_member - btf_members(kern_type); - if (btf_member_bitfield_size(type, i) || - btf_member_bitfield_size(kern_type, kern_member_idx)) { + if (btf_member_bitfield_size(kern_type, kern_member_idx)) { pr_warn("struct_ops init_kern %s: bitfield %s is not supported\n", map->name, mname); return -ENOTSUP;