summaryrefslogtreecommitdiff
path: root/net/bluetooth
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2014-02-09 20:59:07 -0500
committerMarcel Holtmann <marcel@holtmann.org>2014-02-14 13:39:29 -0800
commit1c64834e0624c61735308138e67cc3b527f41621 (patch)
tree912156866fbaa316a2197f261646737f95a88e57 /net/bluetooth
parent960603a54aa0d5f4f1c4f1037bcaee571d03cb1e (diff)
downloadlwn-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')
-rw-r--r--net/bluetooth/rfcomm/tty.c11
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);