aboutsummaryrefslogtreecommitdiffstats
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 16:39:29 -0500
commit1c64834e0624c61735308138e67cc3b527f41621 (patch)
tree912156866fbaa316a2197f261646737f95a88e57
parent960603a54aa0d5f4f1c4f1037bcaee571d03cb1e (diff)
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>
-rw-r--r--include/net/bluetooth/rfcomm.h6
-rw-r--r--net/bluetooth/rfcomm/tty.c11
2 files changed, 14 insertions, 3 deletions
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index c312cfc4e922..b9759eb17cdd 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -324,11 +324,15 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel,
324#define RFCOMMGETDEVINFO _IOR('R', 211, int) 324#define RFCOMMGETDEVINFO _IOR('R', 211, int)
325#define RFCOMMSTEALDLC _IOW('R', 220, int) 325#define RFCOMMSTEALDLC _IOW('R', 220, int)
326 326
327/* rfcomm_dev.flags bit definitions */
327#define RFCOMM_REUSE_DLC 0 328#define RFCOMM_REUSE_DLC 0
328#define RFCOMM_RELEASE_ONHUP 1 329#define RFCOMM_RELEASE_ONHUP 1
329#define RFCOMM_HANGUP_NOW 2 330#define RFCOMM_HANGUP_NOW 2
330#define RFCOMM_TTY_ATTACHED 3 331#define RFCOMM_TTY_ATTACHED 3
331#define RFCOMM_TTY_RELEASED 4 332#define RFCOMM_DEFUNCT_BIT4 4 /* don't reuse this bit - userspace visible */
333
334/* rfcomm_dev.status bit definitions */
335#define RFCOMM_DEV_RELEASED 0
332 336
333struct rfcomm_dev_req { 337struct rfcomm_dev_req {
334 s16 dev_id; 338 s16 dev_id;
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 {
51 unsigned long flags; 51 unsigned long flags;
52 int err; 52 int err;
53 53
54 unsigned long status; /* don't export to userspace */
55
54 bdaddr_t src; 56 bdaddr_t src;
55 bdaddr_t dst; 57 bdaddr_t dst;
56 u8 channel; 58 u8 channel;
@@ -423,6 +425,12 @@ static int rfcomm_release_dev(void __user *arg)
423 return -EPERM; 425 return -EPERM;
424 } 426 }
425 427
428 /* only release once */
429 if (test_and_set_bit(RFCOMM_DEV_RELEASED, &dev->status)) {
430 tty_port_put(&dev->port);
431 return -EALREADY;
432 }
433
426 if (req.flags & (1 << RFCOMM_HANGUP_NOW)) 434 if (req.flags & (1 << RFCOMM_HANGUP_NOW))
427 rfcomm_dlc_close(dev->dlc, 0); 435 rfcomm_dlc_close(dev->dlc, 0);
428 436
@@ -433,8 +441,7 @@ static int rfcomm_release_dev(void __user *arg)
433 tty_kref_put(tty); 441 tty_kref_put(tty);
434 } 442 }
435 443
436 if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) && 444 if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
437 !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
438 tty_port_put(&dev->port); 445 tty_port_put(&dev->port);
439 446
440 tty_port_put(&dev->port); 447 tty_port_put(&dev->port);