BPF List
 help / color / mirror / Atom feed
* [PATCH bpf-next] libbpf: Reject oversized unknown BTF type records
@ 2026-09-02  9:11 Mark Amirkan
  2026-09-02  9:23 ` sashiko-bot
  2026-09-03  0:40 ` Andrii Nakryiko
  0 siblings, 2 replies; 3+ messages in thread
From: Mark Amirkan @ 2026-09-02  9:11 UTC (permalink / raw)
  To: bpf
  Cc: andrii, eddyz87, ihor.solodrai, ast, daniel, memxor, martin.lau,
	song, yonghong.song, jolsa, emil, shuah, linux-kernel,
	linux-kselftest, Mark Amirkan

btf_type_size_unknown() returns an int, but calculates the type record
size using unsigned operands.  With a 24-bit vlen, an unknown kind whose
vlen is 0xffffff and whose info and element sizes are both 252 has a
record size of 0xfc00000c.  Converting this value to int produces
-67108852.

btf_parse_type_sec() returns the negative value, and btf_new() encodes it
with ERR_PTR().  Since the value is outside the error-pointer range,
libbpf_ptr() does not recognize it as an error.  On a 64-bit system, a
129-byte raw BTF input makes btf__new() return 0xfffffffffc00000c while
libbpf_get_error() returns zero and errno remains zero.  Calling
btf__type_cnt() or btf__free() on the result crashes.  The same input
makes bpftool's "btf dump file" command terminate with SIGSEGV.

Calculate the record size as size_t and reject values above INT_MAX
before converting it to int.  Add a regression test for the maximum-vlen
unknown kind.

Fixes: cacd6729c092 ("libbpf: Adjust btf_vlen() to return a __u32")
Assisted-by: Symbolic
Signed-off-by: Mark Amirkan <markdamirkan@gmail.com>
---
Testing:
- normal builds of libbpf and bpftool, plus an ASan/UBSan libbpf build;
- the reproducer through btf__new() and bpftool;
- the added btf_kind test and the existing encoding/decoding subtests;
- identical bpftool output before and after the fix for all 60 BTF blobs
  under /sys/kernel/btf on the test system.

The complete BPF selftest suite was not run locally because clang was not
available.

This fixes code present in Linux v7.2; please consider it for stable.

 tools/lib/bpf/btf.c                           | 11 +++++-
 .../selftests/bpf/prog_tests/btf_kind.c       | 39 +++++++++++++++++++
 2 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index c783359977b46e521965c1af223515cfd8701b12..83a7f199f37dfdc2384107a45a8be5b98c4cd8f1 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -421,6 +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;
+	size_t type_size;
 	__u32 vlen = btf_vlen(t);
 	__u32 kind = btf_kind(t);
 
@@ -448,7 +449,15 @@ static int btf_type_size_unknown(const struct btf *btf, const struct btf_type *t
 		return -EINVAL;
 	}
 
-	return sizeof(struct btf_type) + l[kind].info_sz + vlen * l[kind].elem_sz;
+	type_size = sizeof(struct btf_type) + l[kind].info_sz +
+		    (size_t)vlen * l[kind].elem_sz;
+	if (type_size > INT_MAX) {
+		pr_debug("BTF type size %zu for kind %u is too large\n",
+			 type_size, kind);
+		return -E2BIG;
+	}
+
+	return type_size;
 }
 
 static int btf_type_size(const struct btf *btf, const struct btf_type *t)
diff --git a/tools/testing/selftests/bpf/prog_tests/btf_kind.c b/tools/testing/selftests/bpf/prog_tests/btf_kind.c
index f61afe6a79a51f86f22f62bd86c685b7db8b39d1..fc6a4db9993764536885a5c5f13980a4c3a6bd26 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf_kind.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf_kind.c
@@ -217,10 +217,49 @@ void test_btf_kind_decoding(void)
 	btf__free(btf);
 }
 
