Skip to content

Commit c9ebb1e

Browse files
Paolo Abeniintel-lab-lkp
authored andcommitted
mptcp: make fallback action and fallback decision atomic
Syzkaller reported the following splat: WARNING: CPU: 1 PID: 7704 at net/mptcp/protocol.h:1223 __mptcp_do_fallback net/mptcp/protocol.h:1223 [inline] WARNING: CPU: 1 PID: 7704 at net/mptcp/protocol.h:1223 mptcp_do_fallback net/mptcp/protocol.h:1244 [inline] WARNING: CPU: 1 PID: 7704 at net/mptcp/protocol.h:1223 check_fully_established net/mptcp/options.c:982 [inline] WARNING: CPU: 1 PID: 7704 at net/mptcp/protocol.h:1223 mptcp_incoming_options+0x21a8/0x2510 net/mptcp/options.c:1153 Modules linked in: CPU: 1 UID: 0 PID: 7704 Comm: syz.3.1419 Not tainted 6.16.0-rc3-gbd5ce2324dba torvalds#20 PREEMPT(voluntary) Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 RIP: 0010:__mptcp_do_fallback net/mptcp/protocol.h:1223 [inline] RIP: 0010:mptcp_do_fallback net/mptcp/protocol.h:1244 [inline] RIP: 0010:check_fully_established net/mptcp/options.c:982 [inline] RIP: 0010:mptcp_incoming_options+0x21a8/0x2510 net/mptcp/options.c:1153 Code: 24 18 e8 bb 2a 00 fd e9 1b df ff ff e8 b1 21 0f 00 e8 ec 5f c4 fc 44 0f b7 ac 24 b0 00 00 00 e9 54 f1 ff ff e8 d9 5f c4 fc 90 <0f> 0b 90 e9 b8 f4 ff ff e8 8b 2a 00 fd e9 8d e6 ff ff e8 81 2a 00 RSP: 0018:ffff8880a3f08448 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff8880180a8000 RCX: ffffffff84afcf45 RDX: ffff888090223700 RSI: ffffffff84afdaa7 RDI: 0000000000000001 RBP: ffff888017955780 R08: 0000000000000001 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 R13: ffff8880180a8910 R14: ffff8880a3e9d058 R15: 0000000000000000 FS: 00005555791b8500(0000) GS:ffff88811c495000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000110c2800b7 CR3: 0000000058e44000 CR4: 0000000000350ef0 Call Trace: <IRQ> tcp_reset+0x26f/0x2b0 net/ipv4/tcp_input.c:4432 tcp_validate_incoming+0x1057/0x1b60 net/ipv4/tcp_input.c:5975 tcp_rcv_established+0x5b5/0x21f0 net/ipv4/tcp_input.c:6166 tcp_v4_do_rcv+0x5dc/0xa70 net/ipv4/tcp_ipv4.c:1925 tcp_v4_rcv+0x3473/0x44a0 net/ipv4/tcp_ipv4.c:2363 ip_protocol_deliver_rcu+0xba/0x480 net/ipv4/ip_input.c:205 ip_local_deliver_finish+0x2f1/0x500 net/ipv4/ip_input.c:233 NF_HOOK include/linux/netfilter.h:317 [inline] NF_HOOK include/linux/netfilter.h:311 [inline] ip_local_deliver+0x1be/0x560 net/ipv4/ip_input.c:254 dst_input include/net/dst.h:469 [inline] ip_rcv_finish net/ipv4/ip_input.c:447 [inline] NF_HOOK include/linux/netfilter.h:317 [inline] NF_HOOK include/linux/netfilter.h:311 [inline] ip_rcv+0x514/0x810 net/ipv4/ip_input.c:567 __netif_receive_skb_one_core+0x197/0x1e0 net/core/dev.c:5975 __netif_receive_skb+0x1f/0x120 net/core/dev.c:6088 process_backlog+0x301/0x1360 net/core/dev.c:6440 __napi_poll.constprop.0+0xba/0x550 net/core/dev.c:7453 napi_poll net/core/dev.c:7517 [inline] net_rx_action+0xb44/0x1010 net/core/dev.c:7644 handle_softirqs+0x1d0/0x770 kernel/softirq.c:579 do_softirq+0x3f/0x90 kernel/softirq.c:480 </IRQ> <TASK> __local_bh_enable_ip+0xed/0x110 kernel/softirq.c:407 local_bh_enable include/linux/bottom_half.h:33 [inline] inet_csk_listen_stop+0x2c5/0x1070 net/ipv4/inet_connection_sock.c:1524 mptcp_check_listen_stop.part.0+0x1cc/0x220 net/mptcp/protocol.c:2985 mptcp_check_listen_stop net/mptcp/mib.h:118 [inline] __mptcp_close+0x9b9/0xbd0 net/mptcp/protocol.c:3000 mptcp_close+0x2f/0x140 net/mptcp/protocol.c:3066 inet_release+0xed/0x200 net/ipv4/af_inet.c:435 inet6_release+0x4f/0x70 net/ipv6/af_inet6.c:487 __sock_release+0xb3/0x270 net/socket.c:649 sock_close+0x1c/0x30 net/socket.c:1439 __fput+0x402/0xb70 fs/file_table.c:465 task_work_run+0x150/0x240 kernel/task_work.c:227 resume_user_mode_work include/linux/resume_user_mode.h:50 [inline] exit_to_user_mode_loop+0xd4/0xe0 kernel/entry/common.c:114 exit_to_user_mode_prepare include/linux/entry-common.h:330 [inline] syscall_exit_to_user_mode_work include/linux/entry-common.h:414 [inline] syscall_exit_to_user_mode include/linux/entry-common.h:449 [inline] do_syscall_64+0x245/0x360 arch/x86/entry/syscall_64.c:100 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7fc92f8a36ad Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b0 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007ffcf52802d8 EFLAGS: 00000246 ORIG_RAX: 00000000000001b4 RAX: 0000000000000000 RBX: 00007ffcf52803a8 RCX: 00007fc92f8a36ad RDX: 0000000000000000 RSI: 000000000000001e RDI: 0000000000000003 RBP: 00007fc92fae7ba0 R08: 0000000000000001 R09: 0000002800000000 R10: 00007fc92f700000 R11: 0000000000000246 R12: 00007fc92fae5fac R13: 00007fc92fae5fa0 R14: 0000000000026d00 R15: 0000000000026c51 </TASK> irq event stamp: 4068 hardirqs last enabled at (4076): [<ffffffff81544816>] __up_console_sem+0x76/0x80 kernel/printk/printk.c:344 hardirqs last disabled at (4085): [<ffffffff815447fb>] __up_console_sem+0x5b/0x80 kernel/printk/printk.c:342 softirqs last enabled at (3096): [<ffffffff840e1be0>] local_bh_enable include/linux/bottom_half.h:33 [inline] softirqs last enabled at (3096): [<ffffffff840e1be0>] inet_csk_listen_stop+0x2c0/0x1070 net/ipv4/inet_connection_sock.c:1524 softirqs last disabled at (3097): [<ffffffff813b6b9f>] do_softirq+0x3f/0x90 kernel/softirq.c:480 Since we need to track the 'fallback is possible' condition and the fallback status separately, there are a few possible races open between the check and the actual fallback action. Add a spinlock to protect the fallback related information and use it close all the possible related races. If fallback is not possible, as per RFC, reset the current subflow. Reported by: Matthieu Baerts <[email protected]> Closes: multipath-tcp/mptcp_net-next#570 Reported-by: [email protected] Closes: multipath-tcp/mptcp_net-next#555 Fixes: 0530020 ("mptcp: track and update contiguous data status") Signed-off-by: Paolo Abeni <[email protected]>
1 parent 27ad91d commit c9ebb1e

