|
@@ -217,30 +217,40 @@ int bpf_prog_calc_tag(struct bpf_prog *fp)
|
|
return 0;
|
|
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)
|
|
static void bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta)
|
|
{
|
|
{
|
|
struct bpf_insn *insn = prog->insnsi;
|
|
struct bpf_insn *insn = prog->insnsi;
|
|
u32 i, insn_cnt = prog->len;
|
|
u32 i, insn_cnt = prog->len;
|
|
|
|
+ bool pseudo_call;
|
|
|
|
+ u8 code;
|
|
|
|
+ int off;
|
|
|
|
|
|
for (i = 0; i < insn_cnt; i++, insn++) {
|
|
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;
|
|
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. */
|
|
/* 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -774,8 +784,7 @@ EXPORT_SYMBOL_GPL(__bpf_call_base);
|
|
*
|
|
*
|
|
* Decode and execute eBPF instructions.
|
|
* 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;
|
|
u64 tmp;
|
|
static const void *jumptable[256] = {
|
|
static const void *jumptable[256] = {
|
|
@@ -835,6 +844,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn,
|
|
[BPF_ALU64 | BPF_NEG] = &&ALU64_NEG,
|
|
[BPF_ALU64 | BPF_NEG] = &&ALU64_NEG,
|
|
/* Call instruction */
|
|
/* Call instruction */
|
|
[BPF_JMP | BPF_CALL] = &&JMP_CALL,
|
|
[BPF_JMP | BPF_CALL] = &&JMP_CALL,
|
|
|
|
+ [BPF_JMP | BPF_CALL_ARGS] = &&JMP_CALL_ARGS,
|
|
[BPF_JMP | BPF_TAIL_CALL] = &&JMP_TAIL_CALL,
|
|
[BPF_JMP | BPF_TAIL_CALL] = &&JMP_TAIL_CALL,
|
|
/* Jumps */
|
|
/* Jumps */
|
|
[BPF_JMP | BPF_JA] = &&JMP_JA,
|
|
[BPF_JMP | BPF_JA] = &&JMP_JA,
|
|
@@ -1025,6 +1035,13 @@ select_insn:
|
|
BPF_R4, BPF_R5);
|
|
BPF_R4, BPF_R5);
|
|
CONT;
|
|
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: {
|
|
JMP_TAIL_CALL: {
|
|
struct bpf_map *map = (struct bpf_map *) (unsigned long) BPF_R2;
|
|
struct bpf_map *map = (struct bpf_map *) (unsigned long) BPF_R2;
|
|
struct bpf_array *array = container_of(map, struct bpf_array, map);
|
|
struct bpf_array *array = container_of(map, struct bpf_array, map);
|
|
@@ -1297,6 +1314,23 @@ static unsigned int PROG_NAME(stack_size)(const void *ctx, const struct bpf_insn
|
|
return ___bpf_prog_run(regs, insn, stack); \
|
|
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 EVAL1(FN, X) FN(X)
|
|
#define EVAL2(FN, X, Y...) FN(X) EVAL1(FN, Y)
|
|
#define EVAL2(FN, X, Y...) FN(X) EVAL1(FN, Y)
|
|
#define EVAL3(FN, X, Y...) FN(X) EVAL2(FN, Y)
|
|
#define EVAL3(FN, X, Y...) FN(X) EVAL2(FN, Y)
|
|
@@ -1308,6 +1342,10 @@ EVAL6(DEFINE_BPF_PROG_RUN, 32, 64, 96, 128, 160, 192);
|
|
EVAL6(DEFINE_BPF_PROG_RUN, 224, 256, 288, 320, 352, 384);
|
|
EVAL6(DEFINE_BPF_PROG_RUN, 224, 256, 288, 320, 352, 384);
|
|
EVAL4(DEFINE_BPF_PROG_RUN, 416, 448, 480, 512);
|
|
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),
|
|
#define PROG_NAME_LIST(stack_size) PROG_NAME(stack_size),
|
|
|
|
|
|
static unsigned int (*interpreters[])(const void *ctx,
|
|
static unsigned int (*interpreters[])(const void *ctx,
|
|
@@ -1316,6 +1354,24 @@ EVAL6(PROG_NAME_LIST, 32, 64, 96, 128, 160, 192)
|
|
EVAL6(PROG_NAME_LIST, 224, 256, 288, 320, 352, 384)
|
|
EVAL6(PROG_NAME_LIST, 224, 256, 288, 320, 352, 384)
|
|
EVAL4(PROG_NAME_LIST, 416, 448, 480, 512)
|
|
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;
|
|
|
|
+}
|
|
|
|
|
|
bool bpf_prog_array_compatible(struct bpf_array *array,
|
|
bool bpf_prog_array_compatible(struct bpf_array *array,
|
|
const struct bpf_prog *fp)
|
|
const struct bpf_prog *fp)
|