Skip to content

Commit a833a17

Browse files
andreimateianakryiko
authored andcommitted
bpf: Fix verification of indirect var-off stack access
This patch fixes a bug around the verification of possibly-zero-sized stack accesses. When the access was done through a var-offset stack pointer, check_stack_access_within_bounds was incorrectly computing the maximum-offset of a zero-sized read to be the same as the register's min offset. Instead, we have to take in account the register's maximum possible value. The patch also simplifies how the max offset is checked; the check is now simpler than for min offset. The bug was allowing accesses to erroneously pass the check_stack_access_within_bounds() checks, only to later crash in check_stack_range_initialized() when all the possibly-affected stack slots are iterated (this time with a correct max offset). check_stack_range_initialized() is relying on check_stack_access_within_bounds() for its accesses to the stack-tracking vector to be within bounds; in the case of zero-sized accesses, we were essentially only verifying that the lowest possible slot was within bounds. We would crash when the max-offset of the stack pointer was >= 0 (which shouldn't pass verification, and hopefully is not something anyone's code attempts to do in practice). Thanks Hao for reporting! Fixes: 01f810a ("bpf: Allow variable-offset stack access") Reported-by: Hao Sun <[email protected]> Signed-off-by: Andrei Matei <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Acked-by: Eduard Zingerman <[email protected]> Acked-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected] Closes: https://lore.kernel.org/bpf/CACkBjsZGEUaRCHsmaX=h-efVogsRfK1FPxmkgb0Os_frnHiNdw@mail.gmail.com/
1 parent 2146f7f commit a833a17

File tree

1 file changed

+4
-10
lines changed

1 file changed

+4
-10
lines changed

kernel/bpf/verifier.c

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6620,10 +6620,7 @@ static int check_stack_access_within_bounds(
66206620

66216621
if (tnum_is_const(reg->var_off)) {
66226622
min_off = reg->var_off.value + off;
6623-
if (access_size > 0)
6624-
max_off = min_off + access_size - 1;
6625-
else
6626-
max_off = min_off;
6623+
max_off = min_off + access_size;
66276624
} else {
66286625
if (reg->smax_value >= BPF_MAX_VAR_OFF ||
66296626
reg->smin_value <= -BPF_MAX_VAR_OFF) {
@@ -6632,15 +6629,12 @@ static int check_stack_access_within_bounds(
66326629
return -EACCES;
66336630
}
66346631
min_off = reg->smin_value + off;
6635-
if (access_size > 0)
6636-
max_off = reg->smax_value + off + access_size - 1;
6637-
else
6638-
max_off = min_off;
6632+
max_off = reg->smax_value + off + access_size;
66396633
}
66406634

66416635
err = check_stack_slot_within_bounds(min_off, state, type);
6642-
if (!err)
6643-
err = check_stack_slot_within_bounds(max_off, state, type);
6636+
if (!err && max_off > 0)
6637+
err = -EINVAL; /* out of stack access into non-negative offsets */
66446638

66456639
if (err) {
66466640
if (tnum_is_const(reg->var_off)) {

0 commit comments

Comments
 (0)