diff options
Diffstat (limited to 'kernel/bpf/verifier.c')
-rw-r--r-- | kernel/bpf/verifier.c | 23 |
1 files changed, 14 insertions, 9 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 3fb50757e812..315798037d6c 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -1772,16 +1772,21 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno, | |||
1772 | bitmap_from_u64(mask, stack_mask); | 1772 | bitmap_from_u64(mask, stack_mask); |
1773 | for_each_set_bit(i, mask, 64) { | 1773 | for_each_set_bit(i, mask, 64) { |
1774 | if (i >= func->allocated_stack / BPF_REG_SIZE) { | 1774 | if (i >= func->allocated_stack / BPF_REG_SIZE) { |
1775 | /* This can happen if backtracking | 1775 | /* the sequence of instructions: |
1776 | * is propagating stack precision where | 1776 | * 2: (bf) r3 = r10 |
1777 | * caller has larger stack frame | 1777 | * 3: (7b) *(u64 *)(r3 -8) = r0 |
1778 | * than callee, but backtrack_insn() should | 1778 | * 4: (79) r4 = *(u64 *)(r10 -8) |
1779 | * have returned -ENOTSUPP. | 1779 | * doesn't contain jmps. It's backtracked |
1780 | * as a single block. | ||
1781 | * During backtracking insn 3 is not recognized as | ||
1782 | * stack access, so at the end of backtracking | ||
1783 | * stack slot fp-8 is still marked in stack_mask. | ||
1784 | * However the parent state may not have accessed | ||
1785 | * fp-8 and it's "unallocated" stack space. | ||
1786 | * In such case fallback to conservative. | ||
1780 | */ | 1787 | */ |
1781 | verbose(env, "BUG spi %d stack_size %d\n", | 1788 | mark_all_scalars_precise(env, st); |
1782 | i, func->allocated_stack); | 1789 | return 0; |
1783 | WARN_ONCE(1, "verifier backtracking bug"); | ||
1784 | return -EFAULT; | ||
1785 | } | 1790 | } |
1786 | 1791 | ||
1787 | if (func->stack[i].slot_type[0] != STACK_SPILL) { | 1792 | if (func->stack[i].slot_type[0] != STACK_SPILL) { |