aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/fixups.c25
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)