* [PATCH v3 bpf-next 1/6] bpf: Extend BTF UAPI vlen, kinds to use unused bits
2026-04-17 14:30 [PATCH v3 bpf-next 0/6] bpf: Extend BTF UAPI vlen, kinds to use unused bits Alan Maguire
@ 2026-04-17 14:30 ` Alan Maguire
2026-04-17 18:11 ` Mykyta Yatsenko
2026-04-17 14:30 ` [PATCH v3 bpf-next 2/6] libbpf: Adjust btf_vlen() to return a __u32 Alan Maguire
` (4 subsequent siblings)
5 siblings, 1 reply; 14+ messages in thread
From: Alan Maguire @ 2026-04-17 14:30 UTC (permalink / raw)
To: ast, daniel, andrii
Cc: martin.lau, eddyz87, memxor, song, yonghong.song, jolsa, qmo,
mykyta.yatsenko5, bpf, Alan Maguire
BTF maximum vlen is encoded using 16 bits with a maximum vlen
of 65535. This has sufficed for structs, function parameters
and enumerated type values. However, with upcoming BTF location
information - in particular information about inline sites -
this limit is surpassed. Use bits 16-23 - currently unused in
BTF info - to extend to 24 bits, giving a max vlen of (2^24 - 1),
or 16 million.
Also extend BTF kind encoding from 5 to 7 bits, giving a maximum
available number of kinds of 128. Since with the BTF location work
we use another 3 kinds, we are fast approaching the current limit
of 32.
Convert BTF_MAX_* values to enums to allow them to be encoded in
kernel BTF; this will allow us to detect if the running kernel
supports a 24-bit vlen or not. Add one for max _possible_
(not used) kind.
Fix up a few places in the kernel where a 16-bit vlen is assumed;
remove BTF_INFO_MASK as now all bits are used.
The vlen expansion was suggested by Andrii in [1]; the kind expansion
is tackled here too as it may be needed also to support new kinds
in BTF.
[1] https://lore.kernel.org/bpf/CAEf4BzZx=X6vGqcA8SPU6D+v6k+TR=ZewebXMuXtpmML058piw@mail.gmail.com/
Suggested-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
include/linux/btf.h | 4 ++--
include/uapi/linux/btf.h | 26 ++++++++++++++------------
kernel/bpf/btf.c | 27 ++++++++++-----------------
tools/include/uapi/linux/btf.h | 26 ++++++++++++++------------
4 files changed, 40 insertions(+), 43 deletions(-)
diff --git a/include/linux/btf.h b/include/linux/btf.h
index 48108471c5b1..c82d0d689059 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -415,12 +415,12 @@ static inline bool btf_type_is_array(const struct btf_type *t)
return BTF_INFO_KIND(t->info) == BTF_KIND_ARRAY;
}
-static inline u16 btf_type_vlen(const struct btf_type *t)
+static inline u32 btf_type_vlen(const struct btf_type *t)
{
return BTF_INFO_VLEN(t->info);
}
-static inline u16 btf_vlen(const struct btf_type *t)
+static inline u32 btf_vlen(const struct btf_type *t)
{
return btf_type_vlen(t);
}
diff --git a/include/uapi/linux/btf.h b/include/uapi/linux/btf.h
index 638615ebddc2..618167cab4e6 100644
--- a/include/uapi/linux/btf.h
+++ b/include/uapi/linux/btf.h
@@ -33,20 +33,22 @@ struct btf_header {
__u32 layout_len; /* length of layout section */
};
-/* Max # of type identifier */
-#define BTF_MAX_TYPE 0x000fffff
-/* Max offset into the string section */
-#define BTF_MAX_NAME_OFFSET 0x00ffffff
-/* Max # of struct/union/enum members or func args */
-#define BTF_MAX_VLEN 0xffff
+enum btf_max {
+ /* Max possible kind */
+ BTF_MAX_KIND = 0x0000007f,
+ /* Max # of type identifier */
+ BTF_MAX_TYPE = 0x000fffff,
+ /* Max offset into the string section */
+ BTF_MAX_NAME_OFFSET = 0x00ffffff,
+ /* Max # of struct/union/enum members or func args */
+ BTF_MAX_VLEN = 0x00ffffff,
+};
struct btf_type {
__u32 name_off;
/* "info" bits arrangement
- * bits 0-15: vlen (e.g. # of struct's members)
- * bits 16-23: unused
- * bits 24-28: kind (e.g. int, ptr, array...etc)
- * bits 29-30: unused
+ * bits 0-23: vlen (e.g. # of struct's members)
+ * bits 24-30: kind (e.g. int, ptr, array...etc)
* bit 31: kind_flag, currently used by
* struct, union, enum, fwd, enum64,
* decl_tag and type_tag
@@ -65,8 +67,8 @@ struct btf_type {
};
};
-#define BTF_INFO_KIND(info) (((info) >> 24) & 0x1f)
-#define BTF_INFO_VLEN(info) ((info) & 0xffff)
+#define BTF_INFO_KIND(info) (((info) >> 24) & 0x7f)
+#define BTF_INFO_VLEN(info) ((info) & 0xffffff)
#define BTF_INFO_KFLAG(info) ((info) >> 31)
enum {
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index a62d78581207..fedead837b9a 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -182,7 +182,6 @@
#define BITS_ROUNDUP_BYTES(bits) \
(BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
-#define BTF_INFO_MASK 0x9f00ffff
#define BTF_INT_MASK 0x0fffffff
#define BTF_TYPE_ID_VALID(type_id) ((type_id) <= BTF_MAX_TYPE)
#define BTF_STR_OFFSET_VALID(name_off) ((name_off) <= BTF_MAX_NAME_OFFSET)
@@ -289,7 +288,7 @@ enum verifier_phase {
struct resolve_vertex {
const struct btf_type *t;
u32 type_id;
- u16 next_member;
+ u32 next_member;
};
enum visit_state {
@@ -2031,7 +2030,7 @@ static int env_stack_push(struct btf_verifier_env *env,
}
static void env_stack_set_next_member(struct btf_verifier_env *env,
- u16 next_member)
+ u32 next_member)
{
env->stack[env->top_stack - 1].next_member = next_member;
}
@@ -3293,7 +3292,7 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
struct btf *btf = env->btf;
u32 struct_size = t->size;
u32 offset;
- u16 i;
+ u32 i;
meta_needed = btf_type_vlen(t) * sizeof(*member);
if (meta_left < meta_needed) {
@@ -3369,7 +3368,7 @@ static int btf_struct_resolve(struct btf_verifier_env *env,
{
const struct btf_member *member;
int err;
- u16 i;
+ u32 i;
/* Before continue resolving the next_member,
* ensure the last member is indeed resolved to a
@@ -4447,7 +4446,7 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
const struct btf_enum *enums = btf_type_enum(t);
struct btf *btf = env->btf;
const char *fmt_str;
- u16 i, nr_enums;
+ u32 i, nr_enums;
u32 meta_needed;
nr_enums = btf_type_vlen(t);
@@ -4555,7 +4554,7 @@ static s32 btf_enum64_check_meta(struct btf_verifier_env *env,
const struct btf_enum64 *enums = btf_type_enum64(t);
struct btf *btf = env->btf;
const char *fmt_str;
- u16 i, nr_enums;
+ u32 i, nr_enums;
u32 meta_needed;
nr_enums = btf_type_vlen(t);
@@ -4683,7 +4682,7 @@ static void btf_func_proto_log(struct btf_verifier_env *env,
const struct btf_type *t)
{
const struct btf_param *args = (const struct btf_param *)(t + 1);
- u16 nr_args = btf_type_vlen(t), i;
+ u32 nr_args = btf_type_vlen(t), i;
btf_verifier_log(env, "return=%u args=(", t->type);
if (!nr_args) {
@@ -4929,7 +4928,7 @@ static int btf_datasec_resolve(struct btf_verifier_env *env,
{
const struct btf_var_secinfo *vsi;
struct btf *btf = env->btf;
- u16 i;
+ u32 i;
env->resolve_mode = RESOLVE_TBD;
for_each_vsi_from(i, v->next_member, v->t, vsi) {
@@ -5183,7 +5182,7 @@ static int btf_func_proto_check(struct btf_verifier_env *env,
const struct btf_type *ret_type;
const struct btf_param *args;
const struct btf *btf;
- u16 nr_args, i;
+ u32 nr_args, i;
int err;
btf = env->btf;
@@ -5278,7 +5277,7 @@ static int btf_func_check(struct btf_verifier_env *env,
const struct btf_type *proto_type;
const struct btf_param *args;
const struct btf *btf;
- u16 nr_args, i;
+ u32 nr_args, i;
btf = env->btf;
proto_type = btf_type_by_id(btf, t->type);
@@ -5336,12 +5335,6 @@ static s32 btf_check_meta(struct btf_verifier_env *env,
}
meta_left -= sizeof(*t);
- if (t->info & ~BTF_INFO_MASK) {
- btf_verifier_log(env, "[%u] Invalid btf_info:%x",
- env->log_type_id, t->info);
- return -EINVAL;
- }
-
if (BTF_INFO_KIND(t->info) > BTF_KIND_MAX ||
BTF_INFO_KIND(t->info) == BTF_KIND_UNKN) {
btf_verifier_log(env, "[%u] Invalid kind:%u",
diff --git a/tools/include/uapi/linux/btf.h b/tools/include/uapi/linux/btf.h
index 638615ebddc2..618167cab4e6 100644
--- a/tools/include/uapi/linux/btf.h
+++ b/tools/include/uapi/linux/btf.h
@@ -33,20 +33,22 @@ struct btf_header {
__u32 layout_len; /* length of layout section */
};
-/* Max # of type identifier */
-#define BTF_MAX_TYPE 0x000fffff
-/* Max offset into the string section */
-#define BTF_MAX_NAME_OFFSET 0x00ffffff
-/* Max # of struct/union/enum members or func args */
-#define BTF_MAX_VLEN 0xffff
+enum btf_max {
+ /* Max possible kind */
+ BTF_MAX_KIND = 0x0000007f,
+ /* Max # of type identifier */
+ BTF_MAX_TYPE = 0x000fffff,
+ /* Max offset into the string section */
+ BTF_MAX_NAME_OFFSET = 0x00ffffff,
+ /* Max # of struct/union/enum members or func args */
+ BTF_MAX_VLEN = 0x00ffffff,
+};
struct btf_type {
__u32 name_off;
/* "info" bits arrangement
- * bits 0-15: vlen (e.g. # of struct's members)
- * bits 16-23: unused
- * bits 24-28: kind (e.g. int, ptr, array...etc)
- * bits 29-30: unused
+ * bits 0-23: vlen (e.g. # of struct's members)
+ * bits 24-30: kind (e.g. int, ptr, array...etc)
* bit 31: kind_flag, currently used by
* struct, union, enum, fwd, enum64,
* decl_tag and type_tag
@@ -65,8 +67,8 @@ struct btf_type {
};
};
-#define BTF_INFO_KIND(info) (((info) >> 24) & 0x1f)
-#define BTF_INFO_VLEN(info) ((info) & 0xffff)
+#define BTF_INFO_KIND(info) (((info) >> 24) & 0x7f)
+#define BTF_INFO_VLEN(info) ((info) & 0xffffff)
#define BTF_INFO_KFLAG(info) ((info) >> 31)
enum {
--
2.39.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v3 bpf-next 1/6] bpf: Extend BTF UAPI vlen, kinds to use unused bits
2026-04-17 14:30 ` [PATCH v3 bpf-next 1/6] " Alan Maguire
@ 2026-04-17 18:11 ` Mykyta Yatsenko
0 siblings, 0 replies; 14+ messages in thread
From: Mykyta Yatsenko @ 2026-04-17 18:11 UTC (permalink / raw)
To: Alan Maguire, ast, daniel, andrii
Cc: martin.lau, eddyz87, memxor, song, yonghong.song, jolsa, qmo, bpf
On 4/17/26 3:30 PM, Alan Maguire wrote:
> BTF maximum vlen is encoded using 16 bits with a maximum vlen
> of 65535. This has sufficed for structs, function parameters
> and enumerated type values. However, with upcoming BTF location
> information - in particular information about inline sites -
> this limit is surpassed. Use bits 16-23 - currently unused in
> BTF info - to extend to 24 bits, giving a max vlen of (2^24 - 1),
> or 16 million.
>
> Also extend BTF kind encoding from 5 to 7 bits, giving a maximum
> available number of kinds of 128. Since with the BTF location work
> we use another 3 kinds, we are fast approaching the current limit
> of 32.
>
> Convert BTF_MAX_* values to enums to allow them to be encoded in
> kernel BTF; this will allow us to detect if the running kernel
> supports a 24-bit vlen or not. Add one for max _possible_
> (not used) kind.
>
> Fix up a few places in the kernel where a 16-bit vlen is assumed;
> remove BTF_INFO_MASK as now all bits are used.
>
> The vlen expansion was suggested by Andrii in [1]; the kind expansion
> is tackled here too as it may be needed also to support new kinds
> in BTF.
>
> [1] https://lore.kernel.org/bpf/CAEf4BzZx=X6vGqcA8SPU6D+v6k+TR=ZewebXMuXtpmML058piw@mail.gmail.com/
>
> Suggested-by: Andrii Nakryiko <andrii@kernel.org>
> Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
> ---
It looks like all callsites of vlen have been migrated to u32 (except
the ones that are guaranteed to work with narrower types:
btf_func_linkage(), cs->num_params).
Extending kind from 5 to 7 bits does not require modifying users at all.
Acked-by: Mykyta Yatsenko <yatsenko@meta.com>
> include/linux/btf.h | 4 ++--
> include/uapi/linux/btf.h | 26 ++++++++++++++------------
> kernel/bpf/btf.c | 27 ++++++++++-----------------
> tools/include/uapi/linux/btf.h | 26 ++++++++++++++------------
> 4 files changed, 40 insertions(+), 43 deletions(-)
>
> diff --git a/include/linux/btf.h b/include/linux/btf.h
> index 48108471c5b1..c82d0d689059 100644
> --- a/include/linux/btf.h
> +++ b/include/linux/btf.h
> @@ -415,12 +415,12 @@ static inline bool btf_type_is_array(const struct btf_type *t)
> return BTF_INFO_KIND(t->info) == BTF_KIND_ARRAY;
> }
>
> -static inline u16 btf_type_vlen(const struct btf_type *t)
> +static inline u32 btf_type_vlen(const struct btf_type *t)
> {
> return BTF_INFO_VLEN(t->info);
> }
>
> -static inline u16 btf_vlen(const struct btf_type *t)
> +static inline u32 btf_vlen(const struct btf_type *t)
> {
> return btf_type_vlen(t);
> }
> diff --git a/include/uapi/linux/btf.h b/include/uapi/linux/btf.h
> index 638615ebddc2..618167cab4e6 100644
> --- a/include/uapi/linux/btf.h
> +++ b/include/uapi/linux/btf.h
> @@ -33,20 +33,22 @@ struct btf_header {
> __u32 layout_len; /* length of layout section */
> };
>
> -/* Max # of type identifier */
> -#define BTF_MAX_TYPE 0x000fffff
> -/* Max offset into the string section */
> -#define BTF_MAX_NAME_OFFSET 0x00ffffff
> -/* Max # of struct/union/enum members or func args */
> -#define BTF_MAX_VLEN 0xffff
> +enum btf_max {
> + /* Max possible kind */
> + BTF_MAX_KIND = 0x0000007f,
> + /* Max # of type identifier */
> + BTF_MAX_TYPE = 0x000fffff,
> + /* Max offset into the string section */
> + BTF_MAX_NAME_OFFSET = 0x00ffffff,
> + /* Max # of struct/union/enum members or func args */
> + BTF_MAX_VLEN = 0x00ffffff,
> +};
>
> struct btf_type {
> __u32 name_off;
> /* "info" bits arrangement
> - * bits 0-15: vlen (e.g. # of struct's members)
> - * bits 16-23: unused
> - * bits 24-28: kind (e.g. int, ptr, array...etc)
> - * bits 29-30: unused
> + * bits 0-23: vlen (e.g. # of struct's members)
> + * bits 24-30: kind (e.g. int, ptr, array...etc)
> * bit 31: kind_flag, currently used by
> * struct, union, enum, fwd, enum64,
> * decl_tag and type_tag
> @@ -65,8 +67,8 @@ struct btf_type {
> };
> };
>
> -#define BTF_INFO_KIND(info) (((info) >> 24) & 0x1f)
> -#define BTF_INFO_VLEN(info) ((info) & 0xffff)
> +#define BTF_INFO_KIND(info) (((info) >> 24) & 0x7f)
> +#define BTF_INFO_VLEN(info) ((info) & 0xffffff)
> #define BTF_INFO_KFLAG(info) ((info) >> 31)
>
> enum {
> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index a62d78581207..fedead837b9a 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -182,7 +182,6 @@
> #define BITS_ROUNDUP_BYTES(bits) \
> (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
>
> -#define BTF_INFO_MASK 0x9f00ffff
> #define BTF_INT_MASK 0x0fffffff
> #define BTF_TYPE_ID_VALID(type_id) ((type_id) <= BTF_MAX_TYPE)
> #define BTF_STR_OFFSET_VALID(name_off) ((name_off) <= BTF_MAX_NAME_OFFSET)
> @@ -289,7 +288,7 @@ enum verifier_phase {
> struct resolve_vertex {
> const struct btf_type *t;
> u32 type_id;
> - u16 next_member;
> + u32 next_member;
> };
>
> enum visit_state {
> @@ -2031,7 +2030,7 @@ static int env_stack_push(struct btf_verifier_env *env,
> }
>
> static void env_stack_set_next_member(struct btf_verifier_env *env,
> - u16 next_member)
> + u32 next_member)
> {
> env->stack[env->top_stack - 1].next_member = next_member;
> }
> @@ -3293,7 +3292,7 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
> struct btf *btf = env->btf;
> u32 struct_size = t->size;
> u32 offset;
> - u16 i;
> + u32 i;
>
> meta_needed = btf_type_vlen(t) * sizeof(*member);
> if (meta_left < meta_needed) {
> @@ -3369,7 +3368,7 @@ static int btf_struct_resolve(struct btf_verifier_env *env,
> {
> const struct btf_member *member;
> int err;
> - u16 i;
> + u32 i;
>
> /* Before continue resolving the next_member,
> * ensure the last member is indeed resolved to a
> @@ -4447,7 +4446,7 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
> const struct btf_enum *enums = btf_type_enum(t);
> struct btf *btf = env->btf;
> const char *fmt_str;
> - u16 i, nr_enums;
> + u32 i, nr_enums;
> u32 meta_needed;
>
> nr_enums = btf_type_vlen(t);
> @@ -4555,7 +4554,7 @@ static s32 btf_enum64_check_meta(struct btf_verifier_env *env,
> const struct btf_enum64 *enums = btf_type_enum64(t);
> struct btf *btf = env->btf;
> const char *fmt_str;
> - u16 i, nr_enums;
> + u32 i, nr_enums;
> u32 meta_needed;
>
> nr_enums = btf_type_vlen(t);
> @@ -4683,7 +4682,7 @@ static void btf_func_proto_log(struct btf_verifier_env *env,
> const struct btf_type *t)
> {
> const struct btf_param *args = (const struct btf_param *)(t + 1);
> - u16 nr_args = btf_type_vlen(t), i;
> + u32 nr_args = btf_type_vlen(t), i;
>
> btf_verifier_log(env, "return=%u args=(", t->type);
> if (!nr_args) {
> @@ -4929,7 +4928,7 @@ static int btf_datasec_resolve(struct btf_verifier_env *env,
> {
> const struct btf_var_secinfo *vsi;
> struct btf *btf = env->btf;
> - u16 i;
> + u32 i;
>
> env->resolve_mode = RESOLVE_TBD;
> for_each_vsi_from(i, v->next_member, v->t, vsi) {
> @@ -5183,7 +5182,7 @@ static int btf_func_proto_check(struct btf_verifier_env *env,
> const struct btf_type *ret_type;
> const struct btf_param *args;
> const struct btf *btf;
> - u16 nr_args, i;
> + u32 nr_args, i;
> int err;
>
> btf = env->btf;
> @@ -5278,7 +5277,7 @@ static int btf_func_check(struct btf_verifier_env *env,
> const struct btf_type *proto_type;
> const struct btf_param *args;
> const struct btf *btf;
> - u16 nr_args, i;
> + u32 nr_args, i;
>
> btf = env->btf;
> proto_type = btf_type_by_id(btf, t->type);
> @@ -5336,12 +5335,6 @@ static s32 btf_check_meta(struct btf_verifier_env *env,
> }
> meta_left -= sizeof(*t);
>
> - if (t->info & ~BTF_INFO_MASK) {
> - btf_verifier_log(env, "[%u] Invalid btf_info:%x",
> - env->log_type_id, t->info);
> - return -EINVAL;
> - }
> -
> if (BTF_INFO_KIND(t->info) > BTF_KIND_MAX ||
> BTF_INFO_KIND(t->info) == BTF_KIND_UNKN) {
> btf_verifier_log(env, "[%u] Invalid kind:%u",
> diff --git a/tools/include/uapi/linux/btf.h b/tools/include/uapi/linux/btf.h
> index 638615ebddc2..618167cab4e6 100644
> --- a/tools/include/uapi/linux/btf.h
> +++ b/tools/include/uapi/linux/btf.h
> @@ -33,20 +33,22 @@ struct btf_header {
> __u32 layout_len; /* length of layout section */
> };
>
> -/* Max # of type identifier */
> -#define BTF_MAX_TYPE 0x000fffff
> -/* Max offset into the string section */
> -#define BTF_MAX_NAME_OFFSET 0x00ffffff
> -/* Max # of struct/union/enum members or func args */
> -#define BTF_MAX_VLEN 0xffff
> +enum btf_max {
> + /* Max possible kind */
> + BTF_MAX_KIND = 0x0000007f,
> + /* Max # of type identifier */
> + BTF_MAX_TYPE = 0x000fffff,
> + /* Max offset into the string section */
> + BTF_MAX_NAME_OFFSET = 0x00ffffff,
> + /* Max # of struct/union/enum members or func args */
> + BTF_MAX_VLEN = 0x00ffffff,
> +};
>
> struct btf_type {
> __u32 name_off;
> /* "info" bits arrangement
> - * bits 0-15: vlen (e.g. # of struct's members)
> - * bits 16-23: unused
> - * bits 24-28: kind (e.g. int, ptr, array...etc)
> - * bits 29-30: unused
> + * bits 0-23: vlen (e.g. # of struct's members)
> + * bits 24-30: kind (e.g. int, ptr, array...etc)
> * bit 31: kind_flag, currently used by
> * struct, union, enum, fwd, enum64,
> * decl_tag and type_tag
> @@ -65,8 +67,8 @@ struct btf_type {
> };
> };
>
> -#define BTF_INFO_KIND(info) (((info) >> 24) & 0x1f)
> -#define BTF_INFO_VLEN(info) ((info) & 0xffff)
> +#define BTF_INFO_KIND(info) (((info) >> 24) & 0x7f)
> +#define BTF_INFO_VLEN(info) ((info) & 0xffffff)
> #define BTF_INFO_KFLAG(info) ((info) >> 31)
>
> enum {
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 bpf-next 2/6] libbpf: Adjust btf_vlen() to return a __u32
2026-04-17 14:30 [PATCH v3 bpf-next 0/6] bpf: Extend BTF UAPI vlen, kinds to use unused bits Alan Maguire
2026-04-17 14:30 ` [PATCH v3 bpf-next 1/6] " Alan Maguire
@ 2026-04-17 14:30 ` Alan Maguire
2026-04-17 17:07 ` sashiko-bot
2026-04-17 18:26 ` Mykyta Yatsenko
2026-04-17 14:30 ` [PATCH v3 bpf-next 3/6] bpftool: Support 24-bit vlen Alan Maguire
` (3 subsequent siblings)
5 siblings, 2 replies; 14+ messages in thread
From: Alan Maguire @ 2026-04-17 14:30 UTC (permalink / raw)
To: ast, daniel, andrii
Cc: martin.lau, eddyz87, memxor, song, yonghong.song, jolsa, qmo,
mykyta.yatsenko5, bpf, Alan Maguire
Now that vlen is 24 bits, btf_vlen() must return a __u32.
Adjust use cases in libbpf accordingly. Also add error
handling to avoid vlen overflow in btf_type_inc_vlen().
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
tools/lib/bpf/btf.c | 50 +++++++++++++++++++++++++--------------
tools/lib/bpf/btf.h | 2 +-
tools/lib/bpf/btf_dump.c | 24 +++++++++----------
tools/lib/bpf/relo_core.c | 16 ++++++-------
4 files changed, 53 insertions(+), 39 deletions(-)
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index ceb57b46a878..267904939098 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -421,7 +421,7 @@ static int btf_type_size_unknown(const struct btf *btf, const struct btf_type *t
{
__u32 l_cnt = btf->hdr.layout_len / sizeof(struct btf_layout);
struct btf_layout *l = btf->layout;
- __u16 vlen = btf_vlen(t);
+ __u32 vlen = btf_vlen(t);
__u32 kind = btf_kind(t);
/* Fall back to base BTF if needed as they share layout information */
@@ -454,7 +454,7 @@ static int btf_type_size_unknown(const struct btf *btf, const struct btf_type *t
static int btf_type_size(const struct btf *btf, const struct btf_type *t)
{
const int base_size = sizeof(struct btf_type);
- __u16 vlen = btf_vlen(t);
+ __u32 vlen = btf_vlen(t);
switch (btf_kind(t)) {
case BTF_KIND_FWD:
@@ -506,7 +506,7 @@ static int btf_bswap_type_rest(struct btf_type *t)
struct btf_array *a;
struct btf_param *p;
struct btf_enum *e;
- __u16 vlen = btf_vlen(t);
+ __u32 vlen = btf_vlen(t);
int i;
switch (btf_kind(t)) {
@@ -1007,7 +1007,7 @@ int btf__align_of(const struct btf *btf, __u32 id)
case BTF_KIND_STRUCT:
case BTF_KIND_UNION: {
const struct btf_member *m = btf_members(t);
- __u16 vlen = btf_vlen(t);
+ __u32 vlen = btf_vlen(t);
int i, max_align = 1, align;
for (i = 0; i < vlen; i++, m++) {
@@ -2121,9 +2121,12 @@ static void *btf_add_type_mem(struct btf *btf, size_t add_sz)
btf->hdr.type_len, UINT_MAX, add_sz);
}
-static void btf_type_inc_vlen(struct btf_type *t)
+static int btf_type_inc_vlen(struct btf_type *t)
{
+ if (btf_vlen(t) == BTF_MAX_VLEN)
+ return -ENOSPC;
t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, btf_kflag(t));
+ return 0;
}
static void btf_hdr_update_type_len(struct btf *btf, int new_len)
@@ -2652,6 +2655,8 @@ int btf__add_field(struct btf *btf, const char *name, int type_id,
t = btf_last_type(btf);
if (!btf_is_composite(t))
return libbpf_err(-EINVAL);
+ if (btf_vlen(t) == BTF_MAX_VLEN)
+ return libbpf_err(-ENOSPC);
if (validate_type_id(type_id))
return libbpf_err(-EINVAL);
@@ -2686,6 +2691,7 @@ int btf__add_field(struct btf *btf, const char *name, int type_id,
/* btf_add_type_mem can invalidate t pointer */
t = btf_last_type(btf);
+
/* update parent type's vlen and kflag */
t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, is_bitfield || btf_kflag(t));
@@ -2796,7 +2802,9 @@ int btf__add_enum_value(struct btf *btf, const char *name, __s64 value)
/* update parent type's vlen */
t = btf_last_type(btf);
- btf_type_inc_vlen(t);
+ err = btf_type_inc_vlen(t);
+ if (err)
+ return libbpf_err(err);
/* if negative value, set signedness to signed */
if (value < 0)
@@ -2873,7 +2881,9 @@ int btf__add_enum64_value(struct btf *btf, const char *name, __u64 value)
/* update parent type's vlen */
t = btf_last_type(btf);
- btf_type_inc_vlen(t);
+ err = btf_type_inc_vlen(t);
+ if (err)
+ return libbpf_err(err);
btf_hdr_update_type_len(btf, btf->hdr.type_len + sz);
return 0;
@@ -3115,7 +3125,9 @@ int btf__add_func_param(struct btf *btf, const char *name, int type_id)
/* update parent type's vlen */
t = btf_last_type(btf);
- btf_type_inc_vlen(t);
+ err = btf_type_inc_vlen(t);
+ if (err)
+ return libbpf_err(err);
btf_hdr_update_type_len(btf, btf->hdr.type_len + sz);
return 0;
@@ -3257,7 +3269,9 @@ int btf__add_datasec_var_info(struct btf *btf, int var_type_id, __u32 offset, __
/* update parent type's vlen */
t = btf_last_type(btf);
- btf_type_inc_vlen(t);
+ err = btf_type_inc_vlen(t);
+ if (err)
+ return libbpf_err(err);
btf_hdr_update_type_len(btf, btf->hdr.type_len + sz);
return 0;
@@ -4311,7 +4325,7 @@ static long btf_hash_enum(struct btf_type *t)
static bool btf_equal_enum_members(struct btf_type *t1, struct btf_type *t2)
{
const struct btf_enum *m1, *m2;
- __u16 vlen;
+ __u32 vlen;
int i;
vlen = btf_vlen(t1);
@@ -4329,7 +4343,7 @@ static bool btf_equal_enum_members(struct btf_type *t1, struct btf_type *t2)
static bool btf_equal_enum64_members(struct btf_type *t1, struct btf_type *t2)
{
const struct btf_enum64 *m1, *m2;
- __u16 vlen;
+ __u32 vlen;
int i;
vlen = btf_vlen(t1);
@@ -4406,7 +4420,7 @@ static long btf_hash_struct(struct btf_type *t)
static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
{
const struct btf_member *m1, *m2;
- __u16 vlen;
+ __u32 vlen;
int i;
if (!btf_equal_common(t1, t2))
@@ -4482,7 +4496,7 @@ static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
static long btf_hash_fnproto(struct btf_type *t)
{
const struct btf_param *member = btf_params(t);
- __u16 vlen = btf_vlen(t);
+ __u32 vlen = btf_vlen(t);
long h = btf_hash_common(t);
int i;
@@ -4504,7 +4518,7 @@ static long btf_hash_fnproto(struct btf_type *t)
static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
{
const struct btf_param *m1, *m2;
- __u16 vlen;
+ __u32 vlen;
int i;
if (!btf_equal_common(t1, t2))
@@ -4530,7 +4544,7 @@ static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
{
const struct btf_param *m1, *m2;
- __u16 vlen;
+ __u32 vlen;
int i;
/* skip return type ID */
@@ -5077,7 +5091,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
case BTF_KIND_STRUCT:
case BTF_KIND_UNION: {
const struct btf_member *cand_m, *canon_m;
- __u16 vlen;
+ __u32 vlen;
if (!btf_shallow_equal_struct(cand_type, canon_type))
return 0;
@@ -5105,7 +5119,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
case BTF_KIND_FUNC_PROTO: {
const struct btf_param *cand_p, *canon_p;
- __u16 vlen;
+ __u32 vlen;
if (!btf_compat_fnproto(cand_type, canon_type))
return 0;
@@ -5439,7 +5453,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
case BTF_KIND_FUNC_PROTO: {
struct btf_param *param;
- __u16 vlen;
+ __u32 vlen;
int i;
ref_type_id = btf_dedup_ref_type(d, t->type);
diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
index a1f8deca2603..1a31f2da947f 100644
--- a/tools/lib/bpf/btf.h
+++ b/tools/lib/bpf/btf.h
@@ -435,7 +435,7 @@ static inline __u16 btf_kind(const struct btf_type *t)
return BTF_INFO_KIND(t->info);
}
-static inline __u16 btf_vlen(const struct btf_type *t)
+static inline __u32 btf_vlen(const struct btf_type *t)
{
return BTF_INFO_VLEN(t->info);
}
diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
index 53c6624161d7..cc1ba65bb6c5 100644
--- a/tools/lib/bpf/btf_dump.c
+++ b/tools/lib/bpf/btf_dump.c
@@ -316,7 +316,7 @@ static int btf_dump_mark_referenced(struct btf_dump *d)
{
int i, j, n = btf__type_cnt(d->btf);
const struct btf_type *t;
- __u16 vlen;
+ __u32 vlen;
for (i = d->last_id + 1; i < n; i++) {
t = btf__type_by_id(d->btf, i);
@@ -485,7 +485,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
*/
struct btf_dump_type_aux_state *tstate = &d->type_states[id];
const struct btf_type *t;
- __u16 vlen;
+ __u32 vlen;
int err, i;
/* return true, letting typedefs know that it's ok to be emitted */
@@ -798,7 +798,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
*/
if (top_level_def || t->name_off == 0) {
const struct btf_member *m = btf_members(t);
- __u16 vlen = btf_vlen(t);
+ __u32 vlen = btf_vlen(t);
int i, new_cont_id;
new_cont_id = t->name_off == 0 ? cont_id : id;
@@ -820,7 +820,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
break;
case BTF_KIND_FUNC_PROTO: {
const struct btf_param *p = btf_params(t);
- __u16 n = btf_vlen(t);
+ __u32 n = btf_vlen(t);
int i;
btf_dump_emit_type(d, t->type, cont_id);
@@ -839,7 +839,7 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
{
const struct btf_member *m;
int max_align = 1, align, i, bit_sz;
- __u16 vlen;
+ __u32 vlen;
m = btf_members(t);
vlen = btf_vlen(t);
@@ -973,7 +973,7 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
bool is_struct = btf_is_struct(t);
bool packed, prev_bitfield = false;
int align, i, off = 0;
- __u16 vlen = btf_vlen(t);
+ __u32 vlen = btf_vlen(t);
align = btf__align_of(d->btf, id);
packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;
@@ -1064,7 +1064,7 @@ static void btf_dump_emit_enum_fwd(struct btf_dump *d, __u32 id,
static void btf_dump_emit_enum32_val(struct btf_dump *d,
const struct btf_type *t,
- int lvl, __u16 vlen)
+ int lvl, __u32 vlen)
{
const struct btf_enum *v = btf_enum(t);
bool is_signed = btf_kflag(t);
@@ -1089,7 +1089,7 @@ static void btf_dump_emit_enum32_val(struct btf_dump *d,
static void btf_dump_emit_enum64_val(struct btf_dump *d,
const struct btf_type *t,
- int lvl, __u16 vlen)
+ int lvl, __u32 vlen)
{
const struct btf_enum64 *v = btf_enum64(t);
bool is_signed = btf_kflag(t);
@@ -1122,7 +1122,7 @@ static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
const struct btf_type *t,
int lvl)
{
- __u16 vlen = btf_vlen(t);
+ __u32 vlen = btf_vlen(t);
btf_dump_printf(d, "enum%s%s",
t->name_off ? " " : "",
@@ -1542,7 +1542,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
}
case BTF_KIND_FUNC_PROTO: {
const struct btf_param *p = btf_params(t);
- __u16 vlen = btf_vlen(t);
+ __u32 vlen = btf_vlen(t);
int i;
/*
@@ -2159,7 +2159,7 @@ static int btf_dump_struct_data(struct btf_dump *d,
const void *data)
{
const struct btf_member *m = btf_members(t);
- __u16 n = btf_vlen(t);
+ __u32 n = btf_vlen(t);
int i, err = 0;
/* note that we increment depth before calling btf_dump_print() below;
@@ -2449,7 +2449,7 @@ static int btf_dump_type_data_check_zero(struct btf_dump *d,
case BTF_KIND_STRUCT:
case BTF_KIND_UNION: {
const struct btf_member *m = btf_members(t);
- __u16 n = btf_vlen(t);
+ __u32 n = btf_vlen(t);
/* if any struct/union member is non-zero, the struct/union
* is considered non-zero and dumped.
diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c
index 0ccc8f548cba..6ae3f2a15ad0 100644
--- a/tools/lib/bpf/relo_core.c
+++ b/tools/lib/bpf/relo_core.c
@@ -191,8 +191,8 @@ int __bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
case BTF_KIND_FUNC_PROTO: {
struct btf_param *local_p = btf_params(local_type);
struct btf_param *targ_p = btf_params(targ_type);
- __u16 local_vlen = btf_vlen(local_type);
- __u16 targ_vlen = btf_vlen(targ_type);
+ __u32 local_vlen = btf_vlen(local_type);
+ __u32 targ_vlen = btf_vlen(targ_type);
int i, err;
if (local_vlen != targ_vlen)
@@ -1457,8 +1457,8 @@ static bool bpf_core_names_match(const struct btf *local_btf, size_t local_name_
static int bpf_core_enums_match(const struct btf *local_btf, const struct btf_type *local_t,
const struct btf *targ_btf, const struct btf_type *targ_t)
{
- __u16 local_vlen = btf_vlen(local_t);
- __u16 targ_vlen = btf_vlen(targ_t);
+ __u32 local_vlen = btf_vlen(local_t);
+ __u32 targ_vlen = btf_vlen(targ_t);
int i, j;
if (local_t->size != targ_t->size)
@@ -1498,8 +1498,8 @@ static int bpf_core_composites_match(const struct btf *local_btf, const struct b
bool behind_ptr, int level)
{
const struct btf_member *local_m = btf_members(local_t);
- __u16 local_vlen = btf_vlen(local_t);
- __u16 targ_vlen = btf_vlen(targ_t);
+ __u32 local_vlen = btf_vlen(local_t);
+ __u32 targ_vlen = btf_vlen(targ_t);
int i, j, err;
if (local_vlen > targ_vlen)
@@ -1674,8 +1674,8 @@ int __bpf_core_types_match(const struct btf *local_btf, __u32 local_id, const st
case BTF_KIND_FUNC_PROTO: {
struct btf_param *local_p = btf_params(local_t);
struct btf_param *targ_p = btf_params(targ_t);
- __u16 local_vlen = btf_vlen(local_t);
- __u16 targ_vlen = btf_vlen(targ_t);
+ __u32 local_vlen = btf_vlen(local_t);
+ __u32 targ_vlen = btf_vlen(targ_t);
int i, err;
if (local_k != targ_k)
--
2.39.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v3 bpf-next 2/6] libbpf: Adjust btf_vlen() to return a __u32
2026-04-17 14:30 ` [PATCH v3 bpf-next 2/6] libbpf: Adjust btf_vlen() to return a __u32 Alan Maguire
@ 2026-04-17 17:07 ` sashiko-bot
2026-04-17 18:26 ` Mykyta Yatsenko
1 sibling, 0 replies; 14+ messages in thread
From: sashiko-bot @ 2026-04-17 17:07 UTC (permalink / raw)
To: Alan Maguire; +Cc: bpf
Sashiko AI review found 1 potential issue(s):
- [High] On 32-bit systems, `btf_parse_type_sec()` is vulnerable to pointer arithmetic wrap-around due to missing strict bounds checking, allowing an attacker-crafted BTF layout to bypass safety checks and cause out-of-bounds memory access.
--
commit 0d6d9306686384cb94334ae8845f954db44a9f74
Author: Alan Maguire <alan.maguire@oracle.com>
libbpf: Adjust btf_vlen() to return a __u32
Now that vlen is 24 bits, btf_vlen() must return a __u32.
Adjust use cases in libbpf accordingly. Also add error
handling to avoid vlen overflow in btf_type_inc_vlen().
> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
> index ceb57b46a8782..267904939098c 100644
> --- a/tools/lib/bpf/btf.c
> +++ b/tools/lib/bpf/btf.c
> @@ -421,7 +421,7 @@ static int btf_type_size_unknown(const struct btf *btf, const struct btf_type *t
> {
> __u32 l_cnt = btf->hdr.layout_len / sizeof(struct btf_layout);
> struct btf_layout *l = btf->layout;
> - __u16 vlen = btf_vlen(t);
> + __u32 vlen = btf_vlen(t);
> __u32 kind = btf_kind(t);
Can this lead to a pointer arithmetic wrap-around regression on 32-bit
systems?
The size is calculated later in this function using unsigned 32-bit
arithmetic and returned as a signed int:
return sizeof(struct btf_type) + l[kind].info_sz + vlen * l[kind].elem_sz;
An attacker could provide a custom layout with an artificially large elem_sz
(e.g., 2,000,000,000). For a type with vlen = 1, the calculated size fits
within a positive signed 32-bit int and is returned as a valid positive
type_size.
When btf_parse_type_sec() checks if next_type + type_size > end_type, it
evaluates this using 32-bit pointer arithmetic. If next_type is located high
in the address space, adding 2,000,000,000 wraps around the 32-bit boundary
to a numerically smaller low address, incorrectly passing the bounds check.
This causes next_type to advance to the wrapped address, allowing subsequent
loop iterations to read arbitrary memory and potentially cause out-of-bounds
accesses or crashes.
While this parser logic issue predates this patch, should we address it here
by safely checking the offset instead? For example:
if ((size_t)type_size > (size_t)((char *)end_type - (char *)next_type))
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260417143023.1551481-1-alan.maguire@oracle.com?part=2
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v3 bpf-next 2/6] libbpf: Adjust btf_vlen() to return a __u32
2026-04-17 14:30 ` [PATCH v3 bpf-next 2/6] libbpf: Adjust btf_vlen() to return a __u32 Alan Maguire
2026-04-17 17:07 ` sashiko-bot
@ 2026-04-17 18:26 ` Mykyta Yatsenko
1 sibling, 0 replies; 14+ messages in thread
From: Mykyta Yatsenko @ 2026-04-17 18:26 UTC (permalink / raw)
To: Alan Maguire, ast, daniel, andrii
Cc: martin.lau, eddyz87, memxor, song, yonghong.song, jolsa, qmo, bpf
On 4/17/26 3:30 PM, Alan Maguire wrote:
> Now that vlen is 24 bits, btf_vlen() must return a __u32.
> Adjust use cases in libbpf accordingly. Also add error
> handling to avoid vlen overflow in btf_type_inc_vlen().
>
> Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
> ---
Migrated all vlens in libbpf u16 -> u32, kind does not require widening.
Acked-by: Mykyta Yatsenko <yatsenko@meta.com>
> tools/lib/bpf/btf.c | 50 +++++++++++++++++++++++++--------------
> tools/lib/bpf/btf.h | 2 +-
> tools/lib/bpf/btf_dump.c | 24 +++++++++----------
> tools/lib/bpf/relo_core.c | 16 ++++++-------
> 4 files changed, 53 insertions(+), 39 deletions(-)
>
> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
> index ceb57b46a878..267904939098 100644
> --- a/tools/lib/bpf/btf.c
> +++ b/tools/lib/bpf/btf.c
> @@ -421,7 +421,7 @@ static int btf_type_size_unknown(const struct btf *btf, const struct btf_type *t
> {
> __u32 l_cnt = btf->hdr.layout_len / sizeof(struct btf_layout);
> struct btf_layout *l = btf->layout;
> - __u16 vlen = btf_vlen(t);
> + __u32 vlen = btf_vlen(t);
> __u32 kind = btf_kind(t);
>
> /* Fall back to base BTF if needed as they share layout information */
> @@ -454,7 +454,7 @@ static int btf_type_size_unknown(const struct btf *btf, const struct btf_type *t
> static int btf_type_size(const struct btf *btf, const struct btf_type *t)
> {
> const int base_size = sizeof(struct btf_type);
> - __u16 vlen = btf_vlen(t);
> + __u32 vlen = btf_vlen(t);
>
> switch (btf_kind(t)) {
> case BTF_KIND_FWD:
> @@ -506,7 +506,7 @@ static int btf_bswap_type_rest(struct btf_type *t)
> struct btf_array *a;
> struct btf_param *p;
> struct btf_enum *e;
> - __u16 vlen = btf_vlen(t);
> + __u32 vlen = btf_vlen(t);
> int i;
>
> switch (btf_kind(t)) {
> @@ -1007,7 +1007,7 @@ int btf__align_of(const struct btf *btf, __u32 id)
> case BTF_KIND_STRUCT:
> case BTF_KIND_UNION: {
> const struct btf_member *m = btf_members(t);
> - __u16 vlen = btf_vlen(t);
> + __u32 vlen = btf_vlen(t);
> int i, max_align = 1, align;
>
> for (i = 0; i < vlen; i++, m++) {
> @@ -2121,9 +2121,12 @@ static void *btf_add_type_mem(struct btf *btf, size_t add_sz)
> btf->hdr.type_len, UINT_MAX, add_sz);
> }
>
> -static void btf_type_inc_vlen(struct btf_type *t)
> +static int btf_type_inc_vlen(struct btf_type *t)
> {
> + if (btf_vlen(t) == BTF_MAX_VLEN)
> + return -ENOSPC;
> t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, btf_kflag(t));
> + return 0;
> }
>
> static void btf_hdr_update_type_len(struct btf *btf, int new_len)
> @@ -2652,6 +2655,8 @@ int btf__add_field(struct btf *btf, const char *name, int type_id,
> t = btf_last_type(btf);
> if (!btf_is_composite(t))
> return libbpf_err(-EINVAL);
> + if (btf_vlen(t) == BTF_MAX_VLEN)
> + return libbpf_err(-ENOSPC);
>
> if (validate_type_id(type_id))
> return libbpf_err(-EINVAL);
> @@ -2686,6 +2691,7 @@ int btf__add_field(struct btf *btf, const char *name, int type_id,
>
> /* btf_add_type_mem can invalidate t pointer */
> t = btf_last_type(btf);
> +
> /* update parent type's vlen and kflag */
> t->info = btf_type_info(btf_kind(t), btf_vlen(t) + 1, is_bitfield || btf_kflag(t));
>
> @@ -2796,7 +2802,9 @@ int btf__add_enum_value(struct btf *btf, const char *name, __s64 value)
>
> /* update parent type's vlen */
> t = btf_last_type(btf);
> - btf_type_inc_vlen(t);
> + err = btf_type_inc_vlen(t);
> + if (err)
> + return libbpf_err(err);
>
> /* if negative value, set signedness to signed */
> if (value < 0)
> @@ -2873,7 +2881,9 @@ int btf__add_enum64_value(struct btf *btf, const char *name, __u64 value)
>
> /* update parent type's vlen */
> t = btf_last_type(btf);
> - btf_type_inc_vlen(t);
> + err = btf_type_inc_vlen(t);
> + if (err)
> + return libbpf_err(err);
>
> btf_hdr_update_type_len(btf, btf->hdr.type_len + sz);
> return 0;
> @@ -3115,7 +3125,9 @@ int btf__add_func_param(struct btf *btf, const char *name, int type_id)
>
> /* update parent type's vlen */
> t = btf_last_type(btf);
> - btf_type_inc_vlen(t);
> + err = btf_type_inc_vlen(t);
> + if (err)
> + return libbpf_err(err);
>
> btf_hdr_update_type_len(btf, btf->hdr.type_len + sz);
> return 0;
> @@ -3257,7 +3269,9 @@ int btf__add_datasec_var_info(struct btf *btf, int var_type_id, __u32 offset, __
>
> /* update parent type's vlen */
> t = btf_last_type(btf);
> - btf_type_inc_vlen(t);
> + err = btf_type_inc_vlen(t);
> + if (err)
> + return libbpf_err(err);
>
> btf_hdr_update_type_len(btf, btf->hdr.type_len + sz);
> return 0;
> @@ -4311,7 +4325,7 @@ static long btf_hash_enum(struct btf_type *t)
> static bool btf_equal_enum_members(struct btf_type *t1, struct btf_type *t2)
> {
> const struct btf_enum *m1, *m2;
> - __u16 vlen;
> + __u32 vlen;
> int i;
>
> vlen = btf_vlen(t1);
> @@ -4329,7 +4343,7 @@ static bool btf_equal_enum_members(struct btf_type *t1, struct btf_type *t2)
> static bool btf_equal_enum64_members(struct btf_type *t1, struct btf_type *t2)
> {
> const struct btf_enum64 *m1, *m2;
> - __u16 vlen;
> + __u32 vlen;
> int i;
>
> vlen = btf_vlen(t1);
> @@ -4406,7 +4420,7 @@ static long btf_hash_struct(struct btf_type *t)
> static bool btf_shallow_equal_struct(struct btf_type *t1, struct btf_type *t2)
> {
> const struct btf_member *m1, *m2;
> - __u16 vlen;
> + __u32 vlen;
> int i;
>
> if (!btf_equal_common(t1, t2))
> @@ -4482,7 +4496,7 @@ static bool btf_compat_array(struct btf_type *t1, struct btf_type *t2)
> static long btf_hash_fnproto(struct btf_type *t)
> {
> const struct btf_param *member = btf_params(t);
> - __u16 vlen = btf_vlen(t);
> + __u32 vlen = btf_vlen(t);
> long h = btf_hash_common(t);
> int i;
>
> @@ -4504,7 +4518,7 @@ static long btf_hash_fnproto(struct btf_type *t)
> static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
> {
> const struct btf_param *m1, *m2;
> - __u16 vlen;
> + __u32 vlen;
> int i;
>
> if (!btf_equal_common(t1, t2))
> @@ -4530,7 +4544,7 @@ static bool btf_equal_fnproto(struct btf_type *t1, struct btf_type *t2)
> static bool btf_compat_fnproto(struct btf_type *t1, struct btf_type *t2)
> {
> const struct btf_param *m1, *m2;
> - __u16 vlen;
> + __u32 vlen;
> int i;
>
> /* skip return type ID */
> @@ -5077,7 +5091,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
> case BTF_KIND_STRUCT:
> case BTF_KIND_UNION: {
> const struct btf_member *cand_m, *canon_m;
> - __u16 vlen;
> + __u32 vlen;
>
> if (!btf_shallow_equal_struct(cand_type, canon_type))
> return 0;
> @@ -5105,7 +5119,7 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
>
> case BTF_KIND_FUNC_PROTO: {
> const struct btf_param *cand_p, *canon_p;
> - __u16 vlen;
> + __u32 vlen;
>
> if (!btf_compat_fnproto(cand_type, canon_type))
> return 0;
> @@ -5439,7 +5453,7 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)
>
> case BTF_KIND_FUNC_PROTO: {
> struct btf_param *param;
> - __u16 vlen;
> + __u32 vlen;
> int i;
>
> ref_type_id = btf_dedup_ref_type(d, t->type);
> diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
> index a1f8deca2603..1a31f2da947f 100644
> --- a/tools/lib/bpf/btf.h
> +++ b/tools/lib/bpf/btf.h
> @@ -435,7 +435,7 @@ static inline __u16 btf_kind(const struct btf_type *t)
> return BTF_INFO_KIND(t->info);
> }
>
> -static inline __u16 btf_vlen(const struct btf_type *t)
> +static inline __u32 btf_vlen(const struct btf_type *t)
> {
> return BTF_INFO_VLEN(t->info);
> }
> diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
> index 53c6624161d7..cc1ba65bb6c5 100644
> --- a/tools/lib/bpf/btf_dump.c
> +++ b/tools/lib/bpf/btf_dump.c
> @@ -316,7 +316,7 @@ static int btf_dump_mark_referenced(struct btf_dump *d)
> {
> int i, j, n = btf__type_cnt(d->btf);
> const struct btf_type *t;
> - __u16 vlen;
> + __u32 vlen;
>
> for (i = d->last_id + 1; i < n; i++) {
> t = btf__type_by_id(d->btf, i);
> @@ -485,7 +485,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
> */
> struct btf_dump_type_aux_state *tstate = &d->type_states[id];
> const struct btf_type *t;
> - __u16 vlen;
> + __u32 vlen;
> int err, i;
>
> /* return true, letting typedefs know that it's ok to be emitted */
> @@ -798,7 +798,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
> */
> if (top_level_def || t->name_off == 0) {
> const struct btf_member *m = btf_members(t);
> - __u16 vlen = btf_vlen(t);
> + __u32 vlen = btf_vlen(t);
> int i, new_cont_id;
>
> new_cont_id = t->name_off == 0 ? cont_id : id;
> @@ -820,7 +820,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
> break;
> case BTF_KIND_FUNC_PROTO: {
> const struct btf_param *p = btf_params(t);
> - __u16 n = btf_vlen(t);
> + __u32 n = btf_vlen(t);
> int i;
>
> btf_dump_emit_type(d, t->type, cont_id);
> @@ -839,7 +839,7 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
> {
> const struct btf_member *m;
> int max_align = 1, align, i, bit_sz;
> - __u16 vlen;
> + __u32 vlen;
>
> m = btf_members(t);
> vlen = btf_vlen(t);
> @@ -973,7 +973,7 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
> bool is_struct = btf_is_struct(t);
> bool packed, prev_bitfield = false;
> int align, i, off = 0;
> - __u16 vlen = btf_vlen(t);
> + __u32 vlen = btf_vlen(t);
>
> align = btf__align_of(d->btf, id);
> packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;
> @@ -1064,7 +1064,7 @@ static void btf_dump_emit_enum_fwd(struct btf_dump *d, __u32 id,
>
> static void btf_dump_emit_enum32_val(struct btf_dump *d,
> const struct btf_type *t,
> - int lvl, __u16 vlen)
> + int lvl, __u32 vlen)
> {
> const struct btf_enum *v = btf_enum(t);
> bool is_signed = btf_kflag(t);
> @@ -1089,7 +1089,7 @@ static void btf_dump_emit_enum32_val(struct btf_dump *d,
>
> static void btf_dump_emit_enum64_val(struct btf_dump *d,
> const struct btf_type *t,
> - int lvl, __u16 vlen)
> + int lvl, __u32 vlen)
> {
> const struct btf_enum64 *v = btf_enum64(t);
> bool is_signed = btf_kflag(t);
> @@ -1122,7 +1122,7 @@ static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
> const struct btf_type *t,
> int lvl)
> {
> - __u16 vlen = btf_vlen(t);
> + __u32 vlen = btf_vlen(t);
>
> btf_dump_printf(d, "enum%s%s",
> t->name_off ? " " : "",
> @@ -1542,7 +1542,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
> }
> case BTF_KIND_FUNC_PROTO: {
> const struct btf_param *p = btf_params(t);
> - __u16 vlen = btf_vlen(t);
> + __u32 vlen = btf_vlen(t);
> int i;
>
> /*
> @@ -2159,7 +2159,7 @@ static int btf_dump_struct_data(struct btf_dump *d,
> const void *data)
> {
> const struct btf_member *m = btf_members(t);
> - __u16 n = btf_vlen(t);
> + __u32 n = btf_vlen(t);
> int i, err = 0;
>
> /* note that we increment depth before calling btf_dump_print() below;
> @@ -2449,7 +2449,7 @@ static int btf_dump_type_data_check_zero(struct btf_dump *d,
> case BTF_KIND_STRUCT:
> case BTF_KIND_UNION: {
> const struct btf_member *m = btf_members(t);
> - __u16 n = btf_vlen(t);
> + __u32 n = btf_vlen(t);
>
> /* if any struct/union member is non-zero, the struct/union
> * is considered non-zero and dumped.
> diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c
> index 0ccc8f548cba..6ae3f2a15ad0 100644
> --- a/tools/lib/bpf/relo_core.c
> +++ b/tools/lib/bpf/relo_core.c
> @@ -191,8 +191,8 @@ int __bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
> case BTF_KIND_FUNC_PROTO: {
> struct btf_param *local_p = btf_params(local_type);
> struct btf_param *targ_p = btf_params(targ_type);
> - __u16 local_vlen = btf_vlen(local_type);
> - __u16 targ_vlen = btf_vlen(targ_type);
> + __u32 local_vlen = btf_vlen(local_type);
> + __u32 targ_vlen = btf_vlen(targ_type);
> int i, err;
>
> if (local_vlen != targ_vlen)
> @@ -1457,8 +1457,8 @@ static bool bpf_core_names_match(const struct btf *local_btf, size_t local_name_
> static int bpf_core_enums_match(const struct btf *local_btf, const struct btf_type *local_t,
> const struct btf *targ_btf, const struct btf_type *targ_t)
> {
> - __u16 local_vlen = btf_vlen(local_t);
> - __u16 targ_vlen = btf_vlen(targ_t);
> + __u32 local_vlen = btf_vlen(local_t);
> + __u32 targ_vlen = btf_vlen(targ_t);
> int i, j;
>
> if (local_t->size != targ_t->size)
> @@ -1498,8 +1498,8 @@ static int bpf_core_composites_match(const struct btf *local_btf, const struct b
> bool behind_ptr, int level)
> {
> const struct btf_member *local_m = btf_members(local_t);
> - __u16 local_vlen = btf_vlen(local_t);
> - __u16 targ_vlen = btf_vlen(targ_t);
> + __u32 local_vlen = btf_vlen(local_t);
> + __u32 targ_vlen = btf_vlen(targ_t);
> int i, j, err;
>
> if (local_vlen > targ_vlen)
> @@ -1674,8 +1674,8 @@ int __bpf_core_types_match(const struct btf *local_btf, __u32 local_id, const st
> case BTF_KIND_FUNC_PROTO: {
> struct btf_param *local_p = btf_params(local_t);
> struct btf_param *targ_p = btf_params(targ_t);
> - __u16 local_vlen = btf_vlen(local_t);
> - __u16 targ_vlen = btf_vlen(targ_t);
> + __u32 local_vlen = btf_vlen(local_t);
> + __u32 targ_vlen = btf_vlen(targ_t);
> int i, err;
>
> if (local_k != targ_k)
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 bpf-next 3/6] bpftool: Support 24-bit vlen
2026-04-17 14:30 [PATCH v3 bpf-next 0/6] bpf: Extend BTF UAPI vlen, kinds to use unused bits Alan Maguire
2026-04-17 14:30 ` [PATCH v3 bpf-next 1/6] " Alan Maguire
2026-04-17 14:30 ` [PATCH v3 bpf-next 2/6] libbpf: Adjust btf_vlen() to return a __u32 Alan Maguire
@ 2026-04-17 14:30 ` Alan Maguire
2026-04-17 18:36 ` Mykyta Yatsenko
2026-04-17 14:30 ` [PATCH v3 bpf-next 4/6] selftests/bpf: Fix up btf/invalid test for extended kind Alan Maguire
` (2 subsequent siblings)
5 siblings, 1 reply; 14+ messages in thread
From: Alan Maguire @ 2026-04-17 14:30 UTC (permalink / raw)
To: ast, daniel, andrii
Cc: martin.lau, eddyz87, memxor, song, yonghong.song, jolsa, qmo,
mykyta.yatsenko5, bpf, Alan Maguire
Adjust btf_vlen() usage to handle 24-bit vlen.
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
tools/bpf/bpftool/btf.c | 17 ++++++-----------
tools/bpf/bpftool/btf_dumper.c | 4 ++--
tools/bpf/bpftool/gen.c | 16 +++++++++-------
3 files changed, 17 insertions(+), 20 deletions(-)
diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c
index 2e899e940034..6ef908adf3a4 100644
--- a/tools/bpf/bpftool/btf.c
+++ b/tools/bpf/bpftool/btf.c
@@ -179,8 +179,7 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
case BTF_KIND_STRUCT:
case BTF_KIND_UNION: {
const struct btf_member *m = (const void *)(t + 1);
- __u16 vlen = BTF_INFO_VLEN(t->info);
- int i;
+ __u32 i, vlen = BTF_INFO_VLEN(t->info);
if (json_output) {
jsonw_uint_field(w, "size", t->size);
@@ -225,9 +224,8 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
}
case BTF_KIND_ENUM: {
const struct btf_enum *v = (const void *)(t + 1);
- __u16 vlen = BTF_INFO_VLEN(t->info);
+ __u32 i, vlen = BTF_INFO_VLEN(t->info);
const char *encoding;
- int i;
encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
if (json_output) {
@@ -263,9 +261,8 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
}
case BTF_KIND_ENUM64: {
const struct btf_enum64 *v = btf_enum64(t);
- __u16 vlen = btf_vlen(t);
+ __u32 i, vlen = btf_vlen(t);
const char *encoding;
- int i;
encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
if (json_output) {
@@ -325,8 +322,7 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
}
case BTF_KIND_FUNC_PROTO: {
const struct btf_param *p = (const void *)(t + 1);
- __u16 vlen = BTF_INFO_VLEN(t->info);
- int i;
+ __u32 i, vlen = BTF_INFO_VLEN(t->info);
if (json_output) {
jsonw_uint_field(w, "ret_type_id", t->type);
@@ -369,8 +365,7 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
case BTF_KIND_DATASEC: {
const struct btf_var_secinfo *v = (const void *)(t + 1);
const struct btf_type *vt;
- __u16 vlen = BTF_INFO_VLEN(t->info);
- int i;
+ __u32 i, vlen = BTF_INFO_VLEN(t->info);
if (json_output) {
jsonw_uint_field(w, "size", t->size);
@@ -675,7 +670,7 @@ static __u64 btf_name_hasher(__u64 hash, const struct btf *btf, __u32 name_off)
static __u64 btf_type_disambig_hash(const struct btf *btf, __u32 id, bool include_members)
{
const struct btf_type *t = btf__type_by_id(btf, id);
- int i;
+ __u32 i;
size_t hash = 0;
hash = btf_name_hasher(hash, btf, t->name_off);
diff --git a/tools/bpf/bpftool/btf_dumper.c b/tools/bpf/bpftool/btf_dumper.c
index def297e879f4..9dc8425b1789 100644
--- a/tools/bpf/bpftool/btf_dumper.c
+++ b/tools/bpf/bpftool/btf_dumper.c
@@ -150,7 +150,7 @@ static int btf_dumper_enum(const struct btf_dumper *d,
{
const struct btf_enum *enums = btf_enum(t);
__s64 value;
- __u16 i;
+ __u32 i;
switch (t->size) {
case 8:
@@ -189,7 +189,7 @@ static int btf_dumper_enum64(const struct btf_dumper *d,
const struct btf_enum64 *enums = btf_enum64(t);
__u32 val_lo32, val_hi32;
__u64 value;
- __u16 i;
+ __u32 i;
value = *(__u64 *)data;
val_lo32 = (__u32)value;
diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index 2f9e10752e28..37159e02f418 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -2094,7 +2094,8 @@ btfgen_mark_type(struct btfgen_info *info, unsigned int type_id, bool follow_poi
struct btf_type *cloned_type;
struct btf_param *param;
struct btf_array *array;
- int err, i;
+ __u32 i;
+ int err;
if (type_id == 0)
return 0;
@@ -2229,7 +2230,8 @@ static int btfgen_mark_type_match(struct btfgen_info *info, __u32 type_id, bool
const struct btf_type *btf_type;
struct btf *btf = info->src_btf;
struct btf_type *cloned_type;
- int i, err;
+ int err;
+ __u32 i;
if (type_id == 0)
return 0;
@@ -2249,7 +2251,7 @@ static int btfgen_mark_type_match(struct btfgen_info *info, __u32 type_id, bool
case BTF_KIND_STRUCT:
case BTF_KIND_UNION: {
struct btf_member *m = btf_members(btf_type);
- __u16 vlen = btf_vlen(btf_type);
+ __u32 vlen = btf_vlen(btf_type);
if (behind_ptr)
break;
@@ -2286,7 +2288,7 @@ static int btfgen_mark_type_match(struct btfgen_info *info, __u32 type_id, bool
break;
}
case BTF_KIND_FUNC_PROTO: {
- __u16 vlen = btf_vlen(btf_type);
+ __u32 vlen = btf_vlen(btf_type);
struct btf_param *param;
/* mark ret type */
@@ -2492,8 +2494,9 @@ static struct btf *btfgen_get_btf(struct btfgen_info *info)
{
struct btf *btf_new = NULL;
unsigned int *ids = NULL;
- unsigned int i, n = btf__type_cnt(info->marked_btf);
+ unsigned int n = btf__type_cnt(info->marked_btf);
int err = 0;
+ __u32 i;
btf_new = btf__new_empty();
if (!btf_new) {
@@ -2523,8 +2526,7 @@ static struct btf *btfgen_get_btf(struct btfgen_info *info)
/* add members for struct and union */
if (btf_is_composite(type)) {
struct btf_member *cloned_m, *m;
- unsigned short vlen;
- int idx_src;
+ __u32 vlen, idx_src;
name = btf__str_by_offset(info->src_btf, type->name_off);
--
2.39.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v3 bpf-next 3/6] bpftool: Support 24-bit vlen
2026-04-17 14:30 ` [PATCH v3 bpf-next 3/6] bpftool: Support 24-bit vlen Alan Maguire
@ 2026-04-17 18:36 ` Mykyta Yatsenko
0 siblings, 0 replies; 14+ messages in thread
From: Mykyta Yatsenko @ 2026-04-17 18:36 UTC (permalink / raw)
To: Alan Maguire, ast, daniel, andrii
Cc: martin.lau, eddyz87, memxor, song, yonghong.song, jolsa, qmo, bpf
On 4/17/26 3:30 PM, Alan Maguire wrote:
> Adjust btf_vlen() usage to handle 24-bit vlen.
>
> Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
> ---
> tools/bpf/bpftool/btf.c | 17 ++++++-----------
> tools/bpf/bpftool/btf_dumper.c | 4 ++--
> tools/bpf/bpftool/gen.c | 16 +++++++++-------
> 3 files changed, 17 insertions(+), 20 deletions(-)
>
> diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c
> index 2e899e940034..6ef908adf3a4 100644
> --- a/tools/bpf/bpftool/btf.c
> +++ b/tools/bpf/bpftool/btf.c
> @@ -179,8 +179,7 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
> case BTF_KIND_STRUCT:
> case BTF_KIND_UNION: {
> const struct btf_member *m = (const void *)(t + 1);
> - __u16 vlen = BTF_INFO_VLEN(t->info);
> - int i;
> + __u32 i, vlen = BTF_INFO_VLEN(t->info);
>
> if (json_output) {
> jsonw_uint_field(w, "size", t->size);
> @@ -225,9 +224,8 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
> }
> case BTF_KIND_ENUM: {
> const struct btf_enum *v = (const void *)(t + 1);
> - __u16 vlen = BTF_INFO_VLEN(t->info);
> + __u32 i, vlen = BTF_INFO_VLEN(t->info);
> const char *encoding;
> - int i;
>
> encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
> if (json_output) {
> @@ -263,9 +261,8 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
> }
> case BTF_KIND_ENUM64: {
> const struct btf_enum64 *v = btf_enum64(t);
> - __u16 vlen = btf_vlen(t);
> + __u32 i, vlen = btf_vlen(t);
> const char *encoding;
> - int i;
>
> encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
> if (json_output) {
> @@ -325,8 +322,7 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
> }
> case BTF_KIND_FUNC_PROTO: {
> const struct btf_param *p = (const void *)(t + 1);
> - __u16 vlen = BTF_INFO_VLEN(t->info);
> - int i;
> + __u32 i, vlen = BTF_INFO_VLEN(t->info);
>
> if (json_output) {
> jsonw_uint_field(w, "ret_type_id", t->type);
> @@ -369,8 +365,7 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
> case BTF_KIND_DATASEC: {
> const struct btf_var_secinfo *v = (const void *)(t + 1);
> const struct btf_type *vt;
> - __u16 vlen = BTF_INFO_VLEN(t->info);
> - int i;
> + __u32 i, vlen = BTF_INFO_VLEN(t->info);
>
> if (json_output) {
> jsonw_uint_field(w, "size", t->size);
> @@ -675,7 +670,7 @@ static __u64 btf_name_hasher(__u64 hash, const struct btf *btf, __u32 name_off)
> static __u64 btf_type_disambig_hash(const struct btf *btf, __u32 id, bool include_members)
> {
> const struct btf_type *t = btf__type_by_id(btf, id);
> - int i;
> + __u32 i;
in libbpf, kernel and btf_dumper.c we did not migrate those callsites
that use int for vlen, but we do it here. Not an issue, of course,
either way it's correct.
> size_t hash = 0;
>
> hash = btf_name_hasher(hash, btf, t->name_off);
> diff --git a/tools/bpf/bpftool/btf_dumper.c b/tools/bpf/bpftool/btf_dumper.c
> index def297e879f4..9dc8425b1789 100644
> --- a/tools/bpf/bpftool/btf_dumper.c
> +++ b/tools/bpf/bpftool/btf_dumper.c
> @@ -150,7 +150,7 @@ static int btf_dumper_enum(const struct btf_dumper *d,
> {
> const struct btf_enum *enums = btf_enum(t);
> __s64 value;
> - __u16 i;
> + __u32 i;
>
> switch (t->size) {
> case 8:
> @@ -189,7 +189,7 @@ static int btf_dumper_enum64(const struct btf_dumper *d,
> const struct btf_enum64 *enums = btf_enum64(t);
> __u32 val_lo32, val_hi32;
> __u64 value;
> - __u16 i;
> + __u32 i;
>
> value = *(__u64 *)data;
> val_lo32 = (__u32)value;
> diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
> index 2f9e10752e28..37159e02f418 100644
> --- a/tools/bpf/bpftool/gen.c
> +++ b/tools/bpf/bpftool/gen.c
> @@ -2094,7 +2094,8 @@ btfgen_mark_type(struct btfgen_info *info, unsigned int type_id, bool follow_poi
> struct btf_type *cloned_type;
> struct btf_param *param;
> struct btf_array *array;
> - int err, i;
> + __u32 i;
> + int err;
>
> if (type_id == 0)
> return 0;
> @@ -2229,7 +2230,8 @@ static int btfgen_mark_type_match(struct btfgen_info *info, __u32 type_id, bool
> const struct btf_type *btf_type;
> struct btf *btf = info->src_btf;
> struct btf_type *cloned_type;
> - int i, err;
> + int err;
> + __u32 i;
>
> if (type_id == 0)
> return 0;
> @@ -2249,7 +2251,7 @@ static int btfgen_mark_type_match(struct btfgen_info *info, __u32 type_id, bool
> case BTF_KIND_STRUCT:
> case BTF_KIND_UNION: {
> struct btf_member *m = btf_members(btf_type);
> - __u16 vlen = btf_vlen(btf_type);
> + __u32 vlen = btf_vlen(btf_type);
>
> if (behind_ptr)
> break;
> @@ -2286,7 +2288,7 @@ static int btfgen_mark_type_match(struct btfgen_info *info, __u32 type_id, bool
> break;
> }
> case BTF_KIND_FUNC_PROTO: {
> - __u16 vlen = btf_vlen(btf_type);
> + __u32 vlen = btf_vlen(btf_type);
> struct btf_param *param;
>
> /* mark ret type */
> @@ -2492,8 +2494,9 @@ static struct btf *btfgen_get_btf(struct btfgen_info *info)
> {
> struct btf *btf_new = NULL;
> unsigned int *ids = NULL;
> - unsigned int i, n = btf__type_cnt(info->marked_btf);
> + unsigned int n = btf__type_cnt(info->marked_btf);
> int err = 0;
> + __u32 i;
>
> btf_new = btf__new_empty();
> if (!btf_new) {
> @@ -2523,8 +2526,7 @@ static struct btf *btfgen_get_btf(struct btfgen_info *info)
> /* add members for struct and union */
> if (btf_is_composite(type)) {
> struct btf_member *cloned_m, *m;
> - unsigned short vlen;
> - int idx_src;
> + __u32 vlen, idx_src;
>
> name = btf__str_by_offset(info->src_btf, type->name_off);
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 bpf-next 4/6] selftests/bpf: Fix up btf/invalid test for extended kind
2026-04-17 14:30 [PATCH v3 bpf-next 0/6] bpf: Extend BTF UAPI vlen, kinds to use unused bits Alan Maguire
` (2 preceding siblings ...)
2026-04-17 14:30 ` [PATCH v3 bpf-next 3/6] bpftool: Support 24-bit vlen Alan Maguire
@ 2026-04-17 14:30 ` Alan Maguire
2026-04-17 19:07 ` Mykyta Yatsenko
2026-04-17 14:30 ` [PATCH v3 bpf-next 5/6] selftests/bpf: Fix up __u16 vlen assumptions Alan Maguire
2026-04-17 14:30 ` [PATCH v3 bpf-next 6/6] Documentation/bpf: Update btf doc with updated vlen, kind sizes Alan Maguire
5 siblings, 1 reply; 14+ messages in thread
From: Alan Maguire @ 2026-04-17 14:30 UTC (permalink / raw)
To: ast, daniel, andrii
Cc: martin.lau, eddyz87, memxor, song, yonghong.song, jolsa, qmo,
mykyta.yatsenko5, bpf, Alan Maguire
With extended kinds, 32 becomes a valid (but not used)
BTF info kind value; fix up the test to check for the
"Invalid kind" rather than "Invalid btf_info" message.
Since all bits are used in BTF info, it is no longer
possible to craft an invalid BTF info value. Use
127 (new maximum possible kind value).
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
tools/testing/selftests/bpf/prog_tests/btf.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c
index 054ecb6b1e9f..0cc347e32db3 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf.c
@@ -1924,11 +1924,11 @@ static struct btf_raw_test raw_tests[] = {
},
{
- .descr = "invalid BTF_INFO",
+ .descr = "invalid BTF kind",
.raw_types = {
/* int */ /* [1] */
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
- BTF_TYPE_ENC(0, 0x20000000, 4),
+ BTF_TYPE_ENC(0, 0x7f000000, 4),
BTF_END_RAW,
},
.str_sec = "",
@@ -1941,7 +1941,7 @@ static struct btf_raw_test raw_tests[] = {
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
- .err_str = "Invalid btf_info",
+ .err_str = "Invalid kind",
},
{
--
2.39.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v3 bpf-next 4/6] selftests/bpf: Fix up btf/invalid test for extended kind
2026-04-17 14:30 ` [PATCH v3 bpf-next 4/6] selftests/bpf: Fix up btf/invalid test for extended kind Alan Maguire
@ 2026-04-17 19:07 ` Mykyta Yatsenko
0 siblings, 0 replies; 14+ messages in thread
From: Mykyta Yatsenko @ 2026-04-17 19:07 UTC (permalink / raw)
To: Alan Maguire, ast, daniel, andrii
Cc: martin.lau, eddyz87, memxor, song, yonghong.song, jolsa, qmo, bpf
On 4/17/26 3:30 PM, Alan Maguire wrote:
> With extended kinds, 32 becomes a valid (but not used)
> BTF info kind value; fix up the test to check for the
> "Invalid kind" rather than "Invalid btf_info" message.
> Since all bits are used in BTF info, it is no longer
> possible to craft an invalid BTF info value. Use
> 127 (new maximum possible kind value).
>
> Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
> ---
Acked-by: Mykyta Yatsenko <yatsenko@meta.com>
> tools/testing/selftests/bpf/prog_tests/btf.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c
> index 054ecb6b1e9f..0cc347e32db3 100644
> --- a/tools/testing/selftests/bpf/prog_tests/btf.c
> +++ b/tools/testing/selftests/bpf/prog_tests/btf.c
> @@ -1924,11 +1924,11 @@ static struct btf_raw_test raw_tests[] = {
> },
>
> {
> - .descr = "invalid BTF_INFO",
> + .descr = "invalid BTF kind",
> .raw_types = {
> /* int */ /* [1] */
> BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
> - BTF_TYPE_ENC(0, 0x20000000, 4),
> + BTF_TYPE_ENC(0, 0x7f000000, 4),
> BTF_END_RAW,
> },
> .str_sec = "",
> @@ -1941,7 +1941,7 @@ static struct btf_raw_test raw_tests[] = {
> .value_type_id = 1,
> .max_entries = 4,
> .btf_load_err = true,
> - .err_str = "Invalid btf_info",
> + .err_str = "Invalid kind",
> },
>
> {
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 bpf-next 5/6] selftests/bpf: Fix up __u16 vlen assumptions
2026-04-17 14:30 [PATCH v3 bpf-next 0/6] bpf: Extend BTF UAPI vlen, kinds to use unused bits Alan Maguire
` (3 preceding siblings ...)
2026-04-17 14:30 ` [PATCH v3 bpf-next 4/6] selftests/bpf: Fix up btf/invalid test for extended kind Alan Maguire
@ 2026-04-17 14:30 ` Alan Maguire
2026-04-17 19:06 ` Mykyta Yatsenko
2026-04-17 14:30 ` [PATCH v3 bpf-next 6/6] Documentation/bpf: Update btf doc with updated vlen, kind sizes Alan Maguire
5 siblings, 1 reply; 14+ messages in thread
From: Alan Maguire @ 2026-04-17 14:30 UTC (permalink / raw)
To: ast, daniel, andrii
Cc: martin.lau, eddyz87, memxor, song, yonghong.song, jolsa, qmo,
mykyta.yatsenko5, bpf, Alan Maguire
Fix up a few cases where we assume vlen is 16 bits.
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
tools/testing/selftests/bpf/prog_tests/btf.c | 2 +-
tools/testing/selftests/bpf/prog_tests/btf_dedup_split.c | 3 +--
tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c | 3 +--
tools/testing/selftests/bpf/test_progs.c | 2 +-
4 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c
index 0cc347e32db3..a9de328a8697 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf.c
@@ -8092,7 +8092,7 @@ static struct btf_dedup_test dedup_tests[] = {
static int btf_type_size(const struct btf_type *t)
{
int base_size = sizeof(struct btf_type);
- __u16 vlen = BTF_INFO_VLEN(t->info);
+ __u32 vlen = BTF_INFO_VLEN(t->info);
__u16 kind = BTF_INFO_KIND(t->info);
switch (kind) {
diff --git a/tools/testing/selftests/bpf/prog_tests/btf_dedup_split.c b/tools/testing/selftests/bpf/prog_tests/btf_dedup_split.c
index 5bc15bb6b7ce..6bc31236805c 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf_dedup_split.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf_dedup_split.c
@@ -487,9 +487,8 @@ static void test_split_module(void)
for (i = 0; i < ARRAY_SIZE(mod_funcs); i++) {
const struct btf_param *p;
const struct btf_type *t;
- __u16 vlen;
+ __u32 vlen, j;
__u32 id;
- int j;
id = btf__find_by_name_kind(btf1, mod_funcs[i], BTF_KIND_FUNC);
if (!ASSERT_GE(id, nr_base_types, "func_id"))
diff --git a/tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c b/tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c
index 469e92869523..5064aeb8fe67 100644
--- a/tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c
+++ b/tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c
@@ -253,8 +253,7 @@ static int find_field_offset_aux(struct btf *btf, int btf_id, char *field_name,
{
const struct btf_type *type = btf__type_by_id(btf, btf_id);
const struct btf_member *m;
- __u16 mnum;
- int i;
+ __u32 mnum, i;
if (!type) {
PRINT_FAIL("Can't find btf_type for id %d\n", btf_id);
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
index 7fe16b5131b1..cc14b13e23fe 100644
--- a/tools/testing/selftests/bpf/test_progs.c
+++ b/tools/testing/selftests/bpf/test_progs.c
@@ -1257,7 +1257,7 @@ int get_bpf_max_tramp_links_from(struct btf *btf)
const struct btf_type *t;
__u32 i, type_cnt;
const char *name;
- __u16 j, vlen;
+ __u32 j, vlen;
for (i = 1, type_cnt = btf__type_cnt(btf); i < type_cnt; i++) {
t = btf__type_by_id(btf, i);
--
2.39.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v3 bpf-next 5/6] selftests/bpf: Fix up __u16 vlen assumptions
2026-04-17 14:30 ` [PATCH v3 bpf-next 5/6] selftests/bpf: Fix up __u16 vlen assumptions Alan Maguire
@ 2026-04-17 19:06 ` Mykyta Yatsenko
0 siblings, 0 replies; 14+ messages in thread
From: Mykyta Yatsenko @ 2026-04-17 19:06 UTC (permalink / raw)
To: Alan Maguire, ast, daniel, andrii
Cc: martin.lau, eddyz87, memxor, song, yonghong.song, jolsa, qmo, bpf
On 4/17/26 3:30 PM, Alan Maguire wrote:
> Fix up a few cases where we assume vlen is 16 bits.
>
> Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
> ---
Acked-by: Mykyta Yatsenko <yatsenko@meta.com>
> tools/testing/selftests/bpf/prog_tests/btf.c | 2 +-
> tools/testing/selftests/bpf/prog_tests/btf_dedup_split.c | 3 +--
> tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c | 3 +--
> tools/testing/selftests/bpf/test_progs.c | 2 +-
> 4 files changed, 4 insertions(+), 6 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c
> index 0cc347e32db3..a9de328a8697 100644
> --- a/tools/testing/selftests/bpf/prog_tests/btf.c
> +++ b/tools/testing/selftests/bpf/prog_tests/btf.c
> @@ -8092,7 +8092,7 @@ static struct btf_dedup_test dedup_tests[] = {
> static int btf_type_size(const struct btf_type *t)
> {
> int base_size = sizeof(struct btf_type);
> - __u16 vlen = BTF_INFO_VLEN(t->info);
> + __u32 vlen = BTF_INFO_VLEN(t->info);
> __u16 kind = BTF_INFO_KIND(t->info);
>
> switch (kind) {
> diff --git a/tools/testing/selftests/bpf/prog_tests/btf_dedup_split.c b/tools/testing/selftests/bpf/prog_tests/btf_dedup_split.c
> index 5bc15bb6b7ce..6bc31236805c 100644
> --- a/tools/testing/selftests/bpf/prog_tests/btf_dedup_split.c
> +++ b/tools/testing/selftests/bpf/prog_tests/btf_dedup_split.c
> @@ -487,9 +487,8 @@ static void test_split_module(void)
> for (i = 0; i < ARRAY_SIZE(mod_funcs); i++) {
> const struct btf_param *p;
> const struct btf_type *t;
> - __u16 vlen;
> + __u32 vlen, j;
> __u32 id;
> - int j;
>
> id = btf__find_by_name_kind(btf1, mod_funcs[i], BTF_KIND_FUNC);
> if (!ASSERT_GE(id, nr_base_types, "func_id"))
> diff --git a/tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c b/tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c
> index 469e92869523..5064aeb8fe67 100644
> --- a/tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c
> +++ b/tools/testing/selftests/bpf/prog_tests/ctx_rewrite.c
> @@ -253,8 +253,7 @@ static int find_field_offset_aux(struct btf *btf, int btf_id, char *field_name,
> {
> const struct btf_type *type = btf__type_by_id(btf, btf_id);
> const struct btf_member *m;
> - __u16 mnum;
> - int i;
> + __u32 mnum, i;
>
> if (!type) {
> PRINT_FAIL("Can't find btf_type for id %d\n", btf_id);
> diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
> index 7fe16b5131b1..cc14b13e23fe 100644
> --- a/tools/testing/selftests/bpf/test_progs.c
> +++ b/tools/testing/selftests/bpf/test_progs.c
> @@ -1257,7 +1257,7 @@ int get_bpf_max_tramp_links_from(struct btf *btf)
> const struct btf_type *t;
> __u32 i, type_cnt;
> const char *name;
> - __u16 j, vlen;
> + __u32 j, vlen;
>
> for (i = 1, type_cnt = btf__type_cnt(btf); i < type_cnt; i++) {
> t = btf__type_by_id(btf, i);
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 bpf-next 6/6] Documentation/bpf: Update btf doc with updated vlen, kind sizes
2026-04-17 14:30 [PATCH v3 bpf-next 0/6] bpf: Extend BTF UAPI vlen, kinds to use unused bits Alan Maguire
` (4 preceding siblings ...)
2026-04-17 14:30 ` [PATCH v3 bpf-next 5/6] selftests/bpf: Fix up __u16 vlen assumptions Alan Maguire
@ 2026-04-17 14:30 ` Alan Maguire
2026-04-17 15:39 ` bot+bpf-ci
5 siblings, 1 reply; 14+ messages in thread
From: Alan Maguire @ 2026-04-17 14:30 UTC (permalink / raw)
To: ast, daniel, andrii
Cc: martin.lau, eddyz87, memxor, song, yonghong.song, jolsa, qmo,
mykyta.yatsenko5, bpf, Alan Maguire
Sync doc with updated UAPI changes utilizing unused bts for
extended vlen, kind values.
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
Documentation/bpf/btf.rst | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/Documentation/bpf/btf.rst b/Documentation/bpf/btf.rst
index 3b60583f5db2..3f05f17990ad 100644
--- a/Documentation/bpf/btf.rst
+++ b/Documentation/bpf/btf.rst
@@ -97,10 +97,8 @@ Each type contains the following common data::
struct btf_type {
__u32 name_off;
/* "info" bits arrangement
- * bits 0-15: vlen (e.g. # of struct's members)
- * bits 16-23: unused
- * bits 24-28: kind (e.g. int, ptr, array...etc)
- * bits 29-30: unused
+ * bits 0-23: vlen (e.g. # of struct's members)
+ * bits 24-30: kind (e.g. int, ptr, array...etc)
* bit 31: kind_flag, currently used by
* struct, union, enum, fwd, enum64,
* decl_tag and type_tag
--
2.39.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v3 bpf-next 6/6] Documentation/bpf: Update btf doc with updated vlen, kind sizes
2026-04-17 14:30 ` [PATCH v3 bpf-next 6/6] Documentation/bpf: Update btf doc with updated vlen, kind sizes Alan Maguire
@ 2026-04-17 15:39 ` bot+bpf-ci
0 siblings, 0 replies; 14+ messages in thread
From: bot+bpf-ci @ 2026-04-17 15:39 UTC (permalink / raw)
To: alan.maguire, ast, daniel, andrii
Cc: martin.lau, eddyz87, memxor, song, yonghong.song, jolsa, qmo,
mykyta.yatsenko5, bpf, alan.maguire, ast, andrii, daniel,
martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 1977 bytes --]
> diff --git a/Documentation/bpf/btf.rst b/Documentation/bpf/btf.rst
> index 3b60583f5db2..3f05f17990ad 100644
> --- a/Documentation/bpf/btf.rst
> +++ b/Documentation/bpf/btf.rst
> @@ -97,10 +97,8 @@ Each type contains the following common data::
> struct btf_type {
> __u32 name_off;
> /* "info" bits arrangement
> - * bits 0-15: vlen (e.g. # of struct's members)
> - * bits 16-23: unused
> - * bits 24-28: kind (e.g. int, ptr, array...etc)
> - * bits 29-30: unused
> + * bits 0-23: vlen (e.g. # of struct's members)
> + * bits 24-30: kind (e.g. int, ptr, array...etc)
Does the kind field documentation accurately match the UAPI implementation?
The UAPI defines BTF_INFO_KIND as:
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x7f)
The mask 0x7f is 7 bits, which means kind occupies bits 24-30. This
documentation shows "bits 24-30" which appears correct.
However, checking the actual implementation confirms the kind field uses
only 7 bits (0x7f mask), leaving bit 31 exclusively for kind_flag.
Should the documentation have removed the "bits 16-23: unused" description?
The previous documentation listed bits 16-23 as unused, but after expanding
vlen to bits 0-23, these bits are now part of vlen. The current bit
allocation is:
- Bits 0-23: vlen (24 bits)
- Bits 24-30: kind (7 bits)
- Bit 31: kind_flag (1 bit)
The patch removes the "bits 16-23: unused" line from the struct comment,
which correctly reflects that these bits are now part of the expanded vlen
field.
> * bit 31: kind_flag, currently used by
> * struct, union, enum, fwd, enum64,
> * decl_tag and type_tag
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/24570998051
^ permalink raw reply [flat|nested] 14+ messages in thread