Blob Blame History Raw
From: Stefan Raspl <raspl@linux.ibm.com>
Subject: net/smc: restrict non-blocking connect finish
Patch-mainline: v4.17-rc4
Git-commit: 784813aed6ba24a1f24e7e11d9d0f208cee37a7d
References: FATE#325694, LTC#167874, bsc#1113480

Summary:     net/smc: SMC-R MVP
Description: Add latest upstream patches to push SMC-R to the MVP level

Upstream-Description:

             net/smc: restrict non-blocking connect finish

             The smc_poll code tries to finish connect() if the socket is in
             state SMC_INIT and polling of the internal CLC-socket returns with
             POLLOUT. This makes sense for a select/poll call following a connect
             call, but not without preceding connect().
             With this patch smc_poll starts connect logic only, if the CLC-socket
             is no longer in its initial state TCP_CLOSE.

             In addition, a poll error on the internal CLC-socket is always
             propagated to the SMC socket.

             With this patch the code path mentioned by syzbot
             https://syzkaller.appspot.com/bug?extid=03faa2dc16b8b64be396
             is no longer possible.

             Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
             Reported-by: syzbot+03faa2dc16b8b64be396@syzkaller.appspotmail.com
             Signed-off-by: David S. Miller <davem@davemloft.net>

Signed-off-by: Stefan Raspl <raspl@linux.ibm.com>
Signed-off-by: Petr Tesarik <ptesarik@suse.com>
---
 net/smc/af_smc.c |   14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -1166,13 +1166,15 @@ static unsigned int smc_poll(struct file
 		/* delegate to CLC child sock */
 		release_sock(sk);
 		mask = smc->clcsock->ops->poll(file, smc->clcsock, wait);
-		/* if non-blocking connect finished ... */
 		lock_sock(sk);
-		if ((sk->sk_state == SMC_INIT) && (mask & POLLOUT)) {
-			sk->sk_err = smc->clcsock->sk->sk_err;
-			if (sk->sk_err) {
-				mask |= POLLERR;
-			} else {
+		sk->sk_err = smc->clcsock->sk->sk_err;
+		if (sk->sk_err) {
+			mask |= POLLERR;
+		} else {
+			/* if non-blocking connect finished ... */
+			if (sk->sk_state == SMC_INIT &&
+			    mask & POLLOUT &&
+			    smc->clcsock->sk->sk_state != TCP_CLOSE) {
 				rc = smc_connect_rdma(smc);
 				if (rc < 0)
 					mask |= POLLERR;