--- /dev/null
+From 3363bd0cfbb80dfcd25003cd3815b0ad8b68d0ff Mon Sep 17 00:00:00 2001
+From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Date: Fri, 17 Dec 2021 07:20:24 +0530
+Subject: bpf: Extend kfunc with PTR_TO_CTX, PTR_TO_MEM argument support
+
+From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+
+commit 3363bd0cfbb80dfcd25003cd3815b0ad8b68d0ff upstream.
+
+Allow passing PTR_TO_CTX, if the kfunc expects a matching struct type,
+and punt to PTR_TO_MEM block if reg->type does not fall in one of
+PTR_TO_BTF_ID or PTR_TO_SOCK* types. This will be used by future commits
+to get access to XDP and TC PTR_TO_CTX, and pass various data (flags,
+l4proto, netns_id, etc.) encoded in opts struct passed as pointer to
+kfunc.
+
+For PTR_TO_MEM support, arguments are currently limited to pointer to
+scalar, or pointer to struct composed of scalars. This is done so that
+unsafe scenarios (like passing PTR_TO_MEM where PTR_TO_BTF_ID of
+in-kernel valid structure is expected, which may have pointers) are
+avoided. Since the argument checking happens basd on argument register
+type, it is not easy to ascertain what the expected type is. In the
+future, support for PTR_TO_MEM for kfunc can be extended to serve other
+usecases. The struct type whose pointer is passed in may have maximum
+nesting depth of 4, all recursively composed of scalars or struct with
+scalars.
+
+Future commits will add negative tests that check whether these
+restrictions imposed for kfunc arguments are duly rejected by BPF
+verifier or not.
+
+Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Link: https://lore.kernel.org/bpf/20211217015031.1278167-4-memxor@gmail.com
+Signed-off-by: Edward Liaw <edliaw@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/btf.c | 93 +++++++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 73 insertions(+), 20 deletions(-)
+
+--- a/kernel/bpf/btf.c
++++ b/kernel/bpf/btf.c
+@@ -5447,6 +5447,46 @@ static u32 *reg2btf_ids[__BPF_REG_TYPE_M
+ #endif
+ };
+
++/* Returns true if struct is composed of scalars, 4 levels of nesting allowed */
++static bool __btf_type_is_scalar_struct(struct bpf_verifier_log *log,
++ const struct btf *btf,
++ const struct btf_type *t, int rec)
++{
++ const struct btf_type *member_type;
++ const struct btf_member *member;
++ u32 i;
++
++ if (!btf_type_is_struct(t))
++ return false;
++
++ for_each_member(i, t, member) {
++ const struct btf_array *array;
++
++ member_type = btf_type_skip_modifiers(btf, member->type, NULL);
++ if (btf_type_is_struct(member_type)) {
++ if (rec >= 3) {
++ bpf_log(log, "max struct nesting depth exceeded\n");
++ return false;
++ }
++ if (!__btf_type_is_scalar_struct(log, btf, member_type, rec + 1))
++ return false;
++ continue;
++ }
++ if (btf_type_is_array(member_type)) {
++ array = btf_type_array(member_type);
++ if (!array->nelems)
++ return false;
++ member_type = btf_type_skip_modifiers(btf, array->type, NULL);
++ if (!btf_type_is_scalar(member_type))
++ return false;
++ continue;
++ }
++ if (!btf_type_is_scalar(member_type))
++ return false;
++ }
++ return true;
++}
++
+ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
+ const struct btf *btf, u32 func_id,
+ struct bpf_reg_state *regs,
+@@ -5455,6 +5495,7 @@ static int btf_check_func_arg_match(stru
+ enum bpf_prog_type prog_type = env->prog->type == BPF_PROG_TYPE_EXT ?
+ env->prog->aux->dst_prog->type : env->prog->type;
+ struct bpf_verifier_log *log = &env->log;
++ bool is_kfunc = btf_is_kernel(btf);
+ const char *func_name, *ref_tname;
+ const struct btf_type *t, *ref_t;
+ const struct btf_param *args;
+@@ -5507,7 +5548,20 @@ static int btf_check_func_arg_match(stru
+
+ ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
+ ref_tname = btf_name_by_offset(btf, ref_t->name_off);
+- if (btf_is_kernel(btf)) {
++ if (btf_get_prog_ctx_type(log, btf, t, prog_type, i)) {
++ /* If function expects ctx type in BTF check that caller
++ * is passing PTR_TO_CTX.
++ */
++ if (reg->type != PTR_TO_CTX) {
++ bpf_log(log,
++ "arg#%d expected pointer to ctx, but got %s\n",
++ i, btf_type_str(t));
++ return -EINVAL;
++ }
++ if (check_ctx_reg(env, reg, regno))
++ return -EINVAL;
++ } else if (is_kfunc && (reg->type == PTR_TO_BTF_ID ||
++ (reg2btf_ids[base_type(reg->type)] && !type_flag(reg->type)))) {
+ const struct btf_type *reg_ref_t;
+ const struct btf *reg_btf;
+ const char *reg_ref_tname;
+@@ -5523,14 +5577,9 @@ static int btf_check_func_arg_match(stru
+ if (reg->type == PTR_TO_BTF_ID) {
+ reg_btf = reg->btf;
+ reg_ref_id = reg->btf_id;
+- } else if (reg2btf_ids[base_type(reg->type)]) {
++ } else {
+ reg_btf = btf_vmlinux;
+ reg_ref_id = *reg2btf_ids[base_type(reg->type)];
+- } else {
+- bpf_log(log, "kernel function %s args#%d expected pointer to %s %s but R%d is not a pointer to btf_id\n",
+- func_name, i,
+- btf_type_str(ref_t), ref_tname, regno);
+- return -EINVAL;
+ }
+
+ reg_ref_t = btf_type_skip_modifiers(reg_btf, reg_ref_id,
+@@ -5546,22 +5595,24 @@ static int btf_check_func_arg_match(stru
+ reg_ref_tname);
+ return -EINVAL;
+ }
+- } else if (btf_get_prog_ctx_type(log, btf, t, prog_type, i)) {
+- /* If function expects ctx type in BTF check that caller
+- * is passing PTR_TO_CTX.
+- */
+- if (reg->type != PTR_TO_CTX) {
+- bpf_log(log,
+- "arg#%d expected pointer to ctx, but got %s\n",
+- i, btf_type_str(t));
+- return -EINVAL;
+- }
+- if (check_ctx_reg(env, reg, regno))
+- return -EINVAL;
+ } else if (ptr_to_mem_ok) {
+ const struct btf_type *resolve_ret;
+ u32 type_size;
+
++ if (is_kfunc) {
++ /* Permit pointer to mem, but only when argument
++ * type is pointer to scalar, or struct composed
++ * (recursively) of scalars.
++ */
++ if (!btf_type_is_scalar(ref_t) &&
++ !__btf_type_is_scalar_struct(log, btf, ref_t, 0)) {
++ bpf_log(log,
++ "arg#%d pointer type %s %s must point to scalar or struct with scalar\n",
++ i, btf_type_str(ref_t), ref_tname);
++ return -EINVAL;
++ }
++ }
++
+ resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
+ if (IS_ERR(resolve_ret)) {
+ bpf_log(log,
+@@ -5574,6 +5625,8 @@ static int btf_check_func_arg_match(stru
+ if (check_mem_reg(env, reg, regno, type_size))
+ return -EINVAL;
+ } else {
++ bpf_log(log, "reg type unsupported for arg#%d %sfunction %s#%d\n", i,
++ is_kfunc ? "kernel " : "", func_name, func_id);
+ return -EINVAL;
+ }
+ }
+@@ -5623,7 +5676,7 @@ int btf_check_kfunc_arg_match(struct bpf
+ const struct btf *btf, u32 func_id,
+ struct bpf_reg_state *regs)
+ {
+- return btf_check_func_arg_match(env, btf, func_id, regs, false);
++ return btf_check_func_arg_match(env, btf, func_id, regs, true);
+ }
+
+ /* Convert BTF of a function into bpf_reg_state if possible
--- /dev/null
+From 64620e0a1e712a778095bd35cbb277dc2259281f Mon Sep 17 00:00:00 2001
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Tue, 11 Jan 2022 14:43:41 +0000
+Subject: bpf: Fix out of bounds access for ringbuf helpers
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+commit 64620e0a1e712a778095bd35cbb277dc2259281f upstream.
+
+Both bpf_ringbuf_submit() and bpf_ringbuf_discard() have ARG_PTR_TO_ALLOC_MEM
+in their bpf_func_proto definition as their first argument. They both expect
+the result from a prior bpf_ringbuf_reserve() call which has a return type of
+RET_PTR_TO_ALLOC_MEM_OR_NULL.
+
+Meaning, after a NULL check in the code, the verifier will promote the register
+type in the non-NULL branch to a PTR_TO_MEM and in the NULL branch to a known
+zero scalar. Generally, pointer arithmetic on PTR_TO_MEM is allowed, so the
+latter could have an offset.
+
+The ARG_PTR_TO_ALLOC_MEM expects a PTR_TO_MEM register type. However, the non-
+zero result from bpf_ringbuf_reserve() must be fed into either bpf_ringbuf_submit()
+or bpf_ringbuf_discard() but with the original offset given it will then read
+out the struct bpf_ringbuf_hdr mapping.
+
+The verifier missed to enforce a zero offset, so that out of bounds access
+can be triggered which could be used to escalate privileges if unprivileged
+BPF was enabled (disabled by default in kernel).
+
+Fixes: 457f44363a88 ("bpf: Implement BPF ring buffer and verifier support for it")
+Reported-by: <tr3e.wang@gmail.com> (SecCoder Security Lab)
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: John Fastabend <john.fastabend@gmail.com>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Edward Liaw <edliaw@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -5340,9 +5340,15 @@ static int check_func_arg(struct bpf_ver
+ case PTR_TO_BUF:
+ case PTR_TO_BUF | MEM_RDONLY:
+ case PTR_TO_STACK:
++ /* Some of the argument types nevertheless require a
++ * zero register offset.
++ */
++ if (arg_type == ARG_PTR_TO_ALLOC_MEM)
++ goto force_off_check;
+ break;
+ /* All the rest must be rejected: */
+ default:
++force_off_check:
+ err = __check_ptr_off_reg(env, reg, regno,
+ type == PTR_TO_BTF_ID);
+ if (err < 0)
--- /dev/null
+From a672b2e36a648afb04ad3bda93b6bda947a479a5 Mon Sep 17 00:00:00 2001
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Thu, 13 Jan 2022 11:11:30 +0000
+Subject: bpf: Fix ringbuf memory type confusion when passing to helpers
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+commit a672b2e36a648afb04ad3bda93b6bda947a479a5 upstream.
+
+The bpf_ringbuf_submit() and bpf_ringbuf_discard() have ARG_PTR_TO_ALLOC_MEM
+in their bpf_func_proto definition as their first argument, and thus both expect
+the result from a prior bpf_ringbuf_reserve() call which has a return type of
+RET_PTR_TO_ALLOC_MEM_OR_NULL.
+
+While the non-NULL memory from bpf_ringbuf_reserve() can be passed to other
+helpers, the two sinks (bpf_ringbuf_submit(), bpf_ringbuf_discard()) right now
+only enforce a register type of PTR_TO_MEM.
+
+This can lead to potential type confusion since it would allow other PTR_TO_MEM
+memory to be passed into the two sinks which did not come from bpf_ringbuf_reserve().
+
+Add a new MEM_ALLOC composable type attribute for PTR_TO_MEM, and enforce that:
+
+ - bpf_ringbuf_reserve() returns NULL or PTR_TO_MEM | MEM_ALLOC
+ - bpf_ringbuf_submit() and bpf_ringbuf_discard() only take PTR_TO_MEM | MEM_ALLOC
+ but not plain PTR_TO_MEM arguments via ARG_PTR_TO_ALLOC_MEM
+ - however, other helpers might treat PTR_TO_MEM | MEM_ALLOC as plain PTR_TO_MEM
+ to populate the memory area when they use ARG_PTR_TO_{UNINIT_,}MEM in their
+ func proto description
+
+Fixes: 457f44363a88 ("bpf: Implement BPF ring buffer and verifier support for it")
+Reported-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: John Fastabend <john.fastabend@gmail.com>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Edward Liaw <edliaw@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/bpf.h | 9 +++++++--
+ kernel/bpf/verifier.c | 6 +++++-
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+--- a/include/linux/bpf.h
++++ b/include/linux/bpf.h
+@@ -321,7 +321,12 @@ enum bpf_type_flag {
+ */
+ MEM_RDONLY = BIT(1 + BPF_BASE_TYPE_BITS),
+
+- __BPF_TYPE_LAST_FLAG = MEM_RDONLY,
++ /* MEM was "allocated" from a different helper, and cannot be mixed
++ * with regular non-MEM_ALLOC'ed MEM types.
++ */
++ MEM_ALLOC = BIT(2 + BPF_BASE_TYPE_BITS),
++
++ __BPF_TYPE_LAST_FLAG = MEM_ALLOC,
+ };
+
+ /* Max number of base types. */
+@@ -405,7 +410,7 @@ enum bpf_return_type {
+ RET_PTR_TO_SOCKET_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_SOCKET,
+ RET_PTR_TO_TCP_SOCK_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_TCP_SOCK,
+ RET_PTR_TO_SOCK_COMMON_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_SOCK_COMMON,
+- RET_PTR_TO_ALLOC_MEM_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_ALLOC_MEM,
++ RET_PTR_TO_ALLOC_MEM_OR_NULL = PTR_MAYBE_NULL | MEM_ALLOC | RET_PTR_TO_ALLOC_MEM,
+ RET_PTR_TO_BTF_ID_OR_NULL = PTR_MAYBE_NULL | RET_PTR_TO_BTF_ID,
+
+ /* This must be the last entry. Its purpose is to ensure the enum is
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -573,6 +573,8 @@ static const char *reg_type_str(struct b
+
+ if (type & MEM_RDONLY)
+ strncpy(prefix, "rdonly_", 16);
++ if (type & MEM_ALLOC)
++ strncpy(prefix, "alloc_", 16);
+
+ snprintf(env->type_str_buf, TYPE_STR_BUF_LEN, "%s%s%s",
+ prefix, str[base_type(type)], postfix);
+@@ -5157,6 +5159,7 @@ static const struct bpf_reg_types mem_ty
+ PTR_TO_MAP_KEY,
+ PTR_TO_MAP_VALUE,
+ PTR_TO_MEM,
++ PTR_TO_MEM | MEM_ALLOC,
+ PTR_TO_BUF,
+ },
+ };
+@@ -5174,7 +5177,7 @@ static const struct bpf_reg_types int_pt
+ static const struct bpf_reg_types fullsock_types = { .types = { PTR_TO_SOCKET } };
+ static const struct bpf_reg_types scalar_types = { .types = { SCALAR_VALUE } };
+ static const struct bpf_reg_types context_types = { .types = { PTR_TO_CTX } };
+-static const struct bpf_reg_types alloc_mem_types = { .types = { PTR_TO_MEM } };
++static const struct bpf_reg_types alloc_mem_types = { .types = { PTR_TO_MEM | MEM_ALLOC } };
+ static const struct bpf_reg_types const_map_ptr_types = { .types = { CONST_PTR_TO_MAP } };
+ static const struct bpf_reg_types btf_ptr_types = { .types = { PTR_TO_BTF_ID } };
+ static const struct bpf_reg_types spin_lock_types = { .types = { PTR_TO_MAP_VALUE } };
+@@ -5337,6 +5340,7 @@ static int check_func_arg(struct bpf_ver
+ case PTR_TO_MAP_VALUE:
+ case PTR_TO_MEM:
+ case PTR_TO_MEM | MEM_RDONLY:
++ case PTR_TO_MEM | MEM_ALLOC:
+ case PTR_TO_BUF:
+ case PTR_TO_BUF | MEM_RDONLY:
+ case PTR_TO_STACK:
--- /dev/null
+From be80a1d3f9dbe5aee79a325964f7037fe2d92f30 Mon Sep 17 00:00:00 2001
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Mon, 10 Jan 2022 14:05:49 +0000
+Subject: bpf: Generalize check_ctx_reg for reuse with other types
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+commit be80a1d3f9dbe5aee79a325964f7037fe2d92f30 upstream.
+
+Generalize the check_ctx_reg() helper function into a more generic named one
+so that it can be reused for other register types as well to check whether
+their offset is non-zero. No functional change.
+
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: John Fastabend <john.fastabend@gmail.com>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Edward Liaw <edliaw@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/bpf_verifier.h | 4 ++--
+ kernel/bpf/btf.c | 2 +-
+ kernel/bpf/verifier.c | 21 +++++++++++----------
+ 3 files changed, 14 insertions(+), 13 deletions(-)
+
+--- a/include/linux/bpf_verifier.h
++++ b/include/linux/bpf_verifier.h
+@@ -541,8 +541,8 @@ bpf_prog_offload_replace_insn(struct bpf
+ void
+ bpf_prog_offload_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt);
+
+-int check_ctx_reg(struct bpf_verifier_env *env,
+- const struct bpf_reg_state *reg, int regno);
++int check_ptr_off_reg(struct bpf_verifier_env *env,
++ const struct bpf_reg_state *reg, int regno);
+ int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
+ u32 regno, u32 mem_size);
+
+--- a/kernel/bpf/btf.c
++++ b/kernel/bpf/btf.c
+@@ -5558,7 +5558,7 @@ static int btf_check_func_arg_match(stru
+ i, btf_type_str(t));
+ return -EINVAL;
+ }
+- if (check_ctx_reg(env, reg, regno))
++ if (check_ptr_off_reg(env, reg, regno))
+ return -EINVAL;
+ } else if (is_kfunc && (reg->type == PTR_TO_BTF_ID ||
+ (reg2btf_ids[base_type(reg->type)] && !type_flag(reg->type)))) {
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -3980,16 +3980,16 @@ static int get_callee_stack_depth(struct
+ }
+ #endif
+
+-int check_ctx_reg(struct bpf_verifier_env *env,
+- const struct bpf_reg_state *reg, int regno)
++int check_ptr_off_reg(struct bpf_verifier_env *env,
++ const struct bpf_reg_state *reg, int regno)
+ {
+- /* Access to ctx or passing it to a helper is only allowed in
+- * its original, unmodified form.
++ /* Access to this pointer-typed register or passing it to a helper
++ * is only allowed in its original, unmodified form.
+ */
+
+ if (reg->off) {
+- verbose(env, "dereference of modified ctx ptr R%d off=%d disallowed\n",
+- regno, reg->off);
++ verbose(env, "dereference of modified %s ptr R%d off=%d disallowed\n",
++ reg_type_str(env, reg->type), regno, reg->off);
+ return -EACCES;
+ }
+
+@@ -3997,7 +3997,8 @@ int check_ctx_reg(struct bpf_verifier_en
+ char tn_buf[48];
+
+ tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
+- verbose(env, "variable ctx access var_off=%s disallowed\n", tn_buf);
++ verbose(env, "variable %s access var_off=%s disallowed\n",
++ reg_type_str(env, reg->type), tn_buf);
+ return -EACCES;
+ }
+
+@@ -4447,7 +4448,7 @@ static int check_mem_access(struct bpf_v
+ return -EACCES;
+ }
+
+- err = check_ctx_reg(env, reg, regno);
++ err = check_ptr_off_reg(env, reg, regno);
+ if (err < 0)
+ return err;
+
+@@ -5327,7 +5328,7 @@ static int check_func_arg(struct bpf_ver
+ return err;
+
+ if (type == PTR_TO_CTX) {
+- err = check_ctx_reg(env, reg, regno);
++ err = check_ptr_off_reg(env, reg, regno);
+ if (err < 0)
+ return err;
+ }
+@@ -9561,7 +9562,7 @@ static int check_ld_abs(struct bpf_verif
+ return err;
+ }
+
+- err = check_ctx_reg(env, ®s[ctx_reg], ctx_reg);
++ err = check_ptr_off_reg(env, ®s[ctx_reg], ctx_reg);
+ if (err < 0)
+ return err;
+
--- /dev/null
+From 6788ab23508bddb0a9d88e104284922cb2c22b77 Mon Sep 17 00:00:00 2001
+From: Daniel Borkmann <daniel@iogearbox.net>
+Date: Mon, 10 Jan 2022 14:40:40 +0000
+Subject: bpf: Generally fix helper register offset check
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+commit 6788ab23508bddb0a9d88e104284922cb2c22b77 upstream.
+
+Right now the assertion on check_ptr_off_reg() is only enforced for register
+types PTR_TO_CTX (and open coded also for PTR_TO_BTF_ID), however, this is
+insufficient since many other PTR_TO_* register types such as PTR_TO_FUNC do
+not handle/expect register offsets when passed to helper functions.
+
+Given this can slip-through easily when adding new types, make this an explicit
+allow-list and reject all other current and future types by default if this is
+encountered.
+
+Also, extend check_ptr_off_reg() to handle PTR_TO_BTF_ID as well instead of
+duplicating it. For PTR_TO_BTF_ID, reg->off is used for BTF to match expected
+BTF ids if struct offset is used. This part still needs to be allowed, but the
+dynamic off from the tnum must be rejected.
+
+Fixes: 69c087ba6225 ("bpf: Add bpf_for_each_map_elem() helper")
+Fixes: eaa6bcb71ef6 ("bpf: Introduce bpf_per_cpu_ptr()")
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: John Fastabend <john.fastabend@gmail.com>
+Acked-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Edward Liaw <edliaw@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c | 39 ++++++++++++++++++++++++++++-----------
+ 1 file changed, 28 insertions(+), 11 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -3980,14 +3980,15 @@ static int get_callee_stack_depth(struct
+ }
+ #endif
+
+-int check_ptr_off_reg(struct bpf_verifier_env *env,
+- const struct bpf_reg_state *reg, int regno)
++static int __check_ptr_off_reg(struct bpf_verifier_env *env,
++ const struct bpf_reg_state *reg, int regno,
++ bool fixed_off_ok)
+ {
+ /* Access to this pointer-typed register or passing it to a helper
+ * is only allowed in its original, unmodified form.
+ */
+
+- if (reg->off) {
++ if (!fixed_off_ok && reg->off) {
+ verbose(env, "dereference of modified %s ptr R%d off=%d disallowed\n",
+ reg_type_str(env, reg->type), regno, reg->off);
+ return -EACCES;
+@@ -4005,6 +4006,12 @@ int check_ptr_off_reg(struct bpf_verifie
+ return 0;
+ }
+
++int check_ptr_off_reg(struct bpf_verifier_env *env,
++ const struct bpf_reg_state *reg, int regno)
++{
++ return __check_ptr_off_reg(env, reg, regno, false);
++}
++
+ static int __check_buffer_access(struct bpf_verifier_env *env,
+ const char *buf_info,
+ const struct bpf_reg_state *reg,
+@@ -5267,12 +5274,6 @@ found:
+ kernel_type_name(btf_vmlinux, *arg_btf_id));
+ return -EACCES;
+ }
+-
+- if (!tnum_is_const(reg->var_off) || reg->var_off.value) {
+- verbose(env, "R%d is a pointer to in-kernel struct with non-zero offset\n",
+- regno);
+- return -EACCES;
+- }
+ }
+
+ return 0;
+@@ -5327,10 +5328,26 @@ static int check_func_arg(struct bpf_ver
+ if (err)
+ return err;
+
+- if (type == PTR_TO_CTX) {
+- err = check_ptr_off_reg(env, reg, regno);
++ switch ((u32)type) {
++ case SCALAR_VALUE:
++ /* Pointer types where reg offset is explicitly allowed: */
++ case PTR_TO_PACKET:
++ case PTR_TO_PACKET_META:
++ case PTR_TO_MAP_KEY:
++ case PTR_TO_MAP_VALUE:
++ case PTR_TO_MEM:
++ case PTR_TO_MEM | MEM_RDONLY:
++ case PTR_TO_BUF:
++ case PTR_TO_BUF | MEM_RDONLY:
++ case PTR_TO_STACK:
++ break;
++ /* All the rest must be rejected: */
++ default:
++ err = __check_ptr_off_reg(env, reg, regno,
++ type == PTR_TO_BTF_ID);
+ if (err < 0)
+ return err;
++ break;
+ }
+
+ skip_type_check:
btrfs-record-delayed-inode-root-in-transaction.patch
sunrpc-fix-rpcgss_context-trace-event-acceptor-field.patch
selftests-ftrace-limit-length-in-subsystem-enable-tests.patch
+bpf-extend-kfunc-with-ptr_to_ctx-ptr_to_mem-argument-support.patch
+bpf-generalize-check_ctx_reg-for-reuse-with-other-types.patch
+bpf-generally-fix-helper-register-offset-check.patch
+bpf-fix-out-of-bounds-access-for-ringbuf-helpers.patch
+bpf-fix-ringbuf-memory-type-confusion-when-passing-to-helpers.patch