Skip to contentSkip to conversation

FAILED: patch "[PATCH] mptcp: pm: kernel: drop pending ADD_ADDR when removing ID0" failed to apply to 5.15-stable tree

PATCH New [email protected] 2 participants 3 messages Sep 16 – Sep 17

Subsystems (3)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The 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 2ac7d6e620764f1fc79eb4edd3610a7a661981ca
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026091604-bogus-decent-1706@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'

Possible dependencies:

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From 2ac7d6e620764f1fc79eb4edd3610a7a661981ca Mon Sep 17 00:00:00 2001
From: Kalpan Jani <[email protected]>
Date: Tue, 8 Sep 2026 16:07:09 +0200
Subject: [PATCH] mptcp: pm: kernel: drop pending ADD_ADDR when removing ID0

The in-kernel MPTCP path manager can leave a stale ADD_ADDR announcement entry alive when removing the id 0 endpoint. This happens because the id 0 removal path does not tear down pending announcements, unlike the non-zero id path.

When the PM later reselects id 0 after adding another signal endpoint, it finds the stale anno_list entry and hits WARN_ON_ONCE(mptcp_pm_is_kernel()) in mptcp_pm_announced_alloc().

Root cause: asymmetry between removal paths.
- Non-zero id path: mptcp_nl_remove_subflow_and_signal_addr() calls mptcp_pm_remove_announced() to clean up.
- Id 0 path: mptcp_nl_remove_id_zero_address() skips cleanup entirely.

Fix by making the id 0 path symmetric: call mptcp_pm_announced_remove() and decrement add_addr_signaled before queuing the RM_ADDR.

Subtle detail: signal endpoints are stored in anno_list with port 0, but msk_local carries the connection's local port. In other words, entries linked to ID0 paths should have port == 0. A follow-up patch will ensure that. mptcp_pm_announced_remove() uses use_port=true for comparison. So clear the port before the lookup.

