]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/commitdiff
bpf/verifier: fix verifier instability
authorAlexei Starovoitov <ast@kernel.org>
Wed, 5 Sep 2018 02:13:44 +0000 (19:13 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Thu, 6 Sep 2018 05:21:00 +0000 (22:21 -0700)
Edward Cree says:
In check_mem_access(), for the PTR_TO_CTX case, after check_ctx_access()
has supplied a reg_type, the other members of the register state are set
appropriately.  Previously reg.range was set to 0, but as it is in a
union with reg.map_ptr, which is larger, upper bytes of the latter were
left in place.  This then caused the memcmp() in regsafe() to fail,
preventing some branches from being pruned (and occasionally causing the
same program to take a varying number of processed insns on repeated
verifier runs).

Fix the instability by clearing bpf_reg_state in __mark_reg_[un]known()

Fixes: f1174f77b50c ("bpf/verifier: rework value tracking")
Debugged-by: Edward Cree <ecree@solarflare.com>
Acked-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index f4ff0c569e54515168e9baf1be0ed4f34afdd03e..6ff1bac1795df3b132076f99b4b4db44d6974198 100644 (file)
@@ -570,7 +570,9 @@ static void __mark_reg_not_init(struct bpf_reg_state *reg);
  */
 static void __mark_reg_known(struct bpf_reg_state *reg, u64 imm)
 {
-       reg->id = 0;
+       /* Clear id, off, and union(map_ptr, range) */
+       memset(((u8 *)reg) + sizeof(reg->type), 0,
+              offsetof(struct bpf_reg_state, var_off) - sizeof(reg->type));
        reg->var_off = tnum_const(imm);
        reg->smin_value = (s64)imm;
        reg->smax_value = (s64)imm;
@@ -589,7 +591,6 @@ static void __mark_reg_known_zero(struct bpf_reg_state *reg)
 static void __mark_reg_const_zero(struct bpf_reg_state *reg)
 {
        __mark_reg_known(reg, 0);
-       reg->off = 0;
        reg->type = SCALAR_VALUE;
 }
 
@@ -700,9 +701,12 @@ static void __mark_reg_unbounded(struct bpf_reg_state *reg)
 /* Mark a register as having a completely unknown (scalar) value. */
 static void __mark_reg_unknown(struct bpf_reg_state *reg)
 {
+       /*
+        * Clear type, id, off, and union(map_ptr, range) and
+        * padding between 'type' and union
+        */
+       memset(reg, 0, offsetof(struct bpf_reg_state, var_off));
        reg->type = SCALAR_VALUE;
-       reg->id = 0;
-       reg->off = 0;
        reg->var_off = tnum_unknown;
        reg->frameno = 0;
        __mark_reg_unbounded(reg);
@@ -1640,9 +1644,6 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
                        else
                                mark_reg_known_zero(env, regs,
                                                    value_regno);
-                       regs[value_regno].id = 0;
-                       regs[value_regno].off = 0;
-                       regs[value_regno].range = 0;
                        regs[value_regno].type = reg_type;
                }
 
@@ -2495,7 +2496,6 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
                        regs[BPF_REG_0].type = PTR_TO_MAP_VALUE_OR_NULL;
                /* There is no offset yet applied, variable or fixed */
                mark_reg_known_zero(env, regs, BPF_REG_0);
-               regs[BPF_REG_0].off = 0;
                /* remember map_ptr, so that check_map_access()
                 * can check 'value_size' boundary of memory access
                 * to map element returned from bpf_map_lookup_elem()