Linux Kernel Selftest development
 help / color / mirror / Atom feed
* [PATCH bpf v4 0/5] bpf: Fix NULL-ptr-derefs when showing a void BTF type
@ 2026-09-01 10:47 Jiayuan Chen
  2026-09-01 10:47 ` [PATCH bpf v4 1/5] bpf: Reject key-less BTF for hash maps Jiayuan Chen
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Jiayuan Chen @ 2026-09-01 10:47 UTC (permalink / raw)
  To: bpf
  Cc: Jiayuan Chen, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Emil Tsalapatis, Ihor Solodrai, Shuah Khan, Mykyta Yatsenko,
	Alan Maguire, linux-kernel, linux-kselftest

This series fixes three NULL-ptr-derefs in BTF handling.

Patch 1 handles the syzbot report. A key-less BTF (btf_key_type_id == 0) used
to be rejected for hash maps, until htab and rhtab gained a ->map_check_btf
(to register a dtor) that does not look at the key, so a key-less hash map is
now accepted. Dumping it through bpffs feeds the key type_id 0 into
btf_type_seq_show() and NULL-derefs in btf_type_show(). Reject it again.

Patches 2 and 3 fix two related, pre-existing crashes reachable via
bpf_snprintf_btf(), which renders a type_id taken straight from the BPF
program against the vmlinux BTF. A "const void" (a modifier resolving to
void) NULL-derefs in btf_modifier_show() - void has no ->show op; a
BTF_KIND_VAR NULL-derefs in btf_var_show() - the vmlinux base BTF has no
resolved_ids. Patch 2 falls back to btf_df_show(), the "<unsupported kind:N>"
placeholder already used for FWD/FUNC/FLOAT/DECL_TAG; patch 3 resolves the
var's type directly, mirroring the existing guard in btf_modifier_show().

Patches 4 and 5 add selftests. Patch 4 checks a key-less hash and rhash map is
rejected at creation. Patch 5 extends the snprintf_btf test to render a
"const void" and a BTF_KIND_VAR from the vmlinux BTF and checks they resolve
without crashing.

v3 -> v4: Drop the pin-and-read reproducer from the key-less map test, fold
the void/VAR test into the existing snprintf_btf test, and simplify patch 2's
wording (review comments).

v2 -> v3: Fold in a third fix for the same class of bug, btf_var_show(),
reported while reviewing v2. Address review comments (Fixes attribution,
verbatim syzbot trace, skip instead of fail).

v1 -> v2: AI reported a pre-exist issue. Let's fold it in this series.

v3: https://lore.kernel.org/bpf/20260831110314.150870-1-jiayuan.chen@linux.dev/
v2: https://lore.kernel.org/bpf/20260830073242.148092-1-jiayuan.chen@linux.dev/
v1: https://lore.kernel.org/bpf/20260828093142.179856-1-jiayuan.chen@linux.dev/

Jiayuan Chen (5):
  bpf: Reject key-less BTF for hash maps
  bpf: Fix NULL-ptr-deref when showing a void BTF type
  bpf: Fix NULL-ptr-deref in btf_var_show()
  selftests/bpf: Add test for key-less BTF hash map
  selftests/bpf: Add test for showing a void BTF type

 kernel/bpf/btf.c                              | 19 ++++-
 kernel/bpf/hashtab.c                          |  6 ++
 .../bpf/prog_tests/btf_map_keyless.c          | 59 ++++++++++++++
 .../selftests/bpf/prog_tests/snprintf_btf.c   | 79 +++++++++++++++++++
 .../selftests/bpf/progs/snprintf_btf_void.c   | 24 ++++++
 5 files changed, 185 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/btf_map_keyless.c
 create mode 100644 tools/testing/selftests/bpf/progs/snprintf_btf_void.c

-- 
2.43.0


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

* [PATCH bpf v4 1/5] bpf: Reject key-less BTF for hash maps
  2026-09-01 10:47 [PATCH bpf v4 0/5] bpf: Fix NULL-ptr-derefs when showing a void BTF type Jiayuan Chen
@ 2026-09-01 10:47 ` Jiayuan Chen
  2026-09-01 10:47 ` [PATCH bpf v4 2/5] bpf: Fix NULL-ptr-deref when showing a void BTF type Jiayuan Chen
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Jiayuan Chen @ 2026-09-01 10:47 UTC (permalink / raw)
  To: bpf
  Cc: Jiayuan Chen, syzbot+37b56485bbbf90ad8489, Ihor Solodrai,
	Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Shuah Khan,
	Mykyta Yatsenko, Alan Maguire, linux-kernel, linux-kselftest

map_check_btf() allows a key-less BTF (btf_key_type_id == 0) only for
maps that have a ->map_check_btf callback, and leaves the actual
decision to that callback. Hash maps used to have no ->map_check_btf,
so a key-less BTF was rejected outright.

That changed when htab and rhtab gained a ->map_check_btf to register a
dtor - htab in commit 1df97a7453ee ("bpf: Register dtor for freeing
special fields") and rhtab in commit 6905f8601298 ("bpf: Allow special
fields in resizable hashtab"). Neither looks at the key, so a key-less
hash map now passes map_check_btf() and gets created. Reading it back
through bpffs feeds the key type_id 0 into btf_type_seq_show();
btf_type_by_id() returns the void type, kind_ops[BTF_KIND_UNKN] is NULL,
and btf_type_show() dereferences it:

RIP: 0010:btf_type_show+0x223/0x2e0 kernel/bpf/btf.c:8232
RSP: 0018:ffffc9000399f868 EFLAGS: 00010206
RAX: dffffc0000000000 RBX: 0000000000000000 RCX: 0000000000000000
RDX: 0000000000000005 RSI: 0000000000000000 RDI: 0000000000000028
RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000000
R10: ffffc9000399f970 R11: 0000000000000001 R12: ffffffff9b96b140
R13: ffffc9000399f8e0 R14: ffff88803d393c00 R15: 0000000000000003
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000200000000000 CR3: 000000003d213000 CR4: 0000000000352ef0
DR0: 0000000039ae8f55 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Call Trace:
 <TASK>
 btf_type_seq_show_flags+0xca/0x120 kernel/bpf/btf.c:8250
 htab_map_seq_show_elem+0x12e/0x350 kernel/bpf/hashtab.c:1669
 map_seq_show+0x13d/0x1e0 kernel/bpf/inode.c:293
 traverse.part.0.constprop.0+0x107/0x650 fs/seq_file.c:112
 traverse fs/seq_file.c:99 [inline]
 seq_read_iter+0x93f/0x1270 fs/seq_file.c:196
 seq_read+0x344/0x4d0 fs/seq_file.c:163
 vfs_read+0x1e4/0xb40 fs/read_write.c:572
 ksys_pread64 fs/read_write.c:764 [inline]
 __do_sys_pread64 fs/read_write.c:772 [inline]
 __se_sys_pread64 fs/read_write.c:769 [inline]
 __x64_sys_pread64+0x1eb/0x250 fs/read_write.c:769
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x123/0x790 arch/x86/entry/syscall_64.c:84
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Reject a key-less BTF in htab_map_check_btf() and rhtab_map_check_btf(),
restoring the previous behavior.

Fixes: 1df97a7453ee ("bpf: Register dtor for freeing special fields")
Fixes: 6905f8601298 ("bpf: Allow special fields in resizable hashtab")
Reported-by: syzbot+37b56485bbbf90ad8489@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/all/6a8f4e88.27659fcc.2ceef7.0008.GAE@google.com/T/
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Acked-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
 kernel/bpf/hashtab.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
index d40cb5dd446c..7f55d6421e72 100644
--- a/kernel/bpf/hashtab.c
+++ b/kernel/bpf/hashtab.c
@@ -530,6 +530,9 @@ static int htab_map_check_btf(struct bpf_map *map, const struct btf *btf,
 {
 	struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
 
+	if (btf_type_is_void(key_type))
+		return -EINVAL;
+
 	if (htab_is_prealloc(htab))
 		return 0;
 	/*
@@ -3110,6 +3113,9 @@ static int rhtab_map_check_btf(struct bpf_map *map, const struct btf *btf,
 {
 	struct bpf_rhtab *rhtab = container_of(map, struct bpf_rhtab, map);
 
+	if (btf_type_is_void(key_type))
+		return -EINVAL;
+
 	return bpf_ma_set_dtor(map, &rhtab->ma, rhtab_mem_dtor);
 }
 
-- 
2.43.0


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

* [PATCH bpf v4 2/5] bpf: Fix NULL-ptr-deref when showing a void BTF type
  2026-09-01 10:47 [PATCH bpf v4 0/5] bpf: Fix NULL-ptr-derefs when showing a void BTF type Jiayuan Chen
  2026-09-01 10:47 ` [PATCH bpf v4 1/5] bpf: Reject key-less BTF for hash maps Jiayuan Chen
@ 2026-09-01 10:47 ` Jiayuan Chen
  2026-09-01 10:47 ` [PATCH bpf v4 3/5] bpf: Fix NULL-ptr-deref in btf_var_show() Jiayuan Chen
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Jiayuan Chen @ 2026-09-01 10:47 UTC (permalink / raw)
  To: bpf
  Cc: Jiayuan Chen, Ihor Solodrai, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Emil Tsalapatis, Shuah Khan, Mykyta Yatsenko, Alan Maguire,
	linux-kernel, linux-kselftest

btf_modifier_show() resolves the modifier and then calls
btf_type_ops(t)->show() unconditionally. For the void type (type_id 0,
BTF_KIND_UNKN) kind_ops[] has no entry, so ->show is NULL.

A "const void" (a modifier resolving to void) cannot be a map key or
value - map_check_btf() rejects it because void has no size - so the map
dump path does not reach it. But bpf_snprintf_btf() takes a type_id
straight from the BPF program, and passing such a "const void" from the
vmlinux BTF NULL-derefs:

KASAN: null-ptr-deref in range [0x0000000000000028-0x000000000000002f]
RIP: 0010:btf_modifier_show (kernel/bpf/btf.c:2914)
Call Trace:
 <TASK>
 btf_type_show (kernel/bpf/btf.c:8251)
 btf_type_snprintf_show (kernel/bpf/btf.c:8321)
 bpf_snprintf_btf (kernel/trace/bpf_trace.c:1047)
 bpf_prog_test_run_raw_tp (net/bpf/test_run.c:829)
 __sys_bpf (kernel/bpf/syscall.c:4804)
 do_syscall_64 (arch/x86/entry/syscall_64.c:94)
 entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
 </TASK>

