summaryrefslogtreecommitdiff
path: root/kernel/bpf
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf')
-rw-r--r--kernel/bpf/core.c57
-rw-r--r--kernel/bpf/fixups.c1
2 files changed, 58 insertions, 0 deletions
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 6e32db9777c2..fc22d66d194a 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -2637,11 +2637,68 @@ static bool bpf_prog_select_interpreter(struct bpf_prog *fp)
return select_interpreter;
}
+/*
+ * Whether a function has an insn that works with the arena base, which a JIT
+ * sets up in the prologue when bpf_prog_uses_arena_insns() says so. Decided on
+ * the final insns of the function: an access through an arena pointer, or
+ * through a number in a program loaded with BPF_F_ARENA_SCALAR, has been
+ * rewritten to a BPF_PROBE_MEM32 form by then, a cast to the user address
+ * space keeps BPF_ADDR_SPACE_CAST, and a kfunc call with an __arena argument,
+ * which the JIT rebases, has a function model that says so. A load of an
+ * __arena struct member is rewritten with an immediate and needs none;
+ * dereferencing the result does.
+ */
+bool bpf_prog_has_arena_insns(const struct bpf_prog *prog)
+{
+ const struct bpf_insn *insn = prog->insnsi;
+ const struct btf_func_model *m;
+ int i, j;
+
+ if (!prog->aux->arena)
+ return false;
+
+ for (i = 0; i < prog->len; i++, insn++) {
+ switch (BPF_CLASS(insn->code)) {
+ case BPF_LDX:
+ if (BPF_MODE(insn->code) == BPF_PROBE_MEM32 ||
+ BPF_MODE(insn->code) == BPF_PROBE_MEM32SX)
+ return true;
+ break;
+ case BPF_ST:
+ if (BPF_MODE(insn->code) == BPF_PROBE_MEM32)
+ return true;
+ break;
+ case BPF_STX:
+ if (BPF_MODE(insn->code) == BPF_PROBE_MEM32 ||
+ BPF_MODE(insn->code) == BPF_PROBE_ATOMIC)
+ return true;
+ break;
+ case BPF_ALU64:
+ if (BPF_OP(insn->code) == BPF_MOV && BPF_SRC(insn->code) == BPF_X &&
+ insn->off == BPF_ADDR_SPACE_CAST)
+ return true;
+ break;
+ case BPF_JMP:
+ if (!bpf_pseudo_kfunc_call(insn))
+ break;
+ m = bpf_jit_find_kfunc_model(prog, insn);
+ if (!m)
+ break;
+ for (j = 0; j < m->nr_args; j++)
+ if (m->arg_flags[j] & BTF_FMODEL_ARENA_ARG)
+ return true;
+ break;
+ }
+ }
+ return false;
+}
+
static struct bpf_prog *bpf_prog_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
{
#ifdef CONFIG_BPF_JIT
struct bpf_prog *orig_prog;
+ prog->aux->uses_arena_insns = bpf_prog_has_arena_insns(prog);
if (!bpf_prog_need_blind(prog))
return bpf_int_jit_compile(env, prog);
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index 34b53ebb5841..409b9104c723 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -1448,6 +1448,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
func[i]->aux->jited_linfo = prog->aux->jited_linfo;
func[i]->aux->linfo_idx = env->subprog_info[i].linfo_idx;
func[i]->aux->arena = prog->aux->arena;
+ func[i]->aux->uses_arena_insns = bpf_prog_has_arena_insns(func[i]);
func[i]->aux->used_maps = env->used_maps;
func[i]->aux->used_map_cnt = env->used_map_cnt;
num_exentries = 0;