Re: [PATCH v14 bpf-next 02/10] libbpf: Support layout section handling in BTF

[email protected] Wed, 18 Mar 2026 14:45:27 +0000 (UTC)
Newsgroups org.kernel.vger.dwarves,org.kernel.vger.bpf
Message-ID <9bb62dd69d27eaaf36db9036240de0354722c839121572557dd161a2511c6a43@mail.kernel.org>
> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
> index 40becc9643688..37a3b317cb2f4 100644
> --- a/tools/lib/bpf/btf.c
> +++ b/tools/lib/bpf/btf.c

[ ... ]

> -static void btf_bswap_hdr(struct btf_header *h)
> +static void btf_bswap_hdr(struct btf_header *h, __u32 hdr_len)
>  {
>  	h->magic = bswap_16(h->magic);
>  	h->hdr_len = bswap_32(h->hdr_len);
> @@ -224,66 +246,113 @@ static void btf_bswap_hdr(struct btf_header *h)
>  	h->type_len = bswap_32(h->type_len);
>  	h->str_off = bswap_32(h->str_off);
>  	h->str_len = bswap_32(h->str_len);
> +	/* May be operating on raw data with hdr_len that does not include below fields */
> +	if (hdr_len >= sizeof(struct btf_header)) {
> +		h->layout_off = bswap_32(h->layout_off);
> +		h->layout_len = bswap_32(h->layout_len);
> +	}
>  }
>
>  static int btf_parse_hdr(struct btf *btf)
>  {
> -	struct btf_header *hdr = btf->hdr;
> -	__u32 meta_left;
> +	struct btf_header *hdr = btf->raw_data;
> +	__u32 hdr_len, meta_left;
>
> -	if (btf->raw_size < sizeof(struct btf_header)) {
> +	if (btf->raw_size < offsetofend(struct btf_header, str_len)) {
>  		pr_debug("BTF header not found\n");
>  		return -EINVAL;
>  	}
>
> +	hdr_len = hdr->hdr_len;
> +
>  	if (hdr->magic == bswap_16(BTF_MAGIC)) {
>  		btf->swapped_endian = true;
> -		if (bswap_32(hdr->hdr_len) != sizeof(struct btf_header)) {
> +		hdr_len = bswap_32(hdr->hdr_len);
> +		if (hdr_len < offsetofend(struct btf_header, str_len)) {
>  			pr_warn("Can't load BTF with non-native endianness due to unsupported header length %u\n",
> -				bswap_32(hdr->hdr_len));
> +				hdr_len);
>  			return -ENOTSUP;
>  		}
> -		btf_bswap_hdr(hdr);
> +		btf_bswap_hdr(hdr, hdr_len);

Could btf_bswap_hdr() access memory beyond the raw_data buffer here?

The initial check guarantees raw_size >= offsetofend(str_len) which
is 24 bytes.  But if hdr_len (after bswap) is >= 32,
btf_bswap_hdr() will read and write h->layout_off at offset 24 and
h->layout_len at offset 28.  If raw_size is between 24 and 31,
those accesses go past the end of the raw_data buffer.

The raw_size >= hdr_len check that would catch this comes after the
btf_bswap_hdr() call:

>  	} else if (hdr->magic != BTF_MAGIC) {
>  		pr_debug("Invalid BTF magic: %x\n", hdr->magic);
>  		return -EINVAL;
>  	}
>
> -	if (btf->raw_size < hdr->hdr_len) {
> +	if (btf->raw_size < hdr_len) {
>  		pr_debug("BTF header len %u larger than data size %u\n",
> -			 hdr->hdr_len, btf->raw_size);
> +			 hdr_len, btf->raw_size);
>  		return -EINVAL;
>  	}

Moving this raw_size < hdr_len check (or an equivalent guard) to
before the btf_bswap_hdr() call in the swapped-endian branch would
prevent the out-of-bounds access.


---
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/23248215146