FAILED: patch "[PATCH] gtp: serialize PDP context updates" failed to apply to 5.15-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x 498386b6d402737db1e2eeed4c385acbf0ef9e34
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026083100-implosive-divinity-5dca@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 498386b6d402737db1e2eeed4c385acbf0ef9e34 Mon Sep 17 00:00:00 2001
From: Qing Ming <[email protected]>
Date: Tue, 18 Aug 2026 23:00:00 +0800
Subject: [PATCH] gtp: serialize PDP context updates
PDP contexts can be deleted through GTP_CMD_DELPDP or while the GTP network device is being unregistered. The latter is serialized by RTNL, but the generic-netlink delete path only holds RCU.
Running both paths concurrently can therefore make both paths delete the same PDP context. The issue was found through static analysis and reproduced on a KASAN-enabled kernel by a simple two-thread program racing GTP_CMD_DELPDP against RTM_DELLINK:
Oops: general protection fault, probably for non-canonical address
KASAN: maybe wild-memory-access in range
[0xdead000000000120-0xdead000000000127]
RIP: gtp_genl_del_pdp+0x1c1/0x420 [gtp]
RBP: dead000000000122The second deletion dereferenced the poisoned hlist pprev pointer.
Serialize gtp_pdp_add(), gtp_genl_del_pdp(), and gtp_dellink() with a shared mutex. Keep the mutex held until the final use of a PDP context in the NEWPDP path, and keep the RCU read-side section around the complete PDP context use in the DELPDP path.
drivers/net/gtp.c +17 -4
@@ -12,6 +12,7 @@#define pr_fmt (fmt) KBUILD_MODNAME ": " fmt#include <linux/module.h> +#include <linux/mutex.h> #include <linux/skbuff.h> #include <linux/udp.h> #include <linux/rculist.h>
@@ -108,6 +109,7 @@ struct gtp_net { };static u32 gtp_h_initval; +static DEFINE_MUTEX (gtp_pdp_lock);static struct genl_family gtp_genl_family;
@@ -151,7 +153,8 @@ static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, u64 tid, u16 family) head = >p->tid_hash[gtp0_hashfn (tid) % gtp->hash_size]; -hlist_for_each_entry_rcu (pdp, head, hlist_tid) { +hlist_for_each_entry_rcu (pdp, head, hlist_tid, +lockdep_is_held (>p_pdp_lock)) {if (pdp->af == family && pdp->gtp_version ==GTP_V0 && pdp->u.v0.tid == tid)
@@ -168,7 +171,8 @@ static struct pdp_ctx *gtp1_pdp_find(struct gtp_dev *gtp, u32 tid, u16 family) head = >p->tid_hash[gtp1u_hashfn (tid) % gtp->hash_size]; -hlist_for_each_entry_rcu (pdp, head, hlist_tid) { +hlist_for_each_entry_rcu (pdp, head, hlist_tid, +lockdep_is_held (>p_pdp_lock)) {if (pdp->af == family && pdp->gtp_version ==GTP_V1 && pdp->u.v1.i_tei == tid)
@@ -185,7 +189,8 @@ static struct pdp_ctx *ipv4_pdp_find(struct gtp_dev *gtp, __be32 ms_addr) head = >p->addr_hash[ipv4_hashfn (ms_addr) % gtp->hash_size]; -hlist_for_each_entry_rcu (pdp, head, hlist_addr) { +hlist_for_each_entry_rcu (pdp, head, hlist_addr, +lockdep_is_held (>p_pdp_lock)) {if (pdp->af ==AF_INET && pdp->ms.addr.s_addr == ms_addr)return pdp;
@@ -220,7 +225,8 @@ static struct pdp_ctx *ipv6_pdp_find(struct gtp_dev *gtp, head = >p->addr_hash[ipv6_hashfn (ms_addr) % gtp->hash_size]; -hlist_for_each_entry_rcu (pdp, head, hlist_addr) { +hlist_for_each_entry_rcu (pdp, head, hlist_addr, +lockdep_is_held (>p_pdp_lock)) {if (pdp->af ==AF_INET6 &&ipv6_pdp_addr_equal (&pdp->ms.addr6, ms_addr))return pdp;
@@ -1555,9 +1561,11 @@ static void gtp_dellink(struct net_device *dev, struct list_head *head)struct pdp_ctx *pctx;int i; +mutex_lock (>p_pdp_lock);for (i =0 ; i < gtp->hash_size; i++)hlist_for_each_entry_safe (pctx, next, >p->tid_hash[i], hlist_tid)pdp_context_delete (pctx); +mutex_unlock (>p_pdp_lock);list_del (>p->list);unregister_netdevice_queue (dev, head);
@@ -2053,6 +2061,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) goto out_unlock; } +mutex_lock (>p_pdp_lock); pctx =gtp_pdp_add (gtp, sk, info);if (IS_ERR (pctx)) { err =PTR_ERR (pctx);
@@ -2060,6 +2069,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)gtp_tunnel_notify (pctx,GTP_CMD_NEWPDP ,GFP_KERNEL ); err =0 ; } +mutex_unlock (>p_pdp_lock); out_unlock:rtnl_unlock ();
@@ -2134,6 +2144,8 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)if (!info->attrs[GTPA_VERSION ])return -EINVAL ; +mutex_lock (>p_pdp_lock); +rcu_read_lock (); pctx =gtp_find_pdp (sock_net (skb->sk), info->attrs);
@@ -2154,6 +2166,7 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info) out_unlock:rcu_read_unlock (); +mutex_unlock (>p_pdp_lock);return err; }
Sasha Levin
maintainerPATCH 1/1 gtp: serialize PDP context updates
From: Qing Ming <[email protected]>
[ Upstream commit 498386b6d402737db1e2eeed4c385acbf0ef9e34 ]
PDP contexts can be deleted through GTP_CMD_DELPDP or while the GTP network device is being unregistered. The latter is serialized by RTNL, but the generic-netlink delete path only holds RCU.
Running both paths concurrently can therefore make both paths delete the same PDP context. The issue was found through static analysis and reproduced on a KASAN-enabled kernel by a simple two-thread program racing GTP_CMD_DELPDP against RTM_DELLINK:
Oops: general protection fault, probably for non-canonical address
KASAN: maybe wild-memory-access in range
[0xdead000000000120-0xdead000000000127]
RIP: gtp_genl_del_pdp+0x1c1/0x420 [gtp]
RBP: dead000000000122The second deletion dereferenced the poisoned hlist pprev pointer.
Serialize gtp_pdp_add(), gtp_genl_del_pdp(), and gtp_dellink() with a shared mutex. Keep the mutex held until the final use of a PDP context in the NEWPDP path, and keep the RCU read-side section around the complete PDP context use in the DELPDP path.
--- drivers/net/gtp.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
drivers/net/gtp.c +15 -3
@@ -12,6 +12,7 @@#define pr_fmt (fmt) KBUILD_MODNAME ": " fmt#include <linux/module.h> +#include <linux/mutex.h> #include <linux/skbuff.h> #include <linux/udp.h> #include <linux/rculist.h>
@@ -82,6 +83,7 @@ struct gtp_net { };static u32 gtp_h_initval; +static DEFINE_MUTEX (gtp_pdp_lock);static void pdp_context_delete (struct pdp_ctx *pctx);
@@ -109,7 +111,8 @@ static struct pdp_ctx *gtp0_pdp_find(struct gtp_dev *gtp, u64 tid) head = >p->tid_hash[gtp0_hashfn (tid) % gtp->hash_size]; -hlist_for_each_entry_rcu (pdp, head, hlist_tid) { +hlist_for_each_entry_rcu (pdp, head, hlist_tid, +lockdep_is_held (>p_pdp_lock)) {if (pdp->gtp_version ==GTP_V0 && pdp->u.v0.tid == tid)return pdp;
@@ -125,7 +128,8 @@ static struct pdp_ctx *gtp1_pdp_find(struct gtp_dev *gtp, u32 tid) head = >p->tid_hash[gtp1u_hashfn (tid) % gtp->hash_size]; -hlist_for_each_entry_rcu (pdp, head, hlist_tid) { +hlist_for_each_entry_rcu (pdp, head, hlist_tid, +lockdep_is_held (>p_pdp_lock)) {if (pdp->gtp_version ==GTP_V1 && pdp->u.v1.i_tei == tid)return pdp;
@@ -141,7 +145,8 @@ static struct pdp_ctx *ipv4_pdp_find(struct gtp_dev *gtp, __be32 ms_addr) head = >p->addr_hash[ipv4_hashfn (ms_addr) % gtp->hash_size]; -hlist_for_each_entry_rcu (pdp, head, hlist_addr) { +hlist_for_each_entry_rcu (pdp, head, hlist_addr, +lockdep_is_held (>p_pdp_lock)) {if (pdp->af ==AF_INET && pdp->ms_addr_ip4.s_addr == ms_addr)return pdp;
@@ -720,9 +725,11 @@ static void gtp_dellink(struct net_device *dev, struct list_head *head)struct pdp_ctx *pctx;int i; +mutex_lock (>p_pdp_lock);for (i =0 ; i < gtp->hash_size; i++)hlist_for_each_entry_safe (pctx, next, >p->tid_hash[i], hlist_tid)pdp_context_delete (pctx); +mutex_unlock (>p_pdp_lock);list_del (>p->list);unregister_netdevice_queue (dev, head);
@@ -1110,6 +1117,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info) goto out_unlock; } +mutex_lock (>p_pdp_lock); pctx =gtp_pdp_add (gtp, sk, info);if (IS_ERR (pctx)) { err =PTR_ERR (pctx);
@@ -1117,6 +1125,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)gtp_tunnel_notify (pctx,GTP_CMD_NEWPDP ,GFP_KERNEL ); err =0 ; } +mutex_unlock (>p_pdp_lock); out_unlock:rtnl_unlock ();
@@ -1171,6 +1180,8 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info)if (!info->attrs[GTPA_VERSION ])return -EINVAL ; +mutex_lock (>p_pdp_lock); +rcu_read_lock (); pctx =gtp_find_pdp (sock_net (skb->sk), info->attrs);
@@ -1191,6 +1202,7 @@ static int gtp_genl_del_pdp(struct sk_buff *skb, struct genl_info *info) out_unlock:rcu_read_unlock (); +mutex_unlock (>p_pdp_lock);return err; }
Signature · 1 line
2.53.0