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>
This commit is contained in:
Peter Hurley 2014-02-09 20:59:05 -05:00 committed by Marcel Holtmann
parent c0fdfb8038
commit 082a1532fc

View File

@ -157,12 +157,8 @@ static struct rfcomm_dev *rfcomm_dev_get(int id)
dev = __rfcomm_dev_get(id); dev = __rfcomm_dev_get(id);
if (dev) { if (dev && !tty_port_get(&dev->port))
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) dev = NULL;
dev = NULL;
else
tty_port_get(&dev->port);
}
spin_unlock(&rfcomm_dev_lock); spin_unlock(&rfcomm_dev_lock);