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