net/mptcp/pm_kernel.c +8 -0
index 424f1a7f9248..1a7750813235 100644
@@ -1137,6 +1137,8 @@ static int mptcp_nl_remove_id_zero_address(struct net *net,
 	while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) {
 		struct sock *sk = (struct sock *)msk;
 		struct mptcp_addr_info msk_local;
+		struct mptcp_addr_info anno_addr;
+		bool announced;
 
 		if (list_empty(&msk->conn_list) || mptcp_pm_is_userspace(msk))
 			goto next;
@@ -1146,7 +1148,13 @@ static int mptcp_nl_remove_id_zero_address(struct net *net,
 			goto next;
 
 		lock_sock(sk);
+		/* Drop a possibly pending ADD_ADDR for this address. */
+		anno_addr = msk_local;
+		anno_addr.port = 0;
+		announced = mptcp_pm_announced_remove(msk, &anno_addr);
 		spin_lock_bh(&msk->pm.lock);
+		if (announced)
+			msk->pm.add_addr_signaled--;
 		mptcp_pm_remove_addr(msk, &list);
 		mptcp_pm_rm_subflow(msk, &list);
 		__mark_subflow_endp_available(msk, 0);
maintainer
#1 lore raw

PATCH 1/2 mptcp: pm: uniform announced addresses helpers

From: "Matthieu Baerts (NGI0)" <[email protected]>

[ Upstream commit 7d4dacc8ccca8e40fcb5f2ece9ea3e502da1bd3f ]

Similar to the previous commit, only using the 'add' or 'anno' prefixes is confusing -- generally associated to the action of adding something, or the Latin name for "year" -- and lack of uniformity.

This has been causing issues in the past, e.g. del_add_timer seemed to suggest the goal is to delete a previously added timer.

Instead, use the mptcp_pm_announced_ prefix.

While at it, slightly improves some helpers:

- mptcp_lookup_anno_list_by_saddr: no need to specify what is used to do the lookup: mptcp_pm_announced_lookup.

- mptcp_pm_sport_in_anno_list: it doesn't just compare the port, but the whole address linked to the sublow: mptcp_pm_announced_has_ssk.

- mptcp_pm_alloc_anno_list: it allocates one item of the list, not a whole list: mptcp_pm_announced_alloc.

Backport to 5.15: apply the helper renames to the existing path manager implementations, retaining their types, visibility, locking and behaviour. In particular, rename the existing remove_anno_list_by_saddr() helper to mptcp_pm_announced_remove(); no new functions are introduced. Update the 5.15 destructor in protocol.c as well as all declarations and callers. Drop the userspace path-manager hunks because that implementation is absent.

Move the existing pm_netlink.c to pm_kernel.c and update the MPTCP Makefile so target 2ac7d6e620764f1fc79eb4edd3610a7a661981ca can be cherry-picked without a missing-file conflict. This is only a source-file rename; keep the 5.15 netlink implementation instead of importing the upstream split.

[ sashal: Reduced backport -- upstream 7d4dacc8ccca8 touches 6 file(s), this
backport carries 7. Not backported here:
net/mptcp/pm_userspace.c
This note is generated from the file lists only; see the resolution record for the reasoning. ]

Stable-dep-of: 2ac7d6e62076 ("mptcp: pm: kernel: drop pending ADD_ADDR when removing ID0")

---
 net/mptcp/Makefile                      |  2 +-
 net/mptcp/options.c                     |  2 +-
 net/mptcp/pm.c                          |  4 +--
 net/mptcp/{pm_netlink.c => pm_kernel.c} | 34 ++++++++++++-------------
 net/mptcp/protocol.c                    |  2 +-
 net/mptcp/protocol.h                    | 12 ++++-----
 net/mptcp/subflow.c                     |  4 +--
 7 files changed, 30 insertions(+), 30 deletions(-)
 rename net/mptcp/{pm_netlink.c => pm_kernel.c} (98%)
net/mptcp/Makefile +1 -1
index e54daceac58be..41a84e3d4db50 100644
@@ -2,7 +2,7 @@
 obj-$(CONFIG_MPTCP) += mptcp.o
 
 mptcp-y := protocol.o subflow.o options.o token.o crypto.o ctrl.o pm.o diag.o \
-	   mib.o pm_netlink.o sockopt.o
+	   mib.o pm_kernel.o sockopt.o
 
 obj-$(CONFIG_SYN_COOKIES) += syncookies.o
 obj-$(CONFIG_INET_MPTCP_DIAG) += mptcp_diag.o
net/mptcp/options.c +1 -1
index c913f1903380b..6a79223a4bd64 100644
@@ -1208,7 +1208,7 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
 				MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDR);
 			} else {
 				mptcp_pm_add_addr_echoed(msk, &mp_opt.addr);
-				mptcp_pm_del_add_timer(msk, &mp_opt.addr, true);
+				mptcp_pm_announced_del_timer(msk, &mp_opt.addr, true);
 				MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD);
 			}
 
net/mptcp/pm.c +2 -2
index 737fb96ff690d..4b2a5cec7079e 100644
@@ -215,7 +215,7 @@ void mptcp_pm_add_addr_echoed(struct mptcp_sock *msk,
 
 	spin_lock_bh(&pm->lock);
 
-	if (mptcp_lookup_anno_list_by_saddr(msk, addr) && READ_ONCE(pm->work_pending))
+	if (mptcp_pm_announced_lookup(msk, addr) && READ_ONCE(pm->work_pending))
 		mptcp_pm_schedule_work(msk, MPTCP_PM_SUBFLOW_ESTABLISHED);
 
 	spin_unlock_bh(&pm->lock);
@@ -326,7 +326,7 @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb,
 	 * let the PM state machine progress.
 	 */
 	if (skip_add_addr) {
-		mptcp_pm_del_add_timer(msk, addr, true);
+		mptcp_pm_announced_del_timer(msk, addr, true);
 		mptcp_pm_subflow_established(msk);
 	}
 	return ret;
net/mptcp/pm_kernel.c renamed from net/mptcp/pm_netlink.c +17 -17
similarity index 98%
rename from net/mptcp/pm_netlink.c
rename to net/mptcp/pm_kernel.c
index e912615e008f3..c91ba820e830a 100644
@@ -276,8 +276,8 @@ static void check_work_pending(struct mptcp_sock *msk)
 }
 
 struct mptcp_pm_add_entry *
