]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
selftests/bpf: Add BTF sanitize test covering BTF layout
authorAlan Maguire <alan.maguire@oracle.com>
Wed, 8 Apr 2026 16:57:35 +0000 (17:57 +0100)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 10 Apr 2026 19:34:36 +0000 (12:34 -0700)
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>
Link: https://lore.kernel.org/r/20260408165735.843763-3-alan.maguire@oracle.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/prog_tests/btf_sanitize.c [new file with mode: 0644]

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 (file)
index 0000000..652b51e
--- /dev/null
@@ -0,0 +1,97 @@
+// 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();
+       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"))
+               goto out;
+       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);
+}