From: Cen Zhang <zzzccc427@gmail.com>
To: matttbe@kernel.org, martineau@kernel.org, davem@davemloft.net,
edumazet@kernel.org, kuba@kernel.org, pabeni@redhat.com
Cc: geliang@kernel.org, horms@kernel.org, netdev@vger.kernel.org,
mptcp@lists.linux.dev, linux-kernel@vger.kernel.org,
baijiaju1990@gmail.com, jjzuming@gmail.com, zzzccc427@gmail.com
Subject: [PATCH net 2/2] mptcp: release the parent socket reference with the subflow context
Date: Mon, 26 Oct 2026 20:04:09 +0800 [thread overview]
Message-ID: <pm-mptcp-objects-candidate-0010-v3-14c229ea28a7d31f60a0-2@gmail.com> (raw)
In-Reply-To: <pm-mptcp-objects-candidate-0010-v3-14c229ea28a7d31f60a0-0@gmail.com>
The subflow context owns a reference on its MPTCP parent socket through
ctx->conn, and subflow_ulp_release() drops it when the TCP protocol
state of the subflow is destroyed. Two users of the TCP subflow socket
can outlive that point and still follow the pointer.
bpf_skc_to_mptcp_sock() returns ctx->conn for any TCP socket that has
is_mptcp set. An SK_SKB program can look up a connected subflow with
bpf_sk_lookup_tcp() and hold the TCP child without holding the MPTCP
socket. A concurrent zero-linger close destroys the TCP protocol state
and releases the ULP despite that reference, and once the remaining
MPTCP references drain the program reads the freed MPTCP socket:
SK_SKB reader MPTCP close
rcu_read_lock()
bpf_sk_lookup_tcp() -> ssk
bpf_skc_to_mptcp_sock(ssk) -> msk
mptcp_close()
__mptcp_destroy_sock()
__mptcp_close_ssk()
__tcp_close()
subflow_ulp_release()
sock_put(ctx->conn)
final sock_put(msk)
read msk->token
A delegated action pins the TCP subflow socket, but
mptcp_subflow_process_delegated() locks and updates ctx->conn. A peer
reset followed by the application closing the MPTCP socket releases
the parent before mptcp_napi_poll() takes its data lock:
Delegation / NAPI Peer reset / application close
queue SEND or SNDBUF
sock_hold(ssk)
subflow_ulp_release(ssk)
sock_put(parent)
mptcp_close(parent)
last sock_put(parent)
mptcp_napi_poll()
mptcp_subflow_process_delegated()
mptcp_data_lock(parent)
Now that a retired context stays attached to its socket until
sk_destruct, release the parent reference from the context destructor
instead of from the ULP release. Every reference on the subflow socket
then also keeps the parent alive, and delegated actions need no
reference of their own. The final parent sock_put() may now run from
the subflow destructor in softirq or RCU callback context; the parent
is already closed and its protocol destroy callback has run by then, so
only the generic socket release is left. This depends on the previous
commit, which keeps the context alive until the subflow socket is
destroyed.
The hold around tcp_done() in mptcp_subflow_reset() stays, with its
comment updated: that call can destroy the subflow socket and thereby
release the parent reference.
Both reports below were taken with KASAN poisoning forced for the
SLAB_TYPESAFE_BY_RCU MPTCP socket cache. The first one is the BPF
reader, the second one the delegated action.
BUG: KASAN: slab-use-after-free in ___bpf_prog_run+0x2507/0xbcf0
Read of size 4 at addr ffff888119920930 by task mptcp_skb_looku/492
Call Trace:
<IRQ>
___bpf_prog_run+0x2507/0xbcf0
__bpf_prog_run32+0xda/0x120
bpf_prog_run_pin_on_cpu+0x136/0x3d0
sk_psock_verdict_recv+0x319/0x12c0
tcp_read_skb+0x349/0x500
sk_psock_verdict_data_ready+0x164/0x6f0
tcp_data_ready+0xfe/0x3c0
tcp_data_queue+0x181b/0x48e0
tcp_rcv_established+0x9c5/0x3480
tcp_v4_do_rcv+0x5bf/0xc60
tcp_v4_rcv+0x29cb/0x3da0
ip_protocol_deliver_rcu+0xad/0x430
ip_local_deliver_finish+0x383/0x610
ip_local_deliver+0x16a/0x1c0
ip_rcv+0x2d1/0x380
__netif_receive_skb_one_core+0x19c/0x1f0
__netif_receive_skb+0x22/0x150
process_backlog+0x43c/0x1260
__napi_poll.constprop.0+0xab/0x670
net_rx_action+0x4df/0xe60
handle_softirqs+0x201/0x930
do_softirq+0x47/0xa0
</IRQ>
Allocated by task 492:
kmem_cache_alloc_noprof+0x20b/0x5f0
sk_prot_alloc+0x65/0x260
sk_alloc+0x37/0xb40
inet_create+0x33a/0xf40
__sock_create+0x2c4/0x730
__sys_socket+0x141/0x210
__x64_sys_socket+0x77/0xc0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 496:
kmem_cache_free+0x293/0x670
__sk_destruct+0x4dd/0x8f0
sk_destruct+0xb3/0xd0
__sk_free+0xdd/0x370
sk_free+0x51/0x80
mptcp_close+0x7d/0x100
inet_release+0x11f/0x250
__sock_release+0xb8/0x270
sock_close+0x21/0x30
__fput+0x39f/0xa60
fput_close_sync+0xff/0x200
__x64_sys_close+0x8c/0xf0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
BUG: KASAN: slab-use-after-free in _raw_spin_lock_bh+0x38/0x50
Read of size 1 at addr ffff88810acf25d8 by task ksoftirqd/2/29
Call Trace:
<TASK>
lock_acquire+0x113/0x2f0
_raw_spin_lock_bh+0x38/0x50
mptcp_subflow_process_delegated+0xa6/0x9a0
mptcp_napi_poll+0x50d/0x12f0
__napi_poll.constprop.0+0xab/0x670
net_rx_action+0x4df/0xe60
handle_softirqs+0x201/0x930
run_ksoftirqd+0x33/0x60
smpboot_thread_fn+0x3bd/0x9a0
kthread+0x34f/0x460
ret_from_fork+0x659/0x940
ret_from_fork_asm+0x1a/0x30
</TASK>
Allocated by task 586:
kmem_cache_alloc_noprof+0x20b/0x5f0
sk_prot_alloc+0x65/0x260
sk_alloc+0x37/0xb40
inet_create+0x33a/0xf40
__sock_create+0x2c4/0x730
__sys_socket+0x141/0x210
__x64_sys_socket+0x77/0xc0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Freed by task 586:
kmem_cache_free+0x259/0x5a0
__sk_destruct+0x4a0/0x790
sk_destruct+0xb3/0xd0
__sk_free+0xdd/0x370
sk_free+0x51/0x80
mptcp_close+0x150/0x530
inet_release+0x11f/0x250
__sock_release+0xb8/0x270
sock_close+0x21/0x30
__fput+0x39f/0xa60
fput_close_sync+0xff/0x200
__x64_sys_close+0x8c/0xf0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Fixes: 3bc253c2e652 ("bpf: Add bpf_skc_to_mptcp_sock_proto")
Fixes: b19bc2945b40 ("mptcp: implement delegated actions")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Assisted-by: LLM
---
net/mptcp/subflow.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 8dc0677dc551..ebcface15661 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -471,7 +471,9 @@ void mptcp_subflow_reset(struct sock *ssk)
if (ssk->sk_state == TCP_CLOSE)
return;
- /* must hold: tcp_done() could drop last reference on parent */
+ /* must hold: the parent reference owned by the subflow context is
+ * released together with ssk, which tcp_done() can destroy
+ */
sock_hold(sk);
subflow->resetting = 1;
@@ -820,6 +822,8 @@ static void subflow_ctx_destruct(struct sock *ssk)
rcu_assign_pointer(inet_csk(ssk)->icsk_ulp_data, NULL);
ctx->tcp_sock_destruct(ssk);
+ if (ctx->conn)
+ sock_put(ctx->conn);
kfree_rcu(ctx, rcu);
}
@@ -2120,7 +2124,6 @@ static void subflow_ulp_release(struct sock *ssk)
if (!release && !test_and_set_bit(MPTCP_WORK_CLOSE_SUBFLOW,
&mptcp_sk(sk)->flags))
mptcp_schedule_work(sk);
- sock_put(sk);
}
mptcp_subflow_ops_undo_override(ssk);
prev parent reply other threads:[~2026-10-26 12:04 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 12:04 [PATCH net 0/2] mptcp: subflow context lifetime fixes Cen Zhang
2026-10-26 12:04 ` [PATCH net 1/2] mptcp: keep delegated subflow contexts alive until socket release Cen Zhang
2026-10-26 12:04 ` Cen Zhang [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pm-mptcp-objects-candidate-0010-v3-14c229ea28a7d31f60a0-2@gmail.com \
--to=zzzccc427@gmail.com \
--cc=baijiaju1990@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=geliang@kernel.org \
--cc=horms@kernel.org \
--cc=jjzuming@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=martineau@kernel.org \
--cc=matttbe@kernel.org \
--cc=mptcp@lists.linux.dev \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®