diff options
author | Andrii Nakryiko <andrii@kernel.org> | 2023-12-07 10:57:36 -0800 |
---|---|---|
committer | Andrii Nakryiko <andrii@kernel.org> | 2023-12-07 13:58:14 -0800 |
commit | 483af466e4ee3326d150877ea0626e95c67a395e (patch) | |
tree | ceead968fb8ab47e59d6c55e3bc087a68736c8a8 /kernel/bpf/verifier.c | |
parent | 2146f7fe6e028a3905f0658a1a0d8ef7c115d6c1 (diff) | |
parent | 1d38a9ee81570c4bd61f557832dead4d6f816760 (diff) |
Merge branch 'bpf-fix-verification-of-indirect-var-off-stack-access'
Andrei Matei says:
====================
bpf: fix verification of indirect var-off stack access
V4 to V5:
- split the test into a separate patch
V3 to V4:
- include a test per Eduard's request
- target bpf-next per Alexei's request (patches didn't change)
V2 to V3:
- simplify checks for max_off (don't call
check_stack_slot_within_bounds for it)
- append a commit to protect against overflow in the addition of the
register and the offset
V1 to V2:
- fix max_off calculation for access size = 0
====================
Link: https://lore.kernel.org/r/20231207041150.229139-1-andreimatei1@gmail.com
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Diffstat (limited to 'kernel/bpf/verifier.c')
-rw-r--r-- | kernel/bpf/verifier.c | 20 |
1 files changed, 7 insertions, 13 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 45e85fb76d82..0e77bb52542d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6577,7 +6577,7 @@ static int check_ptr_to_map_access(struct bpf_verifier_env *env, * The minimum valid offset is -MAX_BPF_STACK for writes, and * -state->allocated_stack for reads. */ -static int check_stack_slot_within_bounds(int off, +static int check_stack_slot_within_bounds(s64 off, struct bpf_func_state *state, enum bpf_access_type t) { @@ -6606,7 +6606,7 @@ static int check_stack_access_within_bounds( struct bpf_reg_state *regs = cur_regs(env); struct bpf_reg_state *reg = regs + regno; struct bpf_func_state *state = func(env, reg); - int min_off, max_off; + s64 min_off, max_off; int err; char *err_extra; @@ -6619,11 +6619,8 @@ static int check_stack_access_within_bounds( err_extra = " write to"; if (tnum_is_const(reg->var_off)) { - min_off = reg->var_off.value + off; - if (access_size > 0) - max_off = min_off + access_size - 1; - else - max_off = min_off; + min_off = (s64)reg->var_off.value + off; + max_off = min_off + access_size; } else { if (reg->smax_value >= BPF_MAX_VAR_OFF || reg->smin_value <= -BPF_MAX_VAR_OFF) { @@ -6632,15 +6629,12 @@ static int check_stack_access_within_bounds( return -EACCES; } min_off = reg->smin_value + off; - if (access_size > 0) - max_off = reg->smax_value + off + access_size - 1; - else - max_off = min_off; + max_off = reg->smax_value + off + access_size; } err = check_stack_slot_within_bounds(min_off, state, type); - if (!err) - err = check_stack_slot_within_bounds(max_off, state, type); + if (!err && max_off > 0) + err = -EINVAL; /* out of stack access into non-negative offsets */ if (err) { if (tnum_is_const(reg->var_off)) { |