--- /dev/null
+From stable+bounces-253781-greg=kroah.com@vger.kernel.org Fri May 22 15:01:31 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 May 2026 08:54:20 -0400
+Subject: cgroup/cpuset: Reset DL migration state on can_attach() failure
+To: stable@vger.kernel.org
+Cc: Guopeng Zhang <zhangguopeng@kylinos.cn>, Tejun Heo <tj@kernel.org>, Chen Ridong <chenridong@huaweicloud.com>, Waiman Long <longman@redhat.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260522125420.3841043-1-sashal@kernel.org>
+
+From: Guopeng Zhang <zhangguopeng@kylinos.cn>
+
+[ Upstream commit 4a39eda5fdd867fc39f3c039714dd432cee00268 ]
+
+cpuset_can_attach() accumulates temporary SCHED_DEADLINE migration
+state in the destination cpuset while walking the taskset.
+
+If a later task_can_attach() or security_task_setscheduler() check
+fails, cgroup_migrate_execute() treats cpuset as the failing subsystem
+and does not call cpuset_cancel_attach() for it. The partially
+accumulated state is then left behind and can be consumed by a later
+attach, corrupting cpuset DL task accounting and pending DL bandwidth
+accounting.
+
+Reset the pending DL migration state from the common error exit when
+ret is non-zero. Successful can_attach() keeps the state for
+cpuset_attach() or cpuset_cancel_attach().
+
+Fixes: 2ef269ef1ac0 ("cgroup/cpuset: Free DL BW in case can_attach() fails")
+Cc: stable@vger.kernel.org # v6.10+
+Signed-off-by: Guopeng Zhang <zhangguopeng@kylinos.cn>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reviewed-by: Chen Ridong <chenridong@huaweicloud.com>
+Reviewed-by: Waiman Long <longman@redhat.com>
+[ omitted upstream context line `cs->dl_bw_cpu = cpu;` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/cgroup/cpuset.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/kernel/cgroup/cpuset.c
++++ b/kernel/cgroup/cpuset.c
+@@ -3163,16 +3163,13 @@ static int cpuset_can_attach(struct cgro
+ int cpu = cpumask_any_and(cpu_active_mask, cs->effective_cpus);
+
+ if (unlikely(cpu >= nr_cpu_ids)) {
+- reset_migrate_dl_data(cs);
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ ret = dl_bw_alloc(cpu, cs->sum_migrate_dl_bw);
+- if (ret) {
+- reset_migrate_dl_data(cs);
++ if (ret)
+ goto out_unlock;
+- }
+ }
+
+ out_success:
+@@ -3181,7 +3178,10 @@ out_success:
+ * changes which zero cpus/mems_allowed.
+ */
+ cs->attach_in_progress++;
++
+ out_unlock:
++ if (ret)
++ reset_migrate_dl_data(cs);
+ mutex_unlock(&cpuset_mutex);
+ return ret;
+ }
--- /dev/null
+From stable+bounces-254710-greg=kroah.com@vger.kernel.org Thu May 28 05:21:19 2026
+From: Bin Lan <lanbincn@139.com>
+Date: Thu, 28 May 2026 11:20:28 +0800
+Subject: fs/ntfs3: handle attr_set_size() errors when truncating files
+To: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org, Konstantin Komarov <almaz.alexandrovich@paragon-software.com>, Bin Lan <lanbincn@139.com>
+Message-ID: <20260528032028.58379-1-lanbincn@139.com>
+
+From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
+
+[ Upstream commit 576248a34b927e93b2fd3fff7df735ba73ad7d01 ]
+
+If attr_set_size() fails while truncating down, the error is silently
+ignored and the inode may be left in an inconsistent state.
+
+Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
+[ Minor context conflict resolved. ]
+Signed-off-by: Bin Lan <lanbincn@139.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ntfs3/file.c | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+--- a/fs/ntfs3/file.c
++++ b/fs/ntfs3/file.c
+@@ -458,8 +458,8 @@ static int ntfs_truncate(struct inode *i
+ {
+ struct super_block *sb = inode->i_sb;
+ struct ntfs_inode *ni = ntfs_i(inode);
+- int err, dirty = 0;
+ u64 new_valid;
++ int err;
+
+ if (!S_ISREG(inode->i_mode))
+ return 0;
+@@ -475,7 +475,6 @@ static int ntfs_truncate(struct inode *i
+ }
+
+ new_valid = ntfs_up_block(sb, min_t(u64, ni->i_valid, new_size));
+-
+ truncate_setsize(inode, new_size);
+
+ ni_lock(ni);
+@@ -489,22 +488,19 @@ static int ntfs_truncate(struct inode *i
+ ni->i_valid = new_valid;
+
+ ni_unlock(ni);
++ if (unlikely(err))
++ return err;
+
+ ni->std_fa |= FILE_ATTRIBUTE_ARCHIVE;
+ inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
+ if (!IS_DIRSYNC(inode)) {
+- dirty = 1;
++ mark_inode_dirty(inode);
+ } else {
+ err = ntfs_sync_inode(inode);
+ if (err)
+ return err;
+ }
+
+- if (dirty)
+- mark_inode_dirty(inode);
+-
+- /*ntfs_flush_inodes(inode->i_sb, inode, NULL);*/
+-
+ return 0;
+ }
+
--- /dev/null
+From stable+bounces-253784-greg=kroah.com@vger.kernel.org Fri May 22 15:31:39 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 May 2026 09:02:59 -0400
+Subject: net: ethtool: fix NULL pointer dereference in phy_reply_size
+To: stable@vger.kernel.org
+Cc: Quan Sun <2022090917019@std.uestc.edu.cn>, Maxime Chevallier <maxime.chevallier@bootlin.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260522130300.3869084-1-sashal@kernel.org>
+
+From: Quan Sun <2022090917019@std.uestc.edu.cn>
+
+[ Upstream commit 4908f1395fb1b832ceec11584af649874a2732ea ]
+
+In phy_prepare_data(), several strings such as 'name', 'drvname',
+'upstream_sfp_name', and 'downstream_sfp_name' are allocated using
+kstrdup(). However, these allocations were not checked for failure.
+
+If kstrdup() fails for 'name', it returns NULL while the function
+continues. This leads to a kernel NULL pointer dereference and panic
+later in phy_reply_size() when it unconditionally calls strlen() on
+the NULL pointer.
+
+While other strings like 'upstream_sfp_name' might be checked before
+access in certain code paths, failing to handle these allocations
+consistently can lead to incomplete data reporting or hidden bugs.
+
+Fix this by adding proper NULL checks for all kstrdup() calls in
+phy_prepare_data() and implement a centralized error handling path
+using goto labels to ensure all previously allocated resources are
+freed on failure.
+
+Fixes: 9dd2ad5e92b9 ("net: ethtool: phy: Convert the PHY_GET command to generic phy dump")
+Signed-off-by: Quan Sun <2022090917019@std.uestc.edu.cn>
+Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Link: https://patch.msgid.link/20260507131738.1173835-1-2022090917019@std.uestc.edu.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: e3adf69f8eb1 ("net: ethtool: phy: avoid NULL deref when PHY driver is unbound")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ethtool/phy.c | 32 ++++++++++++++++++++++++++++++--
+ 1 file changed, 30 insertions(+), 2 deletions(-)
+
+--- a/net/ethtool/phy.c
++++ b/net/ethtool/phy.c
+@@ -76,6 +76,7 @@ static int phy_prepare_data(const struct
+ struct nlattr **tb = info->attrs;
+ struct phy_device_node *pdn;
+ struct phy_device *phydev;
++ int ret;
+
+ /* RTNL is held by the caller */
+ phydev = ethnl_req_get_phydev(req_info, tb, ETHTOOL_A_PHY_HEADER,
+@@ -88,8 +89,17 @@ static int phy_prepare_data(const struct
+ return -EOPNOTSUPP;
+
+ rep_data->phyindex = phydev->phyindex;
++
+ rep_data->name = kstrdup(dev_name(&phydev->mdio.dev), GFP_KERNEL);
++ if (!rep_data->name)
++ return -ENOMEM;
++
+ rep_data->drvname = kstrdup(phydev->drv->name, GFP_KERNEL);
++ if (!rep_data->drvname) {
++ ret = -ENOMEM;
++ goto err_free_name;
++ }
++
+ rep_data->upstream_type = pdn->upstream_type;
+
+ if (pdn->upstream_type == PHY_UPSTREAM_PHY) {
+@@ -97,15 +107,33 @@ static int phy_prepare_data(const struct
+ rep_data->upstream_index = upstream->phyindex;
+ }
+
+- if (pdn->parent_sfp_bus)
++ if (pdn->parent_sfp_bus) {
+ rep_data->upstream_sfp_name = kstrdup(sfp_get_name(pdn->parent_sfp_bus),
+ GFP_KERNEL);
++ if (!rep_data->upstream_sfp_name) {
++ ret = -ENOMEM;
++ goto err_free_drvname;
++ }
++ }
+
+- if (phydev->sfp_bus)
++ if (phydev->sfp_bus) {
+ rep_data->downstream_sfp_name = kstrdup(sfp_get_name(phydev->sfp_bus),
+ GFP_KERNEL);
++ if (!rep_data->downstream_sfp_name) {
++ ret = -ENOMEM;
++ goto err_free_upstream_sfp;
++ }
++ }
+
+ return 0;
++
++err_free_upstream_sfp:
++ kfree(rep_data->upstream_sfp_name);
++err_free_drvname:
++ kfree(rep_data->drvname);
++err_free_name:
++ kfree(rep_data->name);
++ return ret;
+ }
+
+ static int phy_fill_reply(struct sk_buff *skb,
--- /dev/null
+From stable+bounces-253785-greg=kroah.com@vger.kernel.org Fri May 22 15:16:54 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 May 2026 09:03:00 -0400
+Subject: net: ethtool: phy: avoid NULL deref when PHY driver is unbound
+To: stable@vger.kernel.org
+Cc: David Carlier <devnexen@gmail.com>, Maxime Chevallier <maxime.chevallier@bootlin.com>, Jakub Kicinski <kuba@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260522130300.3869084-2-sashal@kernel.org>
+
+From: David Carlier <devnexen@gmail.com>
+
+[ Upstream commit e3adf69f8eb121a9128c2b0029efd050d3649153 ]
+
+phydev->drv can become NULL while the phy_device is still attached to
+its net_device, namely after the PHY driver is unbound via sysfs:
+
+ echo <mdio_id> > /sys/bus/mdio_bus/drivers/<phy_drv>/unbind
+
+phy_remove() clears phydev->drv but doesn't call phy_detach(), so the
+phy_device stays in the link topology xarray and ethnl_req_get_phydev()
+still hands it back. ETHTOOL_MSG_PHY_GET then oopses on:
+
+ rep_data->drvname = kstrdup(phydev->drv->name, GFP_KERNEL);
+
+drvname is already treated as optional by phy_reply_size(),
+phy_fill_reply() and phy_cleanup_data(), so just skip the allocation
+when there is no driver bound.
+
+Fixes: 9dd2ad5e92b9 ("net: ethtool: phy: Convert the PHY_GET command to generic phy dump")
+Cc: stable@vger.kernel.org # 6.13.x
+Signed-off-by: David Carlier <devnexen@gmail.com>
+Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Tested-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Link: https://patch.msgid.link/20260509215046.107157-1-devnexen@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ethtool/phy.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/net/ethtool/phy.c
++++ b/net/ethtool/phy.c
+@@ -94,10 +94,12 @@ static int phy_prepare_data(const struct
+ if (!rep_data->name)
+ return -ENOMEM;
+
+- rep_data->drvname = kstrdup(phydev->drv->name, GFP_KERNEL);
+- if (!rep_data->drvname) {
+- ret = -ENOMEM;
+- goto err_free_name;
++ if (phydev->drv) {
++ rep_data->drvname = kstrdup(phydev->drv->name, GFP_KERNEL);
++ if (!rep_data->drvname) {
++ ret = -ENOMEM;
++ goto err_free_name;
++ }
+ }
+
+ rep_data->upstream_type = pdn->upstream_type;
--- /dev/null
+From stable+bounces-253570-greg=kroah.com@vger.kernel.org Thu May 21 16:31:34 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 09:53:58 -0400
+Subject: sched_ext: Avoid UAF in scx_root_enable_workfn() init failure path
+To: stable@vger.kernel.org
+Cc: Tejun Heo <tj@kernel.org>, Sashiko <sashiko-bot@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260521135358.1280483-2-sashal@kernel.org>
+
+From: Tejun Heo <tj@kernel.org>
+
+[ Upstream commit 9a415cc53711f2238e0f0ca8a6bcc796c003b127 ]
+
+In scx_root_enable_workfn(), put_task_struct(p) is called before scx_error()
+dereferences p->comm and p->pid. If the iterator's reference is the last
+drop, the task is freed synchronously and the deref becomes a UAF.
+
+Move put_task_struct() past scx_error().
+
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Closes: https://lore.kernel.org/all/20260511214031.AF5E9C2BCB0@smtp.kernel.org/
+Fixes: f0e1a0643a59 ("sched_ext: Implement BPF extensible scheduler class")
+Cc: stable@vger.kernel.org # v6.12+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+[ kept `scx_init_task()` call site instead of `__scx_init_task()`/`task_rq_lock` ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/sched/ext.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/kernel/sched/ext.c
++++ b/kernel/sched/ext.c
+@@ -4812,10 +4812,10 @@ static void scx_enable_workfn(struct kth
+
+ ret = scx_init_task(p, task_group(p), false);
+ if (ret) {
+- put_task_struct(p);
+ scx_task_iter_stop(&sti);
+ scx_error(sch, "ops.init_task() failed (%d) for %s[%d]",
+ ret, p->comm, p->pid);
++ put_task_struct(p);
+ goto err_disable_unlock_all;
+ }
+
--- /dev/null
+From stable+bounces-253569-greg=kroah.com@vger.kernel.org Thu May 21 16:59:34 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 09:53:57 -0400
+Subject: sched_ext: Fix missing warning in scx_set_task_state() default case
+To: stable@vger.kernel.org
+Cc: Samuele Mariotti <smariotti@disroot.org>, Paolo Valente <paolo.valente@unimore.it>, Andrea Righi <arighi@nvidia.com>, Tejun Heo <tj@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260521135358.1280483-1-sashal@kernel.org>
+
+From: Samuele Mariotti <smariotti@disroot.org>
+
+[ Upstream commit b905ee77d5f557a83a485b4146210f54f13365fc ]
+
+In scx_set_task_state(), the default case was setting the
+warn flag, but then returning immediately. This is problematic
+because the only purpose of the warn flag is to trigger
+WARN_ONCE, but the early return prevented it from ever firing,
+leaving invalid task states undetected and untraced.
+
+To fix this, a WARN_ONCE call is now added directly in the
+default case.
+
+The fix addresses two aspects:
+
+ - Guarantees the invalid task states are properly logged
+ and traced.
+
+ - Provides a distinct warning message
+ ("sched_ext: Invalid task state") specifically for
+ states outside the defined scx_task_state enum values,
+ making it easier to distinguish from other transition
+ warnings.
+
+This ensures proper detection and reporting of invalid states.
+
+Signed-off-by: Samuele Mariotti <smariotti@disroot.org>
+Signed-off-by: Paolo Valente <paolo.valente@unimore.it>
+Reviewed-by: Andrea Righi <arighi@nvidia.com>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Stable-dep-of: 9a415cc53711 ("sched_ext: Avoid UAF in scx_root_enable_workfn() init failure path")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/sched/ext.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/kernel/sched/ext.c
++++ b/kernel/sched/ext.c
+@@ -2800,7 +2800,8 @@ static void scx_set_task_state(struct ta
+ warn = prev_state != SCX_TASK_READY;
+ break;
+ default:
+- warn = true;
++ WARN_ONCE(1, "sched_ext: Invalid task state %d -> %d for %s[%d]",
++ prev_state, state, p->comm, p->pid);
+ return;
+ }
+
netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch
netfilter-ipset-stop-hash-range-iteration-at-end.patch
netfilter-nft_inner-fix-ipv6-inner_thoff-desync.patch
+sched_ext-fix-missing-warning-in-scx_set_task_state-default-case.patch
+sched_ext-avoid-uaf-in-scx_root_enable_workfn-init-failure-path.patch
+tracing-fprobe-remove-unused-local-variable.patch
+tracing-fprobe-use-ftrace-if-config_dynamic_ftrace_with_args.patch
+tracing-fprobe-avoid-kcalloc-in-rcu_read_lock-section.patch
+tracing-fprobe-check-the-same-type-fprobe-on-table-as-the-unregistered-one.patch
+cgroup-cpuset-reset-dl-migration-state-on-can_attach-failure.patch
+net-ethtool-fix-null-pointer-dereference-in-phy_reply_size.patch
+net-ethtool-phy-avoid-null-deref-when-phy-driver-is-unbound.patch
+fs-ntfs3-handle-attr_set_size-errors-when-truncating-files.patch
--- /dev/null
+From stable+bounces-253539-greg=kroah.com@vger.kernel.org Thu May 21 15:10:32 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 08:58:12 -0400
+Subject: tracing/fprobe: Avoid kcalloc() in rcu_read_lock section
+To: stable@vger.kernel.org
+Cc: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260521125813.1165339-3-sashal@kernel.org>
+
+From: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>
+
+[ Upstream commit aa72812b49104bb5a38272fc9541feb62ca6fd32 ]
+
+fprobe_remove_node_in_module() is called under RCU read locked, but
+this invokes kcalloc() if there are more than 8 fprobes installed
+on the module. Sashiko warns it because kcalloc() can sleep [1].
+
+ [1] https://sashiko.dev/#/patchset/177552432201.853249.5125045538812833325.stgit%40mhiramat.tok.corp.google.com
+
+To fix this issue, expand the batch size to 128 and do not expand
+the fprobe_addr_list, but just cancel walking on fprobe_ip_table,
+update fgraph/ftrace_ops and retry the loop again.
+
+Link: https://lore.kernel.org/all/177669367206.132053.1493637946869032744.stgit@mhiramat.tok.corp.google.com/
+
+Fixes: 0de4c70d04a4 ("tracing: fprobe: use rhltable for fprobe_ip_table")
+Cc: stable@vger.kernel.org
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Stable-dep-of: 0ac0058a74ac ("tracing/fprobe: Check the same type fprobe on table as the unregistered one")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/fprobe.c | 92 ++++++++++++++++++++++++--------------------------
+ 1 file changed, 45 insertions(+), 47 deletions(-)
+
+--- a/kernel/trace/fprobe.c
++++ b/kernel/trace/fprobe.c
+@@ -344,11 +344,10 @@ static bool fprobe_is_ftrace(struct fpro
+ }
+
+ #ifdef CONFIG_MODULES
+-static void fprobe_set_ips(unsigned long *ips, unsigned int cnt, int remove,
+- int reset)
++static void fprobe_remove_ips(unsigned long *ips, unsigned int cnt)
+ {
+- ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, remove, reset);
+- ftrace_set_filter_ips(&fprobe_ftrace_ops, ips, cnt, remove, reset);
++ ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, 1, 0);
++ ftrace_set_filter_ips(&fprobe_ftrace_ops, ips, cnt, 1, 0);
+ }
+ #endif
+ #else
+@@ -367,10 +366,9 @@ static bool fprobe_is_ftrace(struct fpro
+ }
+
+ #ifdef CONFIG_MODULES
+-static void fprobe_set_ips(unsigned long *ips, unsigned int cnt, int remove,
+- int reset)
++static void fprobe_remove_ips(unsigned long *ips, unsigned int cnt)
+ {
+- ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, remove, reset);
++ ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, 1, 0);
+ }
+ #endif
+ #endif /* !CONFIG_DYNAMIC_FTRACE_WITH_ARGS && !CONFIG_DYNAMIC_FTRACE_WITH_REGS */
+@@ -543,7 +541,7 @@ static void fprobe_graph_remove_ips(unsi
+
+ #ifdef CONFIG_MODULES
+
+-#define FPROBE_IPS_BATCH_INIT 8
++#define FPROBE_IPS_BATCH_INIT 128
+ /* instruction pointer address list */
+ struct fprobe_addr_list {
+ int index;
+@@ -551,45 +549,24 @@ struct fprobe_addr_list {
+ unsigned long *addrs;
+ };
+
+-static int fprobe_addr_list_add(struct fprobe_addr_list *alist, unsigned long addr)
++static int fprobe_remove_node_in_module(struct module *mod, struct fprobe_hlist_node *node,
++ struct fprobe_addr_list *alist)
+ {
+- unsigned long *addrs;
+-
+- /* Previously we failed to expand the list. */
+- if (alist->index == alist->size)
+- return -ENOSPC;
+-
+- alist->addrs[alist->index++] = addr;
+- if (alist->index < alist->size)
++ if (!within_module(node->addr, mod))
+ return 0;
+
+- /* Expand the address list */
+- addrs = kcalloc(alist->size * 2, sizeof(*addrs), GFP_KERNEL);
+- if (!addrs)
+- return -ENOMEM;
+-
+- memcpy(addrs, alist->addrs, alist->size * sizeof(*addrs));
+- alist->size *= 2;
+- kfree(alist->addrs);
+- alist->addrs = addrs;
++ if (delete_fprobe_node(node))
++ return 0;
++ /* If no address list is available, we can't track this address. */
++ if (!alist->addrs)
++ return 0;
+
++ alist->addrs[alist->index++] = node->addr;
++ if (alist->index == alist->size)
++ return -ENOSPC;
+ return 0;
+ }
+
+-static void fprobe_remove_node_in_module(struct module *mod, struct fprobe_hlist_node *node,
+- struct fprobe_addr_list *alist)
+-{
+- if (!within_module(node->addr, mod))
+- return;
+- if (delete_fprobe_node(node))
+- return;
+- /*
+- * If failed to update alist, just continue to update hlist.
+- * Therefore, at list user handler will not hit anymore.
+- */
+- fprobe_addr_list_add(alist, node->addr);
+-}
+-
+ /* Handle module unloading to manage fprobe_ip_table. */
+ static int fprobe_module_callback(struct notifier_block *nb,
+ unsigned long val, void *data)
+@@ -598,29 +575,50 @@ static int fprobe_module_callback(struct
+ struct fprobe_hlist_node *node;
+ struct rhashtable_iter iter;
+ struct module *mod = data;
++ bool retry;
+
+ if (val != MODULE_STATE_GOING)
+ return NOTIFY_DONE;
+
+ alist.addrs = kcalloc(alist.size, sizeof(*alist.addrs), GFP_KERNEL);
+- /* If failed to alloc memory, we can not remove ips from hash. */
+- if (!alist.addrs)
+- return NOTIFY_DONE;
++ /*
++ * If failed to alloc memory, ftrace_ops will not be able to remove ips from
++ * hash, but we can still remove nodes from fprobe_ip_table, so we can avoid
++ * the potential wrong callback. So just print a warning here and try to
++ * continue without address list.
++ */
++ WARN_ONCE(!alist.addrs,
++ "Failed to allocate memory for fprobe_addr_list, ftrace_ops will not be updated");
+
+ mutex_lock(&fprobe_mutex);
++again:
++ retry = false;
++ alist.index = 0;
+ rhltable_walk_enter(&fprobe_ip_table, &iter);
+ do {
+ rhashtable_walk_start(&iter);
+
+ while ((node = rhashtable_walk_next(&iter)) && !IS_ERR(node))
+- fprobe_remove_node_in_module(mod, node, &alist);
++ if (fprobe_remove_node_in_module(mod, node, &alist) < 0) {
++ retry = true;
++ break;
++ }
+
+ rhashtable_walk_stop(&iter);
+- } while (node == ERR_PTR(-EAGAIN));
++ } while (node == ERR_PTR(-EAGAIN) && !retry);
+ rhashtable_walk_exit(&iter);
++ /* Remove any ips from hash table(s) */
++ if (alist.index > 0) {
++ fprobe_remove_ips(alist.addrs, alist.index);
++ /*
++ * If we break rhashtable walk loop except for -EAGAIN, we need
++ * to restart looping from start for safety. Anyway, this is
++ * not a hotpath.
++ */
++ if (retry)
++ goto again;
++ }
+
+- if (alist.index > 0)
+- fprobe_set_ips(alist.addrs, alist.index, 1, 0);
+ mutex_unlock(&fprobe_mutex);
+
+ kfree(alist.addrs);
--- /dev/null
+From stable+bounces-253540-greg=kroah.com@vger.kernel.org Thu May 21 15:10:33 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 08:58:13 -0400
+Subject: tracing/fprobe: Check the same type fprobe on table as the unregistered one
+To: stable@vger.kernel.org
+Cc: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260521125813.1165339-4-sashal@kernel.org>
+
+From: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>
+
+[ Upstream commit 0ac0058a74ac5765c7ce09ea630f4fdeaf4d80fa ]
+
+Commit 2c67dc457bc6 ("tracing: fprobe: optimization for entry only case")
+introduced a different ftrace_ops for entry-only fprobes.
+
+However, when unregistering an fprobe, the kernel only checks if another
+fprobe exists at the same address, without checking which type of fprobe
+it is.
+If different fprobes are registered at the same address, the same address
+will be registered in both fgraph_ops and ftrace_ops, but only one of
+them will be deleted when unregistering. (the one removed first will not
+be deleted from the ops).
+
+This results in junk entries remaining in either fgraph_ops or ftrace_ops.
+For example:
+ =======
+ cd /sys/kernel/tracing
+
+ # 'Add entry and exit events on the same place'
+ echo 'f:event1 vfs_read' >> dynamic_events
+ echo 'f:event2 vfs_read%return' >> dynamic_events
+
+ # 'Enable both of them'
+ echo 1 > events/fprobes/enable
+ cat enabled_functions
+vfs_read (2) ->arch_ftrace_ops_list_func+0x0/0x210
+
+ # 'Disable and remove exit event'
+ echo 0 > events/fprobes/event2/enable
+ echo -:event2 >> dynamic_events
+
+ # 'Disable and remove all events'
+ echo 0 > events/fprobes/enable
+ echo > dynamic_events
+
+ # 'Add another event'
+ echo 'f:event3 vfs_open%return' > dynamic_events
+ cat dynamic_events
+f:fprobes/event3 vfs_open%return
+
+ echo 1 > events/fprobes/enable
+ cat enabled_functions
+vfs_open (1) tramp: 0xffffffffa0001000 (ftrace_graph_func+0x0/0x60) ->ftrace_graph_func+0x0/0x60 subops: {ent:fprobe_fgraph_entry+0x0/0x620 ret:fprobe_return+0x0/0x150}
+vfs_read (1) tramp: 0xffffffffa0001000 (ftrace_graph_func+0x0/0x60) ->ftrace_graph_func+0x0/0x60 subops: {ent:fprobe_fgraph_entry+0x0/0x620 ret:fprobe_return+0x0/0x150}
+ =======
+
+As you can see, an entry for the vfs_read remains.
+
+To fix this issue, when unregistering, the kernel should also check if
+there is the same type of fprobes still exist at the same address, and
+if not, delete its entry from either fgraph_ops or ftrace_ops.
+
+Link: https://lore.kernel.org/all/177669367993.132053.10553046138528674802.stgit@mhiramat.tok.corp.google.com/
+
+Fixes: 2c67dc457bc6 ("tracing: fprobe: optimization for entry only case")
+Cc: stable@vger.kernel.org
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/fprobe.c | 82 +++++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 65 insertions(+), 17 deletions(-)
+
+--- a/kernel/trace/fprobe.c
++++ b/kernel/trace/fprobe.c
+@@ -92,11 +92,8 @@ static int insert_fprobe_node(struct fpr
+ return ret;
+ }
+
+-/* Return true if there are synonims */
+-static bool delete_fprobe_node(struct fprobe_hlist_node *node)
++static void delete_fprobe_node(struct fprobe_hlist_node *node)
+ {
+- bool ret;
+-
+ lockdep_assert_held(&fprobe_mutex);
+
+ /* Avoid double deleting and non-inserted nodes */
+@@ -105,13 +102,6 @@ static bool delete_fprobe_node(struct fp
+ rhltable_remove(&fprobe_ip_table, &node->hlist,
+ fprobe_rht_params);
+ }
+-
+- rcu_read_lock();
+- ret = !!rhltable_lookup(&fprobe_ip_table, &node->addr,
+- fprobe_rht_params);
+- rcu_read_unlock();
+-
+- return ret;
+ }
+
+ /* Check existence of the fprobe */
+@@ -343,6 +333,32 @@ static bool fprobe_is_ftrace(struct fpro
+ return !fp->exit_handler;
+ }
+
++static bool fprobe_exists_on_hash(unsigned long ip, bool ftrace)
++{
++ struct rhlist_head *head, *pos;
++ struct fprobe_hlist_node *node;
++ struct fprobe *fp;
++
++ guard(rcu)();
++ head = rhltable_lookup(&fprobe_ip_table, &ip,
++ fprobe_rht_params);
++ if (!head)
++ return false;
++ /* We have to check the same type on the list. */
++ rhl_for_each_entry_rcu(node, pos, head, hlist) {
++ if (node->addr != ip)
++ break;
++ fp = READ_ONCE(node->fp);
++ if (likely(fp)) {
++ if ((!ftrace && fp->exit_handler) ||
++ (ftrace && !fp->exit_handler))
++ return true;
++ }
++ }
++
++ return false;
++}
++
+ #ifdef CONFIG_MODULES
+ static void fprobe_remove_ips(unsigned long *ips, unsigned int cnt)
+ {
+@@ -365,6 +381,29 @@ static bool fprobe_is_ftrace(struct fpro
+ return false;
+ }
+
++static bool fprobe_exists_on_hash(unsigned long ip, bool ftrace __maybe_unused)
++{
++ struct rhlist_head *head, *pos;
++ struct fprobe_hlist_node *node;
++ struct fprobe *fp;
++
++ guard(rcu)();
++ head = rhltable_lookup(&fprobe_ip_table, &ip,
++ fprobe_rht_params);
++ if (!head)
++ return false;
++ /* We only need to check fp is there. */
++ rhl_for_each_entry_rcu(node, pos, head, hlist) {
++ if (node->addr != ip)
++ break;
++ fp = READ_ONCE(node->fp);
++ if (likely(fp))
++ return true;
++ }
++
++ return false;
++}
++
+ #ifdef CONFIG_MODULES
+ static void fprobe_remove_ips(unsigned long *ips, unsigned int cnt)
+ {
+@@ -552,18 +591,25 @@ struct fprobe_addr_list {
+ static int fprobe_remove_node_in_module(struct module *mod, struct fprobe_hlist_node *node,
+ struct fprobe_addr_list *alist)
+ {
++ lockdep_assert_in_rcu_read_lock();
++
+ if (!within_module(node->addr, mod))
+ return 0;
+
+- if (delete_fprobe_node(node))
+- return 0;
++ delete_fprobe_node(node);
+ /* If no address list is available, we can't track this address. */
+ if (!alist->addrs)
+ return 0;
++ /*
++ * Don't care the type here, because all fprobes on the same
++ * address must be removed eventually.
++ */
++ if (!rhltable_lookup(&fprobe_ip_table, &node->addr, fprobe_rht_params)) {
++ alist->addrs[alist->index++] = node->addr;
++ if (alist->index == alist->size)
++ return -ENOSPC;
++ }
+
+- alist->addrs[alist->index++] = node->addr;
+- if (alist->index == alist->size)
+- return -ENOSPC;
+ return 0;
+ }
+
+@@ -934,7 +980,9 @@ static int unregister_fprobe_nolock(stru
+ /* Remove non-synonim ips from table and hash */
+ count = 0;
+ for (i = 0; i < hlist_array->size; i++) {
+- if (!delete_fprobe_node(&hlist_array->array[i]) && addrs)
++ delete_fprobe_node(&hlist_array->array[i]);
++ if (addrs && !fprobe_exists_on_hash(hlist_array->array[i].addr,
++ fprobe_is_ftrace(fp)))
+ addrs[count++] = hlist_array->array[i].addr;
+ }
+ del_fprobe_hash(fp);
--- /dev/null
+From stable+bounces-253536-greg=kroah.com@vger.kernel.org Thu May 21 15:10:23 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 08:58:10 -0400
+Subject: tracing: fprobe: Remove unused local variable
+To: stable@vger.kernel.org
+Cc: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>, Menglong Dong <menglong8.dong@gmail.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260521125813.1165339-1-sashal@kernel.org>
+
+From: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>
+
+[ Upstream commit 90e69d291d195d35215b578d210fd3ce0e5a3f42 ]
+
+The 'ret' local variable in fprobe_remove_node_in_module() was used
+for checking the error state in the loop, but commit dfe0d675df82
+("tracing: fprobe: use rhltable for fprobe_ip_table") removed the loop.
+So we don't need it anymore.
+
+Link: https://lore.kernel.org/all/175867358989.600222.6175459620045800878.stgit@devnote2/
+
+Fixes: e5a4cc28a052 ("tracing: fprobe: use rhltable for fprobe_ip_table")
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Acked-by: Menglong Dong <menglong8.dong@gmail.com>
+Stable-dep-of: 0ac0058a74ac ("tracing/fprobe: Check the same type fprobe on table as the unregistered one")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/fprobe.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+--- a/kernel/trace/fprobe.c
++++ b/kernel/trace/fprobe.c
+@@ -561,8 +561,6 @@ static int fprobe_addr_list_add(struct f
+ static void fprobe_remove_node_in_module(struct module *mod, struct fprobe_hlist_node *node,
+ struct fprobe_addr_list *alist)
+ {
+- int ret = 0;
+-
+ if (!within_module(node->addr, mod))
+ return;
+ if (delete_fprobe_node(node))
+@@ -571,8 +569,7 @@ static void fprobe_remove_node_in_module
+ * If failed to update alist, just continue to update hlist.
+ * Therefore, at list user handler will not hit anymore.
+ */
+- if (!ret)
+- ret = fprobe_addr_list_add(alist, node->addr);
++ fprobe_addr_list_add(alist, node->addr);
+ }
+
+ /* Handle module unloading to manage fprobe_ip_table. */
--- /dev/null
+From stable+bounces-253538-greg=kroah.com@vger.kernel.org Thu May 21 15:50:39 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 May 2026 08:58:11 -0400
+Subject: tracing: fprobe: use ftrace if CONFIG_DYNAMIC_FTRACE_WITH_ARGS
+To: stable@vger.kernel.org
+Cc: Menglong Dong <menglong8.dong@gmail.com>, Menglong Dong <dongml2@chinatelecom.cn>, "Masami Hiramatsu (Google)" <mhiramat@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260521125813.1165339-2-sashal@kernel.org>
+
+From: Menglong Dong <menglong8.dong@gmail.com>
+
+[ Upstream commit cd06078a38aaedfebbf8fa0c009da0f99f4473fb ]
+
+For now, we will use ftrace for the fprobe if fp->exit_handler not exists
+and CONFIG_DYNAMIC_FTRACE_WITH_REGS is enabled.
+
+However, CONFIG_DYNAMIC_FTRACE_WITH_REGS is not supported by some arch,
+such as arm. What we need in the fprobe is the function arguments, so we
+can use ftrace for fprobe if CONFIG_DYNAMIC_FTRACE_WITH_ARGS is enabled.
+
+Therefore, use ftrace if CONFIG_DYNAMIC_FTRACE_WITH_REGS or
+CONFIG_DYNAMIC_FTRACE_WITH_ARGS enabled.
+
+Link: https://lore.kernel.org/all/20251103063434.47388-1-dongml2@chinatelecom.cn/
+
+Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Stable-dep-of: 0ac0058a74ac ("tracing/fprobe: Check the same type fprobe on table as the unregistered one")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/fprobe.c | 32 ++++++++++++++++++++++----------
+ 1 file changed, 22 insertions(+), 10 deletions(-)
+
+--- a/kernel/trace/fprobe.c
++++ b/kernel/trace/fprobe.c
+@@ -45,6 +45,7 @@
+ static struct hlist_head fprobe_table[FPROBE_TABLE_SIZE];
+ static struct rhltable fprobe_ip_table;
+ static DEFINE_MUTEX(fprobe_mutex);
++static struct fgraph_ops fprobe_graph_ops;
+
+ static u32 fprobe_node_hashfn(const void *data, u32 len, u32 seed)
+ {
+@@ -259,7 +260,7 @@ static inline int __fprobe_kprobe_handle
+ return ret;
+ }
+
+-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
++#if defined(CONFIG_DYNAMIC_FTRACE_WITH_ARGS) || defined(CONFIG_DYNAMIC_FTRACE_WITH_REGS)
+ /* ftrace_ops callback, this processes fprobes which have only entry_handler. */
+ static void fprobe_ftrace_entry(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_ops *ops, struct ftrace_regs *fregs)
+@@ -300,7 +301,7 @@ NOKPROBE_SYMBOL(fprobe_ftrace_entry);
+
+ static struct ftrace_ops fprobe_ftrace_ops = {
+ .func = fprobe_ftrace_entry,
+- .flags = FTRACE_OPS_FL_SAVE_REGS,
++ .flags = FTRACE_OPS_FL_SAVE_ARGS,
+ };
+ static int fprobe_ftrace_active;
+
+@@ -341,6 +342,15 @@ static bool fprobe_is_ftrace(struct fpro
+ {
+ return !fp->exit_handler;
+ }
++
++#ifdef CONFIG_MODULES
++static void fprobe_set_ips(unsigned long *ips, unsigned int cnt, int remove,
++ int reset)
++{
++ ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, remove, reset);
++ ftrace_set_filter_ips(&fprobe_ftrace_ops, ips, cnt, remove, reset);
++}
++#endif
+ #else
+ static int fprobe_ftrace_add_ips(unsigned long *addrs, int num)
+ {
+@@ -355,7 +365,15 @@ static bool fprobe_is_ftrace(struct fpro
+ {
+ return false;
+ }
++
++#ifdef CONFIG_MODULES
++static void fprobe_set_ips(unsigned long *ips, unsigned int cnt, int remove,
++ int reset)
++{
++ ftrace_set_filter_ips(&fprobe_graph_ops.ops, ips, cnt, remove, reset);
++}
+ #endif
++#endif /* !CONFIG_DYNAMIC_FTRACE_WITH_ARGS && !CONFIG_DYNAMIC_FTRACE_WITH_REGS */
+
+ /* fgraph_ops callback, this processes fprobes which have exit_handler. */
+ static int fprobe_fgraph_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops,
+@@ -601,14 +619,8 @@ static int fprobe_module_callback(struct
+ } while (node == ERR_PTR(-EAGAIN));
+ rhashtable_walk_exit(&iter);
+
+- if (alist.index > 0) {
+- ftrace_set_filter_ips(&fprobe_graph_ops.ops,
+- alist.addrs, alist.index, 1, 0);
+-#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
+- ftrace_set_filter_ips(&fprobe_ftrace_ops,
+- alist.addrs, alist.index, 1, 0);
+-#endif
+- }
++ if (alist.index > 0)
++ fprobe_set_ips(alist.addrs, alist.index, 1, 0);
+ mutex_unlock(&fprobe_mutex);
+
+ kfree(alist.addrs);