[PATCH bpf-next 3/6] libbpf: Add feature for kernel extended vlen/kind support

Alan Maguire
2026-04-14T19:50:52Z

Add feature check for kernel extended vlen/kind support, and reject
BTF that uses extended vlens/kinds if the kernel does not support
it. There is no reasonable path to generally sanitize such BTF.

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

diff --git a/tools/lib/bpf/features.c b/tools/lib/bpf/features.c
index 4f19a0d79b0c..4a75d6717bbb 100644
--- a/tools/lib/bpf/features.c
+++ b/tools/lib/bpf/features.c
@@ -615,6 +615,42 @@ static int probe_kern_btf_layout(int token_fd)
(char *)layout, token_fd));
}

+static int probe_kern_btf_vlen_kind_extended(int token_fd)
+{
+ struct btf *btf;
+ int ret = 0;
+ __s32 id;
+ int err;
+
+ btf = btf__load_vmlinux_btf();
+ err = libbpf_get_error(btf);
+ if (err)
+ return err;
+ id = btf__find_by_name_kind(btf, "btf_max", BTF_KIND_ENUM);
+ if (id > 0) {
+ const struct btf_type *t;
+ const struct btf_enum *e;
+ const char *name;
+ __u32 i, vlen;
+
+ t = btf__type_by_id(btf, id);
+ if (t) {
+ vlen = btf_vlen(t);
+
+ for (i = 0, e = btf_enum(t); i < vlen; i++, e++) {
+ name = btf__name_by_offset(btf, e->name_off);
+ if (!name || strcmp(name, "BTF_MAX_VLEN") != 0)
+ continue;
+ if (e->val > 0xffff)
+ ret = 1;
+ }
+ }
+ }
+ btf__free(btf);
+
+ return ret;
+}
+
typedef int (*feature_probe_fn)(int /* token_fd */);

static struct kern_feature_cache feature_cache;
@@ -699,6 +735,9 @@ static struct kern_feature_desc {
[FEAT_BTF_LAYOUT] = {
"kernel supports BTF layout", probe_kern_btf_layout,
},
+ [FEAT_BTF_VLEN_KIND_EXTENDED] = {
+ "kernel supports extended BTF vlen/kind", probe_kern_btf_vlen_kind_extended,
+ },
};

bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 8b0c3246097f..5f19d8ac17a9 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -3139,10 +3139,11 @@ static bool btf_needs_sanitization(struct bpf_object *obj)
bool has_enum64 = kernel_supports(obj, FEAT_BTF_ENUM64);
bool has_qmark_datasec = kernel_supports(obj, FEAT_BTF_QMARK_DATASEC);
bool has_layout = kernel_supports(obj, FEAT_BTF_LAYOUT);
+ bool has_vlen_kind_extended = kernel_supports(obj, FEAT_BTF_VLEN_KIND_EXTENDED);

return !has_func || !has_datasec || !has_func_global || !has_float ||
!has_decl_tag || !has_type_tag || !has_enum64 || !has_qmark_datasec ||
- !has_layout;
+ !has_layout || !has_vlen_kind_extended;
}

struct btf *bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *orig_btf)
@@ -3156,6 +3157,7 @@ struct btf *bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *orig_bt
bool has_enum64 = kernel_supports(obj, FEAT_BTF_ENUM64);
bool has_qmark_datasec = kernel_supports(obj, FEAT_BTF_QMARK_DATASEC);
bool has_layout = kernel_supports(obj, FEAT_BTF_LAYOUT);
+ bool has_vlen_kind_extended = kernel_supports(obj, FEAT_BTF_VLEN_KIND_EXTENDED);
int enum64_placeholder_id = 0;
const struct btf_header *hdr;
struct btf *btf = NULL;
@@ -3217,6 +3219,19 @@ struct btf *bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *orig_bt
for (i = 1; i < btf__type_cnt(btf); i++) {
t = (struct btf_type *)btf__type_by_id(btf, i);

+ /*
+ * If BTF uses extended vlen/kind and kernel does not support
+ * it, there is nothing we can do.
+ */
+ if (!has_vlen_kind_extended) {
+ if (btf_vlen(t) > 0xffff || btf_kind(t) > 0x1f) {
+ pr_debug("Unsupported %s for id %u\n",
+ btf_kind(t) > 0x1f ? "BTF kind" : "BTF vlen", i);
+ btf__free(btf);
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
if ((!has_datasec && btf_is_var(t)) || (!has_decl_tag && btf_is_decl_tag(t))) {
/* replace VAR/DECL_TAG with INT */
t->info = BTF_INFO_ENC(BTF_KIND_INT, 0, 0);
diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
index 3781c45b46d3..8ef1fc96b73a 100644
--- a/tools/lib/bpf/libbpf_internal.h
+++ b/tools/lib/bpf/libbpf_internal.h
@@ -398,6 +398,8 @@ enum kern_feature_id {
FEAT_UPROBE_SYSCALL,
/* Kernel supports BTF layout information */
FEAT_BTF_LAYOUT,
+ /* Kernel supports BTF vlen > 65535 */
+ FEAT_BTF_VLEN_KIND_EXTENDED,
__FEAT_CNT,
};

--
2.39.3