]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - kernel/bpf/core.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[mirror_ubuntu-jammy-kernel.git] / kernel / bpf / core.c
index 7949e8b8f94e9cc196e0449214493ccce61b0903..887e28408f98e478d352466c76937a610411b1bb 100644 (file)
@@ -94,6 +94,7 @@ struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags)
        fp->pages = size / PAGE_SIZE;
        fp->aux = aux;
        fp->aux->prog = fp;
+       fp->jit_requested = ebpf_jit_enabled();
 
        INIT_LIST_HEAD_RCU(&fp->aux->ksym_lnode);
 
@@ -217,30 +218,40 @@ int bpf_prog_calc_tag(struct bpf_prog *fp)
        return 0;
 }
 
-static bool bpf_is_jmp_and_has_target(const struct bpf_insn *insn)
-{
-       return BPF_CLASS(insn->code) == BPF_JMP  &&
-              /* Call and Exit are both special jumps with no
-               * target inside the BPF instruction image.
-               */
-              BPF_OP(insn->code) != BPF_CALL &&
-              BPF_OP(insn->code) != BPF_EXIT;
-}
-
 static void bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta)
 {
        struct bpf_insn *insn = prog->insnsi;
        u32 i, insn_cnt = prog->len;
+       bool pseudo_call;
+       u8 code;
+       int off;
 
        for (i = 0; i < insn_cnt; i++, insn++) {
-               if (!bpf_is_jmp_and_has_target(insn))
+               code = insn->code;
+               if (BPF_CLASS(code) != BPF_JMP)
+                       continue;
+               if (BPF_OP(code) == BPF_EXIT)
                        continue;
+               if (BPF_OP(code) == BPF_CALL) {
+                       if (insn->src_reg == BPF_PSEUDO_CALL)
+                               pseudo_call = true;
+                       else
+                               continue;
+               } else {
+                       pseudo_call = false;
+               }
+               off = pseudo_call ? insn->imm : insn->off;
 
                /* Adjust offset of jmps if we cross boundaries. */
-               if (i < pos && i + insn->off + 1 > pos)
-                       insn->off += delta;
-               else if (i > pos + delta && i + insn->off + 1 <= pos + delta)
-                       insn->off -= delta;
+               if (i < pos && i + off + 1 > pos)
+                       off += delta;
+               else if (i > pos + delta && i + off + 1 <= pos + delta)
+                       off -= delta;
+
+               if (pseudo_call)
+                       insn->imm = off;
+               else
+                       insn->off = off;
        }
 }
 
@@ -711,7 +722,7 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
        struct bpf_insn *insn;
        int i, rewritten;
 
-       if (!bpf_jit_blinding_enabled())
+       if (!bpf_jit_blinding_enabled(prog) || prog->blinded)
                return prog;
 
        clone = bpf_prog_clone_create(prog, GFP_USER);
@@ -753,13 +764,16 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
                i        += insn_delta;
        }
 
