]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - kernel/bpf/verifier.c
bpf: No need to simulate speculative domain for immediates
[mirror_ubuntu-hirsute-kernel.git] / kernel / bpf / verifier.c
index 33683eafea90edd28e2af35ad4eec70638c2094e..63d761cdd6782198eb47f77c81597767ab7a57c9 100644 (file)
@@ -1304,9 +1304,7 @@ static bool __reg64_bound_s32(s64 a)
 
 static bool __reg64_bound_u32(u64 a)
 {
-       if (a > U32_MIN && a < U32_MAX)
-               return true;
-       return false;
+       return a > U32_MIN && a < U32_MAX;
 }
 
 static void __reg_combine_64_into_32(struct bpf_reg_state *reg)
@@ -1317,10 +1315,10 @@ static void __reg_combine_64_into_32(struct bpf_reg_state *reg)
                reg->s32_min_value = (s32)reg->smin_value;
                reg->s32_max_value = (s32)reg->smax_value;
        }
-       if (__reg64_bound_u32(reg->umin_value))
+       if (__reg64_bound_u32(reg->umin_value) && __reg64_bound_u32(reg->umax_value)) {
                reg->u32_min_value = (u32)reg->umin_value;
-       if (__reg64_bound_u32(reg->umax_value))
                reg->u32_max_value = (u32)reg->umax_value;
+       }
 
        /* Intersecting with the old var_off might have improved our bounds
         * slightly.  e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
@@ -2271,12 +2269,14 @@ static void save_register_state(struct bpf_func_state *state,
                state->stack[spi].slot_type[i] = STACK_SPILL;
 }
 
-/* check_stack_read/write functions track spill/fill of registers,
+/* check_stack_{read,write}_fixed_off functions track spill/fill of registers,
  * stack boundary and alignment are checked in check_mem_access()
  */
