BPF List
 help / color / mirror / Atom feed
* [PATCH bpf 1/2] libbpf: Fix stale raw data after btf__relocate()
@ 2026-11-01 15:56 Jiayuan Chen
  2026-11-01 15:56 ` [PATCH bpf 2/2] selftests/bpf: Add test for btf__raw_data() " Jiayuan Chen
  2026-11-01 18:02 ` [PATCH bpf 1/2] libbpf: Fix stale raw data " Alexei Starovoitov
  0 siblings, 2 replies; 3+ messages in thread
From: Jiayuan Chen @ 2026-11-01 15:56 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, Alan Maguire,
	linux-kernel, linux-kselftest

btf_relocate() rewrites type ids in place but doesn't drop the cached
raw_data, so btf__raw_data() after btf__relocate() returns the old
bytes with pre-relocation ids.

Call btf_ensure_modifiable() first, like other BTF mutators do, so the
cache is invalidated.

Fixes: 19e00c897d50 ("libbpf: Split BTF relocation")
Reported-by: 洛 <wanghai8081@gmail.com>
Closes: https://lore.kernel.org/bpf/455f7257-25b9-4070-8313-42af8005b948@linux.dev/T/#t
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
 tools/lib/bpf/btf.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index d2ff6f5d6d5b..b55dce9fa003 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -6640,8 +6640,13 @@ void btf_set_base_btf(struct btf *btf, const struct btf *base_btf)
 
 int btf__relocate(struct btf *btf, const struct btf *base_btf)
 {
-	int err = btf_relocate(btf, base_btf, NULL, NULL);
+	int err;
+
+	err = btf_ensure_modifiable(btf);
+	if (err)
+		return libbpf_err(err);
 
+	err = btf_relocate(btf, base_btf, NULL, NULL);
 	if (!err)
 		btf->owns_base = false;
 	return libbpf_err(err);
-- 
2.43.0


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

* [PATCH bpf 2/2] selftests/bpf: Add test for btf__raw_data() after btf__relocate()
  2026-11-01 15:56 [PATCH bpf 1/2] libbpf: Fix stale raw data after btf__relocate() Jiayuan Chen
@ 2026-11-01 15:56 ` Jiayuan Chen
  2026-11-01 18:02 ` [PATCH bpf 1/2] libbpf: Fix stale raw data " Alexei Starovoitov
  1 sibling, 0 replies; 3+ messages in thread
From: Jiayuan Chen @ 2026-11-01 15:56 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, Alan Maguire,
	linux-kernel, linux-kselftest

Populate the raw data cache, relocate split BTF to a base where the
referenced type has a different id, and check the serialized BTF
carries the new id.

Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
 .../selftests/bpf/prog_tests/btf_distill.c    | 64 +++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/tools/testing/selftests/bpf/prog_tests/btf_distill.c b/tools/testing/selftests/bpf/prog_tests/btf_distill.c
index f0900b47fd48..7f62a747a0ae 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf_distill.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf_distill.c
@@ -601,6 +601,68 @@ static void test_distilled_endianness(void)
 	btf__free(base);
 }
 