+       clone->blinded = 1;
        return clone;
 }
 #endif /* CONFIG_BPF_JIT */
 
 /* Base function for offset calculation. Needs to go into .text section,
  * therefore keeping it non-static as well; will also be used by JITs
- * anyway later on, so do not let the compiler omit it.
+ * anyway later on, so do not let the compiler omit it. This also needs
+ * to go into kallsyms for correlation from e.g. bpftool, so naming
+ * must not change.
  */
 noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
 {
@@ -775,8 +789,7 @@ EXPORT_SYMBOL_GPL(__bpf_call_base);
  *
  * Decode and execute eBPF instructions.
  */
-static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
-                                   u64 *stack)
+static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack)
 {
        u64 tmp;
        static const void *jumptable[256] = {
@@ -836,6 +849,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
                [BPF_ALU64 | BPF_NEG] = &&ALU64_NEG,
                /* Call instruction */
                [BPF_JMP | BPF_CALL] = &&JMP_CALL,
+               [BPF_JMP | BPF_CALL_ARGS] = &&JMP_CALL_ARGS,
                [BPF_JMP | BPF_TAIL_CALL] = &&JMP_TAIL_CALL,
                /* Jumps */
                [BPF_JMP | BPF_JA] = &&JMP_JA,
@@ -1026,6 +1040,13 @@ select_insn:
                                                       BPF_R4, BPF_R5);
                CONT;
 
+       JMP_CALL_ARGS:
+               BPF_R0 = (__bpf_call_base_args + insn->imm)(BPF_R1, BPF_R2,
+                                                           BPF_R3, BPF_R4,
+                                                           BPF_R5,
+                                                           insn + insn->off + 1);
+               CONT;
+
        JMP_TAIL_CALL: {
                struct bpf_map *map = (struct bpf_map *) (unsigned long) BPF_R2;
                struct bpf_array *array = container_of(map, struct bpf_array, map);
@@ -1298,6 +1319,23 @@ static unsigned int PROG_NAME(stack_size)(const void *ctx, const struct bpf_insn
        return ___bpf_prog_run(regs, insn, stack); \
 }
 
+#define PROG_NAME_ARGS(stack_size) __bpf_prog_run_args##stack_size
+#define DEFINE_BPF_PROG_RUN_ARGS(stack_size) \
+static u64 PROG_NAME_ARGS(stack_size)(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5, \
+                                     const struct bpf_insn *insn) \
+{ \
+       u64 stack[stack_size / sizeof(u64)]; \
+       u64 regs[MAX_BPF_REG]; \
+\
+       FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; \
+       BPF_R1 = r1; \
+       BPF_R2 = r2; \
+       BPF_R3 = r3; \
+       BPF_R4 = r4; \
+       BPF_R5 = r5; \
+       return ___bpf_prog_run(regs, insn, stack); \
+}
+
 #define EVAL1(FN, X) FN(X)
 #define EVAL2(FN, X, Y...) FN(X) EVAL1(FN, Y)
 #define EVAL3(FN, X, Y...) FN(X) EVAL2(FN, Y)
@@ -1309,6 +1347,10 @@ EVAL6(DEFINE_BPF_PROG_RUN, 32, 64, 96, 128, 160, 192);
 EVAL6(DEFINE_BPF_PROG_RUN, 224, 256, 288, 320, 352, 384);
 EVAL4(DEFINE_BPF_PROG_RUN, 416, 448, 480, 512);
 
+EVAL6(DEFINE_BPF_PROG_RUN_ARGS, 32, 64, 96, 128, 160, 192);
+EVAL6(DEFINE_BPF_PROG_RUN_ARGS, 224, 256, 288, 320, 352, 384);
+EVAL4(DEFINE_BPF_PROG_RUN_ARGS, 416, 448, 480, 512);
+
 #define PROG_NAME_LIST(stack_size) PROG_NAME(stack_size),
 
 static unsigned int (*interpreters[])(const void *ctx,
@@ -1317,6 +1359,24 @@ EVAL6(PROG_NAME_LIST, 32, 64, 96, 128, 160, 192)
 EVAL6(PROG_NAME_LIST, 224, 256, 288, 320, 352, 384)
 EVAL4(PROG_NAME_LIST, 416, 448, 480, 512)
 };
+#undef PROG_NAME_LIST
+#define PROG_NAME_LIST(stack_size) PROG_NAME_ARGS(stack_size),
+static u64 (*interpreters_args[])(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5,
+                                 const struct bpf_insn *insn) = {
+EVAL6(PROG_NAME_LIST, 32, 64, 96, 128, 160, 192)
+EVAL6(PROG_NAME_LIST, 224, 256, 288, 320, 352, 384)
+EVAL4(PROG_NAME_LIST, 416, 448, 480, 512)
+};
+#undef PROG_NAME_LIST
+
+void bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth)
+{
+       stack_depth = max_t(u32, stack_depth, 1);
+       insn->off = (s16) insn->imm;
+       insn->imm = interpreters_args[(round_up(stack_depth, 32) / 32) - 1] -
+               __bpf_call_base_args;
+       insn->code = BPF_JMP | BPF_CALL_ARGS;
+}
 
 #else
 static unsigned int __bpf_prog_ret0(const void *ctx,
@@ -1329,6 +1389,9 @@ static unsigned int __bpf_prog_ret0(const void *ctx,
 bool bpf_prog_array_compatible(struct bpf_array *array,
                               const struct bpf_prog *fp)
 {
+       if (fp->kprobe_override)
+               return false;
+
        if (!array->owner_prog_type) {
                /* There's no owner yet where we could check for
                 * compatibility.
@@ -1481,6 +1544,8 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
        rcu_read_lock();
        prog = rcu_dereference(progs)->progs;
        for (; *prog; prog++) {
+               if (*prog == &dummy_bpf_prog.prog)
+                       continue;
                id = (*prog)->aux->id;
                if (copy_to_user(prog_ids + i, &id, sizeof(id))) {
                        rcu_read_unlock();
@@ -1564,14 +1629,41 @@ int bpf_prog_array_copy(struct bpf_prog_array __rcu *old_array,
        return 0;
 }
 
+int bpf_prog_array_copy_info(struct bpf_prog_array __rcu *array,
+                            __u32 __user *prog_ids, u32 request_cnt,
+                            __u32 __user *prog_cnt)
+{
+       u32 cnt = 0;
+
+       if (array)
+               cnt = bpf_prog_array_length(array);
+
+       if (copy_to_user(prog_cnt, &cnt, sizeof(cnt)))
+               return -EFAULT;
+
+       /* return early if user requested only program count or nothing to copy */
+       if (!request_cnt || !cnt)
+               return 0;
+
+       return bpf_prog_array_copy_to_user(array, prog_ids, request_cnt);
+}
+
 static void bpf_prog_free_deferred(struct work_struct *work)
 {
        struct bpf_prog_aux *aux;
+       int i;
 
        aux = container_of(work, struct bpf_prog_aux, work);
        if (bpf_prog_is_dev_bound(aux))
                bpf_prog_offload_destroy(aux->prog);
-       bpf_jit_free(aux->prog);
+       for (i = 0; i < aux->func_cnt; i++)
+               bpf_jit_free(aux->func[i]);
+       if (aux->func_cnt) {
+               kfree(aux->func);
+               bpf_prog_unlock_free(aux->prog);
+       } else {
+               bpf_jit_free(aux->prog);
+       }
 }
 
 /* Free internal BPF program */