diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2014-02-09 20:59:07 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-02-14 13:39:29 -0800 |
commit | 1c64834e0624c61735308138e67cc3b527f41621 (patch) | |
tree | 912156866fbaa316a2197f261646737f95a88e57 /net/bluetooth/rfcomm | |
parent | 960603a54aa0d5f4f1c4f1037bcaee571d03cb1e (diff) | |
download | lwn-1c64834e0624c61735308138e67cc3b527f41621.tar.gz lwn-1c64834e0624c61735308138e67cc3b527f41621.zip |
Bluetooth: Release rfcomm_dev only once
No logic prevents an rfcomm_dev from being released multiple
times. For example, if the rfcomm_dev ref count is large due
to pending tx, then multiple RFCOMMRELEASEDEV ioctls may
mistakenly release the rfcomm_dev too many times. Note that
concurrent ioctls are not required to create this condition.
Introduce RFCOMM_DEV_RELEASED status bit which guarantees the
rfcomm_dev can only be released once.
NB: Since the flags are exported to userspace, introduce the status
field to track state for which userspace should not be aware.
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/rfcomm')
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index b385d9985656..d9d4bc89e638 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -51,6 +51,8 @@ struct rfcomm_dev { unsigned long flags; int err; + unsigned long status; /* don't export to userspace */ + bdaddr_t src; bdaddr_t dst; u8 channel; @@ -423,6 +425,12 @@ static int rfcomm_release_dev(void __user *arg) return -EPERM; } + /* only release once */ + if (test_and_set_bit(RFCOMM_DEV_RELEASED, &dev->status)) { + tty_port_put(&dev->port); + return -EALREADY; + } + if (req.flags & (1 << RFCOMM_HANGUP_NOW)) rfcomm_dlc_close(dev->dlc, 0); @@ -433,8 +441,7 @@ static int rfcomm_release_dev(void __user *arg) tty_kref_put(tty); } - if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) && - !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags)) + if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) tty_port_put(&dev->port); tty_port_put(&dev->port); |