|
@@ -3827,6 +3827,7 @@ static int do_check(struct bpf_verifier_env *env)
|
|
|
return err;
|
|
|
|
|
|
regs = cur_regs(env);
|
|
|
+ env->insn_aux_data[insn_idx].seen = true;
|
|
|
if (class == BPF_ALU || class == BPF_ALU64) {
|
|
|
err = check_alu_op(env, insn);
|
|
|
if (err)
|
|
@@ -4022,6 +4023,7 @@ process_bpf_exit:
|
|
|
return err;
|
|
|
|
|
|
insn_idx++;
|
|
|
+ env->insn_aux_data[insn_idx].seen = true;
|
|
|
} else {
|
|
|
verbose(env, "invalid BPF_LD mode\n");
|
|
|
return -EINVAL;
|
|
@@ -4204,6 +4206,7 @@ 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;
|
|
|
+ int i;
|
|
|
|
|
|
if (cnt == 1)
|
|
|
return 0;
|
|
@@ -4213,6 +4216,8 @@ 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++)
|
|
|
+ new_data[i].seen = true;
|
|
|
env->insn_aux_data = new_data;
|
|
|
vfree(old_data);
|
|
|
return 0;
|
|
@@ -4231,6 +4236,25 @@ static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 of
|
|
|
return new_prog;
|
|
|
}
|
|
|
|
|
|
+/* The verifier does more data flow analysis than llvm and will not explore
|
|
|
+ * branches that are dead at run time. Malicious programs can have dead code
|
|
|
+ * too. Therefore replace all dead at-run-time code with nops.
|
|
|
+ */
|
|
|
+static void sanitize_dead_code(struct bpf_verifier_env *env)
|
|
|
+{
|
|
|
+ struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
|
|
|
+ struct bpf_insn nop = BPF_MOV64_REG(BPF_REG_0, BPF_REG_0);
|
|
|
+ struct bpf_insn *insn = env->prog->insnsi;
|
|
|
+ const int insn_cnt = env->prog->len;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < insn_cnt; i++) {
|
|
|
+ if (aux_data[i].seen)
|
|
|
+ continue;
|
|
|
+ memcpy(insn + i, &nop, sizeof(nop));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/* convert load instructions that access fields of 'struct __sk_buff'
|
|
|
* into sequence of instructions that access fields of 'struct sk_buff'
|
|
|
*/
|
|
@@ -4557,6 +4581,9 @@ skip_full_check:
|
|
|
while (!pop_stack(env, NULL, NULL));
|
|
|
free_states(env);
|
|
|
|
|
|
+ if (ret == 0)
|
|
|
+ sanitize_dead_code(env);
|
|
|
+
|
|
|
if (ret == 0)
|
|
|
/* program is valid, convert *(u32*)(ctx + off) accesses */
|
|
|
ret = convert_ctx_accesses(env);
|