Bluetooth: Fix potential bad memory access with sysfs files
authorMarcel Holtmann <marcel@holtmann.org>
Mon, 15 Mar 2010 21:12:58 +0000 (14:12 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 1 Apr 2010 23:02:13 +0000 (16:02 -0700)
commit 101545f6fef4a0a3ea8daf0b5b880df2c6a92a69 upstream.

When creating a high number of Bluetooth sockets (L2CAP, SCO
and RFCOMM) it is possible to scribble repeatedly on arbitrary
pages of memory. Ensure that the content of these sysfs files is
always less than one page. Even if this means truncating. The
files in question are scheduled to be moved over to debugfs in
the future anyway.

Based on initial patches from Neil Brown and Linus Torvalds

Reported-by: Neil Brown <neilb@suse.de>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/sco.c

index 400efa26ddbab7474fdfc1d1992eb204b4104f20..4609d9c94f418ce67cfcee762bdcf8e2c50bc26a 100644 (file)
@@ -3942,16 +3942,24 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf)
        struct sock *sk;
        struct hlist_node *node;
        char *str = buf;
+       int size = PAGE_SIZE;
 
        read_lock_bh(&l2cap_sk_list.lock);
 
        sk_for_each(sk, node, &l2cap_sk_list.head) {
                struct l2cap_pinfo *pi = l2cap_pi(sk);
+               int len;
 
-               str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n",
+               len = snprintf(str, size, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n",
                                batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
                                sk->sk_state, __le16_to_cpu(pi->psm), pi->scid,
                                pi->dcid, pi->imtu, pi->omtu, pi->sec_level);
+
+               size -= len;
+               if (size <= 0)
+                       break;
+
+               str += len;
        }
 
        read_unlock_bh(&l2cap_sk_list.lock);
index 89f4a59eb82b9a520886a35e6b3aa65a6286ea70..3fe9c7c1d51701d2dbce49880a35c147f8e9bbda 100644 (file)
@@ -2103,6 +2103,7 @@ static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, char *buf)
        struct rfcomm_session *s;
        struct list_head *pp, *p;
        char *str = buf;
+       int size = PAGE_SIZE;
 
        rfcomm_lock();
 
@@ -2111,11 +2112,21 @@ static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, char *buf)
                list_for_each(pp, &s->dlcs) {
                        struct sock *sk = s->sock->sk;
                        struct rfcomm_dlc *d = list_entry(pp, struct rfcomm_dlc, list);
+                       int len;
 
-                       str += sprintf(str, "%s %s %ld %d %d %d %d\n",
+                       len = snprintf(str, size, "%s %s %ld %d %d %d %d\n",
                                        batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
                                        d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
+
+                       size -= len;
+                       if (size <= 0)
+                               break;
+
+                       str += len;
                }
+
+               if (size <= 0)
+                       break;
        }
 
        rfcomm_unlock();
index 4b5968dda6736bab575a4ac2a6200dbff400d7b3..bc03b508f35ecf75be23aab0144709832c29564b 100644 (file)
@@ -1066,13 +1066,22 @@ static ssize_t rfcomm_sock_sysfs_show(struct class *dev, char *buf)
        struct sock *sk;
        struct hlist_node *node;
        char *str = buf;
+       int size = PAGE_SIZE;
 
        read_lock_bh(&rfcomm_sk_list.lock);
 
        sk_for_each(sk, node, &rfcomm_sk_list.head) {
-               str += sprintf(str, "%s %s %d %d\n",
+               int len;
+
+               len = snprintf(str, size, "%s %s %d %d\n",
                                batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
                                sk->sk_state, rfcomm_pi(sk)->channel);
+
+               size -= len;
+               if (size <= 0)
+                       break;
+
+               str += len;
        }
 
        read_unlock_bh(&rfcomm_sk_list.lock);
index dd8f6ec57dcec21cc6401c7dba5a74af67beb782..66cab63e76e3adcaff0237ae7c82f99070e1d3a7 100644 (file)
@@ -958,13 +958,22 @@ static ssize_t sco_sysfs_show(struct class *dev, char *buf)
        struct sock *sk;
        struct hlist_node *node;
        char *str = buf;
+       int size = PAGE_SIZE;
 
        read_lock_bh(&sco_sk_list.lock);
 
        sk_for_each(sk, node, &sco_sk_list.head) {
-               str += sprintf(str, "%s %s %d\n",
+               int len;
+
+               len = snprintf(str, size, "%s %s %d\n",
                                batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
                                sk->sk_state);
+
+               size -= len;
+               if (size <= 0)
+                       break;
+
+               str += len;
        }
 
        read_unlock_bh(&sco_sk_list.lock);