bpf: Guard stack limits against 32bit overflow
[platform/kernel/linux-rpi.git] / kernel / bpf / verifier.c
index 24152ac..4759950 100644 (file)
@@ -6371,7 +6371,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)
 {
@@ -6400,7 +6400,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;
 
@@ -6413,11 +6413,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) {
@@ -6426,15 +6423,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)) {