Re: [PATCH v3 bpf-next 2/6] libbpf: Adjust btf_vlen() to return a __u32

sashiko-bot
2026-04-17T17:07:13Z

Sashiko AI review found 1 potential issue(s):
- [High] On 32-bit systems, `btf_parse_type_sec()` is vulnerable to pointer arithmetic wrap-around due to missing strict bounds checking, allowing an attacker-crafted BTF layout to bypass safety checks and cause out-of-bounds memory access.
--

commit 0d6d9306686384cb94334ae8845f954db44a9f74
Author: Alan Maguire <alan.maguire@oracle.com>

libbpf: Adjust btf_vlen() to return a __u32

Now that vlen is 24 bits, btf_vlen() must return a __u32.
Adjust use cases in libbpf accordingly. Also add error
handling to avoid vlen overflow in btf_type_inc_vlen().

> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
> index ceb57b46a8782..267904939098c 100644
> --- a/tools/lib/bpf/btf.c
> +++ b/tools/lib/bpf/btf.c
> @@ -421,7 +421,7 @@ static int btf_type_size_unknown(const struct btf *btf, const struct btf_type *t
> {
> __u32 l_cnt = btf->hdr.layout_len / sizeof(struct btf_layout);
> struct btf_layout *l = btf->layout;
> - __u16 vlen = btf_vlen(t);
> + __u32 vlen = btf_vlen(t);
> __u32 kind = btf_kind(t);

Can this lead to a pointer arithmetic wrap-around regression on 32-bit
systems?

The size is calculated later in this function using unsigned 32-bit
arithmetic and returned as a signed int:

return sizeof(struct btf_type) + l[kind].info_sz + vlen * l[kind].elem_sz;

An attacker could provide a custom layout with an artificially large elem_sz
(e.g., 2,000,000,000). For a type with vlen = 1, the calculated size fits
within a positive signed 32-bit int and is returned as a valid positive
type_size.

When btf_parse_type_sec() checks if next_type + type_size > end_type, it
evaluates this using 32-bit pointer arithmetic. If next_type is located high
in the address space, adding 2,000,000,000 wraps around the 32-bit boundary
to a numerically smaller low address, incorrectly passing the bounds check.

This causes next_type to advance to the wrapped address, allowing subsequent
loop iterations to read arbitrary memory and potentially cause out-of-bounds
accesses or crashes.

While this parser logic issue predates this patch, should we address it here
by safely checking the offset instead? For example:

if ((size_t)type_size > (size_t)((char *)end_type - (char *)next_type))

--
Sashiko AI review · https://sashiko.dev/#/patchset/20260417143023.1551481-1-alan.maguire@oracle.com?part=2