+static void test_btf_kind_size_overflow(void)
+{
+	/* Max vlen and aligned u8 layout sizes produce type size 0xfc00000c. */
+	struct {
+		struct btf_header hdr;
+		struct btf_type type;
+		struct btf_layout layouts[NR_BTF_KINDS + 1];
+		char strs[1];
+	} __packed raw_btf = {
+		.hdr = {
+			.magic = BTF_MAGIC,
+			.version = BTF_VERSION,
+			.hdr_len = sizeof(struct btf_header),
+			.type_len = sizeof(struct btf_type),
+			.layout_off = sizeof(struct btf_type),
+			.layout_len = sizeof(struct btf_layout) * (NR_BTF_KINDS + 1),
+			.str_off = sizeof(struct btf_type) +
+				   sizeof(struct btf_layout) * (NR_BTF_KINDS + 1),
+			.str_len = 1,
+		},
+		.type.info = (NR_BTF_KINDS << 24) | BTF_MAX_VLEN,
+		.layouts[NR_BTF_KINDS] = {
+			.info_sz = 252,
+			.elem_sz = 252,
+		},
+	};
+	struct btf *btf;
+	int err;
+
+	errno = 0;
+	btf = btf__new(&raw_btf, sizeof(raw_btf));
+	err = libbpf_get_error(btf);
+	if (!ASSERT_EQ(err, -E2BIG, "size_overflow_err"))
+		return;
+	ASSERT_NULL(btf, "size_overflow_btf");
+}
+
 void test_btf_kind(void)
 {
 	if (test__start_subtest("btf_kind_encoding"))
 		test_btf_kind_encoding();
 	if (test__start_subtest("btf_kind_decoding"))
 		test_btf_kind_decoding();
+	if (test__start_subtest("btf_kind_size_overflow"))
+		test_btf_kind_size_overflow();
 }

base-commit: d761934c9483ecde93fe99d8705282f716dfee50
-- 
2.39.3 (Apple Git-146)

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH bpf-next] libbpf: Reject oversized unknown BTF type records
  2026-09-02  9:11 [PATCH bpf-next] libbpf: Reject oversized unknown BTF type records Mark Amirkan
@ 2026-09-02  9:23 ` sashiko-bot
  2026-09-03  0:40 ` Andrii Nakryiko
  1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-09-02  9:23 UTC (permalink / raw)
  To: Mark Amirkan; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Pointer arithmetic overflow in `btf_parse_type_sec` bounds check allows out-of-bounds memory access on 32-bit architectures.
--

commit ecf66a907aa5b49ad6ebbe3433e5a171a1a7138e
Author: Mark Amirkan <markdamirkan@gmail.com>

libbpf: Reject oversized unknown BTF type records

This patch changes btf_type_size_unknown() to calculate type size using size_t
and rejects sizes greater than INT_MAX. This prevents massive unknown types
from wrapping to negative values when cast to int and crashing libbpf.

> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
> index c783359977b46..83a7f199f37df 100644
> --- a/tools/lib/bpf/btf.c
> +++ b/tools/lib/bpf/btf.c
[ ... ]
> @@ -448,7 +449,15 @@ static int btf_type_size_unknown(const struct btf *btf, const struct btf_type *t
>  		return -EINVAL;
>  	}
>  
> -	return sizeof(struct btf_type) + l[kind].info_sz + vlen * l[kind].elem_sz;
> +	type_size = sizeof(struct btf_type) + l[kind].info_sz +
> +		    (size_t)vlen * l[kind].elem_sz;
> +	if (type_size > INT_MAX) {

[Severity: High]
This isn't a bug introduced by this patch, but since we are explicitly
allowing type sizes up to INT_MAX, could this trigger a pointer arithmetic
overflow in the caller?

In tools/lib/bpf/btf.c:btf_parse_type_sec(), the size is bounds-checked like
this:

		type_size = btf_type_size(btf, next_type);
		if (type_size < 0)
			return type_size;
		if (next_type + type_size > end_type) {
			pr_warn("BTF type [%u] is malformed\n", btf->start_id + btf->nr_types);
			return -EINVAL;
		}

On 32-bit architectures, if type_size is close to INT_MAX and next_type is
high in the address space, next_type + type_size can wrap around. This would
cause the check to erroneously evaluate to false, bypassing the validation and
allowing out-of-bounds memory access.

Would it be safer to subtract pointers to prevent overflow here:

		if (type_size > end_type - next_type) {

> +		pr_debug("BTF type size %zu for kind %u is too large\n",
> +			 type_size, kind);
> +		return -E2BIG;
> +	}
> +
> +	return type_size;
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260902091126.59281-1-markdamirkan@gmail.com?part=1

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH bpf-next] libbpf: Reject oversized unknown BTF type records
  2026-09-02  9:11 [PATCH bpf-next] libbpf: Reject oversized unknown BTF type records Mark Amirkan
  2026-09-02  9:23 ` sashiko-bot
@ 2026-09-03  0:40 ` Andrii Nakryiko
  1 sibling, 0 replies; 3+ messages in thread
