aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/rfcomm
diff options
context:
space:
mode:
authorGianluca Anzolin <gianluca@sottospazio.it>2013-07-29 11:08:08 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2013-08-21 10:47:05 -0400
commit396dc223dd36edd218650d042a07c5e61f022c5b (patch)
treeaba106ba73936f4c271f9f3b2d218a435f2cce5c /net/bluetooth/rfcomm
parentc7882cbd1151011ca8e6fb13530cd09eae1c39ee (diff)
Bluetooth: Take proper tty_struct references
In net/bluetooth/rfcomm/tty.c the struct tty_struct is used without taking references. This may lead to a use-after-free of the rfcomm tty. Fix this by taking references properly, using the tty_port_* helpers when possible. The raw assignments of dev->port.tty in rfcomm_tty_open/close are addressed in the later commit 'rfcomm: Implement .activate, .shutdown and .carrier_raised methods'. Signed-off-by: Gianluca Anzolin <gianluca@sottospazio.it> Reviewed-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth/rfcomm')
-rw-r--r--net/bluetooth/rfcomm/tty.c29
1 files changed, 17 insertions, 12 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index b6e44ad6cca6..cd7ff370be38 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -333,10 +333,9 @@ static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
333static void rfcomm_wfree(struct sk_buff *skb) 333static void rfcomm_wfree(struct sk_buff *skb)
334{ 334{
335 struct rfcomm_dev *dev = (void *) skb->sk; 335 struct rfcomm_dev *dev = (void *) skb->sk;
336 struct tty_struct *tty = dev->port.tty;
337 atomic_sub(skb->truesize, &dev->wmem_alloc); 336 atomic_sub(skb->truesize, &dev->wmem_alloc);
338 if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags) && tty) 337 if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
339 tty_wakeup(tty); 338 tty_port_tty_wakeup(&dev->port);
340 tty_port_put(&dev->port); 339 tty_port_put(&dev->port);
341} 340}
342 341
@@ -410,6 +409,7 @@ static int rfcomm_release_dev(void __user *arg)
410{ 409{
411 struct rfcomm_dev_req req; 410 struct rfcomm_dev_req req;
412 struct rfcomm_dev *dev; 411 struct rfcomm_dev *dev;
412 struct tty_struct *tty;
413 413
414 if (copy_from_user(&req, arg, sizeof(req))) 414 if (copy_from_user(&req, arg, sizeof(req)))
415 return -EFAULT; 415 return -EFAULT;
@@ -429,8 +429,11 @@ static int rfcomm_release_dev(void __user *arg)
429 rfcomm_dlc_close(dev->dlc, 0); 429 rfcomm_dlc_close(dev->dlc, 0);
430 430
431 /* Shut down TTY synchronously before freeing rfcomm_dev */ 431 /* Shut down TTY synchronously before freeing rfcomm_dev */
432 if (dev->port.tty) 432 tty = tty_port_tty_get(&dev->port);
433 tty_vhangup(dev->port.tty); 433 if (tty) {
434 tty_vhangup(tty);
435 tty_kref_put(tty);
436 }
434 437
435 if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) 438 if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
436 rfcomm_dev_del(dev); 439 rfcomm_dev_del(dev);
@@ -563,6 +566,7 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
563static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) 566static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
564{ 567{
565 struct rfcomm_dev *dev = dlc->owner; 568 struct rfcomm_dev *dev = dlc->owner;
569 struct tty_struct *tty;
566 if (!dev) 570 if (!dev)
567 return; 571 return;
568 572
@@ -572,7 +576,8 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
572 wake_up_interruptible(&dev->wait); 576 wake_up_interruptible(&dev->wait);
573 577
574 if (dlc->state == BT_CLOSED) { 578 if (dlc->state == BT_CLOSED) {
575 if (!dev->port.tty) { 579 tty = tty_port_tty_get(&dev->port);
580 if (!tty) {
576 if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { 581 if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
577 /* Drop DLC lock here to avoid deadlock 582 /* Drop DLC lock here to avoid deadlock
578 * 1. rfcomm_dev_get will take rfcomm_dev_lock 583 * 1. rfcomm_dev_get will take rfcomm_dev_lock
@@ -591,8 +596,10 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
591 tty_port_put(&dev->port); 596 tty_port_put(&dev->port);
592 rfcomm_dlc_lock(dlc); 597 rfcomm_dlc_lock(dlc);
593 } 598 }
594 } else 599 } else {
595 tty_hangup(dev->port.tty); 600 tty_hangup(tty);
601 tty_kref_put(tty);
602 }
596 } 603 }
597} 604}
598 605
@@ -604,10 +611,8 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
604 611
605 BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig); 612 BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
606 613
607 if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV)) { 614 if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV))
608 if (dev->port.tty && !C_CLOCAL(dev->port.tty)) 615 tty_port_tty_hangup(&dev->port, true);
609 tty_hangup(dev->port.tty);
610 }
611 616
612 dev->modem_status = 617 dev->modem_status =
613 ((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) | 618 ((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |