public inbox for bpf@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 bpf-next 0/2] selftests/bpf: Test BTF sanitization
@ 2026-04-08 10:53 Alan Maguire
  2026-04-08 10:53 ` [PATCH v2 bpf-next 1/2] libbpf: Allow use of feature cache for non-token cases Alan Maguire
  2026-04-08 10:53 ` [PATCH v2 bpf-next 2/2] selftests/bpf: Add BTF sanitize test covering BTF layout Alan Maguire
  0 siblings, 2 replies; 5+ messages in thread
From: Alan Maguire @ 2026-04-08 10:53 UTC (permalink / raw)
  To: andrii
  Cc: ast, daniel, martin.lau, eddyz87, memxor, song, yonghong.song,
	jolsa, bpf, Alan Maguire

Allow simulation of missing BPF features through provision of
a synthetic feature cache set, and use this to simulate case
where FEAT_BTF_LAYOUT is missing.  Ensure sanitization leaves us
with expected BTF (layout info removed, layout header fields
zeroed, strings data adjusted).

Specifying a feature cache with selected missing features will
allow testing of other missing feature codepaths, but for now
add BTF layout sanitization test only.

Changes since v1 [1]:

- renamed to bpf_object_set_feat_cache() (Andrii, patch 1)
- remove __packed, relocate skeleton open/load, fix formatting
  issues (Andrii, patch 2)

[1] https://lore.kernel.org/bpf/20260401164302.3844142-1-alan.maguire@oracle.com/

Alan Maguire (2):
  libbpf: Allow use of feature cache for non-token cases
  selftests/bpf: Add BTF sanitize test covering BTF layout

 tools/lib/bpf/libbpf.c                        |  12 ++-
 tools/lib/bpf/libbpf_internal.h               |   3 +-
 .../selftests/bpf/prog_tests/btf_sanitize.c   | 100 ++++++++++++++++++
 3 files changed, 112 insertions(+), 3 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/btf_sanitize.c

-- 
2.39.3


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

* [PATCH v2 bpf-next 1/2] libbpf: Allow use of feature cache for non-token cases
  2026-04-08 10:53 [PATCH v2 bpf-next 0/2] selftests/bpf: Test BTF sanitization Alan Maguire
@ 2026-04-08 10:53 ` Alan Maguire
  2026-04-08 13:37   ` Jiri Olsa
  2026-04-08 10:53 ` [PATCH v2 bpf-next 2/2] selftests/bpf: Add BTF sanitize test covering BTF layout Alan Maguire
  1 sibling, 1 reply; 5+ messages in thread
From: Alan Maguire @ 2026-04-08 10:53 UTC (permalink / raw)
  To: andrii
  Cc: ast, daniel, martin.lau, eddyz87, memxor, song, yonghong.song,
	jolsa, bpf, Alan Maguire

Allow bpf object feat_cache assignment in BPF selftests
to simulate missing features via inclusion of libbpf_internal.h
and use of bpf_object_set_feat_cache() and bpf_object__sanitize_btf() to
test BTF sanitization for cases where missing features are simulated.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
 tools/lib/bpf/libbpf.c          | 12 ++++++++++--
 tools/lib/bpf/libbpf_internal.h |  3 ++-
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 42bdba4efd0c..b7b636786d38 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -3145,7 +3145,7 @@ static bool btf_needs_sanitization(struct bpf_object *obj)
 	       !has_layout;
 }
 
-static struct btf *bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *orig_btf)
+struct btf *bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *orig_btf)
 {
 	bool has_func_global = kernel_supports(obj, FEAT_BTF_GLOBAL_FUNC);
 	bool has_datasec = kernel_supports(obj, FEAT_BTF_DATASEC);
@@ -5203,12 +5203,20 @@ bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
 		 */
 		return true;
 
-	if (obj->token_fd)
+	if (obj->feat_cache)
 		return feat_supported(obj->feat_cache, feat_id);
 
 	return feat_supported(NULL, feat_id);
 }
 
+/* Used in testing to simulate missing features. */
+void bpf_object_set_feat_cache(struct bpf_object *obj, struct kern_feature_cache *cache)
+{
+	if (obj->feat_cache)
+		zfree(&obj->feat_cache);
+	obj->feat_cache = cache;
+}
+
 static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd)
 {
 	struct bpf_map_info map_info;
diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
index cabdaef79098..3781c45b46d3 100644
--- a/tools/lib/bpf/libbpf_internal.h
+++ b/tools/lib/bpf/libbpf_internal.h
@@ -414,6 +414,7 @@ struct kern_feature_cache {
 
 bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id);
 bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id);
+void bpf_object_set_feat_cache(struct bpf_object *obj, struct kern_feature_cache *cache);
 
 int probe_kern_syscall_wrapper(int token_fd);
 int probe_memcg_account(int token_fd);
@@ -427,7 +428,7 @@ int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
 int libbpf__load_raw_btf_hdr(const struct btf_header *hdr,
 			     const char *raw_types, const char *str_sec,
 			     const char *layout_sec, int token_fd);
-
+struct btf *bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *orig_btf);
 int btf_load_into_kernel(struct btf *btf,
 			 char *log_buf, size_t log_sz, __u32 log_level,
 			 int token_fd);
-- 
2.39.3


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

* [PATCH v2 bpf-next 2/2] selftests/bpf: Add BTF sanitize test covering BTF layout
  2026-04-08 10:53 [PATCH v2 bpf-next 0/2] selftests/bpf: Test BTF sanitization Alan Maguire
  2026-04-08 10:53 ` [PATCH v2 bpf-next 1/2] libbpf: Allow use of feature cache for non-token cases Alan Maguire
@ 2026-04-08 10:53 ` Alan Maguire
  2026-04-08 12:53   ` Chengkaitao
  1 sibling, 1 reply; 5+ messages in thread
From: Alan Maguire @ 2026-04-08 10:53 UTC (permalink / raw)
  To: andrii
  Cc: ast, daniel, martin.lau, eddyz87, memxor, song, yonghong.song,
	jolsa, bpf, Alan Maguire

Add test that fakes up a feature cache of supported BPF
features to simulate an older kernel that does not support
BTF layout information.  Ensure that BTF is sanitized correctly
to remove layout info between types and strings, and that all
offsets and lengths are adjusted appropriately.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
 .../selftests/bpf/prog_tests/btf_sanitize.c   | 100 ++++++++++++++++++
 1 file changed, 100 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/btf_sanitize.c

diff --git a/tools/testing/selftests/bpf/prog_tests/btf_sanitize.c b/tools/testing/selftests/bpf/prog_tests/btf_sanitize.c
new file mode 100644
index 000000000000..470b29298cbc
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/btf_sanitize.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026, Oracle and/or its affiliates. */
+#include <test_progs.h>
+#include <linux/btf.h>
+#include "bpf/libbpf_internal.h"
+#include "../test_btf.h"
+#include "kfree_skb.skel.h"
+
+#define TYPE_LEN	(sizeof(struct btf_type) + sizeof(__u32))
+#define MAX_NR_LAYOUT	2
+#define LAYOUT_LEN	(sizeof(struct btf_layout) * MAX_NR_LAYOUT)
+#define STR_LEN		sizeof("\0int")
+
+struct layout_btf {
+	struct btf_header hdr;
+	__u32 types[TYPE_LEN/sizeof(__u32)];
+	struct btf_layout layout[MAX_NR_LAYOUT];
+	char strs[STR_LEN];
+};
+
+static const struct layout_btf layout_btf = {
+	.hdr = {
+		.magic		= BTF_MAGIC,
+		.version	= BTF_VERSION,
+		.hdr_len	= sizeof(struct btf_header),
+		.type_off	= 0,
+		.type_len	= TYPE_LEN,
+		.str_off	= TYPE_LEN + LAYOUT_LEN,
+		.str_len	= STR_LEN,
+		.layout_off	= TYPE_LEN,
+		.layout_len	= LAYOUT_LEN,
+	},
+	.types = {
+		BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4),
+	},
+	.layout = {
+		{ .info_sz = 0,          .elem_sz = 0, .flags = 0 },
+		{ .info_sz = sizeof(__u32), .elem_sz = 0, .flags = 0 },
+	},
+	.strs = "\0int",
+};
+
+void test_btf_sanitize_layout(void)
+{
+	struct btf *orig = NULL, *sanitized = NULL;
+	struct kern_feature_cache *cache = NULL;
+	struct kfree_skb *skel = NULL;
+	const struct btf_header *hdr;
+	const void *raw;
+	__u32 raw_sz;
+
+	skel = kfree_skb__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "kfree_skb_skel"))
+		return;
+	orig = btf__new(&layout_btf, sizeof(layout_btf));
+	if (!ASSERT_OK_PTR(orig, "btf_new_layout"))
+		return;
+
+	raw = btf__raw_data(orig, &raw_sz);
+	if (!ASSERT_OK_PTR(raw, "btf__raw_data_orig"))
+		goto out;
+	hdr = (struct btf_header *)raw;
+	ASSERT_EQ(hdr->layout_off, TYPE_LEN, "layout_off_nonzero");
+	ASSERT_EQ(hdr->layout_len, LAYOUT_LEN, "layout_len_nonzero");
+
+	cache = calloc(1, sizeof(*cache));
+	if (!ASSERT_OK_PTR(cache, "alloc_feat_cache"))
+		goto out;
+	for (int i = 0; i < __FEAT_CNT; i++)
+		cache->res[i] = FEAT_SUPPORTED;
+	cache->res[FEAT_BTF_LAYOUT] = FEAT_MISSING;
+
+	bpf_object_set_feat_cache(skel->obj, cache);
+
+	if (!ASSERT_FALSE(kernel_supports(skel->obj, FEAT_BTF_LAYOUT), "layout_feature_missing"))
+		goto out;
+
+	if (!ASSERT_TRUE(kernel_supports(skel->obj, FEAT_BTF_FUNC), "other_feature_allowed"))
+		goto out;
+
+	sanitized = bpf_object__sanitize_btf(skel->obj, orig);
+	if (!ASSERT_OK_PTR(sanitized, "bpf_object__sanitize_btf"))
+		goto out;
+
+	raw = btf__raw_data(sanitized, &raw_sz);
+	if (!ASSERT_OK_PTR(raw, "btf__raw_data_sanitized"))
+		goto out;
+	hdr = (struct btf_header *)raw;
+
+	ASSERT_EQ(hdr->layout_off, 0, "layout_off_zero");
+	ASSERT_EQ(hdr->layout_len, 0, "layout_len_zero");
+	ASSERT_EQ(hdr->str_off, TYPE_LEN, "strs_after_types");
+	ASSERT_EQ(hdr->str_len, STR_LEN, "strs_len_unchanged");
+	ASSERT_EQ(raw_sz, hdr->hdr_len + hdr->type_len + hdr->str_len, "btf_raw_sz_reduced");
+out:
+	/* This will free the cache we allocated above */
+	kfree_skb__destroy(skel);
+	btf__free(sanitized);
+	btf__free(orig);
+}
-- 
2.39.3


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

* Re: [PATCH v2 bpf-next 2/2] selftests/bpf: Add BTF sanitize test covering BTF layout
  2026-04-08 10:53 ` [PATCH v2 bpf-next 2/2] selftests/bpf: Add BTF sanitize test covering BTF layout Alan Maguire
@ 2026-04-08 12:53   ` Chengkaitao
  0 siblings, 0 replies; 5+ messages in thread
From: Chengkaitao @ 2026-04-08 12:53 UTC (permalink / raw)
  To: Alan Maguire
  Cc: andrii, ast, daniel, martin.lau, eddyz87, memxor, song,
	yonghong.song, jolsa, bpf

On Wed, Apr 8, 2026 at 6:56 PM Alan Maguire <alan.maguire@oracle.com> wrote:
>
> Add test that fakes up a feature cache of supported BPF
> features to simulate an older kernel that does not support
> BTF layout information.  Ensure that BTF is sanitized correctly
> to remove layout info between types and strings, and that all
> offsets and lengths are adjusted appropriately.
>
> Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
> ---
>  .../selftests/bpf/prog_tests/btf_sanitize.c   | 100 ++++++++++++++++++
>  1 file changed, 100 insertions(+)
>  create mode 100644 tools/testing/selftests/bpf/prog_tests/btf_sanitize.c
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/btf_sanitize.c b/tools/testing/selftests/bpf/prog_tests/btf_sanitize.c
> new file mode 100644
> index 000000000000..470b29298cbc
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/btf_sanitize.c
> @@ -0,0 +1,100 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2026, Oracle and/or its affiliates. */
> +#include <test_progs.h>
> +#include <linux/btf.h>
> +#include "bpf/libbpf_internal.h"
> +#include "../test_btf.h"
> +#include "kfree_skb.skel.h"
> +
> +#define TYPE_LEN       (sizeof(struct btf_type) + sizeof(__u32))
> +#define MAX_NR_LAYOUT  2
> +#define LAYOUT_LEN     (sizeof(struct btf_layout) * MAX_NR_LAYOUT)
> +#define STR_LEN                sizeof("\0int")
> +
> +struct layout_btf {
> +       struct btf_header hdr;
> +       __u32 types[TYPE_LEN/sizeof(__u32)];
> +       struct btf_layout layout[MAX_NR_LAYOUT];
> +       char strs[STR_LEN];
> +};
> +
> +static const struct layout_btf layout_btf = {
> +       .hdr = {
> +               .magic          = BTF_MAGIC,
> +               .version        = BTF_VERSION,
> +               .hdr_len        = sizeof(struct btf_header),
> +               .type_off       = 0,
> +               .type_len       = TYPE_LEN,
> +               .str_off        = TYPE_LEN + LAYOUT_LEN,
> +               .str_len        = STR_LEN,
> +               .layout_off     = TYPE_LEN,
> +               .layout_len     = LAYOUT_LEN,
> +       },
> +       .types = {
> +               BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4),
> +       },
> +       .layout = {
> +               { .info_sz = 0,          .elem_sz = 0, .flags = 0 },
> +               { .info_sz = sizeof(__u32), .elem_sz = 0, .flags = 0 },
> +       },
> +       .strs = "\0int",
> +};
> +
> +void test_btf_sanitize_layout(void)
> +{
> +       struct btf *orig = NULL, *sanitized = NULL;
> +       struct kern_feature_cache *cache = NULL;
> +       struct kfree_skb *skel = NULL;
> +       const struct btf_header *hdr;
> +       const void *raw;
> +       __u32 raw_sz;
> +
> +       skel = kfree_skb__open_and_load();
> +       if (!ASSERT_OK_PTR(skel, "kfree_skb_skel"))
> +               return;
> +       orig = btf__new(&layout_btf, sizeof(layout_btf));
> +       if (!ASSERT_OK_PTR(orig, "btf_new_layout"))
> +               return;

Missing kfree_skb__destroy(skel) here; consider using goto out instead.

> +       raw = btf__raw_data(orig, &raw_sz);
> +       if (!ASSERT_OK_PTR(raw, "btf__raw_data_orig"))
> +               goto out;
> +       hdr = (struct btf_header *)raw;
> +       ASSERT_EQ(hdr->layout_off, TYPE_LEN, "layout_off_nonzero");
> +       ASSERT_EQ(hdr->layout_len, LAYOUT_LEN, "layout_len_nonzero");
> +
> +       cache = calloc(1, sizeof(*cache));
> +       if (!ASSERT_OK_PTR(cache, "alloc_feat_cache"))
> +               goto out;
> +       for (int i = 0; i < __FEAT_CNT; i++)
> +               cache->res[i] = FEAT_SUPPORTED;
> +       cache->res[FEAT_BTF_LAYOUT] = FEAT_MISSING;
> +
> +       bpf_object_set_feat_cache(skel->obj, cache);
> +
> +       if (!ASSERT_FALSE(kernel_supports(skel->obj, FEAT_BTF_LAYOUT), "layout_feature_missing"))
> +               goto out;
> +
> +       if (!ASSERT_TRUE(kernel_supports(skel->obj, FEAT_BTF_FUNC), "other_feature_allowed"))
> +               goto out;
> +
> +       sanitized = bpf_object__sanitize_btf(skel->obj, orig);
> +       if (!ASSERT_OK_PTR(sanitized, "bpf_object__sanitize_btf"))
> +               goto out;
> +
> +       raw = btf__raw_data(sanitized, &raw_sz);
> +       if (!ASSERT_OK_PTR(raw, "btf__raw_data_sanitized"))
> +               goto out;
> +       hdr = (struct btf_header *)raw;
> +
> +       ASSERT_EQ(hdr->layout_off, 0, "layout_off_zero");
> +       ASSERT_EQ(hdr->layout_len, 0, "layout_len_zero");
> +       ASSERT_EQ(hdr->str_off, TYPE_LEN, "strs_after_types");
> +       ASSERT_EQ(hdr->str_len, STR_LEN, "strs_len_unchanged");
> +       ASSERT_EQ(raw_sz, hdr->hdr_len + hdr->type_len + hdr->str_len, "btf_raw_sz_reduced");
> +out:
> +       /* This will free the cache we allocated above */
> +       kfree_skb__destroy(skel);
> +       btf__free(sanitized);
> +       btf__free(orig);
> +}
> --
> 2.39.3
>

-- 
Yours,
Chengkaitao

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

* Re: [PATCH v2 bpf-next 1/2] libbpf: Allow use of feature cache for non-token cases
  2026-04-08 10:53 ` [PATCH v2 bpf-next 1/2] libbpf: Allow use of feature cache for non-token cases Alan Maguire
@ 2026-04-08 13:37   ` Jiri Olsa
  0 siblings, 0 replies; 5+ messages in thread
From: Jiri Olsa @ 2026-04-08 13:37 UTC (permalink / raw)
  To: Alan Maguire
  Cc: andrii, ast, daniel, martin.lau, eddyz87, memxor, song,
	yonghong.song, bpf

On Wed, Apr 08, 2026 at 11:53:23AM +0100, Alan Maguire wrote:
> Allow bpf object feat_cache assignment in BPF selftests
> to simulate missing features via inclusion of libbpf_internal.h
> and use of bpf_object_set_feat_cache() and bpf_object__sanitize_btf() to
> test BTF sanitization for cases where missing features are simulated.
> 
> Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
> ---
>  tools/lib/bpf/libbpf.c          | 12 ++++++++++--
>  tools/lib/bpf/libbpf_internal.h |  3 ++-
>  2 files changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 42bdba4efd0c..b7b636786d38 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -3145,7 +3145,7 @@ static bool btf_needs_sanitization(struct bpf_object *obj)
>  	       !has_layout;
>  }
>  
> -static struct btf *bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *orig_btf)
> +struct btf *bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *orig_btf)
>  {
>  	bool has_func_global = kernel_supports(obj, FEAT_BTF_GLOBAL_FUNC);
>  	bool has_datasec = kernel_supports(obj, FEAT_BTF_DATASEC);
> @@ -5203,12 +5203,20 @@ bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
>  		 */
>  		return true;
>  
> -	if (obj->token_fd)
> +	if (obj->feat_cache)
>  		return feat_supported(obj->feat_cache, feat_id);
>  
>  	return feat_supported(NULL, feat_id);
>  }
>  
> +/* Used in testing to simulate missing features. */
> +void bpf_object_set_feat_cache(struct bpf_object *obj, struct kern_feature_cache *cache)
> +{
> +	if (obj->feat_cache)
> +		zfree(&obj->feat_cache);

nit, no need to zfree, we set it right below

jirka

> +	obj->feat_cache = cache;
> +}
> +
>  static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd)
>  {
>  	struct bpf_map_info map_info;
> diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
> index cabdaef79098..3781c45b46d3 100644
> --- a/tools/lib/bpf/libbpf_internal.h
> +++ b/tools/lib/bpf/libbpf_internal.h
> @@ -414,6 +414,7 @@ struct kern_feature_cache {
>  
>  bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id);
>  bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id);
> +void bpf_object_set_feat_cache(struct bpf_object *obj, struct kern_feature_cache *cache);
>  
>  int probe_kern_syscall_wrapper(int token_fd);
>  int probe_memcg_account(int token_fd);
> @@ -427,7 +428,7 @@ int libbpf__load_raw_btf(const char *raw_types, size_t types_len,
>  int libbpf__load_raw_btf_hdr(const struct btf_header *hdr,
>  			     const char *raw_types, const char *str_sec,
>  			     const char *layout_sec, int token_fd);
> -
> +struct btf *bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *orig_btf);
>  int btf_load_into_kernel(struct btf *btf,
>  			 char *log_buf, size_t log_sz, __u32 log_level,
>  			 int token_fd);
> -- 
> 2.39.3
> 

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

end of thread, other threads:[~2026-04-08 13:37 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-08 10:53 [PATCH v2 bpf-next 0/2] selftests/bpf: Test BTF sanitization Alan Maguire
2026-04-08 10:53 ` [PATCH v2 bpf-next 1/2] libbpf: Allow use of feature cache for non-token cases Alan Maguire
2026-04-08 13:37   ` Jiri Olsa
2026-04-08 10:53 ` [PATCH v2 bpf-next 2/2] selftests/bpf: Add BTF sanitize test covering BTF layout Alan Maguire
2026-04-08 12:53   ` Chengkaitao

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