-mptcp_lookup_anno_list_by_saddr(const struct mptcp_sock *msk,
-				const struct mptcp_addr_info *addr)
+mptcp_pm_announced_lookup(const struct mptcp_sock *msk,
+			  const struct mptcp_addr_info *addr)
 {
 	struct mptcp_pm_add_entry *entry;
 
@@ -291,7 +291,7 @@ mptcp_lookup_anno_list_by_saddr(const struct mptcp_sock *msk,
 	return NULL;
 }
 
-bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk)
+bool mptcp_pm_announced_has_ssk(struct mptcp_sock *msk, const struct sock *sk)
 {
 	struct mptcp_pm_add_entry *entry;
 	struct mptcp_addr_info saddr;
@@ -343,7 +343,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
 
 	spin_lock_bh(&msk->pm.lock);
 
-	/* The cancel path (mptcp_pm_del_add_timer()) can race with this
+	/* The cancel path (mptcp_pm_announced_del_timer()) can race with this
 	 * callback. Once cancel updates retrans_times to MAX, suppress further
 	 * retransmissions here. If this callback acquires pm.lock first, one
 	 * final transmit attempt is still possible.
@@ -376,8 +376,8 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
 }
 
 struct mptcp_pm_add_entry *
-mptcp_pm_del_add_timer(struct mptcp_sock *msk,
-		       const struct mptcp_addr_info *addr, bool check_id)
+mptcp_pm_announced_del_timer(struct mptcp_sock *msk,
+			     const struct mptcp_addr_info *addr, bool check_id)
 {
 	struct mptcp_pm_add_entry *entry;
 	struct sock *sk = (struct sock *)msk;
@@ -386,7 +386,7 @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk,
 	rcu_read_lock();
 
 	spin_lock_bh(&msk->pm.lock);
-	entry = mptcp_lookup_anno_list_by_saddr(msk, addr);
+	entry = mptcp_pm_announced_lookup(msk, addr);
 	if (entry && (!check_id || entry->addr.id == addr->id)) {
 		entry->retrans_times = ADD_ADDR_RETRANS_MAX;
 		stop_timer = true;
@@ -409,7 +409,7 @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk,
 	return entry;
 }
 
-static bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk,
+static bool mptcp_pm_announced_alloc(struct mptcp_sock *msk,
 				     const struct mptcp_pm_addr_entry *entry)
 {
 	struct mptcp_pm_add_entry *add_entry = NULL;
@@ -419,7 +419,7 @@ static bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk,
 
 	lockdep_assert_held(&msk->pm.lock);
 
-	if (mptcp_lookup_anno_list_by_saddr(msk, &entry->addr))
+	if (mptcp_pm_announced_lookup(msk, &entry->addr))
 		return false;
 
 	add_entry = kmalloc(sizeof(*add_entry), GFP_ATOMIC);
@@ -441,7 +441,7 @@ static bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk,
 	return true;
 }
 
-void mptcp_pm_free_anno_list(struct mptcp_sock *msk)
+void mptcp_pm_free_announced_list(struct mptcp_sock *msk)
 {
 	struct mptcp_pm_add_entry *entry, *tmp;
 	struct sock *sk = (struct sock *)msk;
@@ -545,7 +545,7 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
 	if (msk->pm.add_addr_signaled < add_addr_signal_max) {
 		if (select_signal_address(pernet, msk->pm.add_addr_signaled,
 					  &local)) {
-			if (mptcp_pm_alloc_anno_list(msk, &local)) {
+			if (mptcp_pm_announced_alloc(msk, &local)) {
 				msk->pm.add_addr_signaled++;
 				mptcp_pm_announce_addr(msk, &local.addr, false);
 				mptcp_pm_nl_addr_send_ack(msk);
@@ -1466,12 +1466,12 @@ int mptcp_pm_get_flags_and_ifindex_by_id(struct net *net, unsigned int id,
 	return 0;
 }
 
-static bool remove_anno_list_by_saddr(struct mptcp_sock *msk,
+static bool mptcp_pm_announced_remove(struct mptcp_sock *msk,
 				      const struct mptcp_addr_info *addr)
 {
 	struct mptcp_pm_add_entry *entry;
 
-	entry = mptcp_pm_del_add_timer(msk, addr, false);
+	entry = mptcp_pm_announced_del_timer(msk, addr, false);
 	if (entry) {
 		kfree_rcu(entry, rcu);
 		return true;
@@ -1480,7 +1480,7 @@ static bool remove_anno_list_by_saddr(struct mptcp_sock *msk,
 	return false;
 }
 
-static bool mptcp_pm_remove_anno_addr(struct mptcp_sock *msk,
+static bool mptcp_pm_remove_announced(struct mptcp_sock *msk,
 				      const struct mptcp_addr_info *addr,
 				      bool force)
 {
@@ -1489,7 +1489,7 @@ static bool mptcp_pm_remove_anno_addr(struct mptcp_sock *msk,
 
 	list.ids[list.nr++] = addr->id;
 
-	ret = remove_anno_list_by_saddr(msk, addr);
+	ret = mptcp_pm_announced_remove(msk, addr);
 	if (ret || force) {
 		spin_lock_bh(&msk->pm.lock);
 		msk->pm.add_addr_signaled -= ret;
@@ -1516,7 +1516,7 @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net,
 
 		lock_sock(sk);
 		remove_subflow = lookup_subflow_by_saddr(&msk->conn_list, addr);
-		mptcp_pm_remove_anno_addr(msk, addr, remove_subflow);
+		mptcp_pm_remove_announced(msk, addr, remove_subflow);
 		if (remove_subflow)
 			mptcp_pm_remove_subflow(msk, &list);
 		release_sock(sk);
@@ -1632,7 +1632,7 @@ static void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk,
 			alist.ids[alist.nr++] = entry->addr.id;
 			slist.ids[slist.nr++] = entry->addr.id;
 		} else if (alist.nr < MPTCP_RM_IDS_MAX &&
-			   remove_anno_list_by_saddr(msk, &entry->addr)) {
+			   mptcp_pm_announced_remove(msk, &entry->addr)) {
 			alist.ids[alist.nr++] = entry->addr.id;
 		}
 	}
net/mptcp/protocol.c +1 -1
index 522d8740a0f3a..1fa36034afa26 100644
@@ -3110,7 +3110,7 @@ void mptcp_destroy_common(struct mptcp_sock *msk)
 
 	skb_rbtree_purge(&msk->out_of_order_queue);
 	mptcp_token_destroy(msk);
-	mptcp_pm_free_anno_list(msk);
+	mptcp_pm_free_announced_list(msk);
 }
 
 static void mptcp_destroy(struct sock *sk)
net/mptcp/protocol.h +6 -6
index 609e7768fab31..69f53465bdb35 100644
@@ -753,14 +753,14 @@ int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
 				 struct mptcp_addr_info *addr,
 				 u8 bkup);
 void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq);
-void mptcp_pm_free_anno_list(struct mptcp_sock *msk);
-bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk);
+void mptcp_pm_free_announced_list(struct mptcp_sock *msk);
+bool mptcp_pm_announced_has_ssk(struct mptcp_sock *msk, const struct sock *sk);
 struct mptcp_pm_add_entry *
-mptcp_pm_del_add_timer(struct mptcp_sock *msk,
-		       const struct mptcp_addr_info *addr, bool check_id);
+mptcp_pm_announced_del_timer(struct mptcp_sock *msk,
+			     const struct mptcp_addr_info *addr, bool check_id);
 struct mptcp_pm_add_entry *
-mptcp_lookup_anno_list_by_saddr(const struct mptcp_sock *msk,
-				const struct mptcp_addr_info *addr);
+mptcp_pm_announced_lookup(const struct mptcp_sock *msk,
+			  const struct mptcp_addr_info *addr);
 int mptcp_pm_get_flags_and_ifindex_by_id(struct net *net, unsigned int id,
 					 u8 *flags, int *ifindex);
 
net/mptcp/subflow.c +2 -2
index 33b16ea7ae5bc..262df0724fa8b 100644
@@ -230,7 +230,7 @@ static int subflow_check_req(struct request_sock *req,
 			pr_debug("syn inet_sport=%d %d\n",
 				 ntohs(inet_sk(sk_listener)->inet_sport),
 				 ntohs(inet_sk((struct sock *)subflow_req->msk)->inet_sport));
-			if (!mptcp_pm_sport_in_anno_list(subflow_req->msk, sk_listener)) {
+			if (!mptcp_pm_announced_has_ssk(subflow_req->msk, sk_listener)) {
 				SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTSYNRX);
 				return -EPERM;
 			}
@@ -806,7 +806,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
 				pr_debug("ack inet_sport=%d %d\n",
 					 ntohs(inet_sk(sk)->inet_sport),
 					 ntohs(inet_sk((struct sock *)owner)->inet_sport));
-				if (!mptcp_pm_sport_in_anno_list(owner, sk)) {
+				if (!mptcp_pm_announced_has_ssk(owner, sk)) {
 					SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTACKRX);
 					goto dispose_child;
 				}
Signature · 1 line
2.53.0
maintainer
#2 lore raw

PATCH 2/2 mptcp: pm: kernel: drop pending ADD_ADDR when removing ID0

From: Kalpan Jani <[email protected]>

[ Upstream commit 2ac7d6e620764f1fc79eb4edd3610a7a661981ca ]

The in-kernel MPTCP path manager can leave a stale ADD_ADDR announcement entry alive when removing the id 0 endpoint. This happens because the id 0 removal path does not tear down pending announcements, unlike the non-zero id path.

When the PM later reselects id 0 after adding another signal endpoint, it finds the stale anno_list entry and hits WARN_ON_ONCE(mptcp_pm_is_kernel()) in mptcp_pm_announced_alloc().

Root cause: asymmetry between removal paths.
- Non-zero id path: mptcp_nl_remove_subflow_and_signal_addr() calls mptcp_pm_remove_announced() to clean up.
- Id 0 path: mptcp_nl_remove_id_zero_address() skips cleanup entirely.

Fix by making the id 0 path symmetric: call mptcp_pm_announced_remove() and decrement add_addr_signaled before queuing the RM_ADDR.

Subtle detail: signal endpoints are stored in anno_list with port 0, but msk_local carries the connection's local port. In other words, entries linked to ID0 paths should have port == 0. A follow-up patch will ensure that. mptcp_pm_announced_remove() uses use_port=true for comparison. So clear the port before the lookup.

---
 net/mptcp/pm_kernel.c | 8 ++++++++
 1 file changed, 8 insertions(+)
net/mptcp/pm_kernel.c +8 -0
index c91ba820e830a..6bd1686774b77 100644
@@ -1548,6 +1548,8 @@ static int mptcp_nl_remove_id_zero_address(struct net *net,
 	while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) {
 		struct sock *sk = (struct sock *)msk;
 		struct mptcp_addr_info msk_local;
+		struct mptcp_addr_info anno_addr;
+		bool announced;
 
 		if (list_empty(&msk->conn_list))
 			goto next;
@@ -1557,7 +1559,13 @@ static int mptcp_nl_remove_id_zero_address(struct net *net,
 			goto next;
 
 		lock_sock(sk);
+		/* Drop a possibly pending ADD_ADDR for this address. */
+		anno_addr = msk_local;
+		anno_addr.port = 0;
+		announced = mptcp_pm_announced_remove(msk, &anno_addr);
 		spin_lock_bh(&msk->pm.lock);
+		if (announced)
+			msk->pm.add_addr_signaled--;
 		mptcp_pm_remove_addr(msk, &list);
 		mptcp_pm_nl_rm_subflow_received(msk, &list);
 		spin_unlock_bh(&msk->pm.lock);
Signature · 1 line
2.53.0