A global function may already return an arena pointer on its own, and check_global_ret_scalar_reg() accepts one in either half of the R0:R2 pair. Let the members of a by-value struct it returns be arena pointers as well, rather than scalars only. Signed-off-by: Yonghong Song --- kernel/bpf/btf.c | 17 +++++++++++------ .../selftests/bpf/progs/exceptions_fail.c | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index b1f4ef614d4c..70481fadacc0 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -7972,14 +7972,18 @@ static int btf_validate_return_type(struct bpf_verifier_env *env, struct btf *bt if (btf_type_is_struct(t) && t->size <= 16) { /* - * A global function's caller models the return as an opaque - * scalar pair, so it may only return scalars by value. A local - * function is verified inline, so a pointer field stays tracked - * and needs no such restriction. + * A global function may return a struct with scalar(s) or arena + * pointer(s) as its members. A local function is verified inline, + * so its caller receives the real register state and any member + * is fine. */ bool local_func = subprog && !is_global; + u32 member_kinds = BTF_MEMBER_SCALAR; - if (local_func || btf_struct_is_composed_of(env, btf, t, BTF_MEMBER_SCALAR)) + if (subprog) + member_kinds |= BTF_MEMBER_ARENA_PTR; + + if (local_func || btf_struct_is_composed_of(env, btf, t, member_kinds)) return 0; } @@ -8075,7 +8079,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) if (is_global) { bpf_log(log, "Global function %s() has unsupported return type. " - "Only void, scalar, or a scalar-only struct/union up to 16 bytes is supported.\n", + "Only void, a scalar, an arena pointer, or a struct/union of " + "those up to 16 bytes is supported.\n", tname); } return err; diff --git a/tools/testing/selftests/bpf/progs/exceptions_fail.c b/tools/testing/selftests/bpf/progs/exceptions_fail.c index 9708efb93683..35794329640b 100644 --- a/tools/testing/selftests/bpf/progs/exceptions_fail.c +++ b/tools/testing/selftests/bpf/progs/exceptions_fail.c @@ -60,7 +60,7 @@ __noinline int exception_cb_ok_arg_small(int a) SEC("?tc") __exception_cb(exception_cb_bad_ret_type1) -__failure __msg("Only void, scalar, or a scalar-only struct/union up to 16 bytes is supported.") +__failure __msg("Only void, a scalar, an arena pointer, or a struct/union of those") int reject_exception_cb_type_1(struct __sk_buff *ctx) { bpf_throw(0); -- 2.53.0-Meta