Bluetooth: l2cap and rfcomm: fix 1 byte infoleak to userspace.
[linux-flexiantxendom0-natty.git] / net / bluetooth / rfcomm / sock.c
index ce505f2..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)
@@ -261,12 +260,19 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
 
        if (parent) {
                sk->sk_type = parent->sk_type;
-               pi->link_mode = rfcomm_pi(parent)->link_mode;
+               pi->dlc->defer_setup = bt_sk(parent)->defer_setup;
+
+               pi->sec_level = rfcomm_pi(parent)->sec_level;
+               pi->role_switch = rfcomm_pi(parent)->role_switch;
        } else {
-               pi->link_mode = 0;
+               pi->dlc->defer_setup = 0;
+
+               pi->sec_level = BT_SECURITY_LOW;
+               pi->role_switch = 0;
        }
 
-       pi->dlc->link_mode = pi->link_mode;
+       pi->dlc->sec_level = pi->sec_level;
+       pi->dlc->role_switch = pi->role_switch;
 }
 
 static struct proto rfcomm_proto = {
@@ -316,7 +322,8 @@ static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int
        return sk;
 }
 
-static int rfcomm_sock_create(struct net *net, struct socket *sock, int protocol)
+static int rfcomm_sock_create(struct net *net, struct socket *sock,
+                             int protocol, int kern)
 {
        struct sock *sk;
 
@@ -387,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);
@@ -406,7 +414,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
        bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
        rfcomm_pi(sk)->channel = sa->rc_channel;
 
-       d->link_mode = rfcomm_pi(sk)->link_mode;
+       d->sec_level = rfcomm_pi(sk)->sec_level;
+       d->role_switch = rfcomm_pi(sk)->role_switch;
 
        err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
        if (!err)
@@ -491,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) {
@@ -514,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;
@@ -554,6 +563,9 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        struct sk_buff *skb;
        int sent = 0;
 
+       if (test_bit(RFCOMM_DEFER_SETUP, &d->flags))
+               return -ENOTCONN;
+
        if (msg->msg_flags & MSG_OOB)
                return -EOPNOTSUPP;
 
@@ -602,135 +614,187 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        return sent;
 }
 
-static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
+static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+                              struct msghdr *msg, size_t size, int flags)
 {
-       DECLARE_WAITQUEUE(wait, current);
+       struct sock *sk = sock->sk;
+       struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
+       int len;
 
-       add_wait_queue(sk->sk_sleep, &wait);
-       for (;;) {
-               set_current_state(TASK_INTERRUPTIBLE);
+       if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
+               rfcomm_dlc_accept(d);
+               return 0;
+       }
 
-               if (!skb_queue_empty(&sk->sk_receive_queue) ||
-                   sk->sk_err ||
-                   (sk->sk_shutdown & RCV_SHUTDOWN) ||
-                   signal_pending(current) ||
-                   !timeo)
-                       break;
+       len = bt_sock_stream_recvmsg(iocb, sock, msg, size, flags);
 
-               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);
-       }
+       lock_sock(sk);
+       if (!(flags & MSG_PEEK) && len > 0)
+               atomic_sub(len, &sk->sk_rmem_alloc);
 
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
-       return timeo;
+       if (atomic_read(&sk->sk_rmem_alloc) <= (sk->sk_rcvbuf >> 2))
+               rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
+       release_sock(sk);
+
+       return len;
 }
 
