* [PATCH] Bluetooth: hci_core: add lockdep check to hci_conn lookups
@ 2026-07-11 14:29 Pauli Virtanen
2026-07-11 15:43 ` bluez.test.bot
0 siblings, 1 reply; 2+ messages in thread
From: Pauli Virtanen @ 2026-07-11 14:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen, marcel, luiz.dentz, linux-kernel
Add lockdep check for RCU || hdev->lock in hci_conn_hash lookups that
return hci_conn pointer, as dereferencing that without locks can be
TOCTOU issue. It used to be several callsites did not hold appropriate
locks.
The check is equivalent to removing rcu_read_lock() and doing instead
list_for_each_entry_rcu(c, &h->list, list, lockdep_is_held(&hdev->lock))
Although there should not be any remaining callsites without locks,
don't remove the rcu_read_lock() for now, and just add the warning here.
Signed-off-by: Pauli Virtanen <pav@iki.fi>
---
Notes:
The patch series recently merged in bluetooth-next/master added the
locks at remaining callsites, so we should be able to turn this on.
Unfortunately, Context analysis can't do the RCU || hdev->lock
check here as it can't OR lock requirements except in __guarded_by,
so we can only add the lockdep check.
It can however be used for checking the callsites: I added
__must_hold(&hdev->lock) annotation to the lookups, and manually went
through the warnings and checked if RCU was held at the callsite. Based
on this, I did not find any remaining callsites in current code that
would emit these lockdep splats.
include/net/bluetooth/hci_core.h | 44 ++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e7133ff87fbf..211810788a11 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1012,6 +1012,9 @@ static inline bool hci_conn_sc_enabled(struct hci_conn *conn)
static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
{
struct hci_conn_hash *h = &hdev->conn_hash;
+
+ lockdep_assert_held(&hdev->lock);
+
list_add_tail_rcu(&c->list, &h->list);
switch (c->type) {
case ACL_LINK:
@@ -1042,6 +1045,8 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
{
struct hci_conn_hash *h = &hdev->conn_hash;
+ lockdep_assert_held(&hdev->lock);
+
list_del_rcu(&c->list);
synchronize_rcu();
@@ -1070,6 +1075,15 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
}
}
+#ifdef CONFIG_PROVE_RCU
+#define HCI_CONN_HASH_LOCKDEP_CHECK(hdev) \
+ RCU_LOCKDEP_WARN(!lockdep_is_held(&(hdev)->lock) && \
+ !rcu_read_lock_held(), \
+ "suspicious hci_conn locking")
+#else
+#define HCI_CONN_HASH_LOCKDEP_CHECK(hdev) do { } while (0 && (hdev))
+#endif
+
static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
{
struct hci_conn_hash *h = &hdev->conn_hash;
@@ -1151,6 +1165,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_bis(struct hci_dev *hdev,
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1173,6 +1189,8 @@ hci_conn_hash_lookup_create_pa_sync(struct hci_dev *hdev)
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1199,6 +1217,8 @@ hci_conn_hash_lookup_per_adv_bis(struct hci_dev *hdev,
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1223,6 +1243,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1242,6 +1264,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1263,6 +1287,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_role(struct hci_dev *hdev,
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1284,6 +1310,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_le(struct hci_dev *hdev,
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1310,6 +1338,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_cis(struct hci_dev *hdev,
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1342,6 +1372,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_cig(struct hci_dev *hdev,
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1365,6 +1397,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev,
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1389,6 +1423,8 @@ hci_conn_hash_lookup_big_sync_pend(struct hci_dev *hdev,
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1413,6 +1449,8 @@ hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state,
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1436,6 +1474,8 @@ hci_conn_hash_lookup_pa_sync_big_handle(struct hci_dev *hdev, __u8 big)
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1459,6 +1499,8 @@ hci_conn_hash_lookup_pa_sync_handle(struct hci_dev *hdev, __u16 sync_handle)
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -1528,6 +1570,8 @@ static inline struct hci_conn *hci_lookup_le_connect(struct hci_dev *hdev)
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
+ HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
+
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
--
2.55.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* RE: Bluetooth: hci_core: add lockdep check to hci_conn lookups
2026-07-11 14:29 [PATCH] Bluetooth: hci_core: add lockdep check to hci_conn lookups Pauli Virtanen
@ 2026-07-11 15:43 ` bluez.test.bot
0 siblings, 0 replies; 2+ messages in thread
From: bluez.test.bot @ 2026-07-11 15:43 UTC (permalink / raw)
To: linux-bluetooth, pav
[-- Attachment #1: Type: text/plain, Size: 2615 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1125861
---Test result---
Test Summary:
CheckPatch PASS 0.56 seconds
VerifyFixes PASS 0.10 seconds
VerifySignedoff PASS 0.10 seconds
GitLint FAIL 0.24 seconds
SubjectPrefix PASS 0.09 seconds
BuildKernel PASS 19.71 seconds
CheckAllWarning PASS 21.72 seconds
CheckSparse PASS 20.86 seconds
BuildKernel32 PASS 19.14 seconds
CheckKernelLLVM SKIP 0.00 seconds
TestRunnerSetup PASS 356.51 seconds
TestRunner_l2cap-tester PASS 47.17 seconds
TestRunner_iso-tester PASS 71.15 seconds
TestRunner_bnep-tester PASS 14.28 seconds
TestRunner_mgmt-tester FAIL 168.46 seconds
TestRunner_rfcomm-tester PASS 19.39 seconds
TestRunner_sco-tester PASS 25.51 seconds
TestRunner_ioctl-tester PASS 21.28 seconds
TestRunner_mesh-tester FAIL 20.49 seconds
TestRunner_smp-tester PASS 17.79 seconds
TestRunner_userchan-tester PASS 15.24 seconds
TestRunner_6lowpan-tester PASS 17.40 seconds
IncrementalBuild PASS 18.77 seconds
Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
Bluetooth: hci_core: add lockdep check to hci_conn lookups
19: B2 Line has trailing whitespace: " "
23: B2 Line has trailing whitespace: " "
##############################
Test: CheckKernelLLVM - SKIP
Desc: Build kernel with LLVM + context analysis
Output:
Clang not found
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 494, Passed: 489 (99.0%), Failed: 1, Not Run: 4
Failed Test Cases
Read Exp Feature - Success Failed 0.179 seconds
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0
Failed Test Cases
Mesh - Send cancel - 1 Timed out 2.047 seconds
Mesh - Send cancel - 2 Timed out 1.990 seconds
https://github.com/bluez/bluetooth-next/pull/425
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-11 15:43 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-11 14:29 [PATCH] Bluetooth: hci_core: add lockdep check to hci_conn lookups Pauli Virtanen
2026-07-11 15:43 ` bluez.test.bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox