From 82f51391fe98bcaa72836632be897caefe15f7e0 Mon Sep 17 00:00:00 2001 From: Darren Carreras Date: Thu, 13 Aug 2026 20:43:18 -0400 Subject: [PATCH] libbpf: Avoid overflow in BTF.ext bounds check A malformed BTF.ext subsection length in an ELF input can wrap the pointer addition used by btf_ext_parse_sec_info() on 32-bit builds. The wrapped pointer passes the bounds check and parsing then reads beyond the copied BTF.ext data. Ensure the header fits in the copied data, then validate the subsection offset and length with subtraction before forming its pointer. Fixes: ae4ab4b4117d ("btf: expose API to work with raw btf_ext data") Closes: https://issues.oss-fuzz.com/issues/477315119 Signed-off-by: Darren Carreras Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20260813-b4-libbpf-v6-send-20260813-v6-1-56be61c52758@gmail.com --- src/btf.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/btf.c b/src/btf.c index 8417de9..c783359 100644 --- a/src/btf.c +++ b/src/btf.c @@ -3364,7 +3364,7 @@ static int btf_ext_parse_sec_info(struct btf_ext *btf_ext, { const struct btf_ext_info_sec *sinfo; struct btf_ext_info *ext_info; - __u32 info_left, record_size; + __u32 data_left, info_left, record_size; size_t sec_cnt = 0; void *info; @@ -3377,16 +3377,20 @@ static int btf_ext_parse_sec_info(struct btf_ext *btf_ext, return -EINVAL; } - /* The start of the info sec (including the __u32 record_size). */ - info = btf_ext->data + btf_ext->hdr->hdr_len + ext_sec->off; - info_left = ext_sec->len; + if (btf_ext->hdr->hdr_len > btf_ext->data_size) + return -EINVAL; - if (btf_ext->data + btf_ext->data_size < info + ext_sec->len) { + data_left = btf_ext->data_size - btf_ext->hdr->hdr_len; + if (ext_sec->off > data_left || ext_sec->len > data_left - ext_sec->off) { pr_debug("%s section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n", ext_sec->desc, ext_sec->off, ext_sec->len); return -EINVAL; } + /* The start of the info sec (including the __u32 record_size). */ + info = btf_ext->data + btf_ext->hdr->hdr_len + ext_sec->off; + info_left = ext_sec->len; + /* At least a record size */ if (info_left < sizeof(__u32)) { pr_debug(".BTF.ext %s record size not found\n", ext_sec->desc);