bpf: verifier: mark patched-insn with sub-register zext flag
Patched insns do not go through generic verification, therefore doesn't has zero extension information collected during insn walking. We don't bother analyze them at the moment, for any sub-register def comes from them, just conservatively mark it as needing zero extension. Signed-off-by: Jiong Wang <jiong.wang@netronome.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
5327ed3d44
commit
b325fbca4b
|
@ -1269,6 +1269,24 @@ static bool is_reg64(struct bpf_verifier_env *env, struct bpf_insn *insn,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Return TRUE if INSN doesn't have explicit value define. */
|
||||
static bool insn_no_def(struct bpf_insn *insn)
|
||||
{
|
||||
u8 class = BPF_CLASS(insn->code);
|
||||
|
||||
return (class == BPF_JMP || class == BPF_JMP32 ||
|
||||
class == BPF_STX || class == BPF_ST);
|
||||
}
|
||||
|
||||
/* Return TRUE if INSN has defined any 32-bit value explicitly. */
|
||||
static bool insn_has_def32(struct bpf_verifier_env *env, struct bpf_insn *insn)
|
||||
{
|
||||
if (insn_no_def(insn))
|
||||
return false;
|
||||
|
||||
return !is_reg64(env, insn, insn->dst_reg, NULL, DST_OP);
|
||||
}
|
||||
|
||||
static void mark_insn_zext(struct bpf_verifier_env *env,
|
||||
struct bpf_reg_state *reg)
|
||||
{
|
||||
|
@ -7298,14 +7316,23 @@ static void convert_pseudo_ld_imm64(struct bpf_verifier_env *env)
|
|||
* 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)
|
||||
static int adjust_insn_aux_data(struct bpf_verifier_env *env,
|
||||
struct bpf_prog *new_prog, u32 off, u32 cnt)
|
||||
{
|
||||
struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
|
||||
struct bpf_insn *insn = new_prog->insnsi;
|
||||
u32 prog_len;
|
||||
int i;
|
||||
|
||||
/* aux info at OFF always needs adjustment, no matter fast path
|
||||
* (cnt == 1) is taken or not. There is no guarantee INSN at OFF is the
|
||||
* original insn at old prog.
|
||||
*/
|
||||
old_data[off].zext_dst = insn_has_def32(env, insn + off + cnt - 1);
|
||||
|
||||
if (cnt == 1)
|
||||
return 0;
|
||||
prog_len = new_prog->len;
|
||||
new_data = vzalloc(array_size(prog_len,
|
||||
sizeof(struct bpf_insn_aux_data)));
|
||||
if (!new_data)
|
||||
|
@ -7313,8 +7340,10 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env, u32 prog_len,
|
|||
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));
|
||||
for (i = off; i < off + cnt - 1; i++)
|
||||
for (i = off; i < off + cnt - 1; i++) {
|
||||
new_data[i].seen = true;
|
||||
new_data[i].zext_dst = insn_has_def32(env, insn + i);
|
||||
}
|
||||
env->insn_aux_data = new_data;
|
||||
vfree(old_data);
|
||||
return 0;
|
||||
|
@ -7347,7 +7376,7 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of
|
|||
env->insn_aux_data[off].orig_idx);
|
||||
return NULL;
|
||||
}
|
||||
if (adjust_insn_aux_data(env, new_prog->len, off, len))
|
||||
if (adjust_insn_aux_data(env, new_prog, off, len))
|
||||
return NULL;
|
||||
adjust_subprog_starts(env, off, len);
|
||||
return new_prog;
|
||||
|
|
Loading…
Reference in New Issue