mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
Bluetooth: bnep: pin L2CAP connection during netdev registration
bnep_add_connection() reads the L2CAP connection without holding the
channel lock, then passes its HCI device to register_netdev(). Controller
teardown can clear and release that connection concurrently, leaving the
network device registration path to dereference a freed parent device.
Take a reference to the L2CAP connection while holding the channel lock.
Retain it until register_netdev() has taken the parent device reference.
Fixes: 65f53e9802 ("Bluetooth: Access BNEP session addresses through L2CAP channel")
Reported-by: syzbot+fed5dce4553262f3b35c@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=fed5dce4553262f3b35c
Cc: stable@vger.kernel.org
Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
committed by
Luiz Augusto von Dentz
parent
0f8a5dcc66
commit
bb067a99a0
@@ -559,14 +559,18 @@ static int bnep_session(void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct device *bnep_get_device(struct bnep_session *session)
|
||||
static struct l2cap_conn *bnep_get_conn(struct bnep_session *session)
|
||||
{
|
||||
struct l2cap_conn *conn = l2cap_pi(session->sock->sk)->chan->conn;
|
||||
struct l2cap_chan *chan = l2cap_pi(session->sock->sk)->chan;
|
||||
struct l2cap_conn *conn;
|
||||
|
||||
if (!conn || !conn->hcon)
|
||||
return NULL;
|
||||
l2cap_chan_lock(chan);
|
||||
conn = chan->conn;
|
||||
if (conn)
|
||||
l2cap_conn_get(conn);
|
||||
l2cap_chan_unlock(chan);
|
||||
|
||||
return &conn->hcon->dev;
|
||||
return conn;
|
||||
}
|
||||
|
||||
static const struct device_type bnep_type = {
|
||||
@@ -578,6 +582,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
|
||||
u32 valid_flags = BIT(BNEP_SETUP_RESPONSE);
|
||||
struct net_device *dev;
|
||||
struct bnep_session *s, *ss;
|
||||
struct l2cap_conn *conn = NULL;
|
||||
u8 dst[ETH_ALEN], src[ETH_ALEN];
|
||||
int err;
|
||||
|
||||
@@ -637,10 +642,18 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
|
||||
bnep_set_default_proto_filter(s);
|
||||
#endif
|
||||
|
||||
SET_NETDEV_DEV(dev, bnep_get_device(s));
|
||||
conn = bnep_get_conn(s);
|
||||
if (!conn) {
|
||||
err = -ENOTCONN;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
SET_NETDEV_DEV(dev, &conn->hcon->dev);
|
||||
SET_NETDEV_DEVTYPE(dev, &bnep_type);
|
||||
|
||||
err = register_netdev(dev);
|
||||
l2cap_conn_put(conn);
|
||||
conn = NULL;
|
||||
if (err)
|
||||
goto failed;
|
||||
|
||||
@@ -662,6 +675,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
if (conn)
|
||||
l2cap_conn_put(conn);
|
||||
up_write(&bnep_session_sem);
|
||||
free_netdev(dev);
|
||||
return err;
|
||||
|
||||
Reference in New Issue
Block a user