Bluetooth: add annotations for l2cap_data locking context

Add context analysis annotations for hci_conn::l2cap_data locking.

Also add necessary lockdep_assert_held() and __must_hold annotations
to prove the access is safe.

The access in smp_conn_security() is supposed to be guarded by the
caller holding lock that blocks concurrent l2cap_conn_del() eg.
hdev->lock, conn->lock or chan->lock. Mark unsafe as can't be
automatically checked now.

Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Pauli Virtanen
2026-08-01 21:37:24 +03:00
committed by Luiz Augusto von Dentz
parent 2b66c83ff1
commit b80de2cbb1
6 changed files with 24 additions and 4 deletions

View File

@@ -775,7 +775,7 @@ struct hci_conn {
struct hci_dev *hdev;
spinlock_t proto_lock; /* lock guarding protocol data */
void *l2cap_data;
void *l2cap_data __guarded_by(&proto_lock, &hdev->lock);
void *sco_data;
void *iso_data __guarded_by(&proto_lock);

View File

@@ -1007,6 +1007,8 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
return -ENOENT;
}
lockdep_assert_held(&hcon->hdev->lock);
*conn = l2cap_conn_hold_unless_zero(hcon->l2cap_data);
BT_DBG("conn %p dst %pMR type %u", *conn, &hcon->dst, hcon->dst_type);

View File

@@ -1791,6 +1791,7 @@ static void l2cap_unregister_all_users(struct l2cap_conn *conn)
}
static void l2cap_conn_del(struct hci_conn *hcon, int err)
__must_hold(&hcon->hdev->lock)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_chan *chan, *l;
@@ -7153,6 +7154,7 @@ static void process_pending_rx(struct work_struct *work)
}
static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
__must_hold(&hcon->hdev->lock)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct hci_chan *hchan;
@@ -7358,6 +7360,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
goto done;
}
lockdep_assert_held(&hcon->hdev->lock);
conn = l2cap_conn_add(hcon);
if (!conn) {
hci_conn_drop(hcon);
@@ -7528,6 +7532,7 @@ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c,
}
static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
__must_hold(&hcon->hdev->lock)
{
struct hci_dev *hdev = hcon->hdev;
struct l2cap_conn *conn;
@@ -7603,6 +7608,7 @@ int l2cap_disconn_ind(struct hci_conn *hcon)
}
static void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
__must_hold(&hcon->hdev->lock)
{
if (hcon->type != ACL_LINK && hcon->type != LE_LINK)
return;
@@ -7630,6 +7636,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
}
static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
__must_hold(&hcon->hdev->lock)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_chan *chan;
@@ -7814,6 +7821,8 @@ int l2cap_recv_acldata(struct hci_dev *hdev, u16 handle,
return -ENOENT;
}
lockdep_assert_held(&hcon->hdev->lock);
hci_conn_enter_active_mode(hcon, BT_POWER_FORCE_ACTIVE_OFF);
conn = hcon->l2cap_data;

View File

@@ -3876,6 +3876,8 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
}
if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
lockdep_assert_held(&conn->hdev->lock);
err = smp_user_confirm_reply(conn, mgmt_op, passkey);
if (!err)
err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,

View File

@@ -2327,12 +2327,15 @@ static void smp_send_security_req(struct smp_chan *smp, __u8 auth)
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct l2cap_conn *conn;
struct l2cap_chan *chan;
struct smp_chan *smp;
__u8 authreq;
int ret;
/* Caller shall ensure there can be no race with l2cap_conn_del() */
conn = context_unsafe(hcon->l2cap_data);
bt_dev_dbg(hcon->hdev, "conn %p hcon %p level 0x%2.2x", conn, hcon,
sec_level);
@@ -2421,6 +2424,8 @@ int smp_cancel_and_remove_pairing(struct hci_dev *hdev, bdaddr_t *bdaddr,
if (!hcon)
goto done;
lockdep_assert_held(&hcon->hdev->lock);
conn = hcon->l2cap_data;
if (!conn)
goto done;

View File

@@ -180,11 +180,13 @@ enum smp_key_pref {
/* SMP Commands */
int smp_cancel_and_remove_pairing(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 addr_type);
u8 addr_type)
__must_hold(&hdev->lock);
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level,
enum smp_key_pref key_pref);
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey)
__must_hold(&conn->hdev->lock);
bool smp_irk_matches(struct hci_dev *hdev, const u8 irk[16],
const bdaddr_t *bdaddr);