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:
Yousef Alhouseen
2026-06-28 02:50:58 +02:00
committed by Luiz Augusto von Dentz
parent 0f8a5dcc66
commit bb067a99a0

View File

@@ -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;