File tree

4 files changed

+55
-13
lines changed

4 files changed

+55
-13
lines changed

net/mptcp/options.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -978,8 +978,9 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
978978
if (subflow->mp_join)
979979
goto reset;
980980
subflow->mp_capable = 0;
981+
if (mptcp_do_fallback(ssk))
982+
goto reset;
981983
pr_fallback(msk);
982-
mptcp_do_fallback(ssk);
983984
return false;
984985
}
985986

net/mptcp/protocol.c

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -561,10 +561,9 @@ static bool mptcp_check_data_fin(struct sock *sk)
561561

562562
static void mptcp_dss_corruption(struct mptcp_sock *msk, struct sock *ssk)
563563
{
564-
if (READ_ONCE(msk->allow_infinite_fallback)) {
564+
if (mptcp_do_fallback(ssk)) {
565565
MPTCP_INC_STATS(sock_net(ssk),
566566
MPTCP_MIB_DSSCORRUPTIONFALLBACK);
567-
mptcp_do_fallback(ssk);
568567
} else {
569568
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DSSCORRUPTIONRESET);
570569
mptcp_subflow_reset(ssk);
@@ -804,6 +803,14 @@ static bool __mptcp_finish_join(struct mptcp_sock *msk, struct sock *ssk)
804803
if (sk->sk_state != TCP_ESTABLISHED)
805804
return false;
806805

806+
spin_lock_bh(&msk->fallback_lock);
807+
if (__mptcp_check_fallback(msk)) {
808+
spin_unlock_bh(&msk->fallback_lock);
809+
return false;
810+
}
811+
mptcp_subflow_joined(msk, ssk);
812+
spin_unlock_bh(&msk->fallback_lock);
813+
807814
/* attach to msk socket only after we are sure we will deal with it
808815
* at close time
809816
*/
@@ -812,7 +819,6 @@ static bool __mptcp_finish_join(struct mptcp_sock *msk, struct sock *ssk)
812819

813820
mptcp_subflow_ctx(ssk)->subflow_id = msk->subflow_id++;
814821
mptcp_sockopt_sync_locked(msk, ssk);
815-
mptcp_subflow_joined(msk, ssk);
816822
mptcp_stop_tout_timer(sk);
817823
__mptcp_propagate_sndbuf(sk, ssk);
818824
return true;
@@ -1137,10 +1143,14 @@ static void mptcp_update_infinite_map(struct mptcp_sock *msk,
11371143
mpext->infinite_map = 1;
11381144
mpext->data_len = 0;
11391145

1146+
if (!mptcp_do_fallback(ssk)) {
1147+
mptcp_subflow_reset(ssk);
1148+
return;
1149+
}
1150+
11401151
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPTX);
11411152
mptcp_subflow_ctx(ssk)->send_infinite_map = 0;
11421153
pr_fallback(msk);
1143-
mptcp_do_fallback(ssk);
11441154
}
11451155

11461156
#define MPTCP_MAX_GSO_SIZE (GSO_LEGACY_MAX_SIZE - (MAX_TCP_HEADER + 1))
@@ -2544,9 +2554,9 @@ static void mptcp_check_fastclose(struct mptcp_sock *msk)
25442554

25452555
static void __mptcp_retrans(struct sock *sk)
25462556
{
2557+
struct mptcp_sendmsg_info info = { .data_lock_held = true, };
25472558
struct mptcp_sock *msk = mptcp_sk(sk);
25482559
struct mptcp_subflow_context *subflow;
2549-
struct mptcp_sendmsg_info info = {};
25502560
struct mptcp_data_frag *dfrag;
25512561
struct sock *ssk;
25522562
int ret, err;
@@ -2591,6 +2601,18 @@ static void __mptcp_retrans(struct sock *sk)
25912601
info.sent = 0;
25922602
info.limit = READ_ONCE(msk->csum_enabled) ? dfrag->data_len :
25932603
dfrag->already_sent;
2604+
2605+
/*
2606+
* make the whole retrans decision, xmit, disallow
2607+
* fallback atomic
2608+
*/
2609+
spin_lock_bh(&msk->fallback_lock);
2610+
if (__mptcp_check_fallback(msk)) {
2611+
spin_unlock_bh(&msk->fallback_lock);
2612+
release_sock(ssk);
2613+
return;
2614+
}
2615+
25942616
while (info.sent < info.limit) {
25952617
ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info);
25962618
if (ret <= 0)
@@ -2606,6 +2628,7 @@ static void __mptcp_retrans(struct sock *sk)
26062628
info.size_goal);
26072629
WRITE_ONCE(msk->allow_infinite_fallback, false);
26082630
}
2631+
spin_unlock_bh(&msk->fallback_lock);
26092632

