Bluetooth: l2cap and rfcomm: fix 1 byte infoleak to userspace.
[linux-flexiantxendom0-natty.git] / net / bluetooth / rfcomm / sock.c
index ca87d6a..784af0f 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/list.h>
 #include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -80,11 +82,14 @@ static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
 static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
 {
        struct sock *sk = d->owner, *parent;
+       unsigned long flags;
+
        if (!sk)
                return;
 
        BT_DBG("dlc %p state %ld err %d", d, d->state, err);
 
+       local_irq_save(flags);
        bh_lock_sock(sk);
 
        if (err)
@@ -106,6 +111,7 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
        }
 
        bh_unlock_sock(sk);
+       local_irq_restore(flags);
 
        if (parent && sock_flag(sk, SOCK_ZAPPED)) {
                /* We have to drop DLC lock here, otherwise
@@ -134,11 +140,13 @@ static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
 /* Find socket with channel and source bdaddr.
  * Returns closest match.
  */
-static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
+static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
 {
        struct sock *sk = NULL, *sk1 = NULL;
        struct hlist_node *node;
 
+       read_lock(&rfcomm_sk_list.lock);
+
        sk_for_each(sk, node, &rfcomm_sk_list.head) {
                if (state && sk->sk_state != state)
                        continue;
@@ -153,19 +161,10 @@ static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t
                                sk1 = sk;
                }
        }
-       return node ? sk : sk1;
-}
 
-/* Find socket with given address (channel, src).
- * Returns locked socket */
-static inline struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
-{
-       struct sock *s;
-       read_lock(&rfcomm_sk_list.lock);
-       s = __rfcomm_get_sock_by_channel(state, channel, src);
-       if (s) bh_lock_sock(s);
        read_unlock(&rfcomm_sk_list.lock);
-       return s;
+
+       return node ? sk : sk1;
 }
 
 static void rfcomm_sock_destruct(struct sock *sk)
@@ -395,7 +394,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
 
        BT_DBG("sk %p", sk);
 
-       if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc))
+       if (alen < sizeof(struct sockaddr_rc) ||
+           addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
 
        lock_sock(sk);
@@ -500,7 +500,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
        BT_DBG("sk %p timeo %ld", sk, timeo);
 
        /* Wait for an incoming connection. (wake-one). */
-       add_wait_queue_exclusive(sk->sk_sleep, &wait);
+       add_wait_queue_exclusive(sk_sleep(sk), &wait);
        while (!(nsk = bt_accept_dequeue(sk, newsock))) {
                set_current_state(TASK_INTERRUPTIBLE);
                if (!timeo) {
@@ -523,7 +523,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
                }
        }
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
 
        if (err)
                goto done;
@@ -614,121 +614,29 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        return sent;
 }
 
-static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
-{
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(sk->sk_sleep, &wait);
-       for (;;) {
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               if (!skb_queue_empty(&sk->sk_receive_queue) ||
-                   sk->sk_err ||
-                   (sk->sk_shutdown & RCV_SHUTDOWN) ||
-                   signal_pending(current) ||
-                   !timeo)
-                       break;
-
-               set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
-               release_sock(sk);
-               timeo = schedule_timeout(timeo);
-               lock_sock(sk);
-               clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
-       }
-
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
-       return timeo;
-}
-
 static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                               struct msghdr *msg, size_t size, int flags)
 {
        struct sock *sk = sock->sk;
        struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-       int err = 0;
-       size_t target, copied = 0;
-       long timeo;
+       int len;
 
        if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
                rfcomm_dlc_accept(d);
                return 0;
        }
 
-       if (flags & MSG_OOB)
-               return -EOPNOTSUPP;
-
-       msg->msg_namelen = 0;
-
-       BT_DBG("sk %p size %zu", sk, size);
+       len = bt_sock_stream_recvmsg(iocb, sock, msg, size, flags);
 
        lock_sock(sk);
+       if (!(flags & MSG_PEEK) && len > 0)
+               atomic_sub(len, &sk->sk_rmem_alloc);
 
