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 --- 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