-static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
-                              struct msghdr *msg, size_t size, int flags)
+static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
 {
        struct sock *sk = sock->sk;
        int err = 0;
-       size_t target, copied = 0;
-       long timeo;
+       u32 opt;
 
-       if (flags & MSG_OOB)
-               return -EOPNOTSUPP;
+       BT_DBG("sk %p", sk);
 
-       msg->msg_namelen = 0;
+       lock_sock(sk);
 
-       BT_DBG("sk %p size %zu", sk, size);
+       switch (optname) {
+       case RFCOMM_LM:
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
 
-       lock_sock(sk);
+               if (opt & RFCOMM_LM_AUTH)
+                       rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
+               if (opt & RFCOMM_LM_ENCRYPT)
+                       rfcomm_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
+               if (opt & RFCOMM_LM_SECURE)
+                       rfcomm_pi(sk)->sec_level = BT_SECURITY_HIGH;
 
-       target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
-       timeo  = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+               rfcomm_pi(sk)->role_switch = (opt & RFCOMM_LM_MASTER);
+               break;
 
-       do {
-               struct sk_buff *skb;
-               int chunk;
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
 
-               skb = skb_dequeue(&sk->sk_receive_queue);
-               if (!skb) {
-                       if (copied >= target)
-                               break;
+       release_sock(sk);
+       return err;
+}
 
-                       if ((err = sock_error(sk)) != 0)
-                               break;
-                       if (sk->sk_shutdown & RCV_SHUTDOWN)
-                               break;
+static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
+{
+       struct sock *sk = sock->sk;
+       struct bt_security sec;
+       int len, err = 0;
+       u32 opt;
 
-                       err = -EAGAIN;
-                       if (!timeo)
-                               break;
+       BT_DBG("sk %p", sk);
 
-                       timeo = rfcomm_sock_data_wait(sk, timeo);
+       if (level == SOL_RFCOMM)
+               return rfcomm_sock_setsockopt_old(sock, optname, optval, optlen);
 
-                       if (signal_pending(current)) {
-                               err = sock_intr_errno(timeo);
-                               goto out;
-                       }
-                       continue;
+       if (level != SOL_BLUETOOTH)
+               return -ENOPROTOOPT;
+
+       lock_sock(sk);
+
+       switch (optname) {
+       case BT_SECURITY:
+               if (sk->sk_type != SOCK_STREAM) {
+                       err = -EINVAL;
+                       break;
                }
 
-               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;
+               sec.level = BT_SECURITY_LOW;
+
+               len = min_t(unsigned int, sizeof(sec), optlen);
+               if (copy_from_user((char *) &sec, optval, len)) {
+                       err = -EFAULT;
                        break;
                }
-               copied += chunk;
-               size   -= chunk;
 
-               sock_recv_timestamp(msg, sk, skb);
+               if (sec.level > BT_SECURITY_HIGH) {
+                       err = -EINVAL;
+                       break;
+               }
 
-               if (!(flags & MSG_PEEK)) {
-                       atomic_sub(chunk, &sk->sk_rmem_alloc);
+               rfcomm_pi(sk)->sec_level = sec.level;
+               break;
 
-                       skb_pull(skb, chunk);
-                       if (skb->len) {
-                               skb_queue_head(&sk->sk_receive_queue, skb);
-                               break;
-                       }
-                       kfree_skb(skb);
+       case BT_DEFER_SETUP:
+               if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
+                       err = -EINVAL;
+                       break;
+               }
 
-               } else {
-                       /* put message back and return */
-                       skb_queue_head(&sk->sk_receive_queue, skb);
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
                        break;
                }
-       } while (size);
 
-out:
-       if (atomic_read(&sk->sk_rmem_alloc) <= (sk->sk_rcvbuf >> 2))
-               rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
+               bt_sk(sk)->defer_setup = opt;
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
 
        release_sock(sk);
-       return copied ? : err;
+       return err;
 }
 
-static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
+static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
-       int err = 0;
+       struct sock *l2cap_sk;
+       struct rfcomm_conninfo cinfo;
+       int len, err = 0;
        u32 opt;
 
        BT_DBG("sk %p", sk);
 
+       if (get_user(len, optlen))
+               return -EFAULT;
+
        lock_sock(sk);
 
        switch (optname) {
        case RFCOMM_LM:
-               if (get_user(opt, (u32 __user *) optval)) {
+               switch (rfcomm_pi(sk)->sec_level) {
+               case BT_SECURITY_LOW:
+                       opt = RFCOMM_LM_AUTH;
+                       break;
+               case BT_SECURITY_MEDIUM:
+                       opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
+                       break;
+               case BT_SECURITY_HIGH:
+                       opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
+                                                       RFCOMM_LM_SECURE;
+                       break;
+               default:
+                       opt = 0;
+                       break;
+               }
+
+               if (rfcomm_pi(sk)->role_switch)
+                       opt |= RFCOMM_LM_MASTER;
+
+               if (put_user(opt, (u32 __user *) optval))
                        err = -EFAULT;
+               break;
+
+       case RFCOMM_CONNINFO:
+               if (sk->sk_state != BT_CONNECTED &&
+                                       !rfcomm_pi(sk)->dlc->defer_setup) {
+                       err = -ENOTCONN;
                        break;
                }
 
-               rfcomm_pi(sk)->link_mode = opt;
+               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);
+
+               len = min_t(unsigned int, len, sizeof(cinfo));
+               if (copy_to_user(optval, (char *) &cinfo, len))
+                       err = -EFAULT;
+
                break;
 
        default:
@@ -745,36 +809,44 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
 static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
-       struct sock *l2cap_sk;
-       struct rfcomm_conninfo cinfo;
+       struct bt_security sec;
        int len, err = 0;
 
        BT_DBG("sk %p", sk);
 
+       if (level == SOL_RFCOMM)
+               return rfcomm_sock_getsockopt_old(sock, optname, optval, optlen);
+
+       if (level != SOL_BLUETOOTH)
+               return -ENOPROTOOPT;
+
        if (get_user(len, optlen))
                return -EFAULT;
 
        lock_sock(sk);
 
        switch (optname) {
-       case RFCOMM_LM:
-               if (put_user(rfcomm_pi(sk)->link_mode, (u32 __user *) optval))
+       case BT_SECURITY:
+               if (sk->sk_type != SOCK_STREAM) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               sec.level = rfcomm_pi(sk)->sec_level;
+
+               len = min_t(unsigned int, len, sizeof(sec));
+               if (copy_to_user(optval, (char *) &sec, len))
                        err = -EFAULT;
+
                break;
 
-       case RFCOMM_CONNINFO:
-               if (sk->sk_state != BT_CONNECTED) {
-                       err = -ENOTCONN;
+       case BT_DEFER_SETUP:
+               if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
+                       err = -EINVAL;
                        break;
                }
 
-               l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
-
-               cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle;
-               memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3);
-
-               len = min_t(unsigned int, len, sizeof(cinfo));
-               if (copy_to_user(optval, (char *) &cinfo, len))
+               if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
                        err = -EFAULT;
 
                break;
@@ -817,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) {
@@ -867,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);
@@ -891,29 +966,45 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
 
 done:
        bh_unlock_sock(parent);
+
+       if (bt_sk(parent)->defer_setup)
+               parent->sk_state_change(parent);
+
        return result;
 }
 
-static ssize_t rfcomm_sock_sysfs_show(struct class *dev, 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 CLASS_ATTR(rfcomm, S_IRUGO, rfcomm_sock_sysfs_show, NULL);
+static int rfcomm_sock_debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rfcomm_sock_debugfs_show, inode->i_private);
+}
+
+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,
@@ -935,7 +1026,7 @@ static const struct proto_ops rfcomm_sock_ops = {
        .mmap           = sock_no_mmap
 };
 
-static struct net_proto_family rfcomm_sock_family_ops = {
+static const struct net_proto_family rfcomm_sock_family_ops = {
        .family         = PF_BLUETOOTH,
        .owner          = THIS_MODULE,
        .create         = rfcomm_sock_create
@@ -953,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");
 
@@ -968,7 +1063,7 @@ error:
 
 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");