When the BTF of a function in the target program is unreliable, the model of the function given to its trampoline is MAX_BPF_FUNC_REG_ARGS u64 arguments. The verifier takes a static function's stack arguments from its BTF before it finds the BTF unreliable, though, so such a function can still take more: one with six or more arguments, one of them a plain pointer, for example. The trampoline saves and restores five registers then. After an fentry program, the rest of the register arguments, r9 on x86-64 and x5 to x7 on arm64, hold whatever __bpf_prog_exit() left there, and for fexit the stack arguments are not copied either, so the function goes on with garbage in arguments the verifier checked, pointers included. Refuse the attach when such a function has more argument slots in its BTF than fit in registers. The main program is left alone: it takes only its context, and the verifier gives it no stack arguments when its BTF is unreliable. Fixes: 0f6bd5e7a804 ("bpf: Support stack arguments for bpf functions") Signed-off-by: Yonghong Song --- kernel/bpf/verifier.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 6d87f59e99b8..6edddb56451d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -22032,6 +22032,33 @@ static int flatten_bpf_func_model(struct bpf_verifier_log *log, const char *tnam return 0; } +/* + * The verifier lets a static function use stack arguments counted from its + * BTF, even if that BTF turns out unreliable. A trampoline on the function is + * then given only MAX_BPF_FUNC_REG_ARGS u64 arguments and would lose the + * stack arguments, so such a function cannot be attached to. + */ +static int check_unreliable_func_args(struct bpf_verifier_log *log, struct btf *btf, + const struct btf_type *func_proto, const char *tname) +{ + struct btf_func_model m; + u32 i, nslots = 0; + + if (btf_distill_func_proto(NULL, btf, func_proto, tname, &m)) { + /* at least a slot for each argument */ + nslots = btf_type_vlen(func_proto); + } else { + for (i = 0; i < m.nr_args; i++) + nslots += btf_func_model_arg_slots(&m, i); + } + if (nslots <= MAX_BPF_FUNC_REG_ARGS) + return 0; + + bpf_log(log, "Cannot attach to static function %s: unreliable BTF and stack arguments\n", + tname); + return -EINVAL; +} + int bpf_check_attach_target(struct bpf_verifier_log *log, const struct bpf_prog *prog, const struct bpf_prog *tgt_prog, @@ -22299,8 +22326,14 @@ int bpf_check_attach_target(struct bpf_verifier_log *log, prog->aux->saved_dst_attach_type != tgt_prog->expected_attach_type)) return -EINVAL; - if (tgt_prog && conservative) + if (tgt_prog && conservative) { + if (subprog > 0) { + ret = check_unreliable_func_args(log, btf, t, tname); + if (ret) + return ret; + } t = NULL; + } ret = btf_distill_func_proto(log, btf, t, tname, &tgt_info->fmodel); if (ret < 0) -- 2.53.0-Meta