26102633
release_sock(ssk);
26112634
}
@@ -2739,6 +2762,7 @@ static void __mptcp_init_sock(struct sock *sk)
27392762
msk->last_ack_recv = tcp_jiffies32;
27402763

27412764
mptcp_pm_data_init(msk);
2765+
spin_lock_init(&msk->fallback_lock);
27422766

27432767
/* re-use the csk retrans timer for MPTCP-level retrans */
27442768
timer_setup(&msk->sk.icsk_retransmit_timer, mptcp_retransmit_timer, 0);
@@ -3525,7 +3549,13 @@ bool mptcp_finish_join(struct sock *ssk)
35253549

35263550
/* active subflow, already present inside the conn_list */
35273551
if (!list_empty(&subflow->node)) {
3552+
spin_lock_bh(&msk->fallback_lock);
3553+
if (__mptcp_check_fallback(msk)) {
3554+
spin_unlock_bh(&msk->fallback_lock);
3555+
return false;
3556+
}
35283557
mptcp_subflow_joined(msk, ssk);
3558+
spin_unlock_bh(&msk->fallback_lock);
35293559
mptcp_propagate_sndbuf(parent, ssk);
35303560
return true;
35313561
}

net/mptcp/protocol.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ struct mptcp_sock {
352352
u32 subflow_id;
353353
u32 setsockopt_seq;
354354
char ca_name[TCP_CA_NAME_MAX];
355+
spinlock_t fallback_lock; /* protects fallback && allow_infinite_fallback */
355356
};
356357

