A Clang-generated struct_ops mirror with an all-zero private bitfield can crash libbpf. With kind_flag set, the BTF member offset also encodes the bitfield width. bpf_map__init_kern_struct_ops() divided this encoded value by eight before rejecting bitfields. A 31-bit field therefore selects data + 0x3e00000, where libbpf_is_mem_zeroed() triggers an ASan SEGV. The issue was found by comparing the same ELF in JIT and interpreter configurations. JIT+BTF reached the faulty struct_ops path, while the interpreter configuration rejected the object before this code. Reject local bitfields before calculating the data pointer. Preserve the existing all-zero compatibility path for ordinary private fields. Fixes: c911fc61a7ce ("libbpf: Skip zeroed or null fields if not found in the kernel type.") Assisted-by: LLM Signed-off-by: Mingpei CAO --- 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 b749c01742ee0..1738a42220f0c 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: 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; -- 2.43.0