+/*
+ * Raw data cached by btf__raw_data() before btf__relocate() must not be
+ * returned afterwards; serialized split BTF should carry relocated ids.
+ */
+static void test_distilled_relocate_raw_data(void)
+{
+	struct btf *btf1 = NULL, *btf2 = NULL, *btf3 = NULL, *btf4 = NULL;
+	const void *raw_data;
+	__u32 size;
+
+	btf1 = btf__new_empty();
+	if (!ASSERT_OK_PTR(btf1, "empty_main_btf"))
+		return;
+	btf__add_int(btf1, "int", 4, BTF_INT_SIGNED);	/* [1] int */
+	btf2 = btf__new_empty_split(btf1);
+	if (!ASSERT_OK_PTR(btf2, "empty_split_btf"))
+		goto cleanup;
+	btf__add_ptr(btf2, 1);				/* [2] ptr to int */
+	VALIDATE_RAW_BTF(
+		btf2,
+		"[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
+		"[2] PTR '(anon)' type_id=1");
+
+	/* populate raw data cache before relocation */
+	raw_data = btf__raw_data(btf2, &size);
+	if (!ASSERT_OK_PTR(raw_data, "btf__raw_data #1"))
+		goto cleanup;
+
+	/* new base where int has a different type id */
+	btf3 = btf__new_empty();
+	if (!ASSERT_OK_PTR(btf3, "empty_new_base_btf"))
+		goto cleanup;
+	btf__add_int(btf3, "padding", 4, BTF_INT_SIGNED);	/* [1] padding */
+	btf__add_int(btf3, "int", 4, BTF_INT_SIGNED);		/* [2] int */
+
+	if (!ASSERT_EQ(btf__relocate(btf2, btf3), 0, "relocate_split"))
+		goto cleanup;
+	VALIDATE_RAW_BTF(
+		btf2,
+		"[1] INT 'padding' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
+		"[2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
+		"[3] PTR '(anon)' type_id=2");
+
+	/* serialized split BTF must match relocated in-memory BTF */
+	raw_data = btf__raw_data(btf2, &size);
+	if (!ASSERT_OK_PTR(raw_data, "btf__raw_data #2"))
+		goto cleanup;
+	btf4 = btf__new_split(raw_data, size, btf3);
+	if (!ASSERT_OK_PTR(btf4, "btf__new_split"))
+		goto cleanup;
+	VALIDATE_RAW_BTF(
+		btf4,
+		"[1] INT 'padding' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
+		"[2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
+		"[3] PTR '(anon)' type_id=2");
+cleanup:
+	btf__free(btf4);
+	btf__free(btf3);
+	btf__free(btf2);
+	btf__free(btf1);
+}
+
 /* If a needed composite type, which is the member of composite type
  * in the split BTF, has a different size in the base BTF we wish to
  * relocate with, btf__relocate() should error out.
@@ -793,6 +855,8 @@ void test_btf_distill(void)
 		test_distilled_base_vmlinux();
 	if (test__start_subtest("distilled_endianness"))
 		test_distilled_endianness();
+	if (test__start_subtest("distilled_relocate_raw_data"))
+		test_distilled_relocate_raw_data();
 	if (test__start_subtest("distilled_loc"))
 		test_distilled_loc();
 }
-- 
2.43.0


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

* Re: [PATCH bpf 1/2] libbpf: Fix stale raw data after btf__relocate()
  2026-11-01 15:56 [PATCH bpf 1/2] libbpf: Fix stale raw data after btf__relocate() Jiayuan Chen
  2026-11-01 15:56 ` [PATCH bpf 2/2] selftests/bpf: Add test for btf__raw_data() " Jiayuan Chen
@ 2026-11-01 18:02 ` Alexei Starovoitov
  1 sibling, 0 replies; 3+ messages in thread
From: Alexei Starovoitov @ 2026-11-01 18:02 UTC (permalink / raw)
  To: Jiayuan Chen, bpf
  Cc: 洛, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman,
	Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu,
	Yonghong Song, Jiri Olsa, Emil Tsalapatis, Ihor Solodrai,
	Shuah Khan, Alan Maguire, linux-kernel, linux-kselftest

On Sun, Nov 01, 2026 at 07:56 AM Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
> Call btf_ensure_modifiable() first, like other BTF mutators do, so the
> cache is invalidated.

btf_parse_elf() calls btf__relocate() for every module with .BTF.base.
That BTF is read-only. types_data points into raw_data, so raw_data is
not a cache there. Only raw_data_swapped can be stale.
With this patch that path changes:

                    today                 with the patch
  types             rewritten in place    copied
  strings           as-is                 copied and hashed into strset
  named_start_id    kept                  0, lookup by name is linear
  has_hdr_extra     relocates             -EOPNOTSUPP

The last row: btf__parse_split() of a module with new header fields fails.
Ihor removes the same side effect from btf__find_str():
https://lore.kernel.org/bpf/20261030233355.1836749-2-ihor.solodrai@linux.dev/

can we drop only the copies ?
The kernel calls btf_check_sorted() after btf_relocate() too.

Something like this (not even compile tested):

diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index d2ff6f5..d67f78d 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -2033,7 +2033,8 @@ struct btf *btf__load_from_kernel_by_id(__u32 id)

 static void btf_invalidate_raw_data(struct btf *btf)
 {
-	if (btf->raw_data)
+	/* types_data and strs_data of read-only BTF point into raw_data */
+	if (btf->raw_data && btf_is_modifiable(btf))
 		btf_free_raw_data(btf);
 	if (btf->raw_data_swapped) {
 		free(btf->raw_data_swapped);
@@ -2099,11 +2100,11 @@ static int btf_ensure_modifiable(struct btf *btf)
 	if (!btf->base_btf && btf->hdr.str_len == 1)
 		btf->strs_deduped = true;

+	btf->modifiable = true;
+
 	/* invalidate raw_data representation */
 	btf_invalidate_raw_data(btf);

-	btf->modifiable = true;
-
 	return 0;

 err_out:
@@ -6642,8 +6643,12 @@ int btf__relocate(struct btf *btf, const struct btf *base_btf)
 {
 	int err = btf_relocate(btf, base_btf, NULL, NULL);

-	if (!err)
+	/* types are rewritten in place, some of them even on error */
+	btf_invalidate_raw_data(btf);
+	if (!err) {
 		btf->owns_base = false;
+		btf_check_sorted(btf);
+	}
 	return libbpf_err(err);
 }


Also pls target bpf-next. The selftest is contrived.

pw-bot: cr

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

end of thread, other threads:[~2026-11-01 18:02 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-01 15:56 [PATCH bpf 1/2] libbpf: Fix stale raw data after btf__relocate() Jiayuan Chen
2026-11-01 15:56 ` [PATCH bpf 2/2] selftests/bpf: Add test for btf__raw_data() " Jiayuan Chen
2026-11-01 18:02 ` [PATCH bpf 1/2] libbpf: Fix stale raw data " Alexei Starovoitov

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