357358
#define mptcp_data_lock(sk) spin_lock_bh(&(sk)->sk_lock.slock)
@@ -1214,15 +1215,21 @@ static inline bool mptcp_check_fallback(const struct sock *sk)
12141215
return __mptcp_check_fallback(msk);
12151216
}
12161217

1217-
static inline void __mptcp_do_fallback(struct mptcp_sock *msk)
1218+
static inline bool __mptcp_do_fallback(struct mptcp_sock *msk)
12181219
{
12191220
if (__mptcp_check_fallback(msk)) {
12201221
pr_debug("TCP fallback already done (msk=%p)\n", msk);
1221-
return;
1222+
return true;
12221223
}
1223-
if (WARN_ON_ONCE(!READ_ONCE(msk->allow_infinite_fallback)))
1224-
return;
1224+
spin_lock_bh(&msk->fallback_lock);
1225+
if (!msk->allow_infinite_fallback) {
1226+
spin_unlock_bh(&msk->fallback_lock);
1227+
return false;
1228+
}
1229+
12251230
set_bit(MPTCP_FALLBACK_DONE, &msk->flags);
1231+
spin_unlock_bh(&msk->fallback_lock);
1232+
return true;
12261233
}
12271234

12281235
static inline bool __mptcp_has_initial_subflow(const struct mptcp_sock *msk)
@@ -1234,14 +1241,15 @@ static inline bool __mptcp_has_initial_subflow(const struct mptcp_sock *msk)
12341241
TCPF_SYN_RECV | TCPF_LISTEN));
12351242
}
12361243

1237-
static inline void mptcp_do_fallback(struct sock *ssk)
1244+
static inline bool mptcp_do_fallback(struct sock *ssk)
12381245
{
12391246
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
12401247
struct sock *sk = subflow->conn;
12411248
struct mptcp_sock *msk;
12421249

12431250
msk = mptcp_sk(sk);
1244-
__mptcp_do_fallback(msk);
1251+
if (!__mptcp_do_fallback(msk))
1252+
return false;
12451253
if (READ_ONCE(msk->snd_data_fin_enable) && !(ssk->sk_shutdown & SEND_SHUTDOWN)) {
12461254
gfp_t saved_allocation = ssk->sk_allocation;
12471255

@@ -1253,6 +1261,7 @@ static inline void mptcp_do_fallback(struct sock *ssk)
12531261
tcp_shutdown(ssk, SEND_SHUTDOWN);
12541262
ssk->sk_allocation = saved_allocation;
12551263
}
1264+
return true;
12561265
}
12571266

12581267
#define pr_fallback(a) pr_debug("%s:fallback to TCP (msk=%p)\n", __func__, a)

net/mptcp/subflow.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,9 +544,11 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
544544
mptcp_get_options(skb, &mp_opt);
545545
if (subflow->request_mptcp) {
546546
if (!(mp_opt.suboptions & OPTION_MPTCP_MPC_SYNACK)) {
547+
if (!mptcp_do_fallback(sk))
548+
goto do_reset;
549+
547550
MPTCP_INC_STATS(sock_net(sk),
548551
MPTCP_MIB_MPCAPABLEACTIVEFALLBACK);
549-
mptcp_do_fallback(sk);
550552
pr_fallback(msk);
551553
goto fallback;
552554
}

0 commit comments

Comments
 (0)