Skip to content

Commit e4a0fa4

Browse files
Paolo Abenidavem330
authored andcommitted
mptcp: corner case locking for rx path fields initialization
Most MPTCP-level related fields are under the mptcp data lock protection, but are written one-off without such lock at MPC complete time, both for the client and the server Leverage the mptcp_propagate_state() infrastructure to move such initialization under the proper lock client-wise. The server side critical init steps are done by mptcp_subflow_fully_established(): ensure the caller properly held the relevant lock, and avoid acquiring the same lock in the nested scopes. There are no real potential races, as write access to such fields is implicitly serialized by the MPTCP state machine; the primary goal is consistency. Fixes: d22f498 ("mptcp: process MP_CAPABLE data option") Cc: [email protected] Signed-off-by: Paolo Abeni <[email protected]> Reviewed-by: Mat Martineau <[email protected]> Signed-off-by: Matthieu Baerts (NGI0) <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3f83d8a commit e4a0fa4

File tree

5 files changed

+50
-39
lines changed

5 files changed

+50
-39
lines changed

net/mptcp/fastopen.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,12 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf
5959
mptcp_data_unlock(sk);
6060
}
6161

62-
void mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow,
63-
const struct mptcp_options_received *mp_opt)
62+
void __mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow,
63+
const struct mptcp_options_received *mp_opt)
6464
{
6565
struct sock *sk = (struct sock *)msk;
6666
struct sk_buff *skb;
6767

68-
mptcp_data_lock(sk);
6968
skb = skb_peek_tail(&sk->sk_receive_queue);
7069
if (skb) {
7170
WARN_ON_ONCE(MPTCP_SKB_CB(skb)->end_seq);
@@ -77,5 +76,4 @@ void mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_
7776
}
7877

7978
pr_debug("msk=%p ack_seq=%llx", msk, msk->ack_seq);
80-
mptcp_data_unlock(sk);
8179
}

net/mptcp/options.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -962,9 +962,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
962962
/* subflows are fully established as soon as we get any
963963
* additional ack, including ADD_ADDR.
964964
*/
965-
subflow->fully_established = 1;
966-
WRITE_ONCE(msk->fully_established, true);
967-
goto check_notify;
965+
goto set_fully_established;
968966
}
969967

970968
/* If the first established packet does not contain MP_CAPABLE + data
@@ -986,7 +984,10 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
986984
set_fully_established:
987985
if (unlikely(!READ_ONCE(msk->pm.server_side)))
988986
pr_warn_once("bogus mpc option on established client sk");
989-
mptcp_subflow_fully_established(subflow, mp_opt);
987+
988+
mptcp_data_lock((struct sock *)msk);
989+
__mptcp_subflow_fully_established(msk, subflow, mp_opt);
990+
mptcp_data_unlock((struct sock *)msk);
990991

991992
check_notify:
992993
/* if the subflow is not already linked into the conn_list, we can't

net/mptcp/protocol.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3186,6 +3186,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
31863186
{
31873187
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
31883188
struct sock *nsk = sk_clone_lock(sk, GFP_ATOMIC);
3189+
struct mptcp_subflow_context *subflow;
31893190
struct mptcp_sock *msk;
31903191

31913192
if (!nsk)
@@ -3226,7 +3227,8 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
32263227

32273228
/* The msk maintain a ref to each subflow in the connections list */
32283229
WRITE_ONCE(msk->first, ssk);
3229-
list_add(&mptcp_subflow_ctx(ssk)->node, &msk->conn_list);
3230+
subflow = mptcp_subflow_ctx(ssk);
3231+
list_add(&subflow->node, &msk->conn_list);
32303232
sock_hold(ssk);
32313233

32323234
/* new mpc subflow takes ownership of the newly
@@ -3241,6 +3243,9 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
32413243
__mptcp_propagate_sndbuf(nsk, ssk);
32423244

32433245
mptcp_rcv_space_init(msk, ssk);
3246+
3247+
if (mp_opt->suboptions & OPTION_MPTCP_MPC_ACK)
3248+
__mptcp_subflow_fully_established(msk, subflow, mp_opt);
32443249
bh_unlock_sock(nsk);
32453250

32463251
/* note: the newly allocated socket refcount is 2 now */
@@ -3478,8 +3483,6 @@ void mptcp_finish_connect(struct sock *ssk)
34783483
* accessing the field below
34793484
*/
34803485
WRITE_ONCE(msk->local_key, subflow->local_key);
3481-
WRITE_ONCE(msk->snd_una, subflow->idsn + 1);
3482-
WRITE_ONCE(msk->wnd_end, subflow->idsn + 1 + tcp_sk(ssk)->snd_wnd);
34833486

34843487
mptcp_pm_new_connection(msk, ssk, 0);
34853488
}

net/mptcp/protocol.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -622,8 +622,9 @@ unsigned int mptcp_stale_loss_cnt(const struct net *net);
622622
unsigned int mptcp_close_timeout(const struct sock *sk);
623623
int mptcp_get_pm_type(const struct net *net);
624624
const char *mptcp_get_scheduler(const struct net *net);
625-
void mptcp_subflow_fully_established(struct mptcp_subflow_context *subflow,
626-
const struct mptcp_options_received *mp_opt);
625+
void __mptcp_subflow_fully_established(struct mptcp_sock *msk,
626+
struct mptcp_subflow_context *subflow,
627+
const struct mptcp_options_received *mp_opt);
627628
bool __mptcp_retransmit_pending_data(struct sock *sk);
628629
void mptcp_check_and_set_pending(struct sock *sk);
629630
void __mptcp_push_pending(struct sock *sk, unsigned int flags);
@@ -952,8 +953,8 @@ void mptcp_event_pm_listener(const struct sock *ssk,
952953
enum mptcp_event_type event);
953954
bool mptcp_userspace_pm_active(const struct mptcp_sock *msk);
954955

955-
void mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow,
956-
const struct mptcp_options_received *mp_opt);
956+
void __mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow,
957+
const struct mptcp_options_received *mp_opt);
957958
void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subflow,
958959
struct request_sock *req);
959960

net/mptcp/subflow.c

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -441,20 +441,6 @@ void __mptcp_sync_state(struct sock *sk, int state)
441441
}
442442
}
443443

444-
static void mptcp_propagate_state(struct sock *sk, struct sock *ssk)
445-
{
446-
struct mptcp_sock *msk = mptcp_sk(sk);
447-
448-
mptcp_data_lock(sk);
449-
if (!sock_owned_by_user(sk)) {
450-
__mptcp_sync_state(sk, ssk->sk_state);
451-
} else {
452-
msk->pending_state = ssk->sk_state;
453-
__set_bit(MPTCP_SYNC_STATE, &msk->cb_flags);
454-
}
455-
mptcp_data_unlock(sk);
456-
}
457-
458444
static void subflow_set_remote_key(struct mptcp_sock *msk,
459445
struct mptcp_subflow_context *subflow,
460446
const struct mptcp_options_received *mp_opt)
@@ -476,6 +462,31 @@ static void subflow_set_remote_key(struct mptcp_sock *msk,
476462
atomic64_set(&msk->rcv_wnd_sent, subflow->iasn);
477463
}
478464

465+
static void mptcp_propagate_state(struct sock *sk, struct sock *ssk,
466+
struct mptcp_subflow_context *subflow,
467+
const struct mptcp_options_received *mp_opt)
468+
{
469+
struct mptcp_sock *msk = mptcp_sk(sk);
470+
471+
mptcp_data_lock(sk);
472+
if (mp_opt) {
473+
/* Options are available only in the non fallback cases
474+
* avoid updating rx path fields otherwise
475+
*/
476+
WRITE_ONCE(msk->snd_una, subflow->idsn + 1);
477+
WRITE_ONCE(msk->wnd_end, subflow->idsn + 1 + tcp_sk(ssk)->snd_wnd);
478+
subflow_set_remote_key(msk, subflow, mp_opt);
479+
}
480+
481+
if (!sock_owned_by_user(sk)) {
482+
__mptcp_sync_state(sk, ssk->sk_state);
483+
} else {
484+
msk->pending_state = ssk->sk_state;
485+
__set_bit(MPTCP_SYNC_STATE, &msk->cb_flags);
486+
}
487+
mptcp_data_unlock(sk);
488+
}
489+
479490
static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
480491
{
481492
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
@@ -510,10 +521,9 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
510521
if (mp_opt.deny_join_id0)
511522
WRITE_ONCE(msk->pm.remote_deny_join_id0, true);
512523
subflow->mp_capable = 1;
513-
subflow_set_remote_key(msk, subflow, &mp_opt);
514524
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEACK);
515525
mptcp_finish_connect(sk);
516-
mptcp_propagate_state(parent, sk);
526+
mptcp_propagate_state(parent, sk, subflow, &mp_opt);
517527
} else if (subflow->request_join) {
518528
u8 hmac[SHA256_DIGEST_SIZE];
519529

@@ -556,7 +566,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
556566
}
557567
} else if (mptcp_check_fallback(sk)) {
558568
fallback:
559-
mptcp_propagate_state(parent, sk);
569+
mptcp_propagate_state(parent, sk, subflow, NULL);
560570
}
561571
return;
562572

@@ -741,17 +751,16 @@ void mptcp_subflow_drop_ctx(struct sock *ssk)
741751
kfree_rcu(ctx, rcu);
742752
}
743753

744-
void mptcp_subflow_fully_established(struct mptcp_subflow_context *subflow,
745-
const struct mptcp_options_received *mp_opt)
754+
void __mptcp_subflow_fully_established(struct mptcp_sock *msk,
755+
struct mptcp_subflow_context *subflow,
756+
const struct mptcp_options_received *mp_opt)
746757
{
747-
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
748-
749758
subflow_set_remote_key(msk, subflow, mp_opt);
750759
subflow->fully_established = 1;
751760
WRITE_ONCE(msk->fully_established, true);
752761

753762
if (subflow->is_mptfo)
754-
mptcp_fastopen_gen_msk_ackseq(msk, subflow, mp_opt);
763+
__mptcp_fastopen_gen_msk_ackseq(msk, subflow, mp_opt);
755764
}
756765

757766
static struct sock *subflow_syn_recv_sock(const struct sock *sk,
@@ -844,7 +853,6 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
844853
* mpc option
845854
*/
846855
if (mp_opt.suboptions & OPTION_MPTCP_MPC_ACK) {
847-
mptcp_subflow_fully_established(ctx, &mp_opt);
848856
mptcp_pm_fully_established(owner, child);
849857
ctx->pm_notified = 1;
850858
}
@@ -1756,7 +1764,7 @@ static void subflow_state_change(struct sock *sk)
17561764
mptcp_do_fallback(sk);
17571765
pr_fallback(msk);
17581766
subflow->conn_finished = 1;
1759-
mptcp_propagate_state(parent, sk);
1767+
mptcp_propagate_state(parent, sk, subflow, NULL);
17601768
}
17611769

17621770
/* as recvmsg() does not acquire the subflow socket for ssk selection

0 commit comments

Comments
 (0)