Fall back to btf_df_show() when the resolved type has no show op; it
emits the "<unsupported kind:N>" placeholder already used for kinds like
FWD and FUNC. bpf_snprintf_btf() then returns the length as usual.

Fixes: c4d0bfb45068 ("bpf: Add bpf_snprintf_btf helper")
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Acked-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
re bot+bpf-ci: a "const void" is a modifier with a nonzero type_id, so
map_check_btf() rejects it as key or value on the size check. The bare
void key (id 0) is a different path, handled by patch 1.
re sashiko-bot: btf_var_show() has the same bug, fixed in patch 3.
---
 kernel/bpf/btf.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 91b8ce77f699..7835fe201384 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -2911,7 +2911,14 @@ static void btf_modifier_show(const struct btf *btf,
 	else
 		t = btf_type_skip_modifiers(btf, type_id, NULL);
 
-	btf_type_ops(t)->show(btf, t, type_id, data, bits_offset, show);
+	/*
+	 * A modifier can resolve to void, which has no show op; print a
+	 * placeholder rather than dereferencing NULL.
+	 */
+	if (!btf_type_ops(t))
+		btf_df_show(btf, t, type_id, data, bits_offset, show);
+	else
+		btf_type_ops(t)->show(btf, t, type_id, data, bits_offset, show);
 }
 
 static void btf_var_show(const struct btf *btf, const struct btf_type *t,
-- 
2.43.0


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

* [PATCH bpf v4 3/5] bpf: Fix NULL-ptr-deref in btf_var_show()
  2026-09-01 10:47 [PATCH bpf v4 0/5] bpf: Fix NULL-ptr-derefs when showing a void BTF type Jiayuan Chen
  2026-09-01 10:47 ` [PATCH bpf v4 1/5] bpf: Reject key-less BTF for hash maps Jiayuan Chen
  2026-09-01 10:47 ` [PATCH bpf v4 2/5] bpf: Fix NULL-ptr-deref when showing a void BTF type Jiayuan Chen
@ 2026-09-01 10:47 ` Jiayuan Chen
  2026-09-01 10:47 ` [PATCH bpf v4 4/5] selftests/bpf: Add test for key-less BTF hash map Jiayuan Chen
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Jiayuan Chen @ 2026-09-01 10:47 UTC (permalink / raw)
  To: bpf
  Cc: Jiayuan Chen, Ihor Solodrai, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Emil Tsalapatis, Shuah Khan, Mykyta Yatsenko, Alan Maguire,
	linux-kernel, linux-kselftest

btf_var_show() calls btf_type_id_resolve() unconditionally, which
dereferences btf->resolved_ids. That is NULL for a base BTF - e.g. the
vmlinux BTF that bpf_snprintf_btf() renders against - since base BTF is
not resolved during parsing. btf_modifier_show() guards this with
'if (btf->resolved_ids)', but btf_var_show() does not.

A BPF program that passes the type_id of a BTF_KIND_VAR from the vmlinux
BTF to bpf_snprintf_btf() thus NULL-derefs:

KASAN: probably user-memory-access in range [0x46638-0x4663f]
RIP: 0010:btf_var_show (kernel/bpf/btf.c:2929)
Call Trace:
 <TASK>
 btf_type_show (kernel/bpf/btf.c:8259)
 btf_type_snprintf_show (kernel/bpf/btf.c:8329)
 bpf_snprintf_btf (kernel/trace/bpf_trace.c:1047)
 bpf_prog_test_run_raw_tp (net/bpf/test_run.c:829)
 __sys_bpf (kernel/bpf/syscall.c:4804)
 do_syscall_64 (arch/x86/entry/syscall_64.c:84)
 entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
 </TASK>

Resolve the var's type directly with btf_type_skip_modifiers() when
resolved_ids is NULL, mirroring btf_modifier_show().

Fixes: c4d0bfb45068 ("bpf: Add bpf_snprintf_btf helper")
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Acked-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
 kernel/bpf/btf.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 7835fe201384..7c634d639b7f 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -2925,7 +2925,15 @@ static void btf_var_show(const struct btf *btf, const struct btf_type *t,
 			 u32 type_id, void *data, u8 bits_offset,
 			 struct btf_show *show)
 {
-	t = btf_type_id_resolve(btf, &type_id);
+	/*
+	 * btf_type_id_resolve() dereferences btf->resolved_ids, which is NULL
+	 * for a base BTF (e.g. the vmlinux BTF that bpf_snprintf_btf() uses).
+	 * Resolve the var's type directly in that case.
+	 */
+	if (btf->resolved_ids)
+		t = btf_type_id_resolve(btf, &type_id);
+	else
+		t = btf_type_skip_modifiers(btf, t->type, &type_id);
 
 	btf_type_ops(t)->show(btf, t, type_id, data, bits_offset, show);
 }
-- 
2.43.0


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

* [PATCH bpf v4 4/5] selftests/bpf: Add test for key-less BTF hash map
  2026-09-01 10:47 [PATCH bpf v4 0/5] bpf: Fix NULL-ptr-derefs when showing a void BTF type Jiayuan Chen
                   ` (2 preceding siblings ...)
  2026-09-01 10:47 ` [PATCH bpf v4 3/5] bpf: Fix NULL-ptr-deref in btf_var_show() Jiayuan Chen
@ 2026-09-01 10:47 ` Jiayuan Chen
  2026-09-01 10:47 ` [PATCH bpf v4 5/5] selftests/bpf: Add test for showing a void BTF type Jiayuan Chen
  2026-09-03 16:40 ` [PATCH bpf v4 0/5] bpf: Fix NULL-ptr-derefs when " patchwork-bot+netdevbpf
  5 siblings, 0 replies; 7+ messages in thread
From: Jiayuan Chen @ 2026-09-01 10:47 UTC (permalink / raw)
  To: bpf
  Cc: Jiayuan Chen, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Emil Tsalapatis, Ihor Solodrai, Shuah Khan, Mykyta Yatsenko,
	Alan Maguire, linux-kernel, linux-kselftest

Create a hash and an rhash map with btf_key_type_id == 0 and expect
bpf_map_create() to fail with -EINVAL; a positive control with a real
key type confirms the rejection is about the key-less BTF and not some
unrelated failure.

Such a map used to be accepted and then NULL-deref in btf_type_show()
when dumped through bpffs.

Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
re bot+bpf-ci: the positive control is on purpose. Without it, if the map
type is missing both creates return -EINVAL and the key-less check would
pass for the wrong reason.
---
 .../bpf/prog_tests/btf_map_keyless.c          | 59 +++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/btf_map_keyless.c

diff --git a/tools/testing/selftests/bpf/prog_tests/btf_map_keyless.c b/tools/testing/selftests/bpf/prog_tests/btf_map_keyless.c
new file mode 100644
index 000000000000..3248bccc3557
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/btf_map_keyless.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+#include <bpf/btf.h>
+
+/*
+ * A hash map with a key-less BTF (btf_key_type_id == 0) used to be accepted
+ * and then NULL-deref in btf_type_show() when dumped through bpffs. A fixed
+ * kernel rejects it at creation; verify that rejection, with a keyed positive
+ * control so the -EINVAL is about the missing key type and not some unrelated
+ * failure.
+ */
+static void check_keyless(int map_type, __u32 map_flags, int btf_fd, int val_id)
+{
+	LIBBPF_OPTS(bpf_map_create_opts, opts);
+	int map_fd;
+
+	opts.map_flags = map_flags;
+	opts.btf_fd = btf_fd;
+	opts.btf_value_type_id = val_id;
+
+	/* Positive control: the same map with a real key type is accepted. */
+	opts.btf_key_type_id = val_id;
+	map_fd = bpf_map_create(map_type, "keyed_map", 4, 4, 8, &opts);
+	if (!ASSERT_GE(map_fd, 0, "keyed create is accepted"))
+		return;
+	close(map_fd);
+
+	/* A key-less BTF must be rejected. */
+	opts.btf_key_type_id = 0;
+	map_fd = bpf_map_create(map_type, "keyless_map", 4, 4, 8, &opts);
+	ASSERT_EQ(map_fd, -EINVAL, "key-less create is rejected");
+	if (map_fd >= 0)
+		close(map_fd);
+}
+
+void test_btf_map_keyless(void)
+{
+	int btf_fd, val_id;
+	struct btf *btf;
+
+	btf = btf__new_empty();
+	if (!ASSERT_OK_PTR(btf, "btf__new_empty"))
+		return;
+
+	val_id = btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
+	if (!ASSERT_GT(val_id, 0, "btf__add_int"))
+		goto out;
+
+	if (!ASSERT_OK(btf__load_into_kernel(btf), "btf__load_into_kernel"))
+		goto out;
+	btf_fd = btf__fd(btf);
+
+	if (test__start_subtest("hash"))
+		check_keyless(BPF_MAP_TYPE_HASH, 0, btf_fd, val_id);
+	if (test__start_subtest("rhash"))
+		check_keyless(BPF_MAP_TYPE_RHASH, BPF_F_NO_PREALLOC, btf_fd, val_id);
+out:
+	btf__free(btf);
+}
-- 
2.43.0


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

* [PATCH bpf v4 5/5] selftests/bpf: Add test for showing a void BTF type
  2026-09-01 10:47 [PATCH bpf v4 0/5] bpf: Fix NULL-ptr-derefs when showing a void BTF type Jiayuan Chen
                   ` (3 preceding siblings ...)
  2026-09-01 10:47 ` [PATCH bpf v4 4/5] selftests/bpf: Add test for key-less BTF hash map Jiayuan Chen
@ 2026-09-01 10:47 ` Jiayuan Chen
  2026-09-03 16:40 ` [PATCH bpf v4 0/5] bpf: Fix NULL-ptr-derefs when " patchwork-bot+netdevbpf
  5 siblings, 0 replies; 7+ messages in thread
From: Jiayuan Chen @ 2026-09-01 10:47 UTC (permalink / raw)
  To: bpf
  Cc: Jiayuan Chen, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Emil Tsalapatis, Ihor Solodrai, Shuah Khan, Mykyta Yatsenko,
	Alan Maguire, linux-kernel, linux-kselftest

Extend the snprintf_btf test with type_ids from the vmlinux BTF that
used to NULL-deref in the BTF show path: a "const void", checked to
render the "<unsupported kind:0>" placeholder, and a BTF_KIND_VAR,
checked to resolve and render without error.

The program renders from its own buffer and the test picks a VAR whose
resolved type fits it, so the render stays in bounds.

Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
 .../selftests/bpf/prog_tests/snprintf_btf.c   | 79 +++++++++++++++++++
 .../selftests/bpf/progs/snprintf_btf_void.c   | 24 ++++++
 2 files changed, 103 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/progs/snprintf_btf_void.c

diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf_btf.c b/tools/testing/selftests/bpf/prog_tests/snprintf_btf.c
index dd41b826be30..edce9c1b54fb 100644
--- a/tools/testing/selftests/bpf/prog_tests/snprintf_btf.c
+++ b/tools/testing/selftests/bpf/prog_tests/snprintf_btf.c
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <test_progs.h>
 #include <linux/btf.h>
+#include <bpf/btf.h>
 #include "netif_receive_skb.skel.h"
+#include "snprintf_btf_void.skel.h"
 
 /* Demonstrate that bpf_snprintf_btf succeeds and that various data types
  * are formatted correctly.
@@ -58,3 +60,80 @@ void serial_test_snprintf_btf(void)
 cleanup:
 	netif_receive_skb__destroy(skel);
 }
+
+/*
+ * bpf_snprintf_btf() renders a type_id taken straight from the vmlinux BTF.
+ * Two such type_ids used to NULL-deref in the BTF show path:
+ *   - a "const void" (a modifier resolving to void) in btf_modifier_show()
+ *   - a BTF_KIND_VAR in btf_var_show() (base BTF has no resolved_ids)
+ * A fixed kernel renders both without crashing.
+ */
+static long run(struct snprintf_btf_void *skel, __u32 type_id)
+{
+	LIBBPF_OPTS(bpf_test_run_opts, topts);
+	char ctx[8] = {};
+
+	skel->bss->type_id = type_id;
+	topts.ctx_in = ctx;
+	topts.ctx_size_in = sizeof(ctx);
+	if (!ASSERT_OK(bpf_prog_test_run_opts(bpf_program__fd(skel->progs.dump_type),
+					      &topts), "test_run"))
+		return -1;
+	return skel->bss->ret;
+}
+
+void test_snprintf_btf_void(void)
+{
+	const struct btf_type *t;
+	struct snprintf_btf_void *skel;
+	int i, n, cv = 0, var = 0;
+	struct btf *btf;
+
+	btf = btf__parse("/sys/kernel/btf/vmlinux", NULL);
+	if (!btf) {
+		test__skip();
+		return;
+	}
+
+	skel = snprintf_btf_void__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
+		goto out_btf;
+
+	n = btf__type_cnt(btf);
+	for (i = 1; i < n && !(cv && var); i++) {
+		t = btf__type_by_id(btf, i);
+		if (!cv && btf_kind(t) == BTF_KIND_CONST && t->type == 0)
+			cv = i;
+		/* Pick a VAR small enough to render from the program's buffer. */
+		if (!var && btf_kind(t) == BTF_KIND_VAR) {
+			long sz = btf__resolve_size(btf, t->type);
+
+			if (sz > 0 && sz <= (long)sizeof(skel->bss->obj))
+				var = i;
+		}
+	}
+
+	/* "const void" renders the "<unsupported kind:0>" placeholder. */
+	if (test__start_subtest("const_void")) {
+		if (cv) {
+			ASSERT_EQ(run(skel, cv),
+				  sizeof("<unsupported kind:0>") - 1, "ret");
+			ASSERT_STREQ(skel->bss->out, "<unsupported kind:0>",
+				     "placeholder");
+		} else {
+			test__skip();
+		}
+	}
+
+	/* A BTF_KIND_VAR must resolve and render without error. */
+	if (test__start_subtest("var")) {
+		if (var)
+			ASSERT_GT(run(skel, var), 0, "ret");
+		else
+			test__skip();
+	}
+
+	snprintf_btf_void__destroy(skel);
+out_btf:
+	btf__free(btf);
+}
diff --git a/tools/testing/selftests/bpf/progs/snprintf_btf_void.c b/tools/testing/selftests/bpf/progs/snprintf_btf_void.c
new file mode 100644
index 000000000000..44af80fbbb80
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/snprintf_btf_void.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "btf_ptr.h"
+#include <bpf/bpf_helpers.h>
+
+__u32 type_id;
+/* A buffer we own to render the selected type from, kept in bounds. */
+char obj[256];
+char out[64];
+long ret;
+
+SEC("raw_tp/sys_enter")
+int dump_type(void *ctx)
+{
+	struct btf_ptr ptr = {
+		.ptr = obj,
+		.type_id = type_id,
+		.flags = 0,
+	};
+
+	ret = bpf_snprintf_btf(out, sizeof(out), &ptr, sizeof(ptr), 0);
+	return 0;
+}
+
+char _license[] SEC("license") = "GPL";
-- 
2.43.0


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

* Re: [PATCH bpf v4 0/5] bpf: Fix NULL-ptr-derefs when showing a void BTF type
  2026-09-01 10:47 [PATCH bpf v4 0/5] bpf: Fix NULL-ptr-derefs when showing a void BTF type Jiayuan Chen
                   ` (4 preceding siblings ...)
  2026-09-01 10:47 ` [PATCH bpf v4 5/5] selftests/bpf: Add test for showing a void BTF type Jiayuan Chen
@ 2026-09-03 16:40 ` patchwork-bot+netdevbpf
  5 siblings, 0 replies; 7+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-09-03 16:40 UTC (permalink / raw)
  To: Jiayuan Chen
  Cc: bpf, ast, daniel, andrii, eddyz87, memxor, martin.lau, song,
	yonghong.song, jolsa, emil, ihor.solodrai, shuah, yatsenko,
	alan.maguire, linux-kernel, linux-kselftest

Hello:

This series was applied to bpf/bpf.git (master)
by Alexei Starovoitov <ast@kernel.org>:

On Tue,  1 Sep 2026 18:47:34 +0800 you wrote:
> This series fixes three NULL-ptr-derefs in BTF handling.
> 
> Patch 1 handles the syzbot report. A key-less BTF (btf_key_type_id == 0) used
> to be rejected for hash maps, until htab and rhtab gained a ->map_check_btf
> (to register a dtor) that does not look at the key, so a key-less hash map is
> now accepted. Dumping it through bpffs feeds the key type_id 0 into
> btf_type_seq_show() and NULL-derefs in btf_type_show(). Reject it again.
> 
> [...]

Here is the summary with links:
  - [bpf,v4,1/5] bpf: Reject key-less BTF for hash maps
    https://git.kernel.org/bpf/bpf/c/0895a0c07347
  - [bpf,v4,2/5] bpf: Fix NULL-ptr-deref when showing a void BTF type
    https://git.kernel.org/bpf/bpf/c/4ea508b9ebd7
  - [bpf,v4,3/5] bpf: Fix NULL-ptr-deref in btf_var_show()
    https://git.kernel.org/bpf/bpf/c/5403a383f52f
  - [bpf,v4,4/5] selftests/bpf: Add test for key-less BTF hash map
    https://git.kernel.org/bpf/bpf/c/6265b44f2c3b
  - [bpf,v4,5/5] selftests/bpf: Add test for showing a void BTF type
    https://git.kernel.org/bpf/bpf/c/1ae6aa61958a

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



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

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

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01 10:47 [PATCH bpf v4 0/5] bpf: Fix NULL-ptr-derefs when showing a void BTF type Jiayuan Chen
2026-09-01 10:47 ` [PATCH bpf v4 1/5] bpf: Reject key-less BTF for hash maps Jiayuan Chen
2026-09-01 10:47 ` [PATCH bpf v4 2/5] bpf: Fix NULL-ptr-deref when showing a void BTF type Jiayuan Chen
2026-09-01 10:47 ` [PATCH bpf v4 3/5] bpf: Fix NULL-ptr-deref in btf_var_show() Jiayuan Chen
2026-09-01 10:47 ` [PATCH bpf v4 4/5] selftests/bpf: Add test for key-less BTF hash map Jiayuan Chen
2026-09-01 10:47 ` [PATCH bpf v4 5/5] selftests/bpf: Add test for showing a void BTF type Jiayuan Chen
2026-09-03 16:40 ` [PATCH bpf v4 0/5] bpf: Fix NULL-ptr-derefs when " patchwork-bot+netdevbpf

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