Skip to content
This repository has been archived by the owner on Apr 18, 2024. It is now read-only.

Commit

Permalink
mptcp: Never disable MPTCP's static branch
Browse files Browse the repository at this point in the history
It's racy and syzkaller found a way to break it. We went through lengths
to handle the concurrent enabling/disabling in and out of bottom-halves.

Let's just do the same as tcp_tx_delay_enabled. We enable it once and
leave it there.

Fixes: Zero-day bug
Signed-off-by: Christoph Paasch <cpaasch@apple.com>
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
(cherry picked from commit 63b4bd3)
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
(cherry picked from commit 078ffe7)
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
  • Loading branch information
cpaasch authored and matttbe committed Jun 24, 2022
1 parent 76d63a6 commit a446c6e
Show file tree
Hide file tree
Showing 4 changed files with 9 additions and 78 deletions.
1 change: 0 additions & 1 deletion include/net/mptcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,6 @@ void mptcp_reqsk_init(struct request_sock *req, const struct sock *sk,
int mptcp_conn_request(struct sock *sk, struct sk_buff *skb);
void mptcp_enable_sock(struct sock *sk);
void mptcp_disable_sock(struct sock *sk);
void mptcp_disable_static_key(void);
void mptcp_cookies_reqsk_init(struct request_sock *req,
struct mptcp_options_received *mopt,
struct sk_buff *skb);
Expand Down
4 changes: 2 additions & 2 deletions include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1532,10 +1532,10 @@ static inline int tcp_win_from_space(const struct sock *sk, int space)
}

#ifdef CONFIG_MPTCP
extern struct static_key mptcp_static_key;
DECLARE_STATIC_KEY_FALSE(mptcp_static_key);
static inline bool mptcp(const struct tcp_sock *tp)
{
return static_key_false(&mptcp_static_key) && tp->mpc;
return static_branch_unlikely(&mptcp_static_key) && tp->mpc;
}
#else
static inline bool mptcp(const struct tcp_sock *tp)
Expand Down
3 changes: 0 additions & 3 deletions net/ipv4/af_inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,6 @@ void inet_sock_destruct(struct sock *sk)
return;
}

if (sock_flag(sk, SOCK_MPTCP))
mptcp_disable_static_key();

WARN_ON(atomic_read(&sk->sk_rmem_alloc));
WARN_ON(refcount_read(&sk->sk_wmem_alloc));
WARN_ON(sk->sk_wmem_queued);
Expand Down
79 changes: 7 additions & 72 deletions net/mptcp/mptcp_ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ int sysctl_mptcp_syn_retries __read_mostly = 3;

bool mptcp_init_failed __read_mostly;

struct static_key mptcp_static_key = STATIC_KEY_INIT_FALSE;
DEFINE_STATIC_KEY_FALSE(mptcp_static_key);
EXPORT_SYMBOL(mptcp_static_key);

static void mptcp_key_sha1(u64 key, u32 *token, u64 *idsn);
Expand Down Expand Up @@ -384,71 +384,14 @@ static void mptcp_set_key_sk(const struct sock *sk)
&tp->mptcp_loc_token, NULL);
}

#ifdef CONFIG_JUMP_LABEL
static atomic_t mptcp_needed_deferred;
static atomic_t mptcp_wanted;

static void mptcp_clear(struct work_struct *work)
{
int deferred = atomic_xchg(&mptcp_needed_deferred, 0);
int wanted;

wanted = atomic_add_return(deferred, &mptcp_wanted);
if (wanted > 0)
static_key_enable(&mptcp_static_key);
else
static_key_disable(&mptcp_static_key);
}

static DECLARE_WORK(mptcp_work, mptcp_clear);
#endif

static void mptcp_enable_static_key_bh(void)
{
#ifdef CONFIG_JUMP_LABEL
int wanted;

while (1) {
wanted = atomic_read(&mptcp_wanted);
if (wanted <= 0)
break;
if (atomic_cmpxchg(&mptcp_wanted, wanted, wanted + 1) == wanted)
return;
}
atomic_inc(&mptcp_needed_deferred);
schedule_work(&mptcp_work);
#else
static_key_slow_inc(&mptcp_static_key);
#endif
}

static void mptcp_enable_static_key(void)
{
#ifdef CONFIG_JUMP_LABEL
atomic_inc(&mptcp_wanted);
static_key_enable(&mptcp_static_key);
#else
static_key_slow_inc(&mptcp_static_key);
#endif
}

void mptcp_disable_static_key(void)
{
#ifdef CONFIG_JUMP_LABEL
int wanted;
if (!static_branch_unlikely(&mptcp_static_key)) {
static int __mptcp_static_key = 0;

while (1) {
wanted = atomic_read(&mptcp_wanted);
if (wanted <= 1)
break;
if (atomic_cmpxchg(&mptcp_wanted, wanted, wanted - 1) == wanted)
return;
if (cmpxchg(&__mptcp_static_key, 0, 1) == 0)
static_branch_enable(&mptcp_static_key);
}
atomic_dec(&mptcp_needed_deferred);
schedule_work(&mptcp_work);
#else
static_key_slow_dec(&mptcp_static_key);
#endif
}

void mptcp_enable_sock(struct sock *sk)
Expand Down Expand Up @@ -489,8 +432,6 @@ void mptcp_disable_sock(struct sock *sk)
else
inet_csk(sk)->icsk_af_ops = &ipv6_specific;
#endif

mptcp_disable_static_key();
}
}

Expand Down Expand Up @@ -710,8 +651,6 @@ static void mptcp_sock_destruct(struct sock *sk)
mptcp_mpcb_cleanup(tp->mpcb);
}

WARN_ON(!static_key_false(&mptcp_static_key));

/* Must be called here, because this will decrement the jump-label. */
inet_sock_destruct(sk);
}
Expand Down Expand Up @@ -1395,10 +1334,8 @@ static int mptcp_alloc_mpcb(struct sock *meta_sk, __u64 remote_key,
meta_sk->sk_max_ack_backlog = 32;
meta_sk->sk_ack_backlog = 0;

if (!sock_flag(meta_sk, SOCK_MPTCP)) {
mptcp_enable_static_key_bh();
if (!sock_flag(meta_sk, SOCK_MPTCP))
sock_set_flag(meta_sk, SOCK_MPTCP);
}

/* Redefine function-pointers as the meta-sk is now fully ready */
meta_tp->mpc = 1;
Expand Down Expand Up @@ -1501,10 +1438,8 @@ int mptcp_add_sock(struct sock *meta_sk, struct sock *sk, u8 loc_id, u8 rem_id,
tp->mpcb = mpcb;
tp->meta_sk = meta_sk;

if (!sock_flag(sk, SOCK_MPTCP)) {
mptcp_enable_static_key_bh();
if (!sock_flag(sk, SOCK_MPTCP))
sock_set_flag(sk, SOCK_MPTCP);
}

tp->mpc = 1;
tp->ops = &mptcp_sub_specific;
Expand Down

0 comments on commit a446c6e

Please sign in to comment.