From 0878b6667f28772aa7d6b735abff53efc7bf6d91 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 5 May 2007 00:35:59 +0200 Subject: [Bluetooth] Fix L2CAP and HCI setsockopt() information leaks The L2CAP and HCI setsockopt() implementations have a small information leak that makes it possible to leak kernel stack memory to userspace. If the optlen parameter is 0, no data will be copied by copy_from_user(), but the uninitialized stack buffer will be read and stored later. A call to getsockopt() can now retrieve the leaked information. To fix this problem the stack buffer given to copy_from_user() must be initialized with the current settings. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_sock.c | 9 +++++++++ net/bluetooth/l2cap.c | 6 ++++++ 2 files changed, 15 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 832b5f4..bfc9a35 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -499,6 +499,15 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char break; case HCI_FILTER: + { + struct hci_filter *f = &hci_pi(sk)->filter; + + uf.type_mask = f->type_mask; + uf.opcode = f->opcode; + uf.event_mask[0] = *((u32 *) f->event_mask + 0); + uf.event_mask[1] = *((u32 *) f->event_mask + 1); + } + len = min_t(unsigned int, len, sizeof(uf)); if (copy_from_user(&uf, optval, len)) { err = -EFAULT; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index a586787..a59b1fb 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -954,11 +954,17 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch switch (optname) { case L2CAP_OPTIONS: + opts.imtu = l2cap_pi(sk)->imtu; + opts.omtu = l2cap_pi(sk)->omtu; + opts.flush_to = l2cap_pi(sk)->flush_to; + opts.mode = 0x00; + len = min_t(unsigned int, sizeof(opts), optlen); if (copy_from_user((char *) &opts, optval, len)) { err = -EFAULT; break; } + l2cap_pi(sk)->imtu = opts.imtu; l2cap_pi(sk)->omtu = opts.omtu; break; -- cgit v1.1 From 53c1d4b0b22243c093ded25aaa01c8ff8ab6e6b3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 5 May 2007 00:36:03 +0200 Subject: [Bluetooth] Attach host adapters to the Bluetooth bus The Bluetooth host adapters are attached to the Bluetooth class and the low-level connections are children of these class devices. Having class devices as parent of bus devices breaks a lot of reasonable assumptions about sysfs. The host adapters should be attached to the Bluetooth bus to simplify the dependency resolving. For compatibility an additional symlink from the Bluetooth class will be used. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_sysfs.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 801d687..359e344 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -305,7 +305,7 @@ int hci_register_sysfs(struct hci_dev *hdev) BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); - dev->class = bt_class; + dev->bus = &bt_bus; dev->parent = hdev->parent; strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE); @@ -322,6 +322,10 @@ int hci_register_sysfs(struct hci_dev *hdev) if (device_create_file(dev, bt_attrs[i]) < 0) BT_ERR("Failed to create device attribute"); + if (sysfs_create_link(&bt_class->subsys.kset.kobj, + &dev->kobj, kobject_name(&dev->kobj)) < 0) + BT_ERR("Failed to create class symlink"); + return 0; } @@ -329,6 +333,9 @@ void hci_unregister_sysfs(struct hci_dev *hdev) { BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); + sysfs_remove_link(&bt_class->subsys.kset.kobj, + kobject_name(&hdev->dev.kobj)); + device_del(&hdev->dev); } -- cgit v1.1 From 48db9ca4f2ac9f39eb90ccb12ad3ca7b645a552c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 5 May 2007 00:36:06 +0200 Subject: [Bluetooth] Use in-kernel sockets API The kernel provides a new convenient way to access the sockets API for in-kernel users. It is a good idea to actually use it. Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/core.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index fe7df90..71a72fc 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -622,7 +622,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst bacpy(&addr.l2_bdaddr, src); addr.l2_family = AF_BLUETOOTH; addr.l2_psm = 0; - *err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr)); + *err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr)); if (*err < 0) goto failed; @@ -643,7 +643,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst bacpy(&addr.l2_bdaddr, dst); addr.l2_family = AF_BLUETOOTH; addr.l2_psm = htobs(RFCOMM_PSM); - *err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK); + *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK); if (*err == 0 || *err == -EINPROGRESS) return s; @@ -1757,19 +1757,12 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s) BT_DBG("session %p", s); - if (sock_create_lite(PF_BLUETOOTH, sock->type, BTPROTO_L2CAP, &nsock)) + err = kernel_accept(sock, &nsock, O_NONBLOCK); + if (err < 0) return; - nsock->ops = sock->ops; - __module_get(nsock->ops->owner); - err = sock->ops->accept(sock, nsock, O_NONBLOCK); - if (err < 0) { - sock_release(nsock); - return; - } - /* Set our callbacks */ nsock->sk->sk_data_ready = rfcomm_l2data_ready; nsock->sk->sk_state_change = rfcomm_l2state_change; @@ -1885,7 +1878,7 @@ static int rfcomm_add_listener(bdaddr_t *ba) bacpy(&addr.l2_bdaddr, ba); addr.l2_family = AF_BLUETOOTH; addr.l2_psm = htobs(RFCOMM_PSM); - err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr)); + err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0) { BT_ERR("Bind failed %d", err); goto failed; @@ -1898,7 +1891,7 @@ static int rfcomm_add_listener(bdaddr_t *ba) release_sock(sk); /* Start listening on the socket */ - err = sock->ops->listen(sock, 10); + err = kernel_listen(sock, 10); if (err) { BT_ERR("Listen failed %d", err); goto failed; -- cgit v1.1 From 77f2a45fa1ba33147fd6cc8ae546188504a822cd Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 5 May 2007 00:36:10 +0200 Subject: [Bluetooth] Check that device is in rfcomm_dev_list before deleting If RFCOMM_RELEASE_ONHUP flag is on and rfcomm_release_dev is called before connection is closed, rfcomm_dev is deleted twice from the rfcomm_dev_list and refcount is messed up. This patch adds a check before deleting device that the device actually is listed. Signed-off-by: Ville Tervo Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/tty.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 9a7a44f..b2b1cce 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -517,9 +517,10 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) if (dlc->state == BT_CLOSED) { if (!dev->tty) { if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { - rfcomm_dev_hold(dev); - rfcomm_dev_del(dev); + if (rfcomm_dev_get(dev->id) == NULL) + return; + rfcomm_dev_del(dev); /* We have to drop DLC lock here, otherwise rfcomm_dev_put() will dead lock if it's the last reference. */ @@ -974,8 +975,12 @@ static void rfcomm_tty_hangup(struct tty_struct *tty) rfcomm_tty_flush_buffer(tty); - if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) + if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { + if (rfcomm_dev_get(dev->id) == NULL) + return; rfcomm_dev_del(dev); + rfcomm_dev_put(dev); + } } static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused) -- cgit v1.1 From 9cf5b0ea3a7f1432c61029f7aaf4b8b338628884 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 5 May 2007 00:36:13 +0200 Subject: [Bluetooth] Disconnect L2CAP connection after last RFCOMM DLC The RFCOMM specification says that the device closing the last DLC on a particular session is responsible for closing the multiplexer by closing the corresponding L2CAP channel. Signed-off-by: Ville Tervo Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 71a72fc..52e04df 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1058,6 +1058,12 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) case BT_DISCONN: d->state = BT_CLOSED; __rfcomm_dlc_close(d, 0); + + if (list_empty(&s->dlcs)) { + s->state = BT_DISCONN; + rfcomm_send_disc(s, 0); + } + break; } } else { @@ -1067,6 +1073,10 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) s->state = BT_CONNECTED; rfcomm_process_connect(s); break; + + case BT_DISCONN: + rfcomm_session_put(s); + break; } } return 0; -- cgit v1.1