Commit b325fbca authored by Jiong Wang's avatar Jiong Wang Committed by Alexei Starovoitov

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: default avatarJiong Wang <jiong.wang@netronome.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 5327ed3d
...@@ -1269,6 +1269,24 @@ static bool is_reg64(struct bpf_verifier_env *env, struct bpf_insn *insn, ...@@ -1269,6 +1269,24 @@ static bool is_reg64(struct bpf_verifier_env *env, struct bpf_insn *insn,
return true; 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, static void mark_insn_zext(struct bpf_verifier_env *env,
struct bpf_reg_state *reg) struct bpf_reg_state *reg)
{ {
...@@ -7298,14 +7316,23 @@ static void convert_pseudo_ld_imm64(struct bpf_verifier_env *env) ...@@ -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 * 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 * [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, static int adjust_insn_aux_data(struct bpf_verifier_env *env,
u32 off, u32 cnt) 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_aux_data *new_data, *old_data = env->insn_aux_data;
struct bpf_insn *insn = new_prog->insnsi;
u32 prog_len;
int i; 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) if (cnt == 1)
return 0; return 0;
prog_len = new_prog->len;
new_data = vzalloc(array_size(prog_len, new_data = vzalloc(array_size(prog_len,
sizeof(struct bpf_insn_aux_data))); sizeof(struct bpf_insn_aux_data)));
if (!new_data) if (!new_data)
...@@ -7313,8 +7340,10 @@ static int adjust_insn_aux_data(struct bpf_verifier_env *env, u32 prog_len, ...@@ -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, old_data, sizeof(struct bpf_insn_aux_data) * off);
memcpy(new_data + off + cnt - 1, old_data + off, memcpy(new_data + off + cnt - 1, old_data + off,
sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1)); 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].seen = true;
new_data[i].zext_dst = insn_has_def32(env, insn + i);
}
env->insn_aux_data = new_data; env->insn_aux_data = new_data;
vfree(old_data); vfree(old_data);
return 0; return 0;
...@@ -7347,7 +7376,7 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of ...@@ -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); env->insn_aux_data[off].orig_idx);
return NULL; 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; return NULL;
adjust_subprog_starts(env, off, len); adjust_subprog_starts(env, off, len);
return new_prog; return new_prog;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment