--- /dev/null
+From stable+bounces-139108-greg=kroah.com@vger.kernel.org Wed Apr 30 10:20:21 2025
+From: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Date: Wed, 30 Apr 2025 16:19:43 +0800
+Subject: bpf: add find_containing_subprog() utility function
+To: stable@vger.kernel.org
+Cc: Alexei Starovoitov <ast@kernel.org>, Eduard Zingerman <eddyz87@gmail.com>, Nick Zavaritsky <mejedi@gmail.com>, Dan Carpenter <dan.carpenter@linaro.org>, Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Message-ID: <20250430081955.49927-2-shung-hsi.yu@suse.com>
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+commit 27e88bc4df1d80888fe1aaca786a7cc6e69587e2 upstream.
+
+Add a utility function, looking for a subprogram containing a given
+instruction index, rewrite find_subprog() to use this function.
+
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20241210041100.1898468-2-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c | 28 ++++++++++++++++++++++++----
+ 1 file changed, 24 insertions(+), 4 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -2636,16 +2636,36 @@ static int cmp_subprogs(const void *a, c
+ ((struct bpf_subprog_info *)b)->start;
+ }
+
++/* Find subprogram that contains instruction at 'off' */
++static struct bpf_subprog_info *find_containing_subprog(struct bpf_verifier_env *env, int off)
++{
++ struct bpf_subprog_info *vals = env->subprog_info;
++ int l, r, m;
++
++ if (off >= env->prog->len || off < 0 || env->subprog_cnt == 0)
++ return NULL;
++
++ l = 0;
++ r = env->subprog_cnt - 1;
++ while (l < r) {
++ m = l + (r - l + 1) / 2;
++ if (vals[m].start <= off)
++ l = m;
++ else
++ r = m - 1;
++ }
++ return &vals[l];
++}
++
++/* Find subprogram that starts exactly at 'off' */
+ static int find_subprog(struct bpf_verifier_env *env, int off)
+ {
+ struct bpf_subprog_info *p;
+
+- p = bsearch(&off, env->subprog_info, env->subprog_cnt,
+- sizeof(env->subprog_info[0]), cmp_subprogs);
+- if (!p)
++ p = find_containing_subprog(env, off);
++ if (!p || p->start != off)
+ return -ENOENT;
+ return p - env->subprog_info;
+-
+ }
+
+ static int add_subprog(struct bpf_verifier_env *env, int off)
--- /dev/null
+From stable+bounces-139112-greg=kroah.com@vger.kernel.org Wed Apr 30 10:20:34 2025
+From: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Date: Wed, 30 Apr 2025 16:19:47 +0800
+Subject: bpf: check changes_pkt_data property for extension programs
+To: stable@vger.kernel.org
+Cc: Alexei Starovoitov <ast@kernel.org>, Eduard Zingerman <eddyz87@gmail.com>, Nick Zavaritsky <mejedi@gmail.com>, Dan Carpenter <dan.carpenter@linaro.org>, Shung-Hsi Yu <shung-hsi.yu@suse.com>, Alexei Starovoitov <alexei.starovoitov@gmail.com>
+Message-ID: <20250430081955.49927-6-shung-hsi.yu@suse.com>
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+commit 81f6d0530ba031b5f038a091619bf2ff29568852 upstream.
+
+When processing calls to global sub-programs, verifier decides whether
+to invalidate all packet pointers in current state depending on the
+changes_pkt_data property of the global sub-program.
+
+Because of this, an extension program replacing a global sub-program
+must be compatible with changes_pkt_data property of the sub-program
+being replaced.
+
+This commit:
+- adds changes_pkt_data flag to struct bpf_prog_aux:
+ - this flag is set in check_cfg() for main sub-program;
+ - in jit_subprogs() for other sub-programs;
+- modifies bpf_check_attach_btf_id() to check changes_pkt_data flag;
+- moves call to check_attach_btf_id() after the call to check_cfg(),
+ because it needs changes_pkt_data flag to be set:
+
+ bpf_check:
+ ... ...
+ - check_attach_btf_id resolve_pseudo_ldimm64
+ resolve_pseudo_ldimm64 --> bpf_prog_is_offloaded
+ bpf_prog_is_offloaded check_cfg
+ check_cfg + check_attach_btf_id
+ ... ...
+
+The following fields are set by check_attach_btf_id():
+- env->ops
+- prog->aux->attach_btf_trace
+- prog->aux->attach_func_name
+- prog->aux->attach_func_proto
+- prog->aux->dst_trampoline
+- prog->aux->mod
+- prog->aux->saved_dst_attach_type
+- prog->aux->saved_dst_prog_type
+- prog->expected_attach_type
+
+Neither of these fields are used by resolve_pseudo_ldimm64() or
+bpf_prog_offload_verifier_prep() (for netronome and netdevsim
+drivers), so the reordering is safe.
+
+Suggested-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20241210041100.1898468-6-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+[ shung-hsi.yu: adapt to missing fields in "struct bpf_prog_aux". Context
+difference in jit_subprogs() because BPF Exception is not supported. Context
+difference in bpf_check() because commit 5b5f51bff1b6 "bpf:
+no_caller_saved_registers attribute for helper calls" is not present. ]
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/bpf.h | 1 +
+ kernel/bpf/verifier.c | 16 ++++++++++++----
+ 2 files changed, 13 insertions(+), 4 deletions(-)
+
+--- a/include/linux/bpf.h
++++ b/include/linux/bpf.h
+@@ -1430,6 +1430,7 @@ struct bpf_prog_aux {
+ bool sleepable;
+ bool tail_call_reachable;
+ bool xdp_has_frags;
++ bool changes_pkt_data;
+ /* BTF_KIND_FUNC_PROTO for valid attach_btf_id */
+ const struct btf_type *attach_func_proto;
+ /* function name for valid attach_btf_id */
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -15462,6 +15462,7 @@ static int check_cfg(struct bpf_verifier
+ }
+ }
+ ret = 0; /* cfg looks good */
++ env->prog->aux->changes_pkt_data = env->subprog_info[0].changes_pkt_data;
+
+ err_free:
+ kvfree(insn_state);
+@@ -18622,6 +18623,7 @@ static int jit_subprogs(struct bpf_verif
+ }
+ func[i]->aux->num_exentries = num_exentries;
+ func[i]->aux->tail_call_reachable = env->subprog_info[i].tail_call_reachable;
++ func[i]->aux->changes_pkt_data = env->subprog_info[i].changes_pkt_data;
+ func[i] = bpf_int_jit_compile(func[i]);
+ if (!func[i]->jited) {
+ err = -ENOTSUPP;
+@@ -19934,6 +19936,12 @@ int bpf_check_attach_target(struct bpf_v
+ "Extension programs should be JITed\n");
+ return -EINVAL;
+ }
++ if (prog->aux->changes_pkt_data &&
++ !aux->func[subprog]->aux->changes_pkt_data) {
++ bpf_log(log,
++ "Extension program changes packet data, while original does not\n");
++ return -EINVAL;
++ }
+ }
+ if (!tgt_prog->jited) {
+ bpf_log(log, "Can attach to only JITed progs\n");
+@@ -20393,10 +20401,6 @@ int bpf_check(struct bpf_prog **prog, un
+ if (ret < 0)
+ goto skip_full_check;
+
+- ret = check_attach_btf_id(env);
+- if (ret)
+- goto skip_full_check;
+-
+ ret = resolve_pseudo_ldimm64(env);
+ if (ret < 0)
+ goto skip_full_check;
+@@ -20411,6 +20415,10 @@ int bpf_check(struct bpf_prog **prog, un
+ if (ret < 0)
+ goto skip_full_check;
+
++ ret = check_attach_btf_id(env);
++ if (ret)
++ goto skip_full_check;
++
+ ret = do_check_subprogs(env);
+ ret = ret ?: do_check_main(env);
+
--- /dev/null
+From stable+bounces-139114-greg=kroah.com@vger.kernel.org Wed Apr 30 10:20:40 2025
+From: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Date: Wed, 30 Apr 2025 16:19:49 +0800
+Subject: bpf: consider that tail calls invalidate packet pointers
+To: stable@vger.kernel.org
+Cc: Alexei Starovoitov <ast@kernel.org>, Eduard Zingerman <eddyz87@gmail.com>, Nick Zavaritsky <mejedi@gmail.com>, Dan Carpenter <dan.carpenter@linaro.org>, Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Message-ID: <20250430081955.49927-8-shung-hsi.yu@suse.com>
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+commit 1a4607ffba35bf2a630aab299e34dd3f6e658d70 upstream.
+
+Tail-called programs could execute any of the helpers that invalidate
+packet pointers. Hence, conservatively assume that each tail call
+invalidates packet pointers.
+
+Making the change in bpf_helper_changes_pkt_data() automatically makes
+use of check_cfg() logic that computes 'changes_pkt_data' effect for
+global sub-programs, such that the following program could be
+rejected:
+
+ int tail_call(struct __sk_buff *sk)
+ {
+ bpf_tail_call_static(sk, &jmp_table, 0);
+ return 0;
+ }
+
+ SEC("tc")
+ int not_safe(struct __sk_buff *sk)
+ {
+ int *p = (void *)(long)sk->data;
+ ... make p valid ...
+ tail_call(sk);
+ *p = 42; /* this is unsafe */
+ ...
+ }
+
+The tc_bpf2bpf.c:subprog_tc() needs change: mark it as a function that
+can invalidate packet pointers. Otherwise, it can't be freplaced with
+tailcall_freplace.c:entry_freplace() that does a tail call.
+
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20241210041100.1898468-8-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+[ shung-hsi.yu: drop changes to tools/testing/selftests/bpf/progs/tc_bpf2bpf.c
+because it is not present. ]
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/core/filter.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -7893,6 +7893,8 @@ bool bpf_helper_changes_pkt_data(enum bp
+ case BPF_FUNC_xdp_adjust_head:
+ case BPF_FUNC_xdp_adjust_meta:
+ case BPF_FUNC_xdp_adjust_tail:
++ /* tail-called program could call any of the above */
++ case BPF_FUNC_tail_call:
+ return true;
+ default:
+ return false;
--- /dev/null
+From stable+bounces-139116-greg=kroah.com@vger.kernel.org Wed Apr 30 10:20:43 2025
+From: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Date: Wed, 30 Apr 2025 16:19:51 +0800
+Subject: bpf: fix null dereference when computing changes_pkt_data of prog w/o subprogs
+To: stable@vger.kernel.org
+Cc: Alexei Starovoitov <ast@kernel.org>, Eduard Zingerman <eddyz87@gmail.com>, Nick Zavaritsky <mejedi@gmail.com>, Dan Carpenter <dan.carpenter@linaro.org>, Shung-Hsi Yu <shung-hsi.yu@suse.com>, kernel test robot <lkp@intel.com>
+Message-ID: <20250430081955.49927-10-shung-hsi.yu@suse.com>
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+commit ac6542ad92759cda383ad62b4e4cbfc28136abc1 upstream.
+
+bpf_prog_aux->func field might be NULL if program does not have
+subprograms except for main sub-program. The fixed commit does
+bpf_prog_aux->func access unconditionally, which might lead to null
+pointer dereference.
+
+The bug could be triggered by replacing the following BPF program:
+
+ SEC("tc")
+ int main_changes(struct __sk_buff *sk)
+ {
+ bpf_skb_pull_data(sk, 0);
+ return 0;
+ }
+
+With the following BPF program:
+
+ SEC("freplace")
+ long changes_pkt_data(struct __sk_buff *sk)
+ {
+ return bpf_skb_pull_data(sk, 0);
+ }
+
+bpf_prog_aux instance itself represents the main sub-program,
+use this property to fix the bug.
+
+Fixes: 81f6d0530ba0 ("bpf: check changes_pkt_data property for extension programs")
+Reported-by: kernel test robot <lkp@intel.com>
+Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
+Closes: https://lore.kernel.org/r/202412111822.qGw6tOyB-lkp@intel.com/
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20241212070711.427443-1-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -19908,6 +19908,7 @@ int bpf_check_attach_target(struct bpf_v
+ }
+ if (tgt_prog) {
+ struct bpf_prog_aux *aux = tgt_prog->aux;
++ bool tgt_changes_pkt_data;
+
+ if (bpf_prog_is_dev_bound(prog->aux) &&
+ !bpf_prog_dev_bound_match(prog, tgt_prog)) {
+@@ -19936,8 +19937,10 @@ int bpf_check_attach_target(struct bpf_v
+ "Extension programs should be JITed\n");
+ return -EINVAL;
+ }
+- if (prog->aux->changes_pkt_data &&
+- !aux->func[subprog]->aux->changes_pkt_data) {
++ tgt_changes_pkt_data = aux->func
++ ? aux->func[subprog]->aux->changes_pkt_data
++ : aux->changes_pkt_data;
++ if (prog->aux->changes_pkt_data && !tgt_changes_pkt_data) {
+ bpf_log(log,
+ "Extension program changes packet data, while original does not\n");
+ return -EINVAL;
--- /dev/null
+From stable+bounces-139109-greg=kroah.com@vger.kernel.org Wed Apr 30 10:20:23 2025
+From: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Date: Wed, 30 Apr 2025 16:19:44 +0800
+Subject: bpf: refactor bpf_helper_changes_pkt_data to use helper number
+To: stable@vger.kernel.org
+Cc: Alexei Starovoitov <ast@kernel.org>, Eduard Zingerman <eddyz87@gmail.com>, Nick Zavaritsky <mejedi@gmail.com>, Dan Carpenter <dan.carpenter@linaro.org>, Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Message-ID: <20250430081955.49927-3-shung-hsi.yu@suse.com>
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+commit b238e187b4a2d3b54d80aec05a9cab6466b79dde upstream.
+
+Use BPF helper number instead of function pointer in
+bpf_helper_changes_pkt_data(). This would simplify usage of this
+function in verifier.c:check_cfg() (in a follow-up patch),
+where only helper number is easily available and there is no real need
+to lookup helper proto.
+
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20241210041100.1898468-3-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/filter.h | 2 -
+ kernel/bpf/core.c | 2 -
+ kernel/bpf/verifier.c | 2 -
+ net/core/filter.c | 61 +++++++++++++++++++++----------------------------
+ 4 files changed, 30 insertions(+), 37 deletions(-)
+
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -915,7 +915,7 @@ bool bpf_jit_needs_zext(void);
+ bool bpf_jit_supports_subprog_tailcalls(void);
+ bool bpf_jit_supports_kfunc_call(void);
+ bool bpf_jit_supports_far_kfunc_call(void);
+-bool bpf_helper_changes_pkt_data(void *func);
++bool bpf_helper_changes_pkt_data(enum bpf_func_id func_id);
+
+ static inline bool bpf_dump_raw_ok(const struct cred *cred)
+ {
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -2893,7 +2893,7 @@ void __weak bpf_jit_compile(struct bpf_p
+ {
+ }
+
+-bool __weak bpf_helper_changes_pkt_data(void *func)
++bool __weak bpf_helper_changes_pkt_data(enum bpf_func_id func_id)
+ {
+ return false;
+ }
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -10007,7 +10007,7 @@ static int check_helper_call(struct bpf_
+ }
+
+ /* With LD_ABS/IND some JITs save/restore skb from r1. */
+- changes_data = bpf_helper_changes_pkt_data(fn->func);
++ changes_data = bpf_helper_changes_pkt_data(func_id);
+ if (changes_data && fn->arg1_type != ARG_PTR_TO_CTX) {
+ verbose(env, "kernel subsystem misconfigured func %s#%d: r1 != ctx\n",
+ func_id_name(func_id), func_id);
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -7868,42 +7868,35 @@ static const struct bpf_func_proto bpf_t
+
+ #endif /* CONFIG_INET */
+
+-bool bpf_helper_changes_pkt_data(void *func)
++bool bpf_helper_changes_pkt_data(enum bpf_func_id func_id)
+ {
+- if (func == bpf_skb_vlan_push ||
+- func == bpf_skb_vlan_pop ||
+- func == bpf_skb_store_bytes ||
+- func == bpf_skb_change_proto ||
+- func == bpf_skb_change_head ||
+- func == sk_skb_change_head ||
+- func == bpf_skb_change_tail ||
+- func == sk_skb_change_tail ||
+- func == bpf_skb_adjust_room ||
+- func == sk_skb_adjust_room ||
+- func == bpf_skb_pull_data ||
+- func == sk_skb_pull_data ||
+- func == bpf_clone_redirect ||
+- func == bpf_l3_csum_replace ||
+- func == bpf_l4_csum_replace ||
+- func == bpf_xdp_adjust_head ||
+- func == bpf_xdp_adjust_meta ||
+- func == bpf_msg_pull_data ||
+- func == bpf_msg_push_data ||
+- func == bpf_msg_pop_data ||
+- func == bpf_xdp_adjust_tail ||
+-#if IS_ENABLED(CONFIG_IPV6_SEG6_BPF)
+- func == bpf_lwt_seg6_store_bytes ||
+- func == bpf_lwt_seg6_adjust_srh ||
+- func == bpf_lwt_seg6_action ||
+-#endif
+-#ifdef CONFIG_INET
+- func == bpf_sock_ops_store_hdr_opt ||
+-#endif
+- func == bpf_lwt_in_push_encap ||
+- func == bpf_lwt_xmit_push_encap)
++ switch (func_id) {
++ case BPF_FUNC_clone_redirect:
++ case BPF_FUNC_l3_csum_replace:
++ case BPF_FUNC_l4_csum_replace:
++ case BPF_FUNC_lwt_push_encap:
++ case BPF_FUNC_lwt_seg6_action:
++ case BPF_FUNC_lwt_seg6_adjust_srh:
++ case BPF_FUNC_lwt_seg6_store_bytes:
++ case BPF_FUNC_msg_pop_data:
++ case BPF_FUNC_msg_pull_data:
++ case BPF_FUNC_msg_push_data:
++ case BPF_FUNC_skb_adjust_room:
++ case BPF_FUNC_skb_change_head:
++ case BPF_FUNC_skb_change_proto:
++ case BPF_FUNC_skb_change_tail:
++ case BPF_FUNC_skb_pull_data:
++ case BPF_FUNC_skb_store_bytes:
++ case BPF_FUNC_skb_vlan_pop:
++ case BPF_FUNC_skb_vlan_push:
++ case BPF_FUNC_store_hdr_opt:
++ case BPF_FUNC_xdp_adjust_head:
++ case BPF_FUNC_xdp_adjust_meta:
++ case BPF_FUNC_xdp_adjust_tail:
+ return true;
+-
+- return false;
++ default:
++ return false;
++ }
+ }
+
+ const struct bpf_func_proto bpf_event_output_data_proto __weak;
--- /dev/null
+From stable+bounces-139110-greg=kroah.com@vger.kernel.org Wed Apr 30 10:20:25 2025
+From: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Date: Wed, 30 Apr 2025 16:19:45 +0800
+Subject: bpf: track changes_pkt_data property for global functions
+To: stable@vger.kernel.org
+Cc: Alexei Starovoitov <ast@kernel.org>, Eduard Zingerman <eddyz87@gmail.com>, Nick Zavaritsky <mejedi@gmail.com>, Dan Carpenter <dan.carpenter@linaro.org>, Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Message-ID: <20250430081955.49927-4-shung-hsi.yu@suse.com>
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+commit 51081a3f25c742da5a659d7fc6fd77ebfdd555be upstream.
+
+When processing calls to certain helpers, verifier invalidates all
+packet pointers in a current state. For example, consider the
+following program:
+
+ __attribute__((__noinline__))
+ long skb_pull_data(struct __sk_buff *sk, __u32 len)
+ {
+ return bpf_skb_pull_data(sk, len);
+ }
+
+ SEC("tc")
+ int test_invalidate_checks(struct __sk_buff *sk)
+ {
+ int *p = (void *)(long)sk->data;
+ if ((void *)(p + 1) > (void *)(long)sk->data_end) return TCX_DROP;
+ skb_pull_data(sk, 0);
+ *p = 42;
+ return TCX_PASS;
+ }
+
+After a call to bpf_skb_pull_data() the pointer 'p' can't be used
+safely. See function filter.c:bpf_helper_changes_pkt_data() for a list
+of such helpers.
+
+At the moment verifier invalidates packet pointers when processing
+helper function calls, and does not traverse global sub-programs when
+processing calls to global sub-programs. This means that calls to
+helpers done from global sub-programs do not invalidate pointers in
+the caller state. E.g. the program above is unsafe, but is not
+rejected by verifier.
+
+This commit fixes the omission by computing field
+bpf_subprog_info->changes_pkt_data for each sub-program before main
+verification pass.
+changes_pkt_data should be set if:
+- subprogram calls helper for which bpf_helper_changes_pkt_data
+ returns true;
+- subprogram calls a global function,
+ for which bpf_subprog_info->changes_pkt_data should be set.
+
+The verifier.c:check_cfg() pass is modified to compute this
+information. The commit relies on depth first instruction traversal
+done by check_cfg() and absence of recursive function calls:
+- check_cfg() would eventually visit every call to subprogram S in a
+ state when S is fully explored;
+- when S is fully explored:
+ - every direct helper call within S is explored
+ (and thus changes_pkt_data is set if needed);
+ - every call to subprogram S1 called by S was visited with S1 fully
+ explored (and thus S inherits changes_pkt_data from S1).
+
+The downside of such approach is that dead code elimination is not
+taken into account: if a helper call inside global function is dead
+because of current configuration, verifier would conservatively assume
+that the call occurs for the purpose of the changes_pkt_data
+computation.
+
+Reported-by: Nick Zavaritsky <mejedi@gmail.com>
+Closes: https://lore.kernel.org/bpf/0498CA22-5779-4767-9C0C-A9515CEA711F@gmail.com/
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20241210041100.1898468-4-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+[shung-hsi.yu: do not use bitfield in "struct bpf_subprog_info" because commit
+406a6fa44bfb ("bpf: use bitfields for simple per-subprog bool flags") is not
+present and minor context difference in check_func_call() because commit
+491dd8edecbc ("bpf: Emit global subprog name in verifier logs") is not present. ]
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/bpf_verifier.h | 1 +
+ kernel/bpf/verifier.c | 32 +++++++++++++++++++++++++++++++-
+ 2 files changed, 32 insertions(+), 1 deletion(-)
+
+--- a/include/linux/bpf_verifier.h
++++ b/include/linux/bpf_verifier.h
+@@ -573,6 +573,7 @@ struct bpf_subprog_info {
+ bool tail_call_reachable;
+ bool has_ld_abs;
+ bool is_async_cb;
++ bool changes_pkt_data;
+ };
+
+ struct bpf_verifier_env;
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -9364,6 +9364,8 @@ static int check_func_call(struct bpf_ve
+
+ if (env->log.level & BPF_LOG_LEVEL)
+ verbose(env, "Func#%d is global and valid. Skipping.\n", subprog);
++ if (env->subprog_info[subprog].changes_pkt_data)
++ clear_all_pkt_pointers(env);
+ clear_caller_saved_regs(env, caller->regs);
+
+ /* All global functions return a 64-bit SCALAR_VALUE */
+@@ -15114,6 +15116,29 @@ static int check_return_code(struct bpf_
+ return 0;
+ }
+
++static void mark_subprog_changes_pkt_data(struct bpf_verifier_env *env, int off)
++{
++ struct bpf_subprog_info *subprog;
++
++ subprog = find_containing_subprog(env, off);
++ subprog->changes_pkt_data = true;
++}
++
++/* 't' is an index of a call-site.
++ * 'w' is a callee entry point.
++ * Eventually this function would be called when env->cfg.insn_state[w] == EXPLORED.
++ * Rely on DFS traversal order and absence of recursive calls to guarantee that
++ * callee's change_pkt_data marks would be correct at that moment.
++ */
++static void merge_callee_effects(struct bpf_verifier_env *env, int t, int w)
++{
++ struct bpf_subprog_info *caller, *callee;
++
++ caller = find_containing_subprog(env, t);
++ callee = find_containing_subprog(env, w);
++ caller->changes_pkt_data |= callee->changes_pkt_data;
++}
++
+ /* non-recursive DFS pseudo code
+ * 1 procedure DFS-iterative(G,v):
+ * 2 label v as discovered
+@@ -15247,6 +15272,7 @@ static int visit_func_call_insn(int t, s
+ bool visit_callee)
+ {
+ int ret, insn_sz;
++ int w;
+
+ insn_sz = bpf_is_ldimm64(&insns[t]) ? 2 : 1;
+ ret = push_insn(t, t + insn_sz, FALLTHROUGH, env);
+@@ -15258,8 +15284,10 @@ static int visit_func_call_insn(int t, s
+ mark_jmp_point(env, t + insn_sz);
+
+ if (visit_callee) {
++ w = t + insns[t].imm + 1;
+ mark_prune_point(env, t);
+- ret = push_insn(t, t + insns[t].imm + 1, BRANCH, env);
++ merge_callee_effects(env, t, w);
++ ret = push_insn(t, w, BRANCH, env);
+ }
+ return ret;
+ }
+@@ -15311,6 +15339,8 @@ static int visit_insn(int t, struct bpf_
+ mark_prune_point(env, t);
+ mark_jmp_point(env, t);
+ }
++ if (bpf_helper_call(insn) && bpf_helper_changes_pkt_data(insn->imm))
++ mark_subprog_changes_pkt_data(env, t);
+ if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
+ struct bpf_kfunc_call_arg_meta meta;
+
--- /dev/null
+From b46064a18810bad3aea089a79993ca5ea7a3d2b2 Mon Sep 17 00:00:00 2001
+From: Robin Murphy <robin.murphy@arm.com>
+Date: Fri, 28 Feb 2025 15:46:30 +0000
+Subject: iommu: Handle race with default domain setup
+
+From: Robin Murphy <robin.murphy@arm.com>
+
+commit b46064a18810bad3aea089a79993ca5ea7a3d2b2 upstream.
+
+It turns out that deferred default domain creation leaves a subtle
+race window during iommu_device_register() wherein a client driver may
+asynchronously probe in parallel and get as far as performing DMA API
+operations with dma-direct, only to be switched to iommu-dma underfoot
+once the default domain attachment finally happens, with obviously
+disastrous consequences. Even the wonky of_iommu_configure() path is at
+risk, since iommu_fwspec_init() will no longer defer client probe as the
+instance ops are (necessarily) already registered, and the "replay"
+iommu_probe_device() call can see dev->iommu_group already set and so
+think there's nothing to do either.
+
+Fortunately we already have the right tool in the right place in the
+form of iommu_device_use_default_domain(), which just needs to ensure
+that said default domain is actually ready to *be* used. Deferring the
+client probe shouldn't have too much impact, given that this only
+happens while the IOMMU driver is probing, and thus due to kick the
+deferred probe list again once it finishes.
+
+Reported-by: Charan Teja Kalla <quic_charante@quicinc.com>
+Fixes: 98ac73f99bc4 ("iommu: Require a default_domain for all iommu drivers")
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+Link: https://lore.kernel.org/r/e88b94c9b575034a2c98a48b3d383654cbda7902.1740753261.git.robin.murphy@arm.com
+Signed-off-by: Joerg Roedel <jroedel@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+---
+ drivers/iommu/iommu.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+--- a/drivers/iommu/iommu.c
++++ b/drivers/iommu/iommu.c
+@@ -566,6 +566,18 @@ int iommu_probe_device(struct device *de
+ mutex_lock(&iommu_probe_device_lock);
+ ret = __iommu_probe_device(dev, NULL);
+ mutex_unlock(&iommu_probe_device_lock);
++
++ /*
++ * The dma_configure replay paths need bus_iommu_probe() to
++ * finish before they can call arch_setup_dma_ops()
++ */
++ if (IS_ENABLED(CONFIG_IOMMU_DMA) && !ret && dev->iommu_group) {
++ mutex_lock(&dev->iommu_group->mutex);
++ if (!dev->iommu_group->default_domain &&
++ !dev_iommu_ops(dev)->set_platform_dma_ops)
++ ret = -EPROBE_DEFER;
++ mutex_unlock(&dev->iommu_group->mutex);
++ }
+ if (ret)
+ return ret;
+
+@@ -3149,6 +3161,12 @@ int iommu_device_use_default_domain(stru
+ return 0;
+
+ mutex_lock(&group->mutex);
++ /* We may race against bus_iommu_probe() finalising groups here */
++ if (IS_ENABLED(CONFIG_IOMMU_DMA) && !group->default_domain &&
++ !dev_iommu_ops(dev)->set_platform_dma_ops) {
++ ret = -EPROBE_DEFER;
++ goto unlock_out;
++ }
+ if (group->owner_cnt) {
+ if (group->owner || !iommu_is_default_domain(group) ||
+ !xa_empty(&group->pasid_array)) {
--- /dev/null
+From c2fee09fc167c74a64adb08656cb993ea475197e Mon Sep 17 00:00:00 2001
+From: Sean Christopherson <seanjc@google.com>
+Date: Fri, 24 Jan 2025 17:18:33 -0800
+Subject: KVM: x86: Load DR6 with guest value only before entering .vcpu_run() loop
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit c2fee09fc167c74a64adb08656cb993ea475197e upstream.
+
+Move the conditional loading of hardware DR6 with the guest's DR6 value
+out of the core .vcpu_run() loop to fix a bug where KVM can load hardware
+with a stale vcpu->arch.dr6.
+
+When the guest accesses a DR and host userspace isn't debugging the guest,
+KVM disables DR interception and loads the guest's values into hardware on
+VM-Enter and saves them on VM-Exit. This allows the guest to access DRs
+at will, e.g. so that a sequence of DR accesses to configure a breakpoint
+only generates one VM-Exit.
+
+For DR0-DR3, the logic/behavior is identical between VMX and SVM, and also
+identical between KVM_DEBUGREG_BP_ENABLED (userspace debugging the guest)
+and KVM_DEBUGREG_WONT_EXIT (guest using DRs), and so KVM handles loading
+DR0-DR3 in common code, _outside_ of the core kvm_x86_ops.vcpu_run() loop.
+
+But for DR6, the guest's value doesn't need to be loaded into hardware for
+KVM_DEBUGREG_BP_ENABLED, and SVM provides a dedicated VMCB field whereas
+VMX requires software to manually load the guest value, and so loading the
+guest's value into DR6 is handled by {svm,vmx}_vcpu_run(), i.e. is done
+_inside_ the core run loop.
+
+Unfortunately, saving the guest values on VM-Exit is initiated by common
+x86, again outside of the core run loop. If the guest modifies DR6 (in
+hardware, when DR interception is disabled), and then the next VM-Exit is
+a fastpath VM-Exit, KVM will reload hardware DR6 with vcpu->arch.dr6 and
+clobber the guest's actual value.
+
+The bug shows up primarily with nested VMX because KVM handles the VMX
+preemption timer in the fastpath, and the window between hardware DR6
+being modified (in guest context) and DR6 being read by guest software is
+orders of magnitude larger in a nested setup. E.g. in non-nested, the
+VMX preemption timer would need to fire precisely between #DB injection
+and the #DB handler's read of DR6, whereas with a KVM-on-KVM setup, the
+window where hardware DR6 is "dirty" extends all the way from L1 writing
+DR6 to VMRESUME (in L1).
+
+ L1's view:
+ ==========
+ <L1 disables DR interception>
+ CPU 0/KVM-7289 [023] d.... 2925.640961: kvm_entry: vcpu 0
+ A: L1 Writes DR6
+ CPU 0/KVM-7289 [023] d.... 2925.640963: <hack>: Set DRs, DR6 = 0xffff0ff1
+
+ B: CPU 0/KVM-7289 [023] d.... 2925.640967: kvm_exit: vcpu 0 reason EXTERNAL_INTERRUPT intr_info 0x800000ec
+
+ D: L1 reads DR6, arch.dr6 = 0
+ CPU 0/KVM-7289 [023] d.... 2925.640969: <hack>: Sync DRs, DR6 = 0xffff0ff0
+
+ CPU 0/KVM-7289 [023] d.... 2925.640976: kvm_entry: vcpu 0
+ L2 reads DR6, L1 disables DR interception
+ CPU 0/KVM-7289 [023] d.... 2925.640980: kvm_exit: vcpu 0 reason DR_ACCESS info1 0x0000000000000216
+ CPU 0/KVM-7289 [023] d.... 2925.640983: kvm_entry: vcpu 0
+
+ CPU 0/KVM-7289 [023] d.... 2925.640983: <hack>: Set DRs, DR6 = 0xffff0ff0
+
+ L2 detects failure
+ CPU 0/KVM-7289 [023] d.... 2925.640987: kvm_exit: vcpu 0 reason HLT
+ L1 reads DR6 (confirms failure)
+ CPU 0/KVM-7289 [023] d.... 2925.640990: <hack>: Sync DRs, DR6 = 0xffff0ff0
+
+ L0's view:
+ ==========
+ L2 reads DR6, arch.dr6 = 0
+ CPU 23/KVM-5046 [001] d.... 3410.005610: kvm_exit: vcpu 23 reason DR_ACCESS info1 0x0000000000000216
+ CPU 23/KVM-5046 [001] ..... 3410.005610: kvm_nested_vmexit: vcpu 23 reason DR_ACCESS info1 0x0000000000000216
+
+ L2 => L1 nested VM-Exit
+ CPU 23/KVM-5046 [001] ..... 3410.005610: kvm_nested_vmexit_inject: reason: DR_ACCESS ext_inf1: 0x0000000000000216
+
+ CPU 23/KVM-5046 [001] d.... 3410.005610: kvm_entry: vcpu 23
+ CPU 23/KVM-5046 [001] d.... 3410.005611: kvm_exit: vcpu 23 reason VMREAD
+ CPU 23/KVM-5046 [001] d.... 3410.005611: kvm_entry: vcpu 23
+ CPU 23/KVM-5046 [001] d.... 3410.005612: kvm_exit: vcpu 23 reason VMREAD
+ CPU 23/KVM-5046 [001] d.... 3410.005612: kvm_entry: vcpu 23
+
+ L1 writes DR7, L0 disables DR interception
+ CPU 23/KVM-5046 [001] d.... 3410.005612: kvm_exit: vcpu 23 reason DR_ACCESS info1 0x0000000000000007
+ CPU 23/KVM-5046 [001] d.... 3410.005613: kvm_entry: vcpu 23
+
+ L0 writes DR6 = 0 (arch.dr6)
+ CPU 23/KVM-5046 [001] d.... 3410.005613: <hack>: Set DRs, DR6 = 0xffff0ff0
+
+ A: <L1 writes DR6 = 1, no interception, arch.dr6 is still '0'>
+
+ B: CPU 23/KVM-5046 [001] d.... 3410.005614: kvm_exit: vcpu 23 reason PREEMPTION_TIMER
+ CPU 23/KVM-5046 [001] d.... 3410.005614: kvm_entry: vcpu 23
+
+ C: L0 writes DR6 = 0 (arch.dr6)
+ CPU 23/KVM-5046 [001] d.... 3410.005614: <hack>: Set DRs, DR6 = 0xffff0ff0
+
+ L1 => L2 nested VM-Enter
+ CPU 23/KVM-5046 [001] d.... 3410.005616: kvm_exit: vcpu 23 reason VMRESUME
+
+ L0 reads DR6, arch.dr6 = 0
+
+Reported-by: John Stultz <jstultz@google.com>
+Closes: https://lkml.kernel.org/r/CANDhNCq5_F3HfFYABqFGCA1bPd_%2BxgNj-iDQhH4tDk%2Bwi8iZZg%40mail.gmail.com
+Fixes: 375e28ffc0cf ("KVM: X86: Set host DR6 only on VMX and for KVM_DEBUGREG_WONT_EXIT")
+Fixes: d67668e9dd76 ("KVM: x86, SVM: isolate vcpu->arch.dr6 from vmcb->save.dr6")
+Cc: stable@vger.kernel.org
+Cc: Jim Mattson <jmattson@google.com>
+Tested-by: John Stultz <jstultz@google.com>
+Link: https://lore.kernel.org/r/20250125011833.3644371-1-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+[jth: Handled conflicts with kvm_x86_ops reshuffle]
+Signed-off-by: James Houghton <jthoughton@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/include/asm/kvm-x86-ops.h | 1 +
+ arch/x86/include/asm/kvm_host.h | 1 +
+ arch/x86/kvm/svm/svm.c | 13 ++++++-------
+ arch/x86/kvm/vmx/vmx.c | 11 +++++++----
+ arch/x86/kvm/x86.c | 3 +++
+ 5 files changed, 18 insertions(+), 11 deletions(-)
+
+--- a/arch/x86/include/asm/kvm-x86-ops.h
++++ b/arch/x86/include/asm/kvm-x86-ops.h
+@@ -48,6 +48,7 @@ KVM_X86_OP(set_idt)
+ KVM_X86_OP(get_gdt)
+ KVM_X86_OP(set_gdt)
+ KVM_X86_OP(sync_dirty_debug_regs)
++KVM_X86_OP(set_dr6)
+ KVM_X86_OP(set_dr7)
+ KVM_X86_OP(cache_reg)
+ KVM_X86_OP(get_rflags)
+--- a/arch/x86/include/asm/kvm_host.h
++++ b/arch/x86/include/asm/kvm_host.h
+@@ -1595,6 +1595,7 @@ struct kvm_x86_ops {
+ void (*get_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
+ void (*set_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
+ void (*sync_dirty_debug_regs)(struct kvm_vcpu *vcpu);
++ void (*set_dr6)(struct kvm_vcpu *vcpu, unsigned long value);
+ void (*set_dr7)(struct kvm_vcpu *vcpu, unsigned long value);
+ void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
+ unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
+--- a/arch/x86/kvm/svm/svm.c
++++ b/arch/x86/kvm/svm/svm.c
+@@ -2014,11 +2014,11 @@ static void new_asid(struct vcpu_svm *sv
+ svm->asid = sd->next_asid++;
+ }
+
+-static void svm_set_dr6(struct vcpu_svm *svm, unsigned long value)
++static void svm_set_dr6(struct kvm_vcpu *vcpu, unsigned long value)
+ {
+- struct vmcb *vmcb = svm->vmcb;
++ struct vmcb *vmcb = to_svm(vcpu)->vmcb;
+
+- if (svm->vcpu.arch.guest_state_protected)
++ if (vcpu->arch.guest_state_protected)
+ return;
+
+ if (unlikely(value != vmcb->save.dr6)) {
+@@ -4220,10 +4220,8 @@ static __no_kcsan fastpath_t svm_vcpu_ru
+ * Run with all-zero DR6 unless needed, so that we can get the exact cause
+ * of a #DB.
+ */
+- if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT))
+- svm_set_dr6(svm, vcpu->arch.dr6);
+- else
+- svm_set_dr6(svm, DR6_ACTIVE_LOW);
++ if (likely(!(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)))
++ svm_set_dr6(vcpu, DR6_ACTIVE_LOW);
+
+ clgi();
+ kvm_load_guest_xsave_state(vcpu);
+@@ -5002,6 +5000,7 @@ static struct kvm_x86_ops svm_x86_ops __
+ .set_idt = svm_set_idt,
+ .get_gdt = svm_get_gdt,
+ .set_gdt = svm_set_gdt,
++ .set_dr6 = svm_set_dr6,
+ .set_dr7 = svm_set_dr7,
+ .sync_dirty_debug_regs = svm_sync_dirty_debug_regs,
+ .cache_reg = svm_cache_reg,
+--- a/arch/x86/kvm/vmx/vmx.c
++++ b/arch/x86/kvm/vmx/vmx.c
+@@ -5617,6 +5617,12 @@ static void vmx_sync_dirty_debug_regs(st
+ set_debugreg(DR6_RESERVED, 6);
+ }
+
++static void vmx_set_dr6(struct kvm_vcpu *vcpu, unsigned long val)
++{
++ lockdep_assert_irqs_disabled();
++ set_debugreg(vcpu->arch.dr6, 6);
++}
++
+ static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val)
+ {
+ vmcs_writel(GUEST_DR7, val);
+@@ -7356,10 +7362,6 @@ static fastpath_t vmx_vcpu_run(struct kv
+ vmx->loaded_vmcs->host_state.cr4 = cr4;
+ }
+
+- /* When KVM_DEBUGREG_WONT_EXIT, dr6 is accessible in guest. */
+- if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT))
+- set_debugreg(vcpu->arch.dr6, 6);
+-
+ /* When single-stepping over STI and MOV SS, we must clear the
+ * corresponding interruptibility bits in the guest state. Otherwise
+ * vmentry fails as it then expects bit 14 (BS) in pending debug
+@@ -8292,6 +8294,7 @@ static struct kvm_x86_ops vmx_x86_ops __
+ .set_idt = vmx_set_idt,
+ .get_gdt = vmx_get_gdt,
+ .set_gdt = vmx_set_gdt,
++ .set_dr6 = vmx_set_dr6,
+ .set_dr7 = vmx_set_dr7,
+ .sync_dirty_debug_regs = vmx_sync_dirty_debug_regs,
+ .cache_reg = vmx_cache_reg,
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -10772,6 +10772,9 @@ static int vcpu_enter_guest(struct kvm_v
+ set_debugreg(vcpu->arch.eff_db[1], 1);
+ set_debugreg(vcpu->arch.eff_db[2], 2);
+ set_debugreg(vcpu->arch.eff_db[3], 3);
++ /* When KVM_DEBUGREG_WONT_EXIT, dr6 is accessible in guest. */
++ if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT))
++ static_call(kvm_x86_set_dr6)(vcpu, vcpu->arch.dr6);
+ } else if (unlikely(hw_breakpoint_active())) {
+ set_debugreg(0, 7);
+ }
--- /dev/null
+From stable+bounces-139573-greg=kroah.com@vger.kernel.org Sun May 4 21:15:49 2025
+From: Ryan Matthews <ryanmatthews@fastmail.com>
+Date: Sun, 4 May 2025 15:13:56 -0400
+Subject: PCI: imx6: Skip controller_id generation logic for i.MX7D
+To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: "Richard Zhu" <hongxing.zhu@nxp.com>, "Lucas Stach" <l.stach@pengutronix.de>, stable@vger.kernel.org, linux-pci@vger.kernel.org, "Ryan Matthews" <ryanmatthews@fastmail.com>, "Krzysztof Wilczyński" <kwilczynski@kernel.org>, "Bjorn Helgaas" <bhelgaas@google.com>, "Manivannan Sadhasivam" <manivannan.sadhasivam@linaro.org>, "Frank Li" <Frank.Li@nxp.com>
+Message-ID: <20250504191356.17732-3-ryanmatthews@fastmail.com>
+
+From: Richard Zhu <hongxing.zhu@nxp.com>
+
+[ Upstream commit f068ffdd034c93f0c768acdc87d4d2d7023c1379 ]
+
+The i.MX7D only has one PCIe controller, so controller_id should always be
+0. The previous code is incorrect although yielding the correct result.
+
+Fix by removing "IMX7D" from the switch case branch.
+
+Fixes: 2d8ed461dbc9 ("PCI: imx6: Add support for i.MX8MQ")
+Link: https://lore.kernel.org/r/20241126075702.4099164-5-hongxing.zhu@nxp.com
+Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
+Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Reviewed-by: Frank Li <Frank.Li@nxp.com>
+[Because this switch case does more than just controller_id
+ logic, move the "IMX7D" case label instead of removing it entirely.]
+Signed-off-by: Ryan Matthews <ryanmatthews@fastmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/controller/dwc/pci-imx6.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/pci/controller/dwc/pci-imx6.c
++++ b/drivers/pci/controller/dwc/pci-imx6.c
+@@ -1281,10 +1281,10 @@ static int imx6_pcie_probe(struct platfo
+ switch (imx6_pcie->drvdata->variant) {
+ case IMX8MQ:
+ case IMX8MQ_EP:
+- case IMX7D:
+ if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR)
+ imx6_pcie->controller_id = 1;
+-
++ fallthrough;
++ case IMX7D:
+ imx6_pcie->pciephy_reset = devm_reset_control_get_exclusive(dev,
+ "pciephy");
+ if (IS_ERR(imx6_pcie->pciephy_reset)) {
--- /dev/null
+From stable+bounces-139572-greg=kroah.com@vger.kernel.org Sun May 4 21:15:30 2025
+From: Ryan Matthews <ryanmatthews@fastmail.com>
+Date: Sun, 4 May 2025 15:13:55 -0400
+Subject: Revert "PCI: imx6: Skip controller_id generation logic for i.MX7D"
+To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Richard Zhu <hongxing.zhu@nxp.com>, Lucas Stach <l.stach@pengutronix.de>, stable@vger.kernel.org, linux-pci@vger.kernel.org, Ryan Matthews <ryanmatthews@fastmail.com>
+Message-ID: <20250504191356.17732-2-ryanmatthews@fastmail.com>
+
+From: Ryan Matthews <ryanmatthews@fastmail.com>
+
+This reverts commit 2a12efc567a270a155e3b886258297abd79cdea0 which is
+commit f068ffdd034c93f0c768acdc87d4d2d7023c1379 upstream.
+
+This is a backport mistake.
+
+Deleting "IMX7D" here skips more than just controller_id logic. It skips
+reset assignments too, which causes:
+
+ imx6q-pcie 33800000.pcie: PCIe PLL lock timeout
+
+In my case, in addition to broken PCIe, kernel boot hangs entirely.
+
+This isn't a problem upstream because before this, they moved the rest of
+the code out of the switch case.
+
+Signed-off-by: Ryan Matthews <ryanmatthews@fastmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/controller/dwc/pci-imx6.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/pci/controller/dwc/pci-imx6.c
++++ b/drivers/pci/controller/dwc/pci-imx6.c
+@@ -1281,6 +1281,7 @@ static int imx6_pcie_probe(struct platfo
+ switch (imx6_pcie->drvdata->variant) {
+ case IMX8MQ:
+ case IMX8MQ_EP:
++ case IMX7D:
+ if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR)
+ imx6_pcie->controller_id = 1;
+
--- /dev/null
+From stable+bounces-139117-greg=kroah.com@vger.kernel.org Wed Apr 30 10:20:50 2025
+From: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Date: Wed, 30 Apr 2025 16:19:52 +0800
+Subject: selftests/bpf: extend changes_pkt_data with cases w/o subprograms
+To: stable@vger.kernel.org
+Cc: Alexei Starovoitov <ast@kernel.org>, Eduard Zingerman <eddyz87@gmail.com>, Nick Zavaritsky <mejedi@gmail.com>, Dan Carpenter <dan.carpenter@linaro.org>, Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Message-ID: <20250430081955.49927-11-shung-hsi.yu@suse.com>
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+commit 04789af756a4a43e72986185f66f148e65b32fed upstream.
+
+Extend changes_pkt_data tests with test cases freplacing the main
+program that does not have subprograms. Try four combinations when
+both main program and replacement do and do not change packet data.
+
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20241212070711.427443-2-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c | 55 +++++++---
+ tools/testing/selftests/bpf/progs/changes_pkt_data.c | 27 +++-
+ tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c | 6 -
+ 3 files changed, 66 insertions(+), 22 deletions(-)
+
+--- a/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c
++++ b/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c
+@@ -10,10 +10,14 @@ static void print_verifier_log(const cha
+ fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log);
+ }
+
+-static void test_aux(const char *main_prog_name, const char *freplace_prog_name, bool expect_load)
++static void test_aux(const char *main_prog_name,
++ const char *to_be_replaced,
++ const char *replacement,
++ bool expect_load)
+ {
+ struct changes_pkt_data_freplace *freplace = NULL;
+ struct bpf_program *freplace_prog = NULL;
++ struct bpf_program *main_prog = NULL;
+ LIBBPF_OPTS(bpf_object_open_opts, opts);
+ struct changes_pkt_data *main = NULL;
+ char log[16*1024];
+@@ -26,6 +30,10 @@ static void test_aux(const char *main_pr
+ main = changes_pkt_data__open_opts(&opts);
+ if (!ASSERT_OK_PTR(main, "changes_pkt_data__open"))
+ goto out;
++ main_prog = bpf_object__find_program_by_name(main->obj, main_prog_name);
++ if (!ASSERT_OK_PTR(main_prog, "main_prog"))
++ goto out;
++ bpf_program__set_autoload(main_prog, true);
+ err = changes_pkt_data__load(main);
+ print_verifier_log(log);
+ if (!ASSERT_OK(err, "changes_pkt_data__load"))
+@@ -33,14 +41,14 @@ static void test_aux(const char *main_pr
+ freplace = changes_pkt_data_freplace__open_opts(&opts);
+ if (!ASSERT_OK_PTR(freplace, "changes_pkt_data_freplace__open"))
+ goto out;
+- freplace_prog = bpf_object__find_program_by_name(freplace->obj, freplace_prog_name);
++ freplace_prog = bpf_object__find_program_by_name(freplace->obj, replacement);
+ if (!ASSERT_OK_PTR(freplace_prog, "freplace_prog"))
+ goto out;
+ bpf_program__set_autoload(freplace_prog, true);
+ bpf_program__set_autoattach(freplace_prog, true);
+ bpf_program__set_attach_target(freplace_prog,
+- bpf_program__fd(main->progs.dummy),
+- main_prog_name);
++ bpf_program__fd(main_prog),
++ to_be_replaced);
+ err = changes_pkt_data_freplace__load(freplace);
+ print_verifier_log(log);
+ if (expect_load) {
+@@ -62,15 +70,38 @@ out:
+ * that either do or do not. It is only ok to freplace subprograms
+ * that do not change packet data with those that do not as well.
+ * The below tests check outcomes for each combination of such freplace.
++ * Also test a case when main subprogram itself is replaced and is a single
++ * subprogram in a program.
+ */
+ void test_changes_pkt_data_freplace(void)
+ {
+- if (test__start_subtest("changes_with_changes"))
+- test_aux("changes_pkt_data", "changes_pkt_data", true);
+- if (test__start_subtest("changes_with_doesnt_change"))
+- test_aux("changes_pkt_data", "does_not_change_pkt_data", true);
+- if (test__start_subtest("doesnt_change_with_changes"))
+- test_aux("does_not_change_pkt_data", "changes_pkt_data", false);
+- if (test__start_subtest("doesnt_change_with_doesnt_change"))
+- test_aux("does_not_change_pkt_data", "does_not_change_pkt_data", true);
++ struct {
++ const char *main;
++ const char *to_be_replaced;
++ bool changes;
++ } mains[] = {
++ { "main_with_subprogs", "changes_pkt_data", true },
++ { "main_with_subprogs", "does_not_change_pkt_data", false },
++ { "main_changes", "main_changes", true },
++ { "main_does_not_change", "main_does_not_change", false },
++ };
++ struct {
++ const char *func;
++ bool changes;
++ } replacements[] = {
++ { "changes_pkt_data", true },
++ { "does_not_change_pkt_data", false }
++ };
++ char buf[64];
++
++ for (int i = 0; i < ARRAY_SIZE(mains); ++i) {
++ for (int j = 0; j < ARRAY_SIZE(replacements); ++j) {
++ snprintf(buf, sizeof(buf), "%s_with_%s",
++ mains[i].to_be_replaced, replacements[j].func);
++ if (!test__start_subtest(buf))
++ continue;
++ test_aux(mains[i].main, mains[i].to_be_replaced, replacements[j].func,
++ mains[i].changes || !replacements[j].changes);
++ }
++ }
+ }
+--- a/tools/testing/selftests/bpf/progs/changes_pkt_data.c
++++ b/tools/testing/selftests/bpf/progs/changes_pkt_data.c
+@@ -4,22 +4,35 @@
+ #include <bpf/bpf_helpers.h>
+
+ __noinline
+-long changes_pkt_data(struct __sk_buff *sk, __u32 len)
++long changes_pkt_data(struct __sk_buff *sk)
+ {
+- return bpf_skb_pull_data(sk, len);
++ return bpf_skb_pull_data(sk, 0);
+ }
+
+ __noinline __weak
+-long does_not_change_pkt_data(struct __sk_buff *sk, __u32 len)
++long does_not_change_pkt_data(struct __sk_buff *sk)
+ {
+ return 0;
+ }
+
+-SEC("tc")
+-int dummy(struct __sk_buff *sk)
++SEC("?tc")
++int main_with_subprogs(struct __sk_buff *sk)
++{
++ changes_pkt_data(sk);
++ does_not_change_pkt_data(sk);
++ return 0;
++}
++
++SEC("?tc")
++int main_changes(struct __sk_buff *sk)
++{
++ bpf_skb_pull_data(sk, 0);
++ return 0;
++}
++
++SEC("?tc")
++int main_does_not_change(struct __sk_buff *sk)
+ {
+- changes_pkt_data(sk, 0);
+- does_not_change_pkt_data(sk, 0);
+ return 0;
+ }
+
+--- a/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c
++++ b/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c
+@@ -4,13 +4,13 @@
+ #include <bpf/bpf_helpers.h>
+
+ SEC("?freplace")
+-long changes_pkt_data(struct __sk_buff *sk, __u32 len)
++long changes_pkt_data(struct __sk_buff *sk)
+ {
+- return bpf_skb_pull_data(sk, len);
++ return bpf_skb_pull_data(sk, 0);
+ }
+
+ SEC("?freplace")
+-long does_not_change_pkt_data(struct __sk_buff *sk, __u32 len)
++long does_not_change_pkt_data(struct __sk_buff *sk)
+ {
+ return 0;
+ }
--- /dev/null
+From stable+bounces-139113-greg=kroah.com@vger.kernel.org Wed Apr 30 10:20:36 2025
+From: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Date: Wed, 30 Apr 2025 16:19:48 +0800
+Subject: selftests/bpf: freplace tests for tracking of changes_packet_data
+To: stable@vger.kernel.org
+Cc: Alexei Starovoitov <ast@kernel.org>, Eduard Zingerman <eddyz87@gmail.com>, Nick Zavaritsky <mejedi@gmail.com>, Dan Carpenter <dan.carpenter@linaro.org>, Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Message-ID: <20250430081955.49927-7-shung-hsi.yu@suse.com>
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+commit 89ff40890d8f12a7d7e93fb602cc27562f3834f0 upstream.
+
+Try different combinations of global functions replacement:
+- replace function that changes packet data with one that doesn't;
+- replace function that changes packet data with one that does;
+- replace function that doesn't change packet data with one that does;
+- replace function that doesn't change packet data with one that doesn't;
+
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20241210041100.1898468-7-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c | 76 ++++++++++
+ tools/testing/selftests/bpf/progs/changes_pkt_data.c | 26 +++
+ tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c | 18 ++
+ 3 files changed, 120 insertions(+)
+ create mode 100644 tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c
+ create mode 100644 tools/testing/selftests/bpf/progs/changes_pkt_data.c
+ create mode 100644 tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c
+
+--- /dev/null
++++ b/tools/testing/selftests/bpf/prog_tests/changes_pkt_data.c
+@@ -0,0 +1,76 @@
++// SPDX-License-Identifier: GPL-2.0
++#include "bpf/libbpf.h"
++#include "changes_pkt_data_freplace.skel.h"
++#include "changes_pkt_data.skel.h"
++#include <test_progs.h>
++
++static void print_verifier_log(const char *log)
++{
++ if (env.verbosity >= VERBOSE_VERY)
++ fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log);
++}
++
++static void test_aux(const char *main_prog_name, const char *freplace_prog_name, bool expect_load)
++{
++ struct changes_pkt_data_freplace *freplace = NULL;
++ struct bpf_program *freplace_prog = NULL;
++ LIBBPF_OPTS(bpf_object_open_opts, opts);
++ struct changes_pkt_data *main = NULL;
++ char log[16*1024];
++ int err;
++
++ opts.kernel_log_buf = log;
++ opts.kernel_log_size = sizeof(log);
++ if (env.verbosity >= VERBOSE_SUPER)
++ opts.kernel_log_level = 1 | 2 | 4;
++ main = changes_pkt_data__open_opts(&opts);
++ if (!ASSERT_OK_PTR(main, "changes_pkt_data__open"))
++ goto out;
++ err = changes_pkt_data__load(main);
++ print_verifier_log(log);
++ if (!ASSERT_OK(err, "changes_pkt_data__load"))
++ goto out;
++ freplace = changes_pkt_data_freplace__open_opts(&opts);
++ if (!ASSERT_OK_PTR(freplace, "changes_pkt_data_freplace__open"))
++ goto out;
++ freplace_prog = bpf_object__find_program_by_name(freplace->obj, freplace_prog_name);
++ if (!ASSERT_OK_PTR(freplace_prog, "freplace_prog"))
++ goto out;
++ bpf_program__set_autoload(freplace_prog, true);
++ bpf_program__set_autoattach(freplace_prog, true);
++ bpf_program__set_attach_target(freplace_prog,
++ bpf_program__fd(main->progs.dummy),
++ main_prog_name);
++ err = changes_pkt_data_freplace__load(freplace);
++ print_verifier_log(log);
++ if (expect_load) {
++ ASSERT_OK(err, "changes_pkt_data_freplace__load");
++ } else {
++ ASSERT_ERR(err, "changes_pkt_data_freplace__load");
++ ASSERT_HAS_SUBSTR(log, "Extension program changes packet data", "error log");
++ }
++
++out:
++ changes_pkt_data_freplace__destroy(freplace);
++ changes_pkt_data__destroy(main);
++}
++
++/* There are two global subprograms in both changes_pkt_data.skel.h:
++ * - one changes packet data;
++ * - another does not.
++ * It is ok to freplace subprograms that change packet data with those
++ * that either do or do not. It is only ok to freplace subprograms
++ * that do not change packet data with those that do not as well.
++ * The below tests check outcomes for each combination of such freplace.
++ */
++void test_changes_pkt_data_freplace(void)
++{
++ if (test__start_subtest("changes_with_changes"))
++ test_aux("changes_pkt_data", "changes_pkt_data", true);
++ if (test__start_subtest("changes_with_doesnt_change"))
++ test_aux("changes_pkt_data", "does_not_change_pkt_data", true);
++ if (test__start_subtest("doesnt_change_with_changes"))
++ test_aux("does_not_change_pkt_data", "changes_pkt_data", false);
++ if (test__start_subtest("doesnt_change_with_doesnt_change"))
++ test_aux("does_not_change_pkt_data", "does_not_change_pkt_data", true);
++}
+--- /dev/null
++++ b/tools/testing/selftests/bpf/progs/changes_pkt_data.c
+@@ -0,0 +1,26 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <linux/bpf.h>
++#include <bpf/bpf_helpers.h>
++
++__noinline
++long changes_pkt_data(struct __sk_buff *sk, __u32 len)
++{
++ return bpf_skb_pull_data(sk, len);
++}
++
++__noinline __weak
++long does_not_change_pkt_data(struct __sk_buff *sk, __u32 len)
++{
++ return 0;
++}
++
++SEC("tc")
++int dummy(struct __sk_buff *sk)
++{
++ changes_pkt_data(sk, 0);
++ does_not_change_pkt_data(sk, 0);
++ return 0;
++}
++
++char _license[] SEC("license") = "GPL";
+--- /dev/null
++++ b/tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c
+@@ -0,0 +1,18 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <linux/bpf.h>
++#include <bpf/bpf_helpers.h>
++
++SEC("?freplace")
++long changes_pkt_data(struct __sk_buff *sk, __u32 len)
++{
++ return bpf_skb_pull_data(sk, len);
++}
++
++SEC("?freplace")
++long does_not_change_pkt_data(struct __sk_buff *sk, __u32 len)
++{
++ return 0;
++}
++
++char _license[] SEC("license") = "GPL";
--- /dev/null
+From stable+bounces-139111-greg=kroah.com@vger.kernel.org Wed Apr 30 10:20:26 2025
+From: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Date: Wed, 30 Apr 2025 16:19:46 +0800
+Subject: selftests/bpf: test for changing packet data from global functions
+To: stable@vger.kernel.org
+Cc: Alexei Starovoitov <ast@kernel.org>, Eduard Zingerman <eddyz87@gmail.com>, Nick Zavaritsky <mejedi@gmail.com>, Dan Carpenter <dan.carpenter@linaro.org>, Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Message-ID: <20250430081955.49927-5-shung-hsi.yu@suse.com>
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+commit 3f23ee5590d9605dbde9a5e1d4b97637a4803329 upstream.
+
+Check if verifier is aware of packet pointers invalidation done in
+global functions. Based on a test shared by Nick Zavaritsky in [0].
+
+[0] https://lore.kernel.org/bpf/0498CA22-5779-4767-9C0C-A9515CEA711F@gmail.com/
+
+Suggested-by: Nick Zavaritsky <mejedi@gmail.com>
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20241210041100.1898468-5-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/bpf/progs/verifier_sock.c | 28 ++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+--- a/tools/testing/selftests/bpf/progs/verifier_sock.c
++++ b/tools/testing/selftests/bpf/progs/verifier_sock.c
+@@ -977,4 +977,32 @@ l1_%=: r0 = *(u8*)(r7 + 0); \
+ : __clobber_all);
+ }
+
++__noinline
++long skb_pull_data2(struct __sk_buff *sk, __u32 len)
++{
++ return bpf_skb_pull_data(sk, len);
++}
++
++__noinline
++long skb_pull_data1(struct __sk_buff *sk, __u32 len)
++{
++ return skb_pull_data2(sk, len);
++}
++
++/* global function calls bpf_skb_pull_data(), which invalidates packet
++ * pointers established before global function call.
++ */
++SEC("tc")
++__failure __msg("invalid mem access")
++int invalidate_pkt_pointers_from_global_func(struct __sk_buff *sk)
++{
++ int *p = (void *)(long)sk->data;
++
++ if ((void *)(p + 1) > (void *)(long)sk->data_end)
++ return TCX_DROP;
++ skb_pull_data1(sk, 0);
++ *p = 42; /* this is unsafe */
++ return TCX_PASS;
++}
++
+ char _license[] SEC("license") = "GPL";
--- /dev/null
+From stable+bounces-139115-greg=kroah.com@vger.kernel.org Wed Apr 30 10:20:40 2025
+From: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Date: Wed, 30 Apr 2025 16:19:50 +0800
+Subject: selftests/bpf: validate that tail call invalidates packet pointers
+To: stable@vger.kernel.org
+Cc: Alexei Starovoitov <ast@kernel.org>, Eduard Zingerman <eddyz87@gmail.com>, Nick Zavaritsky <mejedi@gmail.com>, Dan Carpenter <dan.carpenter@linaro.org>, Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Message-ID: <20250430081955.49927-9-shung-hsi.yu@suse.com>
+
+From: Eduard Zingerman <eddyz87@gmail.com>
+
+commit d9706b56e13b7916461ca6b4b731e169ed44ed09 upstream.
+
+Add a test case with a tail call done from a global sub-program. Such
+tails calls should be considered as invalidating packet pointers.
+
+Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20241210041100.1898468-9-eddyz87@gmail.com
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/bpf/progs/verifier_sock.c | 28 ++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+--- a/tools/testing/selftests/bpf/progs/verifier_sock.c
++++ b/tools/testing/selftests/bpf/progs/verifier_sock.c
+@@ -50,6 +50,13 @@ struct {
+ __uint(map_flags, BPF_F_NO_PREALLOC);
+ } sk_storage_map SEC(".maps");
+
++struct {
++ __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
++ __uint(max_entries, 1);
++ __uint(key_size, sizeof(__u32));
++ __uint(value_size, sizeof(__u32));
++} jmp_table SEC(".maps");
++
+ SEC("cgroup/skb")
+ __description("skb->sk: no NULL check")
+ __failure __msg("invalid mem access 'sock_common_or_null'")
+@@ -1004,5 +1011,26 @@ int invalidate_pkt_pointers_from_global_
+ *p = 42; /* this is unsafe */
+ return TCX_PASS;
+ }
++
++__noinline
++int tail_call(struct __sk_buff *sk)
++{
++ bpf_tail_call_static(sk, &jmp_table, 0);
++ return 0;
++}
++
++/* Tail calls invalidate packet pointers. */
++SEC("tc")
++__failure __msg("invalid mem access")
++int invalidate_pkt_pointers_by_tail_call(struct __sk_buff *sk)
++{
++ int *p = (void *)(long)sk->data;
++
++ if ((void *)(p + 1) > (void *)(long)sk->data_end)
++ return TCX_DROP;
++ tail_call(sk);
++ *p = 42; /* this is unsafe */
++ return TCX_PASS;
++}
+
+ char _license[] SEC("license") = "GPL";
cpufreq-avoid-using-inconsistent-policy-min-and-policy-max.patch
cpufreq-fix-setting-policy-limits-when-frequency-tables-are-used.patch
tracing-fix-oob-write-in-trace_seq_to_buffer.patch
+bpf-add-find_containing_subprog-utility-function.patch
+bpf-refactor-bpf_helper_changes_pkt_data-to-use-helper-number.patch
+bpf-track-changes_pkt_data-property-for-global-functions.patch
+selftests-bpf-test-for-changing-packet-data-from-global-functions.patch
+bpf-check-changes_pkt_data-property-for-extension-programs.patch
+selftests-bpf-freplace-tests-for-tracking-of-changes_packet_data.patch
+bpf-consider-that-tail-calls-invalidate-packet-pointers.patch
+selftests-bpf-validate-that-tail-call-invalidates-packet-pointers.patch
+bpf-fix-null-dereference-when-computing-changes_pkt_data-of-prog-w-o-subprogs.patch
+selftests-bpf-extend-changes_pkt_data-with-cases-w-o-subprograms.patch
+revert-pci-imx6-skip-controller_id-generation-logic-for-i.mx7d.patch
+pci-imx6-skip-controller_id-generation-logic-for-i.mx7d.patch
+kvm-x86-load-dr6-with-guest-value-only-before-entering-.vcpu_run-loop.patch
+iommu-handle-race-with-default-domain-setup.patch