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 22:58:54 +0000 (15:58 -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 947f8bbb4bb34e55ca29f57ce95551bd6013306b..62df208af94f8d6a4fc1af5ee0fbb543e068ee35 100644 (file)
@@ -3885,16 +3885,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 b3bcd4bffb2e1fb8b76070f0c920da1e70156d06..ef3abf28c12039cd9d538b2f826a410dc647d545 100644 (file)
@@ -2096,6 +2096,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();
 
@@ -2104,11 +2105,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 8a20aaf1f2316676564501c49bb59c3fe56c898b..30a36499ee7741afc4f6116c633273ee87032fae 100644 (file)
@@ -1065,13 +1065,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 77f4153bdb5e5ebe434487497d1e8d3ed0253cbf..5c0685eba947db01aa38d0ae9a4b3d1dd62e12a3 100644 (file)
@@ -957,13 +957,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);