Add BPF verifier support for single- and multi-level pointer parameters and return values in BPF trampolines. The implementation treats these parameters as SCALAR_VALUE. The following new single level pointer support is added: - pointers to enum, 32 and 64 - pointers to functions The following multi-level pointer support is added: - multi-level pointers to int - multi-level pointers to void - multi-level pointers to enum, 32 and 64 - multi-level pointers to function - multi-level pointers to structure This is consistent with the existing pointers to int and void already treated as SCALAR. This provides consistent logic for single and multi-level pointers - if the type is treated as SCALAR for a single level pointer, the same is applicable for multi-level pointers, except the pointer to struct which is currently PTR_TO_BTF_ID, but in case of multi-level pointer it is treated as scalar as the verifier lacks the context to infer the size of their target memory regions. Signed-off-by: Slava Imameev --- kernel/bpf/btf.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 4872d2a6c42d..c2d06d2597d6 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -6508,11 +6508,30 @@ struct btf *bpf_prog_get_target_btf(const struct bpf_prog *prog) return prog->aux->attach_btf; } -static bool is_void_or_int_ptr(struct btf *btf, const struct btf_type *t) +static bool is_ptr_treated_as_scalar(const struct btf *btf, + const struct btf_type *t) { - /* skip modifiers */ + int depth = 1; + + WARN_ON(!btf_type_is_ptr(t)); + t = btf_type_skip_modifiers(btf, t->type, NULL); - return btf_type_is_void(t) || btf_type_is_int(t); + while (btf_type_is_ptr(t) && depth < MAX_RESOLVE_DEPTH) { + depth += 1; + t = btf_type_skip_modifiers(btf, t->type, NULL); + } + + /* + * If it's a single or multilevel pointer to void, int, enum, + * or function, it's the same as scalar from the verifier + * safety POV. Multilevel pointers to structures are treated as + * scalars. The verifier lacks the context to infer the size of + * their target memory regions. Either way, no further pointer + * walking is allowed. + */ + return btf_type_is_void(t) || btf_type_is_int(t) || + btf_is_any_enum(t) || btf_type_is_func_proto(t) || + (btf_type_is_struct(t) && depth > 1); } u32 btf_ctx_arg_idx(struct btf *btf, const struct btf_type *func_proto, @@ -6902,11 +6921,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, } } - /* - * If it's a pointer to void, it's the same as scalar from the verifier - * safety POV. Either way, no futher pointer walking is allowed. - */ - if (is_void_or_int_ptr(btf, t)) + if (is_ptr_treated_as_scalar(btf, t)) return true; /* this is a pointer to another type */ -- 2.34.1