bpf: unconditionally reset backtrack_state masks on global func exit
authorAndrii Nakryiko <andrii@kernel.org>
Mon, 18 Sep 2023 21:01:10 +0000 (14:01 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 20 Sep 2023 10:26:25 +0000 (03:26 -0700)
In mark_chain_precision() logic, when we reach the entry to a global
func, it is expected that R1-R5 might be still requested to be marked
precise. This would correspond to some integer input arguments being
tracked as precise. This is all expected and handled as a special case.

What's not expected is that we'll leave backtrack_state structure with
some register bits set. This is because for subsequent precision
propagations backtrack_state is reused without clearing masks, as all
code paths are carefully written in a way to leave empty backtrack_state
with zeroed out masks, for speed.

The fix is trivial, we always clear register bit in the register mask, and
then, optionally, set reg->precise if register is SCALAR_VALUE type.

Reported-by: Chris Mason <clm@meta.com>
Fixes: be2ef8161572 ("bpf: allow precision tracking for programs with subprogs")
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20230918210110.2241458-1-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index bb78212..c0c7d13 100644 (file)
@@ -4047,11 +4047,9 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno)
                                bitmap_from_u64(mask, bt_reg_mask(bt));
                                for_each_set_bit(i, mask, 32) {
                                        reg = &st->frame[0]->regs[i];
-                                       if (reg->type != SCALAR_VALUE) {
-                                               bt_clear_reg(bt, i);
-                                               continue;
-                                       }
-                                       reg->precise = true;
+                                       bt_clear_reg(bt, i);
+                                       if (reg->type == SCALAR_VALUE)
+                                               reg->precise = true;
                                }
                                return 0;
                        }