}
 
 static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
-                                  int access_size, bool zero_size_allowed,
+                                  int access_size, enum bpf_access_type access_type,
+                                  bool zero_size_allowed,
                                   struct bpf_call_arg_meta *meta)
 {
        struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno];
                return check_packet_access(env, regno, reg->off, access_size,
                                           zero_size_allowed);
        case PTR_TO_MAP_KEY:
-               if (meta && meta->raw_mode) {
+               if (access_type == BPF_WRITE) {
                        verbose(env, "R%d cannot write into %s\n", regno,
                                reg_type_str(env, reg->type));
                        return -EACCES;
                return check_mem_region_access(env, regno, reg->off, access_size,
                                               reg->map_ptr->key_size, false);
        case PTR_TO_MAP_VALUE:
-               if (check_map_access_type(env, regno, reg->off, access_size,
-                                         meta && meta->raw_mode ? BPF_WRITE :
-                                         BPF_READ))
+               if (check_map_access_type(env, regno, reg->off, access_size, access_type))
                        return -EACCES;
                return check_map_access(env, regno, reg->off, access_size,
                                        zero_size_allowed, ACCESS_HELPER);
        case PTR_TO_MEM:
                if (type_is_rdonly_mem(reg->type)) {
-                       if (meta && meta->raw_mode) {
+                       if (access_type == BPF_WRITE) {
                                verbose(env, "R%d cannot write into %s\n", regno,
                                        reg_type_str(env, reg->type));
                                return -EACCES;
                                               zero_size_allowed);
        case PTR_TO_BUF:
                if (type_is_rdonly_mem(reg->type)) {
-                       if (meta && meta->raw_mode) {
+                       if (access_type == BPF_WRITE) {
                                verbose(env, "R%d cannot write into %s\n", regno,
                                        reg_type_str(env, reg->type));
                                return -EACCES;
                 * Dynamically check it now.
                 */
                if (!env->ops->convert_ctx_access) {
-                       enum bpf_access_type atype = meta && meta->raw_mode ? BPF_WRITE : BPF_READ;
                        int offset = access_size - 1;
 
                        /* Allow zero-byte read from PTR_TO_CTX */
                                return zero_size_allowed ? 0 : -EACCES;
 
                        return check_mem_access(env, env->insn_idx, regno, offset, BPF_B,
-                                               atype, -1, false, false);
+                                               access_type, -1, false, false);
                }
 
                fallthrough;
  */
 static int check_mem_size_reg(struct bpf_verifier_env *env,
                              struct bpf_reg_state *reg, u32 regno,
+                             enum bpf_access_type access_type,
                              bool zero_size_allowed,
                              struct bpf_call_arg_meta *meta)
 {
         */
        meta->msize_max_value = reg->umax_value;
 
-       /* The register is SCALAR_VALUE; the access check
-        * happens using its boundaries.
+       /* The register is SCALAR_VALUE; the access check happens using
+        * its boundaries. For unprivileged variable accesses, disable
+        * raw mode so that the program is required to initialize all
+        * the memory that the helper could just partially fill up.
         */
        if (!tnum_is_const(reg->var_off))
-               /* For unprivileged variable accesses, disable raw
-                * mode so that the program is required to
-                * initialize all the memory that the helper could
-                * just partially fill up.
-                */
                meta = NULL;
 
        if (reg->smin_value < 0) {
                        regno);
                return -EACCES;
        }
-       err = check_helper_mem_access(env, regno - 1,
-                                     reg->umax_value,
-                                     zero_size_allowed, meta);
+       err = check_helper_mem_access(env, regno - 1, reg->umax_value,
+                                     access_type, zero_size_allowed, meta);
        if (!err)
                err = mark_chain_precision(env, regno);
        return err;
 {
        bool may_be_null = type_may_be_null(reg->type);
        struct bpf_reg_state saved_reg;
-       struct bpf_call_arg_meta meta;
        int err;
 
        if (register_is_null(reg))
                return 0;
 
-       memset(&meta, 0, sizeof(meta));
        /* Assuming that the register contains a value check if the memory
         * access is safe. Temporarily save and restore the register's state as
         * the conversion shouldn't be visible to a caller.
                mark_ptr_not_null_reg(reg);
        }
 
-       err = check_helper_mem_access(env, regno, mem_size, true, &meta);
-       /* Check access for BPF_WRITE */
-       meta.raw_mode = true;
-       err = err ?: check_helper_mem_access(env, regno, mem_size, true, &meta);
+       err = check_helper_mem_access(env, regno, mem_size, BPF_READ, true, NULL);
+       err = err ?: check_helper_mem_access(env, regno, mem_size, BPF_WRITE, true, NULL);
 
        if (may_be_null)
                *reg = saved_reg;
                mark_ptr_not_null_reg(mem_reg);
        }
 
-       err = check_mem_size_reg(env, reg, regno, true, &meta);
-       /* Check access for BPF_WRITE */
-       meta.raw_mode = true;
-       err = err ?: check_mem_size_reg(env, reg, regno, true, &meta);
+       err = check_mem_size_reg(env, reg, regno, BPF_READ, true, &meta);
+       err = err ?: check_mem_size_reg(env, reg, regno, BPF_WRITE, true, &meta);
 
        if (may_be_null)
                *mem_reg = saved_reg;
+
        return err;
 }
 
                        verbose(env, "invalid map_ptr to access map->key\n");
                        return -EACCES;
                }
-               err = check_helper_mem_access(env, regno,
-                                             meta->map_ptr->key_size, false,
-                                             NULL);
+               err = check_helper_mem_access(env, regno, meta->map_ptr->key_size,
+                                             BPF_READ, false, NULL);
                break;
        case ARG_PTR_TO_MAP_VALUE:
                if (type_may_be_null(arg_type) && register_is_null(reg))
                        return -EACCES;
                }
                meta->raw_mode = arg_type & MEM_UNINIT;
-               err = check_helper_mem_access(env, regno,
-                                             meta->map_ptr->value_size, false,
-                                             meta);
+               err = check_helper_mem_access(env, regno, meta->map_ptr->value_size,
+                                             arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ,
+                                             false, meta);
                break;
        case ARG_PTR_TO_PERCPU_BTF_ID:
                if (!reg->btf_id) {
                 */
                meta->raw_mode = arg_type & MEM_UNINIT;
                if (arg_type & MEM_FIXED_SIZE) {
-                       err = check_helper_mem_access(env, regno, fn->arg_size[arg], false, meta);
+                       err = check_helper_mem_access(env, regno, fn->arg_size[arg],
+                                                     arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ,
+                                                     false, meta);
                        if (err)
                                return err;
                        if (arg_type & MEM_ALIGNED)
                }
                break;
        case ARG_CONST_SIZE:
-               err = check_mem_size_reg(env, reg, regno, false, meta);
+               err = check_mem_size_reg(env, reg, regno,
+                                        fn->arg_type[arg - 1] & MEM_WRITE ?
+                                        BPF_WRITE : BPF_READ,
+                                        false, meta);
                break;
        case ARG_CONST_SIZE_OR_ZERO:
-               err = check_mem_size_reg(env, reg, regno, true, meta);
+               err = check_mem_size_reg(env, reg, regno,
+                                        fn->arg_type[arg - 1] & MEM_WRITE ?
+                                        BPF_WRITE : BPF_READ,
+                                        true, meta);
                break;
        case ARG_PTR_TO_DYNPTR:
                err = process_dynptr_func(env, regno, insn_idx, arg_type, 0);