bpf_convert_ctx_accesses() inserts the store of the context pointer for the epilogue in front of the first instruction, and then the prologue in front of it as well. bpf_patch_list_insert() only takes an instruction that has no patch queued yet, so the second insertion is refused. Put insns inserted in front of a queued patch in front of all of it, and move the patch down behind them the same way as a single instruction. Signed-off-by: Qiliang Yuan --- kernel/bpf/core.c | 27 +++++++++++++++------------ kernel/bpf/fixups.c | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 6e356e16613b3..0447e3b4cfa48 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -746,24 +746,27 @@ int __bpf_patch_list_del(struct bpf_patch_list *pl, const struct bpf_prog *prog, * Queue 'insns[0..cnt)' to go in front of insn 'off'. Jumps to 'off', * instruction arrays and poke descriptors still name the insn at 'off', while * subprogs, line info, function pointers and calls that start at 'off' start - * at the first inserted insn. + * at the first inserted insn. Inserting in front of a queued patch puts the + * insns in front of it. */ int __bpf_patch_list_insert(struct bpf_patch_list *pl, const struct bpf_prog *prog, u32 off, const struct bpf_insn *insns, u32 cnt) { - struct bpf_insn_patch *p; + struct bpf_insn_patch *p = pl->cnt ? &pl->patches[pl->cnt - 1] : NULL; int err; - err = patch_list_reserve_patch(pl) ?: patch_list_reserve_insns(pl, 1); - if (err) - return err; - p = &pl->patches[pl->cnt++]; - p->off = off; - p->len = 1; - p->target = 0; - p->start = pl->insn_cnt; - p->orig = prog->insnsi[off]; - pl->insns[pl->insn_cnt++] = p->orig; + if (!p || off != p->off) { + err = patch_list_reserve_patch(pl) ?: patch_list_reserve_insns(pl, 1); + if (err) + return err; + p = &pl->patches[pl->cnt++]; + p->off = off; + p->len = 1; + p->target = 0; + p->start = pl->insn_cnt; + p->orig = prog->insnsi[off]; + pl->insns[pl->insn_cnt++] = p->orig; + } err = patch_list_reserve_insns(pl, cnt); if (err) diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c index bb4fd75a70624..6d99de1be2581 100644 --- a/kernel/bpf/fixups.c +++ b/kernel/bpf/fixups.c @@ -429,7 +429,7 @@ int bpf_patch_list_insert(struct bpf_verifier_env *env, u32 off, return -EINTR; if (verifier_bug_if(!cnt || off >= env->prog->len || - (p && off <= p->off), + (p && (off < p->off || (off == p->off && !p->len))), env, "insns inserted at %u out of order", off)) return -EFAULT; -- 2.43.0