aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2014-02-09 20:59:05 -0500
committerMarcel Holtmann <marcel@holtmann.org>2014-02-14 16:39:29 -0500
commit082a1532fc7607727f759c069eb8dd9fa5ae3f37 (patch)
tree15f3c98d06aac088502669dd8e35291e399bd734 /net/bluetooth
parentc0fdfb80382e4901473ce0e31d1e7833c1d297be (diff)
Bluetooth: Fix racy acquire of rfcomm_dev reference
rfcomm_dev_get() can return a rfcomm_dev reference for a device for which destruction may be commencing. This can happen on tty destruction, which calls rfcomm_tty_cleanup(), the last port reference may have been released but RFCOMM_TTY_RELEASED was not set. The following race is also possible: CPU 0 | CPU 1 | rfcomm_release_dev rfcomm_dev_get | . spin_lock | . dev = __rfcomm_dev_get | . if dev | . if test_bit(TTY_RELEASED) | . | !test_and_set_bit(TTY_RELEASED) | tty_port_put <<<< last reference else | tty_port_get | The reference acquire is bogus because destruction will commence with the release of the last reference. Ignore the external state change of TTY_RELEASED and instead rely on the reference acquire itself to determine if the reference is valid. Cc: Jiri Slaby <jslaby@suse.cz> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Tested-By: Alexander Holler <holler@ahsoftware.de> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/rfcomm/tty.c8
1 files changed, 2 insertions, 6 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index a535ef148ef6..7cf193f0eea7 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -157,12 +157,8 @@ static struct rfcomm_dev *rfcomm_dev_get(int id)
157 157
158 dev = __rfcomm_dev_get(id); 158 dev = __rfcomm_dev_get(id);
159 159
160 if (dev) { 160 if (dev && !tty_port_get(&dev->port))
161 if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) 161 dev = NULL;
162 dev = NULL;
163 else
164 tty_port_get(&dev->port);
165 }
166 162
167 spin_unlock(&rfcomm_dev_lock); 163 spin_unlock(&rfcomm_dev_lock);
168 164