Commit 1c64834e authored by Peter Hurley's avatar Peter Hurley Committed by Marcel Holtmann

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: default avatarPeter Hurley <peter@hurleysoftware.com>
Tested-By: default avatarAlexander Holler <holler@ahsoftware.de>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 960603a5
...@@ -324,11 +324,15 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, ...@@ -324,11 +324,15 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel,
#define RFCOMMGETDEVINFO _IOR('R', 211, int) #define RFCOMMGETDEVINFO _IOR('R', 211, int)
#define RFCOMMSTEALDLC _IOW('R', 220, int) #define RFCOMMSTEALDLC _IOW('R', 220, int)
/* rfcomm_dev.flags bit definitions */
#define RFCOMM_REUSE_DLC 0 #define RFCOMM_REUSE_DLC 0
#define RFCOMM_RELEASE_ONHUP 1 #define RFCOMM_RELEASE_ONHUP 1
#define RFCOMM_HANGUP_NOW 2 #define RFCOMM_HANGUP_NOW 2
#define RFCOMM_TTY_ATTACHED 3 #define RFCOMM_TTY_ATTACHED 3
#define RFCOMM_TTY_RELEASED 4 #define RFCOMM_DEFUNCT_BIT4 4 /* don't reuse this bit - userspace visible */
/* rfcomm_dev.status bit definitions */
#define RFCOMM_DEV_RELEASED 0
struct rfcomm_dev_req { struct rfcomm_dev_req {
s16 dev_id; s16 dev_id;
......
...@@ -51,6 +51,8 @@ struct rfcomm_dev { ...@@ -51,6 +51,8 @@ struct rfcomm_dev {
unsigned long flags; unsigned long flags;
int err; int err;
unsigned long status; /* don't export to userspace */
bdaddr_t src; bdaddr_t src;
bdaddr_t dst; bdaddr_t dst;
u8 channel; u8 channel;
...@@ -423,6 +425,12 @@ static int rfcomm_release_dev(void __user *arg) ...@@ -423,6 +425,12 @@ static int rfcomm_release_dev(void __user *arg)
return -EPERM; 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)) if (req.flags & (1 << RFCOMM_HANGUP_NOW))
rfcomm_dlc_close(dev->dlc, 0); rfcomm_dlc_close(dev->dlc, 0);
...@@ -433,8 +441,7 @@ static int rfcomm_release_dev(void __user *arg) ...@@ -433,8 +441,7 @@ static int rfcomm_release_dev(void __user *arg)
tty_kref_put(tty); tty_kref_put(tty);
} }
if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) && if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
!test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
tty_port_put(&dev->port); tty_port_put(&dev->port);
tty_port_put(&dev->port); tty_port_put(&dev->port);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment