When the target function receives more arguments than available registers, the additional arguments are passed on stack, and so the generated trampoline needs to read those to prepare the bpf context, but also to prepare the target function stack when it is in charge of calling it. This works well for scalar types, but if the value is a struct, we can not know for sure the exact struct location, as it may have been packed or manually aligned to a greater value.
Prevent wrong readings by refusing trampoline attachment if the target function receives a struct on stack. While at it, move the max bpf args check in the new function.
Fixes: 6801b0aef79d ("riscv, bpf: Add 12-argument support for RV64 bpf trampoline") Signed-off-by: Alexis Lothoré (eBPF Foundation) alexis.lothore@bootlin.com --- arch/riscv/net/bpf_jit_comp64.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 10e01ff06312d9f1e6e213bb069c6ea749ea9af2..ea3a1c3af6bc129057c16a4070c33dbf00e6c611 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -1005,6 +1005,24 @@ static int invoke_bpf_prog(struct bpf_tramp_link *l, int args_off, int retval_of return ret; }
+static int validate_args(const struct btf_func_model *m) +{ + int i, nr_arg_slots, nr_regs = 0; + + if (m->nr_args > MAX_BPF_FUNC_ARGS) + return -ENOTSUPP; + + for (i = 0; i < m->nr_args; i++) { + nr_arg_slots = round_up(m->arg_size[i], 8) / 8; + if (nr_regs + nr_arg_slots > RV_MAX_REG_ARGS && + m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG) + return -ENOTSUPP; + nr_regs += nr_arg_slots; + } + + return 0; +} + static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, const struct btf_func_model *m, struct bpf_tramp_links *tlinks, @@ -1069,8 +1087,12 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, if (flags & (BPF_TRAMP_F_ORIG_STACK | BPF_TRAMP_F_SHARE_IPMODIFY)) return -ENOTSUPP;
- if (m->nr_args > MAX_BPF_FUNC_ARGS) - return -ENOTSUPP; + /* make sure that any argument can be located and processed by the + * trampoline + */ + ret = validate_args(m); + if (ret) + return ret;
for (i = 0; i < m->nr_args; i++) nr_arg_slots += round_up(m->arg_size[i], 8) / 8;