From: Mykyta Yatsenko The verifier currently special-cases dynptr initialization kfuncs to set the correct dynptr type for an uninitialized argument. This patch moves that logic into kfunc metadata. Introduce KF_DYNPTR_* kfunc flags and a helper, dynptr_type_from_kfunc_flags(), which translates those flags into the appropriate DYNPTR_TYPE_* mask. With the type encoded in the kfunc declaration, the verifier no longer needs explicit checks for bpf_dynptr_from_xdp(), bpf_dynptr_from_skb(), and bpf_dynptr_from_skb_meta(). This simplifies the verifier and centralizes dynptr typing in kfunc declarations, with no user-visible behavior change. Signed-off-by: Mykyta Yatsenko --- include/linux/btf.h | 3 +++ kernel/bpf/verifier.c | 31 +++++++++++++++++++++++-------- net/core/filter.c | 6 +++--- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/include/linux/btf.h b/include/linux/btf.h index 9eda6b113f9b..d41d6a0d1085 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -79,6 +79,9 @@ #define KF_ARENA_RET (1 << 13) /* kfunc returns an arena pointer */ #define KF_ARENA_ARG1 (1 << 14) /* kfunc takes an arena pointer as its first argument */ #define KF_ARENA_ARG2 (1 << 15) /* kfunc takes an arena pointer as its second argument */ +#define KF_DYNPTR_XDP (1 << 16) /* kfunc takes dynptr to XDP */ +#define KF_DYNPTR_SKB (1 << 17) /* kfunc takes dynptr to SKB */ +#define KF_DYNPTR_SKB_META (1 << 18) /* kfunc takes dynptr to SKB metadata */ /* * Tag marking a kernel function as a kfunc. This is meant to minimize the diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b9394f8fac0e..9aa2f00ede49 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2282,6 +2282,25 @@ static bool reg_is_dynptr_slice_pkt(const struct bpf_reg_state *reg) (DYNPTR_TYPE_SKB | DYNPTR_TYPE_XDP | DYNPTR_TYPE_SKB_META)); } +static u64 dynptr_type_from_kfunc_flags(const struct bpf_kfunc_call_arg_meta *meta) +{ + static const struct { + u64 mask; + enum bpf_type_flag type; + } type_flags[] = { + { KF_DYNPTR_SKB, DYNPTR_TYPE_SKB }, + { KF_DYNPTR_XDP, DYNPTR_TYPE_XDP }, + { KF_DYNPTR_SKB_META, DYNPTR_TYPE_SKB_META }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(type_flags); ++i) { + if (type_flags[i].mask & meta->kfunc_flags) + return type_flags[i].type; + } + return 0; +} + /* Unmodified PTR_TO_PACKET[_META,_END] register from ctx access. */ static bool reg_is_init_pkt_pointer(const struct bpf_reg_state *reg, enum bpf_reg_type which) @@ -13258,14 +13277,10 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ if (is_kfunc_arg_uninit(btf, &args[i])) dynptr_arg_type |= MEM_UNINIT; - if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) { - dynptr_arg_type |= DYNPTR_TYPE_SKB; - } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_xdp]) { - dynptr_arg_type |= DYNPTR_TYPE_XDP; - } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb_meta]) { - dynptr_arg_type |= DYNPTR_TYPE_SKB_META; - } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_clone] && - (dynptr_arg_type & MEM_UNINIT)) { + dynptr_arg_type |= dynptr_type_from_kfunc_flags(meta); + + if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_clone] && + (dynptr_arg_type & MEM_UNINIT)) { enum bpf_dynptr_type parent_type = meta->initialized_dynptr.type; if (parent_type == BPF_DYNPTR_TYPE_INVALID) { diff --git a/net/core/filter.c b/net/core/filter.c index 63f3baee2daf..9f58bb757bea 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -12224,15 +12224,15 @@ int bpf_dynptr_from_skb_rdonly(struct __sk_buff *skb, u64 flags, } BTF_KFUNCS_START(bpf_kfunc_check_set_skb) -BTF_ID_FLAGS(func, bpf_dynptr_from_skb, KF_TRUSTED_ARGS) +BTF_ID_FLAGS(func, bpf_dynptr_from_skb, KF_TRUSTED_ARGS | KF_DYNPTR_SKB) BTF_KFUNCS_END(bpf_kfunc_check_set_skb) BTF_KFUNCS_START(bpf_kfunc_check_set_skb_meta) -BTF_ID_FLAGS(func, bpf_dynptr_from_skb_meta, KF_TRUSTED_ARGS) +BTF_ID_FLAGS(func, bpf_dynptr_from_skb_meta, KF_TRUSTED_ARGS | KF_DYNPTR_SKB_META) BTF_KFUNCS_END(bpf_kfunc_check_set_skb_meta) BTF_KFUNCS_START(bpf_kfunc_check_set_xdp) -BTF_ID_FLAGS(func, bpf_dynptr_from_xdp) +BTF_ID_FLAGS(func, bpf_dynptr_from_xdp, KF_DYNPTR_XDP) BTF_KFUNCS_END(bpf_kfunc_check_set_xdp) BTF_KFUNCS_START(bpf_kfunc_check_set_sock_addr) -- 2.51.0