bpf_do_misc_fixups() sets up the counter of may_goto in front of each subprog that needs one. It patches the program for each of these subprogs, and then walks all jumps again with adjust_jmp_off() to move the ones to the first instruction of the subprog past the setup. Insert the setup with bpf_patch_list_insert(), which leaves the jumps to the instruction it inserts in front of on that instruction, and commit once. adjust_jmp_off() has no users left, remove it. Signed-off-by: Qiliang Yuan --- kernel/bpf/fixups.c | 73 ++++++++--------------------------------------------- 1 file changed, 10 insertions(+), 63 deletions(-) diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c index 08c89f2baffb6..f55ac904b4e78 100644 --- a/kernel/bpf/fixups.c +++ b/kernel/bpf/fixups.c @@ -723,44 +723,6 @@ static int bpf_adj_moved_insn(struct bpf_insn *insn, u32 delta) return 0; } -/* - * For all jmp insns in a given 'prog' that point to 'tgt_idx' insn adjust the - * jump offset by 'delta'. - */ -static int adjust_jmp_off(struct bpf_prog *prog, u32 tgt_idx, u32 delta) -{ - struct bpf_insn *insn = prog->insnsi; - u32 insn_cnt = prog->len, i; - s32 imm; - s16 off; - - for (i = 0; i < insn_cnt; i++, insn++) { - u8 code = insn->code; - - if (tgt_idx <= i && i < tgt_idx + delta) - continue; - - if ((BPF_CLASS(code) != BPF_JMP && BPF_CLASS(code) != BPF_JMP32) || - BPF_OP(code) == BPF_CALL || BPF_OP(code) == BPF_EXIT) - continue; - - if (insn->code == (BPF_JMP32 | BPF_JA)) { - if (i + 1 + insn->imm != tgt_idx) - continue; - if (check_add_overflow(insn->imm, delta, &imm)) - return -ERANGE; - insn->imm = imm; - } else { - if (i + 1 + insn->off != tgt_idx) - continue; - if (check_add_overflow(insn->off, delta, &off)) - return -ERANGE; - insn->off = off; - } - } - return 0; -} - /* Clean up dynamically allocated fields of aux data for instructions [start, ...] */ void bpf_clear_insn_aux_data(struct bpf_verifier_env *env, int start, int len) { @@ -1988,7 +1950,6 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env) const struct bpf_map_ops *ops; struct bpf_insn_aux_data *aux; struct bpf_insn *insn_buf = env->insn_buf; - struct bpf_prog *new_prog; struct bpf_map *map_ptr; int i, ret, cnt, cur_subprog = 0; struct bpf_subprog_info *subprogs = env->subprog_info; @@ -2828,10 +2789,8 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env) env->prog->aux->stack_depth = subprogs[0].stack_depth; for (i = 0; i < env->subprog_cnt; i++) { - int delta = bpf_jit_supports_timed_may_goto() ? 2 : 1; - int subprog_start = subprogs[i].start; + int slots = bpf_jit_supports_timed_may_goto() ? 2 : 1; int stack_slots = subprogs[i].stack_extra / 8; - int slots = delta, cnt = 0; if (!stack_slots) continue; @@ -2841,6 +2800,7 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env) return -EFAULT; } + cnt = 0; stack_depth = subprogs[i].stack_depth; if (bpf_jit_supports_timed_may_goto()) { insn_buf[cnt++] = BPF_ST_MEM(BPF_DW, BPF_REG_FP, -stack_depth, @@ -2851,30 +2811,17 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env) insn_buf[cnt++] = BPF_ST_MEM(BPF_DW, BPF_REG_FP, -stack_depth, BPF_MAX_LOOPS); } - /* Copy first actual insn to preserve it */ - insn_buf[cnt] = env->prog->insnsi[subprog_start]; - ret = bpf_adj_moved_insn(&insn_buf[cnt], cnt); - if (ret) { - verbose(env, "insn %d cannot be patched due to 16-bit range\n", - env->insn_aux_data[subprog_start].orig_idx); + /* jumps to the first insn of the subprog skip the setup */ + ret = bpf_patch_list_insert(env, subprogs[i].start, insn_buf, cnt); + if (ret) return ret; - } - cnt++; - - new_prog = __bpf_patch_insn_data(env, subprog_start, insn_buf, cnt, - BPF_PATCH_MOVE_TARGET); - if (!new_prog) - return -ENOMEM; - env->prog = prog = new_prog; - /* - * If may_goto is a first insn of a prog there could be a jmp - * insn that points to it, hence adjust all such jmps to point - * to insn after BPF_ST that inits may_goto count. - * Adjustment will succeed because bpf_patch_insn_data() didn't fail. - */ - WARN_ON(adjust_jmp_off(env->prog, subprog_start, delta)); } + ret = bpf_patch_list_commit(env); + if (ret) + return ret; + prog = env->prog; + /* Since poke tab is now finalized, publish aux to tracker. */ for (i = 0; i < prog->aux->size_poke_tab; i++) { map_ptr = prog->aux->poke_tab[i].tail_call.map; -- 2.43.0