bpf: adjust insn_aux_data when patching insns
convert_ctx_accesses() replaces single bpf instruction with a set of instructions. Adjust corresponding insn_aux_data while patching. It's needed to make sure subsequent 'for(all insn)' loops have matching insn and insn_aux_data. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
79741b3bde
commit
8041902dae
|
@ -3162,6 +3162,41 @@ static void convert_pseudo_ld_imm64(struct bpf_verifier_env *env)
|
|||
insn->src_reg = 0;
|
||||
}
|
||||
|
||||
/* single env->prog->insni[off] instruction was replaced with the range
|
||||
* insni[off, off + cnt). Adjust corresponding insn_aux_data by copying
|
||||
* [0, off) and [off, end) to new locations, so the patched range stays zero
|
||||
*/
|
||||
static int adjust_insn_aux_data(struct bpf_verifier_env *env, u32 prog_len,
|
||||
u32 off, u32 cnt)
|
||||
{
|
||||
struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
|
||||
|
||||
if (cnt == 1)
|
||||
return 0;
|
||||
new_data = vzalloc(sizeof(struct bpf_insn_aux_data) * prog_len);
|
||||
if (!new_data)
|
||||
return -ENOMEM;
|
||||
memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off);
|
||||
memcpy(new_data + off + cnt - 1, old_data + off,
|
||||
sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
|
||||
env->insn_aux_data = new_data;
|
||||
vfree(old_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
|
||||
const struct bpf_insn *patch, u32 len)
|
||||
{
|
||||
struct bpf_prog *new_prog;
|
||||
|
||||
new_prog = bpf_patch_insn_single(env->prog, off, patch, len);
|
||||
if (!new_prog)
|
||||
return NULL;
|
||||
if (adjust_insn_aux_data(env, new_prog->len, off, len))
|
||||
return NULL;
|
||||
return new_prog;
|
||||
}
|
||||
|
||||
/* convert load instructions that access fields of 'struct __sk_buff'
|
||||
* into sequence of instructions that access fields of 'struct sk_buff'
|
||||
*/
|
||||
|
@ -3181,10 +3216,10 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
|
|||
verbose("bpf verifier is misconfigured\n");
|
||||
return -EINVAL;
|
||||
} else if (cnt) {
|
||||
new_prog = bpf_patch_insn_single(env->prog, 0,
|
||||
insn_buf, cnt);
|
||||
new_prog = bpf_patch_insn_data(env, 0, insn_buf, cnt);
|
||||
if (!new_prog)
|
||||
return -ENOMEM;
|
||||
|
||||
env->prog = new_prog;
|
||||
delta += cnt - 1;
|
||||
}
|
||||
|
@ -3209,7 +3244,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
|
|||
else
|
||||
continue;
|
||||
|
||||
if (env->insn_aux_data[i].ptr_type != PTR_TO_CTX)
|
||||
if (env->insn_aux_data[i + delta].ptr_type != PTR_TO_CTX)
|
||||
continue;
|
||||
|
||||
cnt = ops->convert_ctx_access(type, insn, insn_buf, env->prog);
|
||||
|
@ -3218,8 +3253,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
new_prog = bpf_patch_insn_single(env->prog, i + delta, insn_buf,
|
||||
cnt);
|
||||
new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
|
||||
if (!new_prog)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
Loading…
Reference in New Issue