-       target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
-       timeo  = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
-
-       do {
-               struct sk_buff *skb;
-               int chunk;
-
-               skb = skb_dequeue(&sk->sk_receive_queue);
-               if (!skb) {
-                       if (copied >= target)
-                               break;
-
-                       if ((err = sock_error(sk)) != 0)
-                               break;
-                       if (sk->sk_shutdown & RCV_SHUTDOWN)
-                               break;
-
-                       err = -EAGAIN;
-                       if (!timeo)
-                               break;
-
-                       timeo = rfcomm_sock_data_wait(sk, timeo);
-
-                       if (signal_pending(current)) {
-                               err = sock_intr_errno(timeo);
-                               goto out;
-                       }
-                       continue;
-               }
-
-               chunk = min_t(unsigned int, skb->len, size);
-               if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
-                       skb_queue_head(&sk->sk_receive_queue, skb);
-                       if (!copied)
-                               copied = -EFAULT;
-                       break;
-               }
-               copied += chunk;
-               size   -= chunk;
-
-               sock_recv_ts_and_drops(msg, sk, skb);
-
-               if (!(flags & MSG_PEEK)) {
-                       atomic_sub(chunk, &sk->sk_rmem_alloc);
-
-                       skb_pull(skb, chunk);
-                       if (skb->len) {
-                               skb_queue_head(&sk->sk_receive_queue, skb);
-                               break;
-                       }
-                       kfree_skb(skb);
-
-               } else {
-                       /* put message back and return */
-                       skb_queue_head(&sk->sk_receive_queue, skb);
-                       break;
-               }
-       } while (size);
-
-out:
        if (atomic_read(&sk->sk_rmem_alloc) <= (sk->sk_rcvbuf >> 2))
                rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
-
        release_sock(sk);
-       return copied ? : err;
+
+       return len;
 }
 
 static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
@@ -879,6 +787,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
 
                l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
 
+               memset(&cinfo, 0, sizeof(cinfo));
                cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle;
                memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3);
 
@@ -980,7 +889,8 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how)
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
-       if (!sk) return 0;
+       if (!sk)
+               return 0;
 
        lock_sock(sk);
        if (!sk->sk_shutdown) {
@@ -1030,6 +940,8 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
        if (!parent)
                return 0;
 
+       bh_lock_sock(parent);
+
        /* Check for backlog size */
        if (sk_acceptq_is_full(parent)) {
                BT_DBG("backlog full %d", parent->sk_ack_backlog);
@@ -1061,28 +973,38 @@ done:
        return result;
 }
 
-static ssize_t rfcomm_sock_sysfs_show(struct class *dev,
-                                     struct class_attribute *attr,
-                                     char *buf)
+static int rfcomm_sock_debugfs_show(struct seq_file *f, void *p)
 {
        struct sock *sk;
        struct hlist_node *node;
-       char *str = buf;
 
        read_lock_bh(&rfcomm_sk_list.lock);
 
        sk_for_each(sk, node, &rfcomm_sk_list.head) {
-               str += sprintf(str, "%s %s %d %d\n",
-                               batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+               seq_printf(f, "%s %s %d %d\n",
+                               batostr(&bt_sk(sk)->src),
+                               batostr(&bt_sk(sk)->dst),
                                sk->sk_state, rfcomm_pi(sk)->channel);
        }
 
        read_unlock_bh(&rfcomm_sk_list.lock);
 
-       return (str - buf);
+       return 0;
+}
+
+static int rfcomm_sock_debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rfcomm_sock_debugfs_show, inode->i_private);
 }
 
-static CLASS_ATTR(rfcomm, S_IRUGO, rfcomm_sock_sysfs_show, NULL);
+static const struct file_operations rfcomm_sock_debugfs_fops = {
+       .open           = rfcomm_sock_debugfs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static struct dentry *rfcomm_sock_debugfs;
 
 static const struct proto_ops rfcomm_sock_ops = {
        .family         = PF_BLUETOOTH,
@@ -1122,8 +1044,12 @@ int __init rfcomm_init_sockets(void)
        if (err < 0)
                goto error;
 
-       if (class_create_file(bt_class, &class_attr_rfcomm) < 0)
-               BT_ERR("Failed to create RFCOMM info file");
+       if (bt_debugfs) {
+               rfcomm_sock_debugfs = debugfs_create_file("rfcomm", 0444,
+                               bt_debugfs, NULL, &rfcomm_sock_debugfs_fops);
+               if (!rfcomm_sock_debugfs)
+                       BT_ERR("Failed to create RFCOMM debug file");
+       }
 
        BT_INFO("RFCOMM socket layer initialized");
 
@@ -1135,9 +1061,9 @@ error:
        return err;
 }
 
-void rfcomm_cleanup_sockets(void)
+void __exit rfcomm_cleanup_sockets(void)
 {
-       class_remove_file(bt_class, &class_attr_rfcomm);
+       debugfs_remove(rfcomm_sock_debugfs);
 
        if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
                BT_ERR("RFCOMM socket layer unregistration failed");