Skip to content

Commit b6985b9

Browse files
Paolo Abenikuba-moo
Paolo Abeni
authored andcommitted
mptcp: use the workqueue to destroy unaccepted sockets
Christoph reported a UaF at token lookup time after having refactored the passive socket initialization part: BUG: KASAN: use-after-free in __token_bucket_busy+0x253/0x260 Read of size 4 at addr ffff88810698d5b0 by task syz-executor653/3198 CPU: 1 PID: 3198 Comm: syz-executor653 Not tainted 6.2.0-rc59af4eaa31c1f6c00c8f1e448ed99a45c66340dd5 #6 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x6e/0x91 print_report+0x16a/0x46f kasan_report+0xad/0x130 __token_bucket_busy+0x253/0x260 mptcp_token_new_connect+0x13d/0x490 mptcp_connect+0x4ed/0x860 __inet_stream_connect+0x80e/0xd90 tcp_sendmsg_fastopen+0x3ce/0x710 mptcp_sendmsg+0xff1/0x1a20 inet_sendmsg+0x11d/0x140 __sys_sendto+0x405/0x490 __x64_sys_sendto+0xdc/0x1b0 do_syscall_64+0x3b/0x90 entry_SYSCALL_64_after_hwframe+0x72/0xdc We need to properly clean-up all the paired MPTCP-level resources and be sure to release the msk last, even when the unaccepted subflow is destroyed by the TCP internals via inet_child_forget(). We can re-use the existing MPTCP_WORK_CLOSE_SUBFLOW infra, explicitly checking that for the critical scenario: the closed subflow is the MPC one, the msk is not accepted and eventually going through full cleanup. With such change, __mptcp_destroy_sock() is always called on msk sockets, even on accepted ones. We don't need anymore to transiently drop one sk reference at msk clone time. Please note this commit depends on the parent one: mptcp: refactor passive socket initialization Fixes: 58b0991 ("mptcp: create msk early") Cc: [email protected] Reported-and-tested-by: Christoph Paasch <[email protected]> Closes: multipath-tcp/mptcp_net-next#347 Signed-off-by: Paolo Abeni <[email protected]> Reviewed-by: Matthieu Baerts <[email protected]> Signed-off-by: Matthieu Baerts <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 3a236ae commit b6985b9

File tree

3 files changed

+46
-16
lines changed

3 files changed

+46
-16
lines changed

net/mptcp/protocol.c

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2342,15 +2342,27 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
23422342
goto out;
23432343
}
23442344

2345-
sock_orphan(ssk);
23462345
subflow->disposable = 1;
23472346

23482347
/* if ssk hit tcp_done(), tcp_cleanup_ulp() cleared the related ops
23492348
* the ssk has been already destroyed, we just need to release the
23502349
* reference owned by msk;
23512350
*/
23522351
if (!inet_csk(ssk)->icsk_ulp_ops) {
2352+
WARN_ON_ONCE(!sock_flag(ssk, SOCK_DEAD));
23532353
kfree_rcu(subflow, rcu);
2354+
} else if (msk->in_accept_queue && msk->first == ssk) {
2355+
/* if the first subflow moved to a close state, e.g. due to
2356+
* incoming reset and we reach here before inet_child_forget()
2357+
* the TCP stack could later try to close it via
2358+
* inet_csk_listen_stop(), or deliver it to the user space via
2359+
* accept().
2360+
* We can't delete the subflow - or risk a double free - nor let
2361+
* the msk survive - or will be leaked in the non accept scenario:
2362+
* fallback and let TCP cope with the subflow cleanup.
2363+
*/
2364+
WARN_ON_ONCE(sock_flag(ssk, SOCK_DEAD));
2365+
mptcp_subflow_drop_ctx(ssk);
23542366
} else {
23552367
/* otherwise tcp will dispose of the ssk and subflow ctx */
23562368
if (ssk->sk_state == TCP_LISTEN) {
@@ -2398,9 +2410,10 @@ static unsigned int mptcp_sync_mss(struct sock *sk, u32 pmtu)
23982410
return 0;
23992411
}
24002412

2401-
static void __mptcp_close_subflow(struct mptcp_sock *msk)
2413+
static void __mptcp_close_subflow(struct sock *sk)
24022414
{
24032415
struct mptcp_subflow_context *subflow, *tmp;
2416+
struct mptcp_sock *msk = mptcp_sk(sk);
24042417

24052418
might_sleep();
24062419

@@ -2414,7 +2427,15 @@ static void __mptcp_close_subflow(struct mptcp_sock *msk)
24142427
if (!skb_queue_empty_lockless(&ssk->sk_receive_queue))
24152428
continue;
24162429

2417-
mptcp_close_ssk((struct sock *)msk, ssk, subflow);
2430+
mptcp_close_ssk(sk, ssk, subflow);
2431+
}
2432+
2433+
/* if the MPC subflow has been closed before the msk is accepted,
2434+
* msk will never be accept-ed, close it now
2435+
*/
2436+
if (!msk->first && msk->in_accept_queue) {
2437+
sock_set_flag(sk, SOCK_DEAD);
2438+
inet_sk_state_store(sk, TCP_CLOSE);
24182439
}
24192440
}
24202441

@@ -2623,6 +2644,9 @@ static void mptcp_worker(struct work_struct *work)
26232644
__mptcp_check_send_data_fin(sk);
26242645
mptcp_check_data_fin(sk);
26252646

2647+
if (test_and_clear_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags))
2648+
__mptcp_close_subflow(sk);
2649+
26262650
/* There is no point in keeping around an orphaned sk timedout or
26272651
* closed, but we need the msk around to reply to incoming DATA_FIN,
26282652
* even if it is orphaned and in FIN_WAIT2 state
@@ -2638,9 +2662,6 @@ static void mptcp_worker(struct work_struct *work)
26382662
}
26392663
}
26402664

2641-
if (test_and_clear_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags))
2642-
__mptcp_close_subflow(msk);
2643-
26442665
if (test_and_clear_bit(MPTCP_WORK_RTX, &msk->flags))
26452666
__mptcp_retrans(sk);
26462667

@@ -3078,6 +3099,7 @@ struct sock *mptcp_sk_clone(const struct sock *sk,
30783099
msk->local_key = subflow_req->local_key;
30793100
msk->token = subflow_req->token;
30803101
msk->subflow = NULL;
3102+
msk->in_accept_queue = 1;
30813103
WRITE_ONCE(msk->fully_established, false);
30823104
if (mp_opt->suboptions & OPTION_MPTCP_CSUMREQD)
30833105
WRITE_ONCE(msk->csum_enabled, true);
@@ -3095,8 +3117,7 @@ struct sock *mptcp_sk_clone(const struct sock *sk,
30953117
security_inet_csk_clone(nsk, req);
30963118
bh_unlock_sock(nsk);
30973119

3098-
/* keep a single reference */
3099-
__sock_put(nsk);
3120+
/* note: the newly allocated socket refcount is 2 now */
31003121
return nsk;
31013122
}
31023123

@@ -3152,8 +3173,6 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
31523173
goto out;
31533174
}
31543175

3155-
/* acquire the 2nd reference for the owning socket */
3156-
sock_hold(new_mptcp_sock);
31573176
newsk = new_mptcp_sock;
31583177
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEPASSIVEACK);
31593178
} else {
@@ -3704,6 +3723,7 @@ static int mptcp_stream_accept(struct socket *sock, struct socket *newsock,
37043723
struct sock *newsk = newsock->sk;
37053724

37063725
set_bit(SOCK_CUSTOM_SOCKOPT, &newsock->flags);
3726+
msk->in_accept_queue = 0;
37073727

37083728
lock_sock(newsk);
37093729

net/mptcp/protocol.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,8 @@ struct mptcp_sock {
295295
u8 recvmsg_inq:1,
296296
cork:1,
297297
nodelay:1,
298-
fastopening:1;
298+
fastopening:1,
299+
in_accept_queue:1;
299300
int connect_flags;
300301
struct work_struct work;
301302
struct sk_buff *ooo_last_skb;
@@ -666,6 +667,8 @@ void mptcp_subflow_set_active(struct mptcp_subflow_context *subflow);
666667

667668
bool mptcp_subflow_active(struct mptcp_subflow_context *subflow);
668669

670+
void mptcp_subflow_drop_ctx(struct sock *ssk);
671+
669672
static inline void mptcp_subflow_tcp_fallback(struct sock *sk,
670673
struct mptcp_subflow_context *ctx)
671674
{

net/mptcp/subflow.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -699,9 +699,10 @@ static bool subflow_hmac_valid(const struct request_sock *req,
699699

700700
static void mptcp_force_close(struct sock *sk)
701701
{
702-
/* the msk is not yet exposed to user-space */
702+
/* the msk is not yet exposed to user-space, and refcount is 2 */
703703
inet_sk_state_store(sk, TCP_CLOSE);
704704
sk_common_release(sk);
705+
sock_put(sk);
705706
}
706707

707708
static void subflow_ulp_fallback(struct sock *sk,
@@ -717,7 +718,7 @@ static void subflow_ulp_fallback(struct sock *sk,
717718
mptcp_subflow_ops_undo_override(sk);
718719
}
719720

720-
static void subflow_drop_ctx(struct sock *ssk)
721+
void mptcp_subflow_drop_ctx(struct sock *ssk)
721722
{
722723
struct mptcp_subflow_context *ctx = mptcp_subflow_ctx(ssk);
723724

@@ -823,7 +824,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
823824

824825
if (new_msk)
825826
mptcp_copy_inaddrs(new_msk, child);
826-
subflow_drop_ctx(child);
827+
mptcp_subflow_drop_ctx(child);
827828
goto out;
828829
}
829830

@@ -914,7 +915,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
914915
return child;
915916

916917
dispose_child:
917-
subflow_drop_ctx(child);
918+
mptcp_subflow_drop_ctx(child);
918919
tcp_rsk(req)->drop_req = true;
919920
inet_csk_prepare_for_destroy_sock(child);
920921
tcp_done(child);
@@ -1866,7 +1867,6 @@ void mptcp_subflow_queue_clean(struct sock *listener_sk, struct sock *listener_s
18661867
struct sock *sk = (struct sock *)msk;
18671868
bool do_cancel_work;
18681869

1869-
sock_hold(sk);
18701870
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
18711871
next = msk->dl_next;
18721872
msk->first = NULL;
@@ -1954,6 +1954,13 @@ static void subflow_ulp_release(struct sock *ssk)
19541954
* when the subflow is still unaccepted
19551955
*/
19561956
release = ctx->disposable || list_empty(&ctx->node);
1957+
1958+
/* inet_child_forget() does not call sk_state_change(),
1959+
* explicitly trigger the socket close machinery
1960+
*/
1961+
if (!release && !test_and_set_bit(MPTCP_WORK_CLOSE_SUBFLOW,
1962+
&mptcp_sk(sk)->flags))
1963+
mptcp_schedule_work(sk);
19571964
sock_put(sk);
19581965
}
19591966

0 commit comments

Comments
 (0)