net/smc: return 0 for ioctl calls in states INIT and CLOSED
authorUrsula Braun <ubraun@linux.ibm.com>
Wed, 23 May 2018 14:38:09 +0000 (16:38 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 23 May 2018 20:02:35 +0000 (16:02 -0400)
A connected SMC-socket contains addresses of descriptors for the
send buffer and the rmb (receive buffer). Fields of these descriptors
are used to determine the answer for certain ioctl requests.
Add extra handling for unconnected SMC socket states without valid
buffer descriptor addresses.

Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
Reported-by: syzbot+e6714328fda813fc670f@syzkaller.appspotmail.com
Signed-off-by: David S. Miller <davem@davemloft.net>
net/smc/af_smc.c

index 48530dab5c9411e40ad983da406bde1179afd6ea..f2d925921d818ce66fbeccc907f27da867765308 100644 (file)
@@ -1490,20 +1490,32 @@ static int smc_ioctl(struct socket *sock, unsigned int cmd,
        case SIOCINQ: /* same as FIONREAD */
                if (smc->sk.sk_state == SMC_LISTEN)
                        return -EINVAL;
-               answ = atomic_read(&smc->conn.bytes_to_rcv);
+               if (smc->sk.sk_state == SMC_INIT ||
+                   smc->sk.sk_state == SMC_CLOSED)
+                       answ = 0;
+               else
+                       answ = atomic_read(&smc->conn.bytes_to_rcv);
                break;
        case SIOCOUTQ:
                /* output queue size (not send + not acked) */
                if (smc->sk.sk_state == SMC_LISTEN)
                        return -EINVAL;
-               answ = smc->conn.sndbuf_desc->len -
+               if (smc->sk.sk_state == SMC_INIT ||
+                   smc->sk.sk_state == SMC_CLOSED)
+                       answ = 0;
+               else
+                       answ = smc->conn.sndbuf_desc->len -
                                        atomic_read(&smc->conn.sndbuf_space);
                break;
        case SIOCOUTQNSD:
                /* output queue size (not send only) */
                if (smc->sk.sk_state == SMC_LISTEN)
                        return -EINVAL;
-               answ = smc_tx_prepared_sends(&smc->conn);
+               if (smc->sk.sk_state == SMC_INIT ||
+                   smc->sk.sk_state == SMC_CLOSED)
+                       answ = 0;
+               else
+                       answ = smc_tx_prepared_sends(&smc->conn);
                break;
        default:
                return -ENOIOCTLCMD;