-static int check_stack_write(struct bpf_verifier_env *env,
-                            struct bpf_func_state *state, /* func where register points to */
-                            int off, int size, int value_regno, int insn_idx)
+static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
+                                      /* stack frame we're writing to */
+                                      struct bpf_func_state *state,
+                                      int off, int size, int value_regno,
+                                      int insn_idx)
 {
        struct bpf_func_state *cur; /* state of the current function */
        int i, slot = -off - 1, spi = slot / BPF_REG_SIZE, err;
@@ -2402,9 +2402,175 @@ static int check_stack_write(struct bpf_verifier_env *env,
        return 0;
 }
 
-static int check_stack_read(struct bpf_verifier_env *env,
-                           struct bpf_func_state *reg_state /* func where register points to */,
-                           int off, int size, int value_regno)
+/* Write the stack: 'stack[ptr_regno + off] = value_regno'. 'ptr_regno' is
+ * known to contain a variable offset.
+ * This function checks whether the write is permitted and conservatively
+ * tracks the effects of the write, considering that each stack slot in the
+ * dynamic range is potentially written to.
+ *
+ * 'off' includes 'regno->off'.
+ * 'value_regno' can be -1, meaning that an unknown value is being written to
+ * the stack.
+ *
+ * Spilled pointers in range are not marked as written because we don't know
+ * what's going to be actually written. This means that read propagation for
+ * future reads cannot be terminated by this write.
+ *
+ * For privileged programs, uninitialized stack slots are considered
+ * initialized by this write (even though we don't know exactly what offsets
+ * are going to be written to). The idea is that we don't want the verifier to
+ * reject future reads that access slots written to through variable offsets.
+ */
+static int check_stack_write_var_off(struct bpf_verifier_env *env,
+                                    /* func where register points to */
+                                    struct bpf_func_state *state,
+                                    int ptr_regno, int off, int size,
+                                    int value_regno, int insn_idx)
+{
+       struct bpf_func_state *cur; /* state of the current function */
+       int min_off, max_off;
+       int i, err;
+       struct bpf_reg_state *ptr_reg = NULL, *value_reg = NULL;
+       bool writing_zero = false;
+       /* set if the fact that we're writing a zero is used to let any
+        * stack slots remain STACK_ZERO
+        */
+       bool zero_used = false;
+
+       cur = env->cur_state->frame[env->cur_state->curframe];
+       ptr_reg = &cur->regs[ptr_regno];
+       min_off = ptr_reg->smin_value + off;
+       max_off = ptr_reg->smax_value + off + size;
+       if (value_regno >= 0)
+               value_reg = &cur->regs[value_regno];
+       if (value_reg && register_is_null(value_reg))
+               writing_zero = true;
+
+       err = realloc_func_state(state, round_up(-min_off, BPF_REG_SIZE),
+                                state->acquired_refs, true);
+       if (err)
+               return err;
+
+
+       /* Variable offset writes destroy any spilled pointers in range. */
+       for (i = min_off; i < max_off; i++) {
+               u8 new_type, *stype;
+               int slot, spi;
+
+               slot = -i - 1;
+               spi = slot / BPF_REG_SIZE;
+               stype = &state->stack[spi].slot_type[slot % BPF_REG_SIZE];
+
+               if (!env->allow_ptr_leaks
+                               && *stype != NOT_INIT
+                               && *stype != SCALAR_VALUE) {
+                       /* Reject the write if there's are spilled pointers in
+                        * range. If we didn't reject here, the ptr status
+                        * would be erased below (even though not all slots are
+                        * actually overwritten), possibly opening the door to
+                        * leaks.
+                        */
+                       verbose(env, "spilled ptr in range of var-offset stack write; insn %d, ptr off: %d",
+                               insn_idx, i);
+                       return -EINVAL;
+               }
+
+               /* Erase all spilled pointers. */
+               state->stack[spi].spilled_ptr.type = NOT_INIT;
+
+               /* Update the slot type. */
+               new_type = STACK_MISC;
+               if (writing_zero && *stype == STACK_ZERO) {
+                       new_type = STACK_ZERO;
+                       zero_used = true;
+               }
+               /* If the slot is STACK_INVALID, we check whether it's OK to
+                * pretend that it will be initialized by this write. The slot
+                * might not actually be written to, and so if we mark it as
+                * initialized future reads might leak uninitialized memory.
+                * For privileged programs, we will accept such reads to slots
+                * that may or may not be written because, if we're reject
+                * them, the error would be too confusing.
+                */
+               if (*stype == STACK_INVALID && !env->allow_uninit_stack) {
+                       verbose(env, "uninit stack in range of var-offset write prohibited for !root; insn %d, off: %d",
+                                       insn_idx, i);
+                       return -EINVAL;
+               }
+               *stype = new_type;
+       }
+       if (zero_used) {
+               /* backtracking doesn't work for STACK_ZERO yet. */
+               err = mark_chain_precision(env, value_regno);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+/* When register 'dst_regno' is assigned some values from stack[min_off,
+ * max_off), we set the register's type according to the types of the
+ * respective stack slots. If all the stack values are known to be zeros, then
+ * so is the destination reg. Otherwise, the register is considered to be
+ * SCALAR. This function does not deal with register filling; the caller must
+ * ensure that all spilled registers in the stack range have been marked as
+ * read.
+ */
+static void mark_reg_stack_read(struct bpf_verifier_env *env,
+                               /* func where src register points to */
+                               struct bpf_func_state *ptr_state,
+                               int min_off, int max_off, int dst_regno)
+{
+       struct bpf_verifier_state *vstate = env->cur_state;
+       struct bpf_func_state *state = vstate->frame[vstate->curframe];
+       int i, slot, spi;
+       u8 *stype;
+       int zeros = 0;
+
+       for (i = min_off; i < max_off; i++) {
+               slot = -i - 1;
+               spi = slot / BPF_REG_SIZE;
+               stype = ptr_state->stack[spi].slot_type;
+               if (stype[slot % BPF_REG_SIZE] != STACK_ZERO)
+                       break;
+               zeros++;
+       }
+       if (zeros == max_off - min_off) {
+               /* any access_size read into register is zero extended,
+                * so the whole register == const_zero
+                */
+               __mark_reg_const_zero(&state->regs[dst_regno]);
+               /* backtracking doesn't support STACK_ZERO yet,
+                * so mark it precise here, so that later
+                * backtracking can stop here.
+                * Backtracking may not need this if this register
+                * doesn't participate in pointer adjustment.
+                * Forward propagation of precise flag is not
+                * necessary either. This mark is only to stop
+                * backtracking. Any register that contributed
+                * to const 0 was marked precise before spill.
+                */
+               state->regs[dst_regno].precise = true;
+       } else {
+               /* have read misc data from the stack */
+               mark_reg_unknown(env, state->regs, dst_regno);
+       }
+       state->regs[dst_regno].live |= REG_LIVE_WRITTEN;
+}
+
+/* Read the stack at 'off' and put the results into the register indicated by
+ * 'dst_regno'. It handles reg filling if the addressed stack slot is a
+ * spilled reg.
+ *
+ * 'dst_regno' can be -1, meaning that the read value is not going to a
+ * register.
+ *
+ * The access is assumed to be within the current stack bounds.
+ */
+static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
+                                     /* func where src register points to */
+                                     struct bpf_func_state *reg_state,
+                                     int off, int size, int dst_regno)
 {
        struct bpf_verifier_state *vstate = env->cur_state;
        struct bpf_func_state *state = vstate->frame[vstate->curframe];
@@ -2412,11 +2578,6 @@ static int check_stack_read(struct bpf_verifier_env *env,
        struct bpf_reg_state *reg;
        u8 *stype;
 
-       if (reg_state->allocated_stack <= slot) {
-               verbose(env, "invalid read from stack off %d+0 size %d\n",
-                       off, size);
-               return -EACCES;
-       }
        stype = reg_state->stack[spi].slot_type;
        reg = &reg_state->stack[spi].spilled_ptr;
 
@@ -2427,9 +2588,9 @@ static int check_stack_read(struct bpf_verifier_env *env,
                                verbose(env, "invalid size of register fill\n");
                                return -EACCES;
                        }
-                       if (value_regno >= 0) {
-                               mark_reg_unknown(env, state->regs, value_regno);
-                               state->regs[value_regno].live |= REG_LIVE_WRITTEN;
+                       if (dst_regno >= 0) {
+                               mark_reg_unknown(env, state->regs, dst_regno);
+                               state->regs[dst_regno].live |= REG_LIVE_WRITTEN;
                        }
                        mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64);
                        return 0;
@@ -2441,16 +2602,16 @@ static int check_stack_read(struct bpf_verifier_env *env,
                        }
                }
 
-               if (value_regno >= 0) {
+               if (dst_regno >= 0) {
                        /* restore register state from stack */
-                       state->regs[value_regno] = *reg;
+                       state->regs[dst_regno] = *reg;
                        /* mark reg as written since spilled pointer state likely
                         * has its liveness marks cleared by is_state_visited()
                         * which resets stack/reg liveness for state transitions
                         */
-                       state->regs[value_regno].live |= REG_LIVE_WRITTEN;
+                       state->regs[dst_regno].live |= REG_LIVE_WRITTEN;
                } else if (__is_pointer_value(env->allow_ptr_leaks, reg)) {
-                       /* If value_regno==-1, the caller is asking us whether
+                       /* If dst_regno==-1, the caller is asking us whether
                         * it is acceptable to use this value as a SCALAR_VALUE
                         * (e.g. for XADD).
                         * We must not allow unprivileged callers to do that
@@ -2462,70 +2623,167 @@ static int check_stack_read(struct bpf_verifier_env *env,
                }
                mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64);
        } else {
-               int zeros = 0;
+               u8 type;
 
                for (i = 0; i < size; i++) {
-                       if (stype[(slot - i) % BPF_REG_SIZE] == STACK_MISC)
+                       type = stype[(slot - i) % BPF_REG_SIZE];
+                       if (type == STACK_MISC)
                                continue;
-                       if (stype[(slot - i) % BPF_REG_SIZE] == STACK_ZERO) {
-                               zeros++;
+                       if (type == STACK_ZERO)
                                continue;
-                       }
                        verbose(env, "invalid read from stack off %d+%d size %d\n",
                                off, i, size);
                        return -EACCES;
                }
                mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64);
-               if (value_regno >= 0) {
-                       if (zeros == size) {
-                               /* any size read into register is zero extended,
-                                * so the whole register == const_zero
-                                */
-                               __mark_reg_const_zero(&state->regs[value_regno]);
-                               /* backtracking doesn't support STACK_ZERO yet,
-                                * so mark it precise here, so that later
-                                * backtracking can stop here.
-                                * Backtracking may not need this if this register
-                                * doesn't participate in pointer adjustment.
-                                * Forward propagation of precise flag is not
-                                * necessary either. This mark is only to stop
-                                * backtracking. Any register that contributed
-                                * to const 0 was marked precise before spill.
-                                */
-                               state->regs[value_regno].precise = true;
-                       } else {
-                               /* have read misc data from the stack */
-                               mark_reg_unknown(env, state->regs, value_regno);
-                       }
-                       state->regs[value_regno].live |= REG_LIVE_WRITTEN;
-               }
+               if (dst_regno >= 0)
+                       mark_reg_stack_read(env, reg_state, off, off + size, dst_regno);
        }
        return 0;
 }
 
-static int check_stack_access(struct bpf_verifier_env *env,
-                             const struct bpf_reg_state *reg,
-                             int off, int size)
+enum stack_access_src {
+       ACCESS_DIRECT = 1,  /* the access is performed by an instruction */
+       ACCESS_HELPER = 2,  /* the access is performed by a helper */
+};
+
+static int check_stack_range_initialized(struct bpf_verifier_env *env,
+                                        int regno, int off, int access_size,
+                                        bool zero_size_allowed,
+                                        enum stack_access_src type,
+                                        struct bpf_call_arg_meta *meta);
+
+static struct bpf_reg_state *reg_state(struct bpf_verifier_env *env, int regno)
+{
+       return cur_regs(env) + regno;
+}
+
+/* Read the stack at 'ptr_regno + off' and put the result into the register
+ * 'dst_regno'.
+ * 'off' includes the pointer register's fixed offset(i.e. 'ptr_regno.off'),
+ * but not its variable offset.
+ * 'size' is assumed to be <= reg size and the access is assumed to be aligned.
+ *
+ * As opposed to check_stack_read_fixed_off, this function doesn't deal with
+ * filling registers (i.e. reads of spilled register cannot be detected when
+ * the offset is not fixed). We conservatively mark 'dst_regno' as containing
+ * SCALAR_VALUE. That's why we assert that the 'ptr_regno' has a variable
+ * offset; for a fixed offset check_stack_read_fixed_off should be used
+ * instead.
+ */
+static int check_stack_read_var_off(struct bpf_verifier_env *env,
+                                   int ptr_regno, int off, int size, int dst_regno)
 {
-       /* Stack accesses must be at a fixed offset, so that we
-        * can determine what type of data were returned. See
-        * check_stack_read().
+       /* The state of the source register. */
+       struct bpf_reg_state *reg = reg_state(env, ptr_regno);
+       struct bpf_func_state *ptr_state = func(env, reg);
+       int err;
+       int min_off, max_off;
+
+       /* Note that we pass a NULL meta, so raw access will not be permitted.
         */
-       if (!tnum_is_const(reg->var_off)) {
+       err = check_stack_range_initialized(env, ptr_regno, off, size,
+                                           false, ACCESS_DIRECT, NULL);
+       if (err)
+               return err;
+
+       min_off = reg->smin_value + off;
+       max_off = reg->smax_value + off;
+       mark_reg_stack_read(env, ptr_state, min_off, max_off + size, dst_regno);
+       return 0;
+}
+
+/* check_stack_read dispatches to check_stack_read_fixed_off or
+ * check_stack_read_var_off.
+ *
+ * The caller must ensure that the offset falls within the allocated stack
+ * bounds.
+ *
+ * 'dst_regno' is a register which will receive the value from the stack. It
+ * can be -1, meaning that the read value is not going to a register.
+ */
+static int check_stack_read(struct bpf_verifier_env *env,
+                           int ptr_regno, int off, int size,
+                           int dst_regno)
+{
+       struct bpf_reg_state *reg = reg_state(env, ptr_regno);
+       struct bpf_func_state *state = func(env, reg);
+       int err;
+       /* Some accesses are only permitted with a static offset. */
+       bool var_off = !tnum_is_const(reg->var_off);
+
+       /* The offset is required to be static when reads don't go to a
+        * register, in order to not leak pointers (see
+        * check_stack_read_fixed_off).
+        */
+       if (dst_regno < 0 && var_off) {
                char tn_buf[48];
 
                tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
-               verbose(env, "variable stack access var_off=%s off=%d size=%d\n",
+               verbose(env, "variable offset stack pointer cannot be passed into helper function; var_off=%s off=%d size=%d\n",
                        tn_buf, off, size);
                return -EACCES;
        }
+       /* Variable offset is prohibited for unprivileged mode for simplicity
+        * since it requires corresponding support in Spectre masking for stack
+        * ALU. See also retrieve_ptr_limit().
+        */
+       if (!env->bypass_spec_v1 && var_off) {
+               char tn_buf[48];
 
-       if (off >= 0 || off < -MAX_BPF_STACK) {
-               verbose(env, "invalid stack off=%d size=%d\n", off, size);
+               tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
+               verbose(env, "R%d variable offset stack access prohibited for !root, var_off=%s\n",
+                               ptr_regno, tn_buf);
                return -EACCES;
        }
 
-       return 0;
+       if (!var_off) {
+               off += reg->var_off.value;
+               err = check_stack_read_fixed_off(env, state, off, size,
+                                                dst_regno);
+       } else {
+               /* Variable offset stack reads need more conservative handling
+                * than fixed offset ones. Note that dst_regno >= 0 on this
+                * branch.
+                */
+               err = check_stack_read_var_off(env, ptr_regno, off, size,
+                                              dst_regno);
+       }
+       return err;
+}
+
+
+/* check_stack_write dispatches to check_stack_write_fixed_off or
+ * check_stack_write_var_off.
+ *
+ * 'ptr_regno' is the register used as a pointer into the stack.
+ * 'off' includes 'ptr_regno->off', but not its variable offset (if any).
+ * 'value_regno' is the register whose value we're writing to the stack. It can
+ * be -1, meaning that we're not writing from a register.
+ *
+ * The caller must ensure that the offset falls within the maximum stack size.
+ */
+static int check_stack_write(struct bpf_verifier_env *env,
+                            int ptr_regno, int off, int size,
+                            int value_regno, int insn_idx)
+{
+       struct bpf_reg_state *reg = reg_state(env, ptr_regno);
+       struct bpf_func_state *state = func(env, reg);
+       int err;
+
+       if (tnum_is_const(reg->var_off)) {
+               off += reg->var_off.value;
+               err = check_stack_write_fixed_off(env, state, off, size,
+                                                 value_regno, insn_idx);
+       } else {
+               /* Variable offset stack reads need more conservative handling
+                * than fixed offset ones.
+                */
+               err = check_stack_write_var_off(env, state,
+                                               ptr_regno, off, size,
+                                               value_regno, insn_idx);
+       }
+       return err;
 }
 
 static int check_map_access_type(struct bpf_verifier_env *env, u32 regno,
@@ -2858,11 +3116,6 @@ static int check_sock_access(struct bpf_verifier_env *env, int insn_idx,
        return -EACCES;
 }
 
-static struct bpf_reg_state *reg_state(struct bpf_verifier_env *env, int regno)
-{
-       return cur_regs(env) + regno;
-}
-
 static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
 {
        return __is_pointer_value(env->allow_ptr_leaks, reg_state(env, regno));
@@ -2981,8 +3234,8 @@ static int check_ptr_alignment(struct bpf_verifier_env *env,
                break;
        case PTR_TO_STACK:
                pointer_desc = "stack ";
-               /* The stack spill tracking logic in check_stack_write()
-                * and check_stack_read() relies on stack accesses being
+               /* The stack spill tracking logic in check_stack_write_fixed_off()
+                * and check_stack_read_fixed_off() relies on stack accesses being
                 * aligned.
                 */
                strict = true;
@@ -3400,6 +3653,91 @@ static int check_ptr_to_map_access(struct bpf_verifier_env *env,
        return 0;
 }
 
+/* Check that the stack access at the given offset is within bounds. The
+ * maximum valid offset is -1.
+ *
+ * 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,
+                                         struct bpf_func_state *state,
+                                         enum bpf_access_type t)
+{
+       int min_valid_off;
+
+       if (t == BPF_WRITE)
+               min_valid_off = -MAX_BPF_STACK;
+       else
+               min_valid_off = -state->allocated_stack;
+
+       if (off < min_valid_off || off > -1)
+               return -EACCES;
+       return 0;
+}
+
+/* Check that the stack access at 'regno + off' falls within the maximum stack
+ * bounds.
+ *
+ * 'off' includes `regno->offset`, but not its dynamic part (if any).
+ */
+static int check_stack_access_within_bounds(
+               struct bpf_verifier_env *env,
+               int regno, int off, int access_size,
+               enum stack_access_src src, enum bpf_access_type type)
+{
+       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;
+       int err;
+       char *err_extra;
+
+       if (src == ACCESS_HELPER)
+               /* We don't know if helpers are reading or writing (or both). */
+               err_extra = " indirect access to";
+       else if (type == BPF_READ)
+               err_extra = " read from";
+       else
+               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;
+       } else {
+               if (reg->smax_value >= BPF_MAX_VAR_OFF ||
+                   reg->smin_value <= -BPF_MAX_VAR_OFF) {
+                       verbose(env, "invalid unbounded variable-offset%s stack R%d\n",
+                               err_extra, regno);
+                       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;
+       }
+
+       err = check_stack_slot_within_bounds(min_off, state, type);
+       if (!err)
+               err = check_stack_slot_within_bounds(max_off, state, type);
+
+       if (err) {
+               if (tnum_is_const(reg->var_off)) {
+                       verbose(env, "invalid%s stack R%d off=%d size=%d\n",
+                               err_extra, regno, off, access_size);
+               } else {
+                       char tn_buf[48];
+
+                       tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
+                       verbose(env, "invalid variable-offset%s stack R%d var_off=%s size=%d\n",
+                               err_extra, regno, tn_buf, access_size);
+               }
+       }
+       return err;
+}
 
 /* check whether memory at (regno + off) is accessible for t = (read | write)
  * if t==write, value_regno is a register which value is stored into memory
@@ -3515,8 +3853,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
                }
 
        } else if (reg->type == PTR_TO_STACK) {
-               off += reg->var_off.value;
-               err = check_stack_access(env, reg, off, size);
+               /* Basic bounds checks. */
+               err = check_stack_access_within_bounds(env, regno, off, size, ACCESS_DIRECT, t);
                if (err)
                        return err;
 
@@ -3525,12 +3863,12 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
                if (err)
                        return err;
 
-               if (t == BPF_WRITE)
-                       err = check_stack_write(env, state, off, size,
-                                               value_regno, insn_idx);
-               else
-                       err = check_stack_read(env, state, off, size,
+               if (t == BPF_READ)
+                       err = check_stack_read(env, regno, off, size,
                                               value_regno);
+               else
+                       err = check_stack_write(env, regno, off, size,
+                                               value_regno, insn_idx);
        } else if (reg_is_pkt_pointer(reg)) {
                if (t == BPF_WRITE && !may_access_direct_pkt_data(env, NULL, t)) {
                        verbose(env, "cannot write into packet\n");
@@ -3652,49 +3990,53 @@ static int check_xadd(struct bpf_verifier_env *env, int insn_idx, struct bpf_ins
                                BPF_SIZE(insn->code), BPF_WRITE, -1, true);
 }
 
-static int __check_stack_boundary(struct bpf_verifier_env *env, u32 regno,
-                                 int off, int access_size,
-                                 bool zero_size_allowed)
+/* When register 'regno' is used to read the stack (either directly or through
+ * a helper function) make sure that it's within stack boundary and, depending
+ * on the access type, that all elements of the stack are initialized.
+ *
+ * 'off' includes 'regno->off', but not its dynamic part (if any).
+ *
+ * All registers that have been spilled on the stack in the slots within the
+ * read offsets are marked as read.
+ */
+static int check_stack_range_initialized(
+               struct bpf_verifier_env *env, int regno, int off,
+               int access_size, bool zero_size_allowed,
+               enum stack_access_src type, struct bpf_call_arg_meta *meta)
 {
        struct bpf_reg_state *reg = reg_state(env, regno);
+       struct bpf_func_state *state = func(env, reg);
+       int err, min_off, max_off, i, j, slot, spi;
+       char *err_extra = type == ACCESS_HELPER ? " indirect" : "";
+       enum bpf_access_type bounds_check_type;
+       /* Some accesses can write anything into the stack, others are
+        * read-only.
+        */
+       bool clobber = false;
 
-       if (off >= 0 || off < -MAX_BPF_STACK || off + access_size > 0 ||
-           access_size < 0 || (access_size == 0 && !zero_size_allowed)) {
-               if (tnum_is_const(reg->var_off)) {
-                       verbose(env, "invalid stack type R%d off=%d access_size=%d\n",
-                               regno, off, access_size);
-               } else {
-                       char tn_buf[48];
-
-                       tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
-                       verbose(env, "invalid stack type R%d var_off=%s access_size=%d\n",
-                               regno, tn_buf, access_size);
-               }
+       if (access_size == 0 && !zero_size_allowed) {
+               verbose(env, "invalid zero-sized read\n");
                return -EACCES;
        }
-       return 0;
-}
 
-/* when register 'regno' is passed into function that will read 'access_size'
- * bytes from that pointer, make sure that it's within stack boundary
- * and all elements of stack are initialized.
- * Unlike most pointer bounds-checking functions, this one doesn't take an
- * 'off' argument, so it has to add in reg->off itself.
- */
-static int check_stack_boundary(struct bpf_verifier_env *env, int regno,
-                               int access_size, bool zero_size_allowed,
-                               struct bpf_call_arg_meta *meta)
-{
-       struct bpf_reg_state *reg = reg_state(env, regno);
-       struct bpf_func_state *state = func(env, reg);
-       int err, min_off, max_off, i, j, slot, spi;
+       if (type == ACCESS_HELPER) {
+               /* The bounds checks for writes are more permissive than for
+                * reads. However, if raw_mode is not set, we'll do extra
+                * checks below.
+                */
+               bounds_check_type = BPF_WRITE;
+               clobber = true;
+       } else {
+               bounds_check_type = BPF_READ;
+       }
+       err = check_stack_access_within_bounds(env, regno, off, access_size,
+                                              type, bounds_check_type);
+       if (err)
+               return err;
+
 
        if (tnum_is_const(reg->var_off)) {
-               min_off = max_off = reg->var_off.value + reg->off;
-               err = __check_stack_boundary(env, regno, min_off, access_size,
-                                            zero_size_allowed);
-               if (err)
-                       return err;
+               min_off = max_off = reg->var_off.value + off;
        } else {
                /* Variable offset is prohibited for unprivileged mode for
                 * simplicity since it requires corresponding support in
@@ -3705,8 +4047,8 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno,
                        char tn_buf[48];
 
                        tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
-                       verbose(env, "R%d indirect variable offset stack access prohibited for !root, var_off=%s\n",
-                               regno, tn_buf);
+                       verbose(env, "R%d%s variable offset stack access prohibited for !root, var_off=%s\n",
+                               regno, err_extra, tn_buf);
                        return -EACCES;
                }
                /* Only initialized buffer on stack is allowed to be accessed
@@ -3718,28 +4060,8 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno,
                if (meta && meta->raw_mode)
                        meta = NULL;
 
-               if (reg->smax_value >= BPF_MAX_VAR_OFF ||
-                   reg->smax_value <= -BPF_MAX_VAR_OFF) {
-                       verbose(env, "R%d unbounded indirect variable offset stack access\n",
-                               regno);
-                       return -EACCES;
-               }
-               min_off = reg->smin_value + reg->off;
-               max_off = reg->smax_value + reg->off;
-               err = __check_stack_boundary(env, regno, min_off, access_size,
-                                            zero_size_allowed);
-               if (err) {
-                       verbose(env, "R%d min value is outside of stack bound\n",
-                               regno);
-                       return err;
-               }
-               err = __check_stack_boundary(env, regno, max_off, access_size,
-                                            zero_size_allowed);
-               if (err) {
-                       verbose(env, "R%d max value is outside of stack bound\n",
-                               regno);
-                       return err;
-               }
+               min_off = reg->smin_value + off;
+               max_off = reg->smax_value + off;
        }
 
        if (meta && meta->raw_mode) {
@@ -3759,8 +4081,10 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno,
                if (*stype == STACK_MISC)
                        goto mark;
                if (*stype == STACK_ZERO) {
-                       /* helper can write anything into the stack */
-                       *stype = STACK_MISC;
+                       if (clobber) {
+                               /* helper can write anything into the stack */
+                               *stype = STACK_MISC;
+                       }
                        goto mark;
                }
 
@@ -3771,22 +4095,24 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno,
                if (state->stack[spi].slot_type[0] == STACK_SPILL &&
                    (state->stack[spi].spilled_ptr.type == SCALAR_VALUE ||
                     env->allow_ptr_leaks)) {
-                       __mark_reg_unknown(env, &state->stack[spi].spilled_ptr);
-                       for (j = 0; j < BPF_REG_SIZE; j++)
-                               state->stack[spi].slot_type[j] = STACK_MISC;
+                       if (clobber) {
+                               __mark_reg_unknown(env, &state->stack[spi].spilled_ptr);
+                               for (j = 0; j < BPF_REG_SIZE; j++)
+                                       state->stack[spi].slot_type[j] = STACK_MISC;
+                       }
                        goto mark;
                }
 
 err:
                if (tnum_is_const(reg->var_off)) {
-                       verbose(env, "invalid indirect read from stack off %d+%d size %d\n",
-                               min_off, i - min_off, access_size);
+                       verbose(env, "invalid%s read from stack R%d off %d+%d size %d\n",
+                               err_extra, regno, min_off, i - min_off, access_size);
                } else {
                        char tn_buf[48];
 
                        tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
-                       verbose(env, "invalid indirect read from stack var_off %s+%d size %d\n",
-                               tn_buf, i - min_off, access_size);
+                       verbose(env, "invalid%s read from stack R%d var_off %s+%d size %d\n",
+                               err_extra, regno, tn_buf, i - min_off, access_size);
                }
                return -EACCES;
 mark:
@@ -3835,8 +4161,10 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
                                           "rdwr",
                                           &env->prog->aux->max_rdwr_access);
        case PTR_TO_STACK:
-               return check_stack_boundary(env, regno, access_size,
-                                           zero_size_allowed, meta);
+               return check_stack_range_initialized(
+                               env,
+                               regno, reg->off, access_size,
+                               zero_size_allowed, ACCESS_HELPER, meta);
        default: /* scalar_value or invalid ptr */
                /* Allow zero-byte read from NULL, regardless of pointer type */
                if (zero_size_allowed && access_size == 0 &&
@@ -5384,35 +5712,43 @@ static struct bpf_insn_aux_data *cur_aux(struct bpf_verifier_env *env)
        return &env->insn_aux_data[env->insn_idx];
 }
 
+enum {
+       REASON_BOUNDS   = -1,
+       REASON_TYPE     = -2,
+       REASON_PATHS    = -3,
+       REASON_LIMIT    = -4,
+       REASON_STACK    = -5,
+};
+
 static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
-                             u32 *ptr_limit, u8 opcode, bool off_is_neg)
+                             u32 *alu_limit, bool mask_to_left)
 {
-       bool mask_to_left = (opcode == BPF_ADD &&  off_is_neg) ||
-                           (opcode == BPF_SUB && !off_is_neg);
-       u32 off;
+       u32 max = 0, ptr_limit = 0;
 
        switch (ptr_reg->type) {
        case PTR_TO_STACK:
-               /* Indirect variable offset stack access is prohibited in
-                * unprivileged mode so it's not handled here.
+               /* Offset 0 is out-of-bounds, but acceptable start for the
+                * left direction, see BPF_REG_FP. Also, unknown scalar
+                * offset where we would need to deal with min/max bounds is
+                * currently prohibited for unprivileged.
                 */
-               off = ptr_reg->off + ptr_reg->var_off.value;
-               if (mask_to_left)
-                       *ptr_limit = MAX_BPF_STACK + off;
-               else
-                       *ptr_limit = -off;
-               return 0;
+               max = MAX_BPF_STACK + mask_to_left;
+               ptr_limit = -(ptr_reg->var_off.value + ptr_reg->off);
+               break;
        case PTR_TO_MAP_VALUE:
-               if (mask_to_left) {
-                       *ptr_limit = ptr_reg->umax_value + ptr_reg->off;
-               } else {
-                       off = ptr_reg->smin_value + ptr_reg->off;
-                       *ptr_limit = ptr_reg->map_ptr->value_size - off;
-               }
-               return 0;
+               max = ptr_reg->map_ptr->value_size;
+               ptr_limit = (mask_to_left ?
+                            ptr_reg->smin_value :
+                            ptr_reg->umax_value) + ptr_reg->off;
+               break;
        default:
-               return -EINVAL;
+               return REASON_TYPE;
        }
+
+       if (ptr_limit >= max)
+               return REASON_LIMIT;
+       *alu_limit = ptr_limit;
+       return 0;
 }
 
 static bool can_skip_alu_sanitation(const struct bpf_verifier_env *env,
@@ -5430,7 +5766,7 @@ static int update_alu_sanitation_state(struct bpf_insn_aux_data *aux,
        if (aux->alu_state &&
            (aux->alu_state != alu_state ||
             aux->alu_limit != alu_limit))
-               return -EACCES;
+               return REASON_PATHS;
 
        /* Corresponding fixup done in fixup_bpf_calls(). */
        aux->alu_state = alu_state;
@@ -5449,19 +5785,34 @@ static int sanitize_val_alu(struct bpf_verifier_env *env,
        return update_alu_sanitation_state(aux, BPF_ALU_NON_POINTER, 0);
 }
 
+static bool sanitize_needed(u8 opcode)
+{
+       return opcode == BPF_ADD || opcode == BPF_SUB;
+}
+
+struct bpf_sanitize_info {
+       struct bpf_insn_aux_data aux;
+       bool mask_to_left;
+};
+
 static int sanitize_ptr_alu(struct bpf_verifier_env *env,
                            struct bpf_insn *insn,
                            const struct bpf_reg_state *ptr_reg,
+                           const struct bpf_reg_state *off_reg,
                            struct bpf_reg_state *dst_reg,
-                           bool off_is_neg)
+                           struct bpf_sanitize_info *info,
+                           const bool commit_window)
 {
+       struct bpf_insn_aux_data *aux = commit_window ? cur_aux(env) : &info->aux;
        struct bpf_verifier_state *vstate = env->cur_state;
-       struct bpf_insn_aux_data *aux = cur_aux(env);
+       bool off_is_imm = tnum_is_const(off_reg->var_off);
+       bool off_is_neg = off_reg->smin_value < 0;
        bool ptr_is_dst_reg = ptr_reg == dst_reg;
        u8 opcode = BPF_OP(insn->code);
        u32 alu_state, alu_limit;
        struct bpf_reg_state tmp;
        bool ret;
+       int err;
 
        if (can_skip_alu_sanitation(env, insn))
                return 0;
@@ -5473,15 +5824,47 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env,
        if (vstate->speculative)
                goto do_sim;
 
-       alu_state  = off_is_neg ? BPF_ALU_NEG_VALUE : 0;
-       alu_state |= ptr_is_dst_reg ?
-                    BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST;
+       if (!commit_window) {
+               if (!tnum_is_const(off_reg->var_off) &&
+                   (off_reg->smin_value < 0) != (off_reg->smax_value < 0))
+                       return REASON_BOUNDS;
 
-       if (retrieve_ptr_limit(ptr_reg, &alu_limit, opcode, off_is_neg))
-               return 0;
-       if (update_alu_sanitation_state(aux, alu_state, alu_limit))
-               return -EACCES;
+               info->mask_to_left = (opcode == BPF_ADD &&  off_is_neg) ||
+                                    (opcode == BPF_SUB && !off_is_neg);
+       }
+
+       err = retrieve_ptr_limit(ptr_reg, &alu_limit, info->mask_to_left);
+       if (err < 0)
+               return err;
+
+       if (commit_window) {
+               /* In commit phase we narrow the masking window based on
+                * the observed pointer move after the simulated operation.
+                */
+               alu_state = info->aux.alu_state;
+               alu_limit = abs(info->aux.alu_limit - alu_limit);
+       } else {
+               alu_state  = off_is_neg ? BPF_ALU_NEG_VALUE : 0;
+               alu_state |= off_is_imm ? BPF_ALU_IMMEDIATE : 0;
+               alu_state |= ptr_is_dst_reg ?
+                            BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST;
+       }
+
+       err = update_alu_sanitation_state(aux, alu_state, alu_limit);
+       if (err < 0)
+               return err;
 do_sim:
+       /* If we're in commit phase, we're done here given we already
+        * pushed the truncated dst_reg into the speculative verification
+        * stack.
+        *
+        * Also, when register is a known constant, we rewrite register-based
+        * operation to immediate-based, and thus do not need masking (and as
+        * a consequence, do not need to simulate the zero-truncation either).
+        */
+       if (commit_window || off_is_imm)
+               return 0;
+
        /* Simulate and find potential out-of-bounds access under
         * speculative execution from truncation as a result of
         * masking when off was not within expected range. If off
@@ -5498,7 +5881,112 @@ do_sim:
        ret = push_stack(env, env->insn_idx + 1, env->insn_idx, true);
        if (!ptr_is_dst_reg && ret)
                *dst_reg = tmp;
-       return !ret ? -EFAULT : 0;
+       return !ret ? REASON_STACK : 0;
+}
+
+static int sanitize_err(struct bpf_verifier_env *env,
+                       const struct bpf_insn *insn, int reason,
+                       const struct bpf_reg_state *off_reg,
+                       const struct bpf_reg_state *dst_reg)
+{
+       static const char *err = "pointer arithmetic with it prohibited for !root";
+       const char *op = BPF_OP(insn->code) == BPF_ADD ? "add" : "sub";
+       u32 dst = insn->dst_reg, src = insn->src_reg;
+
+       switch (reason) {
+       case REASON_BOUNDS:
+               verbose(env, "R%d has unknown scalar with mixed signed bounds, %s\n",
+                       off_reg == dst_reg ? dst : src, err);
+               break;
+       case REASON_TYPE:
+               verbose(env, "R%d has pointer with unsupported alu operation, %s\n",
+                       off_reg == dst_reg ? src : dst, err);
+               break;
+       case REASON_PATHS:
+               verbose(env, "R%d tried to %s from different maps, paths or scalars, %s\n",
+                       dst, op, err);
+               break;
+       case REASON_LIMIT:
+               verbose(env, "R%d tried to %s beyond pointer bounds, %s\n",
+                       dst, op, err);
+               break;
+       case REASON_STACK:
+               verbose(env, "R%d could not be pushed for speculative verification, %s\n",
+                       dst, err);
+               break;
+       default:
+               verbose(env, "verifier internal error: unknown reason (%d)\n",
+                       reason);
+               break;
+       }
+
+       return -EACCES;
+}
+
+/* check that stack access falls within stack limits and that 'reg' doesn't
+ * have a variable offset.
+ *
+ * Variable offset is prohibited for unprivileged mode for simplicity since it
+ * requires corresponding support in Spectre masking for stack ALU.  See also
+ * retrieve_ptr_limit().
+ *
+ *
+ * 'off' includes 'reg->off'.
+ */
+static int check_stack_access_for_ptr_arithmetic(
+                               struct bpf_verifier_env *env,
+                               int regno,
+                               const struct bpf_reg_state *reg,
+                               int off)
+{
+       if (!tnum_is_const(reg->var_off)) {
+               char tn_buf[48];
+
+               tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
+               verbose(env, "R%d variable stack access prohibited for !root, var_off=%s off=%d\n",
+                       regno, tn_buf, off);
+               return -EACCES;
+       }
+
+       if (off >= 0 || off < -MAX_BPF_STACK) {
+               verbose(env, "R%d stack pointer arithmetic goes out of range, "
+                       "prohibited for !root; off=%d\n", regno, off);
+               return -EACCES;
+       }
+
+       return 0;
+}
+
+static int sanitize_check_bounds(struct bpf_verifier_env *env,
+                                const struct bpf_insn *insn,
+                                const struct bpf_reg_state *dst_reg)
+{
+       u32 dst = insn->dst_reg;
+
+       /* For unprivileged we require that resulting offset must be in bounds
+        * in order to be able to sanitize access later on.
+        */
+       if (env->bypass_spec_v1)
+               return 0;
+
+       switch (dst_reg->type) {
+       case PTR_TO_STACK:
+               if (check_stack_access_for_ptr_arithmetic(env, dst, dst_reg,
+                                       dst_reg->off + dst_reg->var_off.value))
+                       return -EACCES;
+               break;
+       case PTR_TO_MAP_VALUE:
+               if (check_map_access(env, dst, dst_reg->off, 1, false)) {
+                       verbose(env, "R%d pointer arithmetic of map value goes out of range, "
+                               "prohibited for !root\n", dst);
+                       return -EACCES;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
 }
 
 /* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off.
@@ -5519,8 +6007,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
            smin_ptr = ptr_reg->smin_value, smax_ptr = ptr_reg->smax_value;
        u64 umin_val = off_reg->umin_value, umax_val = off_reg->umax_value,
            umin_ptr = ptr_reg->umin_value, umax_ptr = ptr_reg->umax_value;
-       u32 dst = insn->dst_reg, src = insn->src_reg;
+       struct bpf_sanitize_info info = {};
        u8 opcode = BPF_OP(insn->code);
+       u32 dst = insn->dst_reg;
        int ret;
 
        dst_reg = &regs[dst];
@@ -5568,13 +6057,6 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
                verbose(env, "R%d pointer arithmetic on %s prohibited\n",
                        dst, reg_type_str[ptr_reg->type]);
                return -EACCES;
-       case PTR_TO_MAP_VALUE:
-               if (!env->allow_ptr_leaks && !known && (smin_val < 0) != (smax_val < 0)) {
-                       verbose(env, "R%d has unknown scalar with mixed signed bounds, pointer arithmetic with it prohibited for !root\n",
-                               off_reg == dst_reg ? dst : src);
-                       return -EACCES;
-               }
-               fallthrough;
        default:
                break;
        }
@@ -5592,13 +6074,15 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
        /* pointer types do not carry 32-bit bounds at the moment. */
        __mark_reg32_unbounded(dst_reg);
 
+       if (sanitize_needed(opcode)) {
+               ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg,
+                                      &info, false);
+               if (ret < 0)
+                       return sanitize_err(env, insn, ret, off_reg, dst_reg);
+       }
+
        switch (opcode) {
        case BPF_ADD:
-               ret = sanitize_ptr_alu(env, insn, ptr_reg, dst_reg, smin_val < 0);
-               if (ret < 0) {
-                       verbose(env, "R%d tried to add from different maps or paths\n", dst);
-                       return ret;
-               }
                /* We can take a fixed offset as long as it doesn't overflow
                 * the s32 'off' field
                 */
@@ -5649,11 +6133,6 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
                }
                break;
        case BPF_SUB:
-               ret = sanitize_ptr_alu(env, insn, ptr_reg, dst_reg, smin_val < 0);
-               if (ret < 0) {
-                       verbose(env, "R%d tried to sub from different maps or paths\n", dst);
-                       return ret;
-               }
                if (dst_reg == off_reg) {
                        /* scalar -= pointer.  Creates an unknown scalar */
                        verbose(env, "R%d tried to subtract pointer from scalar\n",
@@ -5734,22 +6213,13 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
        __reg_deduce_bounds(dst_reg);
        __reg_bound_offset(dst_reg);
 
-       /* For unprivileged we require that resulting offset must be in bounds
-        * in order to be able to sanitize access later on.
-        */
-       if (!env->bypass_spec_v1) {
-               if (dst_reg->type == PTR_TO_MAP_VALUE &&
-                   check_map_access(env, dst, dst_reg->off, 1, false)) {
-                       verbose(env, "R%d pointer arithmetic of map value goes out of range, "
-                               "prohibited for !root\n", dst);
-                       return -EACCES;
-               } else if (dst_reg->type == PTR_TO_STACK &&
-                          check_stack_access(env, dst_reg, dst_reg->off +
-                                             dst_reg->var_off.value, 1)) {
-                       verbose(env, "R%d stack pointer arithmetic goes out of range, "
-                               "prohibited for !root\n", dst);
-                       return -EACCES;
-               }
+       if (sanitize_check_bounds(env, insn, dst_reg) < 0)
+               return -EACCES;
+       if (sanitize_needed(opcode)) {
+               ret = sanitize_ptr_alu(env, insn, dst_reg, off_reg, dst_reg,
+                                      &info, true);
+               if (ret < 0)
+                       return sanitize_err(env, insn, ret, off_reg, dst_reg);
        }
 
        return 0;
@@ -5936,11 +6406,10 @@ static void scalar32_min_max_and(struct bpf_reg_state *dst_reg,
        s32 smin_val = src_reg->s32_min_value;
        u32 umax_val = src_reg->u32_max_value;
 
-       /* Assuming scalar64_min_max_and will be called so its safe
-        * to skip updating register for known 32-bit case.
-        */
-       if (src_known && dst_known)
+       if (src_known && dst_known) {
+               __mark_reg32_known(dst_reg, var32_off.value);
                return;
+       }
 
        /* We get our minimum from the var_off, since that's inherently
         * bitwise.  Our maximum is the minimum of the operands' maxima.
@@ -5960,7 +6429,6 @@ static void scalar32_min_max_and(struct bpf_reg_state *dst_reg,
                dst_reg->s32_min_value = dst_reg->u32_min_value;
                dst_reg->s32_max_value = dst_reg->u32_max_value;
        }
-
 }
 
 static void scalar_min_max_and(struct bpf_reg_state *dst_reg,
@@ -6007,11 +6475,10 @@ static void scalar32_min_max_or(struct bpf_reg_state *dst_reg,
        s32 smin_val = src_reg->s32_min_value;
        u32 umin_val = src_reg->u32_min_value;
 
-       /* Assuming scalar64_min_max_or will be called so it is safe
-        * to skip updating register for known case.
-        */
-       if (src_known && dst_known)
+       if (src_known && dst_known) {
+               __mark_reg32_known(dst_reg, var32_off.value);
                return;
+       }
 
        /* We get our maximum from the var_off, and our minimum is the
         * maximum of the operands' minima
@@ -6076,11 +6543,10 @@ static void scalar32_min_max_xor(struct bpf_reg_state *dst_reg,
        struct tnum var32_off = tnum_subreg(dst_reg->var_off);
        s32 smin_val = src_reg->s32_min_value;
 
-       /* Assuming scalar64_min_max_xor will be called so it is safe
-        * to skip updating register for known case.
-        */
-       if (src_known && dst_known)
+       if (src_known && dst_known) {
+               __mark_reg32_known(dst_reg, var32_off.value);
                return;
+       }
 
        /* We get both minimum and maximum from the var32_off. */
        dst_reg->u32_min_value = var32_off.value;
@@ -6343,9 +6809,8 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
        s32 s32_min_val, s32_max_val;
        u32 u32_min_val, u32_max_val;
        u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32;
-       u32 dst = insn->dst_reg;
-       int ret;
        bool alu32 = (BPF_CLASS(insn->code) != BPF_ALU64);
+       int ret;
 
        smin_val = src_reg.smin_value;
        smax_val = src_reg.smax_value;
@@ -6387,6 +6852,12 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
                return 0;
        }
 
+       if (sanitize_needed(opcode)) {
+               ret = sanitize_val_alu(env, insn);
+               if (ret < 0)
+                       return sanitize_err(env, insn, ret, NULL, NULL);
+       }
+
        /* Calculate sign/unsigned bounds and tnum for alu32 and alu64 bit ops.
         * There are two classes of instructions: The first class we track both
         * alu32 and alu64 sign/unsigned bounds independently this provides the
@@ -6403,21 +6874,11 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
         */
        switch (opcode) {
        case BPF_ADD:
-               ret = sanitize_val_alu(env, insn);
-               if (ret < 0) {
-                       verbose(env, "R%d tried to add from different pointers or scalars\n", dst);
-                       return ret;
-               }
                scalar32_min_max_add(dst_reg, &src_reg);
                scalar_min_max_add(dst_reg, &src_reg);
                dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off);
                break;
        case BPF_SUB:
-               ret = sanitize_val_alu(env, insn);
-               if (ret < 0) {
-                       verbose(env, "R%d tried to sub from different pointers or scalars\n", dst);
-                       return ret;
-               }
                scalar32_min_max_sub(dst_reg, &src_reg);
                scalar_min_max_sub(dst_reg, &src_reg);
                dst_reg->var_off = tnum_sub(dst_reg->var_off, src_reg.var_off);
@@ -8571,6 +9032,10 @@ static int check_btf_info(struct bpf_verifier_env *env,
        btf = btf_get_by_fd(attr->prog_btf_fd);
        if (IS_ERR(btf))
                return PTR_ERR(btf);
+       if (btf_is_kernel(btf)) {
+               btf_put(btf);
+               return -EACCES;
+       }
        env->prog->aux->btf = btf;
 
        err = check_btf_func(env, attr, uattr);
@@ -11064,7 +11529,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
                        const u8 code_sub = BPF_ALU64 | BPF_SUB | BPF_X;
                        struct bpf_insn insn_buf[16];
                        struct bpf_insn *patch = &insn_buf[0];
-                       bool issrc, isneg;
+                       bool issrc, isneg, isimm;
                        u32 off_reg;
 
                        aux = &env->insn_aux_data[i + delta];
@@ -11075,28 +11540,29 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
                        isneg = aux->alu_state & BPF_ALU_NEG_VALUE;
                        issrc = (aux->alu_state & BPF_ALU_SANITIZE) ==
                                BPF_ALU_SANITIZE_SRC;
+                       isimm = aux->alu_state & BPF_ALU_IMMEDIATE;
 
                        off_reg = issrc ? insn->src_reg : insn->dst_reg;
-                       if (isneg)
-                               *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1);
-                       *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit - 1);
-                       *patch++ = BPF_ALU64_REG(BPF_SUB, BPF_REG_AX, off_reg);
-                       *patch++ = BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg);
-                       *patch++ = BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0);
-                       *patch++ = BPF_ALU64_IMM(BPF_ARSH, BPF_REG_AX, 63);
-                       if (issrc) {
-                               *patch++ = BPF_ALU64_REG(BPF_AND, BPF_REG_AX,
-                                                        off_reg);
-                               insn->src_reg = BPF_REG_AX;
+                       if (isimm) {
+                               *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit);
                        } else {
-                               *patch++ = BPF_ALU64_REG(BPF_AND, off_reg,
-                                                        BPF_REG_AX);
+                               if (isneg)
+                                       *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1);
+                               *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit);
+                               *patch++ = BPF_ALU64_REG(BPF_SUB, BPF_REG_AX, off_reg);
+                               *patch++ = BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg);
+                               *patch++ = BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0);
+                               *patch++ = BPF_ALU64_IMM(BPF_ARSH, BPF_REG_AX, 63);
+                               *patch++ = BPF_ALU64_REG(BPF_AND, BPF_REG_AX, off_reg);
                        }
+                       if (!issrc)
+                               *patch++ = BPF_MOV64_REG(insn->dst_reg, insn->src_reg);
+                       insn->src_reg = BPF_REG_AX;
                        if (isneg)
                                insn->code = insn->code == code_add ?
                                             code_sub : code_add;
                        *patch++ = *insn;
-                       if (issrc && isneg)
+                       if (issrc && isneg && !isimm)
                                *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1);
                        cnt = patch - insn_buf;
 
@@ -11557,6 +12023,11 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env)
        u32 btf_id, member_idx;
        const char *mname;
 
+       if (!prog->gpl_compatible) {
+               verbose(env, "struct ops programs must have a GPL compatible license\n");
+               return -EINVAL;
+       }
+
        btf_id = prog->aux->attach_btf_id;
        st_ops = bpf_struct_ops_find(btf_id);
        if (!st_ops) {
@@ -12010,6 +12481,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
                env->strict_alignment = false;
 
        env->allow_ptr_leaks = bpf_allow_ptr_leaks();
+       env->allow_uninit_stack = bpf_allow_uninit_stack();
        env->allow_ptr_to_map_access = bpf_allow_ptr_to_map_access();
        env->bypass_spec_v1 = bpf_bypass_spec_v1();
        env->bypass_spec_v4 = bpf_bypass_spec_v4();