diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/bpf/fixups.c | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c index fe59e3114d82..a8739fbd0349 100644 --- a/kernel/bpf/fixups.c +++ b/kernel/bpf/fixups.c @@ -858,6 +858,25 @@ apply_patch_buffer: return 0; } +/* + * The prologue takes the context from R1, and it can clobber R2-R5. An + * extension gets the arguments of the function that it replaces. + */ +static bool ext_prog_takes_prologue(const struct bpf_verifier_env *env) +{ + const struct bpf_subprog_info *sub = &env->subprog_info[0]; + int i, cnt = min_t(int, sub->arg_slot_cnt, MAX_BPF_FUNC_REG_ARGS); + + if (!cnt || sub->args[0].arg_type != ARG_PTR_TO_CTX) + return false; + + for (i = 1; i < cnt; i++) + if (sub->args[i].arg_type != ARG_SCALAR) + return false; + + return true; +} + /* convert load instructions that access fields of a context type into a * sequence of instructions that access fields of the underlying structure: * struct __sk_buff -> struct sk_buff @@ -915,6 +934,12 @@ int bpf_convert_ctx_accesses(struct bpf_verifier_env *env) verifier_bug(env, "prologue is too long"); return -EFAULT; } else if (cnt) { + if (env->prog->type == BPF_PROG_TYPE_EXT && + !ext_prog_takes_prologue(env)) { + verbose(env, + "Extension writing packet data must take ctx and scalars only\n"); + return -EINVAL; + } new_prog = __bpf_patch_insn_data(env, 0, insn_buf, cnt, BPF_PATCH_MOVE_TARGET); if (!new_prog) |
