]> Pileus Git - ~andy/linux/blobdiff - net/nfc/llcp/sock.c
NFC: Fix possible NULL ptr deref when getting the name of a socket
[~andy/linux] / net / nfc / llcp / sock.c
index c13e02ebdef9b08e5c995f5cbb5a671db42d8e3c..17a707db40eb9865000cd073d3661fef1d1ced13 100644 (file)
 #include "../nfc.h"
 #include "llcp.h"
 
+static int sock_wait_state(struct sock *sk, int state, unsigned long timeo)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int err = 0;
+
+       pr_debug("sk %p", sk);
+
+       add_wait_queue(sk_sleep(sk), &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       while (sk->sk_state != state) {
+               if (!timeo) {
+                       err = -EINPROGRESS;
+                       break;
+               }
+
+               if (signal_pending(current)) {
+                       err = sock_intr_errno(timeo);
+                       break;
+               }
+
+               release_sock(sk);
+               timeo = schedule_timeout(timeo);
+               lock_sock(sk);
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               err = sock_error(sk);
+               if (err)
+                       break;
+       }
+
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(sk_sleep(sk), &wait);
+       return err;
+}
+
 static struct proto llcp_sock_proto = {
        .name     = "NFC_LLCP",
        .owner    = THIS_MODULE,
@@ -256,6 +292,9 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr,
 
        pr_debug("%p\n", sk);
 
+       if (llcp_sock == NULL)
+               return -EBADFD;
+
        addr->sa_family = AF_NFC;
        *len = sizeof(struct sockaddr_nfc_llcp);
 
@@ -304,11 +343,24 @@ static unsigned int llcp_sock_poll(struct file *file, struct socket *sock,
                mask |= POLLERR;
 
        if (!skb_queue_empty(&sk->sk_receive_queue))
-               mask |= POLLIN;
+               mask |= POLLIN | POLLRDNORM;
 
        if (sk->sk_state == LLCP_CLOSED)
                mask |= POLLHUP;
 
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLRDHUP | POLLIN | POLLRDNORM;
+
+       if (sk->sk_shutdown == SHUTDOWN_MASK)
+               mask |= POLLHUP;
+
+       if (sock_writeable(sk))
+               mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+       else
+               set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+
+       pr_debug("mask 0x%x\n", mask);
+
        return mask;
 }
 
@@ -462,9 +514,13 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
        if (ret)
                goto put_dev;
 
-       sk->sk_state = LLCP_CONNECTED;
+       ret = sock_wait_state(sk, LLCP_CONNECTED,
+                             sock_sndtimeo(sk, flags & O_NONBLOCK));
+       if (ret)
+               goto put_dev;
 
        release_sock(sk);
+
        return 0;
 
 put_dev: