| From 7fdfaf5d8b6d0c8b5b5237a4a49d8b2055b8e96b Mon Sep 17 00:00:00 2001 |
| From: Ursula Braun <ubraun@linux.ibm.com> |
| Date: Thu, 12 Dec 2019 22:35:58 +0100 |
| Subject: [PATCH] net/smc: add fallback check to connect() |
| |
| commit 86434744fedf0cfe07a9eee3f4632c0e25c1d136 upstream. |
| |
| FASTOPEN setsockopt() or sendmsg() may switch the SMC socket to fallback |
| mode. Once fallback mode is active, the native TCP socket functions are |
| called. Nevertheless there is a small race window, when FASTOPEN |
| setsockopt/sendmsg runs in parallel to a connect(), and switch the |
| socket into fallback mode before connect() takes the sock lock. |
| Make sure the SMC-specific connect setup is omitted in this case. |
| |
| This way a syzbot-reported refcount problem is fixed, triggered by |
| different threads running non-blocking connect() and FASTOPEN_KEY |
| setsockopt. |
| |
| Reported-by: syzbot+96d3f9ff6a86d37e44c8@syzkaller.appspotmail.com |
| Fixes: 6d6dd528d5af ("net/smc: fix refcount non-blocking connect() -part 2") |
| Signed-off-by: Ursula Braun <ubraun@linux.ibm.com> |
| Signed-off-by: Karsten Graul <kgraul@linux.ibm.com> |
| Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c |
| index a9f12fae156b..fe955fae2995 100644 |
| --- a/net/smc/af_smc.c |
| +++ b/net/smc/af_smc.c |
| @@ -844,6 +844,8 @@ static int smc_connect(struct socket *sock, struct sockaddr *addr, |
| goto out; |
| |
| sock_hold(&smc->sk); /* sock put in passive closing */ |
| + if (smc->use_fallback) |
| + goto out; |
| if (flags & O_NONBLOCK) { |
| if (schedule_work(&smc->connect_work)) |
| smc->connect_nonblock = 1; |
| @@ -1725,8 +1727,6 @@ static int smc_setsockopt(struct socket *sock, int level, int optname, |
| sk->sk_err = smc->clcsock->sk->sk_err; |
| sk->sk_error_report(sk); |
| } |
| - if (rc) |
| - return rc; |
| |
| if (optlen < sizeof(int)) |
| return -EINVAL; |
| @@ -1734,6 +1734,8 @@ static int smc_setsockopt(struct socket *sock, int level, int optname, |
| return -EFAULT; |
| |
| lock_sock(sk); |
| + if (rc || smc->use_fallback) |
| + goto out; |
| switch (optname) { |
| case TCP_ULP: |
| case TCP_FASTOPEN: |
| @@ -1745,15 +1747,14 @@ static int smc_setsockopt(struct socket *sock, int level, int optname, |
| smc_switch_to_fallback(smc); |
| smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP; |
| } else { |
| - if (!smc->use_fallback) |
| - rc = -EINVAL; |
| + rc = -EINVAL; |
| } |
| break; |
| case TCP_NODELAY: |
| if (sk->sk_state != SMC_INIT && |
| sk->sk_state != SMC_LISTEN && |
| sk->sk_state != SMC_CLOSED) { |
| - if (val && !smc->use_fallback) |
| + if (val) |
| mod_delayed_work(system_wq, &smc->conn.tx_work, |
| 0); |
| } |
| @@ -1762,7 +1763,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname, |
| if (sk->sk_state != SMC_INIT && |
| sk->sk_state != SMC_LISTEN && |
| sk->sk_state != SMC_CLOSED) { |
| - if (!val && !smc->use_fallback) |
| + if (!val) |
| mod_delayed_work(system_wq, &smc->conn.tx_work, |
| 0); |
| } |
| @@ -1773,6 +1774,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname, |
| default: |
| break; |
| } |
| +out: |
| release_sock(sk); |
| |
| return rc; |
| -- |
| 2.7.4 |
| |