From: Andrii Nakryiko @ 2026-09-03  0:40 UTC (permalink / raw)
  To: Mark Amirkan
  Cc: bpf, andrii, eddyz87, ihor.solodrai, ast, daniel, memxor,
	martin.lau, song, yonghong.song, jolsa, emil, shuah, linux-kernel,
	linux-kselftest

On Wed, Sep 2, 2026 at 2:11 AM Mark Amirkan <markdamirkan@gmail.com> wrote:
>
> btf_type_size_unknown() returns an int, but calculates the type record
> size using unsigned operands.  With a 24-bit vlen, an unknown kind whose
> vlen is 0xffffff and whose info and element sizes are both 252 has a
> record size of 0xfc00000c.  Converting this value to int produces
> -67108852.
>
> btf_parse_type_sec() returns the negative value, and btf_new() encodes it
> with ERR_PTR().  Since the value is outside the error-pointer range,
> libbpf_ptr() does not recognize it as an error.  On a 64-bit system, a
> 129-byte raw BTF input makes btf__new() return 0xfffffffffc00000c while
> libbpf_get_error() returns zero and errno remains zero.  Calling
> btf__type_cnt() or btf__free() on the result crashes.  The same input
> makes bpftool's "btf dump file" command terminate with SIGSEGV.
>
> Calculate the record size as size_t and reject values above INT_MAX
> before converting it to int.  Add a regression test for the maximum-vlen
> unknown kind.
>
> Fixes: cacd6729c092 ("libbpf: Adjust btf_vlen() to return a __u32")
> Assisted-by: Symbolic
> Signed-off-by: Mark Amirkan <markdamirkan@gmail.com>
> ---
> Testing:
> - normal builds of libbpf and bpftool, plus an ASan/UBSan libbpf build;
> - the reproducer through btf__new() and bpftool;
> - the added btf_kind test and the existing encoding/decoding subtests;
> - identical bpftool output before and after the fix for all 60 BTF blobs
>   under /sys/kernel/btf on the test system.
>
> The complete BPF selftest suite was not run locally because clang was not
> available.

that's ok, I hope AI wasn't too stressed about this unfortunate state
of things...

we are not going to harden libbpf against any possible malicious
corruption of BTF contents. If you don't trust the source of data,
don't pass it to libbpf (or do it in a VM or some such).

pw-bot: cr

>
> This fixes code present in Linux v7.2; please consider it for stable.
>

Do you use libbpf in practice? and where do you get its source code from, if so?

>  tools/lib/bpf/btf.c                           | 11 +++++-
>  .../selftests/bpf/prog_tests/btf_kind.c       | 39 +++++++++++++++++++
>  2 files changed, 49 insertions(+), 1 deletion(-)
>

[...]

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-03  0:40 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-02  9:11 [PATCH bpf-next] libbpf: Reject oversized unknown BTF type records Mark Amirkan
2026-09-02  9:23 ` sashiko-bot
2026-09-03  0:40 ` Andrii Nakryiko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox