]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
net/smc: add fallback check to connect()
authorUrsula Braun <ubraun@linux.ibm.com>
Thu, 12 Dec 2019 21:35:58 +0000 (22:35 +0100)
committerSeth Forshee <seth.forshee@canonical.com>
Mon, 6 Jan 2020 16:11:59 +0000 (10:11 -0600)
BugLink: https://bugs.launchpad.net/bugs/1858429
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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
net/smc/af_smc.c

index 737b49909a7af7e8bdd58fbaa4bc73aa007ad564..6a6d3b2aa5a90db30f477008bf8b39ce5b06a98e 100644 (file)
@@ -854,6 +854,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;
@@ -1716,8 +1718,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;
@@ -1725,6 +1725,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:
@@ -1736,15 +1738,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);
                }
@@ -1753,7 +1754,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);
                }
@@ -1764,6 +1765,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
        default:
                break;
        }
+out:
        release_sock(sk);
 
        return rc;