]> git.hungrycats.org Git - linux/commitdiff
[Bluetooth] Fix non-blocking socket race conditions
authorMarcel Holtmann <marcel@holtmann.org>
Wed, 11 Feb 2004 22:37:02 +0000 (23:37 +0100)
committerMarcel Holtmann <marcel@holtmann.org>
Wed, 11 Feb 2004 22:37:02 +0000 (23:37 +0100)
A poll on a non-blocking listen socket signals readable too early. The
first time the socket should be readable is if a child is in connected
state. And don't signal writeable if the socket is in config state.

Noticed by Jean Tourrilhes <jt@hpl.hp.com>

net/bluetooth/af_bluetooth.c

index c17195bbcf8a6bd5e125788c996775d2abf9d82a..8aa8e3f74c482b9d23cf44f850a7552444ad0147 100644 (file)
@@ -236,15 +236,31 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
        return err ? : copied;
 }
 
+static inline unsigned int bt_accept_poll(struct sock *parent)
+{
+       struct list_head *p, *n;
+       struct sock *sk;
+
+       list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
+               sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
+               if (sk->sk_state == BT_CONNECTED)
+                       return POLLIN | POLLRDNORM;
+       }
+
+       return 0;
+}
+
 unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
 {
        struct sock *sk = sock->sk;
-       unsigned int mask;
+       unsigned int mask = 0;
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
        poll_wait(file, sk->sk_sleep, wait);
-       mask = 0;
+
+       if (sk->sk_state == BT_LISTEN)
+               return bt_accept_poll(sk);
 
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR;
@@ -253,16 +269,17 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
                mask |= POLLHUP;
 
        if (!skb_queue_empty(&sk->sk_receive_queue) || 
-                       !list_empty(&bt_sk(sk)->accept_q) ||
                        (sk->sk_shutdown & RCV_SHUTDOWN))
                mask |= POLLIN | POLLRDNORM;
 
        if (sk->sk_state == BT_CLOSED)
                mask |= POLLHUP;
 
-       if (sk->sk_state == BT_CONNECT || sk->sk_state == BT_CONNECT2)
+       if (sk->sk_state == BT_CONNECT ||
+                       sk->sk_state == BT_CONNECT2 ||
+                       sk->sk_state == BT_CONFIG)
                return mask;
-       
+
        if (sock_writeable(sk))
                mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
        else