linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Gianluca Anzolin <gianluca@sottospazio.it>
To: marcel@holtmann.org
Cc: gustavo@padovan.org, linux-bluetooth@vger.kernel.org
Subject: [PATCH 1/2] Fix tty refcounting in rfcomm/tty.c
Date: Tue, 9 Jul 2013 19:05:02 +0200	[thread overview]
Message-ID: <20130709170502.GA32765@debian.seek.priv> (raw)

[-- Attachment #1: Type: text/plain, Size: 602 bytes --]

In net/bluetooth/rfcomm/tty.c the struct tty is used without proper
refcounting. This leads to OOPS and panics triggered by the tty layer functions
which are invoked after the struct tty has already been destroyed.

This happens for example when the bluetooth connection is lost because the host
goes down unexpectedly.

The fix uses the tty_port_* helpers already in place.

This patch depends on patch "Fix refcount leak in tty_port.c" already sent to
linux-kernel. [0]

Signed-off-by: Gianluca Anzolin <gianluca@sottospazio.it>

[0] http://lkml.indiana.edu/hypermail/linux/kernel/1307.1/00600.html


[-- Attachment #2: rfcomm-tty-refcount.patch --]
[-- Type: text/x-diff, Size: 3067 bytes --]

--- linux/net/bluetooth/rfcomm/tty.c.orig	2013-07-09 18:10:09.071322663 +0200
+++ linux/net/bluetooth/rfcomm/tty.c	2013-07-09 18:14:44.517783673 +0200
@@ -333,10 +333,11 @@ static inline unsigned int rfcomm_room(s
 static void rfcomm_wfree(struct sk_buff *skb)
 {
 	struct rfcomm_dev *dev = (void *) skb->sk;
-	struct tty_struct *tty = dev->port.tty;
+
 	atomic_sub(skb->truesize, &dev->wmem_alloc);
-	if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags) && tty)
-		tty_wakeup(tty);
+	if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
+		tty_port_tty_wakeup(&dev->port);
+
 	tty_port_put(&dev->port);
 }
 
@@ -410,6 +411,7 @@ static int rfcomm_release_dev(void __use
 {
 	struct rfcomm_dev_req req;
 	struct rfcomm_dev *dev;
+	struct tty_struct *tty;
 
 	if (copy_from_user(&req, arg, sizeof(req)))
 		return -EFAULT;
@@ -429,11 +431,15 @@ static int rfcomm_release_dev(void __use
 		rfcomm_dlc_close(dev->dlc, 0);
 
 	/* Shut down TTY synchronously before freeing rfcomm_dev */
-	if (dev->port.tty)
-		tty_vhangup(dev->port.tty);
+	tty = tty_port_tty_get(&dev->port);
+	if (tty) {
+		tty_vhangup(tty);
+		tty_kref_put(tty);
+	}
 
 	if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
 		rfcomm_dev_del(dev);
+
 	tty_port_put(&dev->port);
 	return 0;
 }
@@ -563,6 +569,7 @@ static void rfcomm_dev_data_ready(struct
 static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
 {
 	struct rfcomm_dev *dev = dlc->owner;
+	struct tty_struct *tty;
 	if (!dev)
 		return;
 
@@ -572,7 +579,8 @@ static void rfcomm_dev_state_change(stru
 	wake_up_interruptible(&dev->wait);
 
 	if (dlc->state == BT_CLOSED) {
-		if (!dev->port.tty) {
+		tty = tty_port_tty_get(&dev->port);
+		if (!tty) {
 			if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
 				/* Drop DLC lock here to avoid deadlock
 				 * 1. rfcomm_dev_get will take rfcomm_dev_lock
@@ -591,8 +599,10 @@ static void rfcomm_dev_state_change(stru
 				tty_port_put(&dev->port);
 				rfcomm_dlc_lock(dlc);
 			}
-		} else
-			tty_hangup(dev->port.tty);
+		} else {
+			tty_hangup(tty);
+			tty_kref_put(tty);
+		}
 	}
 }
 
@@ -604,10 +614,8 @@ static void rfcomm_dev_modem_status(stru
 
 	BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
 
-	if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV)) {
-		if (dev->port.tty && !C_CLOCAL(dev->port.tty))
-			tty_hangup(dev->port.tty);
-	}
+	if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV))
+		tty_port_tty_hangup(&dev->port, true);
 
 	dev->modem_status =
 		((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |
@@ -674,7 +682,7 @@ static int rfcomm_tty_open(struct tty_st
 
 	rfcomm_dlc_lock(dlc);
 	tty->driver_data = dev;
-	dev->port.tty = tty;
+	tty_port_tty_set(&dev->port, tty);
 	rfcomm_dlc_unlock(dlc);
 	set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
 
@@ -742,7 +750,7 @@ static void rfcomm_tty_close(struct tty_
 
 		rfcomm_dlc_lock(dev->dlc);
 		tty->driver_data = NULL;
-		dev->port.tty = NULL;
+		tty_port_tty_set(&dev->port, NULL);
 		rfcomm_dlc_unlock(dev->dlc);
 
 		if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {

             reply	other threads:[~2013-07-09 17:05 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-07-09 17:05 Gianluca Anzolin [this message]
2013-07-10  8:17 ` [PATCH 1/2] Fix tty refcounting in rfcomm/tty.c Dean Jenkins
2013-07-10  8:39   ` Mathias Hasselmann
2013-07-10 11:24     ` Gianluca Anzolin
2013-07-10  9:37   ` Gianluca Anzolin
2013-07-10 10:43     ` Gianluca Anzolin
2013-07-10 15:46 ` Gustavo Padovan
2013-07-10 16:24   ` Gianluca Anzolin
2013-07-10 16:55     ` Gustavo Padovan
2013-07-10 17:01       ` Gianluca Anzolin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20130709170502.GA32765@debian.seek.priv \
    --to=gianluca@sottospazio.it \
    --cc=gustavo@padovan.org \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=marcel@holtmann.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).