syzbot


ID Workflow Result Correct Bug Created Started Finished Revision Error
e9f9712f-37cc-4d04-b648-45d0442ddfb8 assessment-kcsan Benign: ❌  Confident: ✅  KCSAN: data-race in bacpy / memcmp 2026/02/13 12:59 2026/02/13 13:13 2026/02/13 13:20 54290dbc8f9e8d4533df2bb39cf823e93897fb2c
Decision History:
Time User Decision
2026/02/21 20:02 dvyukov@google.com

Benign: ❌    Confident: ✅   

Explanation:
The data race occurs between `l2cap_sock_bind()` and `l2cap_sock_connect()` on the same Bluetooth socket. 

In `l2cap_sock_bind()`, the socket lock (`lock_sock(sk)`) is held while the source address (`chan->src`) and its type (`chan->src_type`) are being updated:
```c
132:    bacpy(&chan->src, &la.l2_bdaddr);
133:    chan->src_type = la.l2_bdaddr_type;
```

In `l2cap_sock_connect()`, the socket lock is acquired and then immediately released:
```c
192:    lock_sock(sk);
193:    zapped = sock_flag(sk, SOCK_ZAPPED);
194:    release_sock(sk);
```
Later, it accesses `chan->src` and `chan->src_type` without holding the lock:
```c
218:    if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) &&
219:        bdaddr_type_is_le(la.l2_bdaddr_type)) {
...
236:        chan->src_type = BDADDR_LE_PUBLIC;
237:    }
```
And it calls `l2cap_chan_connect(chan, ...)` which also reads these fields.

Because `l2cap_sock_connect()` does not hold the socket lock during these checks, it can race with a concurrent `l2cap_sock_bind()` call. Since `chan->src` is a 6-byte structure (`bdaddr_t`), a race can result in `l2cap_sock_connect()` reading a partially written or inconsistent address. This inconsistent data is used to make decisions about address type "fix-ups" and is used for routing the connection in `hci_get_route()`.

This race is harmful because:
1. It involves a multi-byte structure that is not accessed atomically.
2. It can lead to incorrect kernel logic and connection failures (e.g., failing to find a route to the Bluetooth device).
3. The fields are intended to be protected by the socket lock, but `l2cap_sock_connect()` fails to maintain that protection during its validation and setup phase.
4. It is not a simple statistic or flag, but core connection parameters.

While it may not lead to a kernel crash or memory corruption, it is a functional bug in the protocol implementation caused by a lack of proper synchronization.

Crash report:
==================================================================
BUG: KCSAN: data-race in bacpy / memcmp

write to 0xffff888199203818 of 6 bytes by task 18359 on cpu 1:
 bacpy+0x1e/0x30 include/net/bluetooth/bluetooth.h:380
 l2cap_sock_bind+0x275/0x5b0 net/bluetooth/l2cap_sock.c:132
 __sys_bind_socket net/socket.c:1874 [inline]
 __sys_bind+0x1d0/0x290 net/socket.c:1905
 __do_sys_bind net/socket.c:1910 [inline]
 __se_sys_bind net/socket.c:1908 [inline]
 __x64_sys_bind+0x3f/0x50 net/socket.c:1908
 x64_sys_call+0x2ceb/0x3000 arch/x86/include/generated/asm/syscalls_64.h:50
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xc0/0x2a0 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

read to 0xffff88819920381b of 1 bytes by task 18360 on cpu 0:
 memcmp+0x52/0x90 lib/string.c:694
 memcmp include/linux/fortify-string.h:727 [inline]
 bacmp+0x1e/0x30 include/net/bluetooth/bluetooth.h:376
 l2cap_sock_connect+0x25a/0x4c0 net/bluetooth/l2cap_sock.c:218
 __sys_connect_file net/socket.c:2089 [inline]
 __sys_connect+0x1f1/0x2a0 net/socket.c:2108
 __do_sys_connect net/socket.c:2114 [inline]
 __se_sys_connect net/socket.c:2111 [inline]
 __x64_sys_connect+0x3f/0x50 net/socket.c:2111
 x64_sys_call+0x2e09/0x3000 arch/x86/include/generated/asm/syscalls_64.h:43
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xc0/0x2a0 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

value changed: 0x00 -> 0xff

Reported by Kernel Concurrency Sanitizer on:
CPU: 0 UID: 0 PID: 18360 Comm: syz.0.12425 Tainted: G        W           syzkaller #0 PREEMPT(voluntary) 
Tainted: [W]=WARN
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/24/2026
==================================================================

Trajectory:
Seq Timestamp Type Name Duration
0/0 2026/02/13 13:13 flow assessment-kcsan
6m Results:
map[Benign:false Confident:true Explanation:The data race occurs between `l2cap_sock_bind()` and `l2cap_sock_connect()` on the same Bluetooth socket. 

In `l2cap_sock_bind()`, the socket lock (`lock_sock(sk)`) is held while the source address (`chan->src`) and its type (`chan->src_type`) are being updated:
```c
132:    bacpy(&chan->src, &la.l2_bdaddr);
133:    chan->src_type = la.l2_bdaddr_type;
```

In `l2cap_sock_connect()`, the socket lock is acquired and then immediately released:
```c
192:    lock_sock(sk);
193:    zapped = sock_flag(sk, SOCK_ZAPPED);
194:    release_sock(sk);
```
Later, it accesses `chan->src` and `chan->src_type` without holding the lock:
```c
218:    if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) &&
219:        bdaddr_type_is_le(la.l2_bdaddr_type)) {
...
236:        chan->src_type = BDADDR_LE_PUBLIC;
237:    }
```
And it calls `l2cap_chan_connect(chan, ...)` which also reads these fields.

Because `l2cap_sock_connect()` does not hold the socket lock during these checks, it can race with a concurrent `l2cap_sock_bind()` call. Since `chan->src` is a 6-byte structure (`bdaddr_t`), a race can result in `l2cap_sock_connect()` reading a partially written or inconsistent address. This inconsistent data is used to make decisions about address type "fix-ups" and is used for routing the connection in `hci_get_route()`.

This race is harmful because:
1. It involves a multi-byte structure that is not accessed atomically.
2. It can lead to incorrect kernel logic and connection failures (e.g., failing to find a route to the Bluetooth device).
3. The fields are intended to be protected by the socket lock, but `l2cap_sock_connect()` fails to maintain that protection during its validation and setup phase.
4. It is not a simple statistic or flag, but core connection parameters.

While it may not lead to a kernel crash or memory corruption, it is a functional bug in the protocol implementation caused by a lack of proper synchronization.]

1/1 2026/02/13 13:13 action kernel-checkouter
0m Results:
map[KernelSrc:/usr/local/google/home/dvyukov/syzkaller/agent/workdir/cache/src/3eb9d021cd2314b4bfa83fd102abcdf74ea2e8fa]

2/1 2026/02/13 13:13 action kernel-builder
0m Results:
map[KernelObj:/usr/local/google/home/dvyukov/syzkaller/agent/workdir/cache/build/b3136ccdf9bebca7cb1e2755d466d30eb3959d08]

3/1 2026/02/13 13:13 action codesearch-prepare
3m Results:
map[Index:codesearch-index]

4/1 2026/02/13 13:16 agent expert
3m Model:
gemini-3-flash-preview

Results:
map[Benign:false Confident:true]

Instruction:
You are an experienced Linux kernel developer tasked with determining if the given kernel
data race is benign or not. The data race report is from KCSAN tool.
It contains 2 stack traces of the memory accesses that constitute a data race.

A "benign" data races are on a simple int/bool variable or similar field,
and the accesses are not supposed to be protected by any mutual exclusion primitives.
Common examples of such "benign" data races are accesses to various flags fields,
statistics counters, and similar. A "benign" data race does not lead to memory corruption/crash
with a conservative compiler that compiles memory accesses to primitive types
effectively as atomic.

A non-benign (or "harmful" data race) can lead to corruption/crash even with
a conservative compiler that compiles memory accesses to primitive types
effectively as atomic. A common example of a "harmful" data races is race on
a complex container (list/hashmap/etc), where accesses are supposed to be protected
by a mutual exclusion primitive.

Also consider races that happen at the same time with the given one.
If there is no synchronization in between, other memory accesses in the involved threads
race with each other if they access the same memory. For example, if both threads execute:

	some_struct->have_elements = true;
	list_add(new_node, &some_struct->list_head);

the race on some_struct->have_elements may appear benign, however it also implies there
is a race on some_struct->list_head which is not benign, since the list is not thread-safe.

Take into account that on 32-bit systems 64-bit memory accesses may be split into two accesses,
and thus even with a conservative compiler may not be fully atomic. However, such races may
still be benign depending on how writes are done, and how read data is used.

In the final reply explain why you think the given data race is benign or is harmful.

Use the provided tools to confirm any assumptions, variables/fields being accessed, etc.
In particular, don't make assumptions about the kernel source code,
use codesearch tools to read the actual source code.

Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
The data race report is:

==================================================================
BUG: KCSAN: data-race in bacpy / memcmp

write to 0xffff888199203818 of 6 bytes by task 18359 on cpu 1:
 bacpy+0x1e/0x30 include/net/bluetooth/bluetooth.h:380
 l2cap_sock_bind+0x275/0x5b0 net/bluetooth/l2cap_sock.c:132
 __sys_bind_socket net/socket.c:1874 [inline]
 __sys_bind+0x1d0/0x290 net/socket.c:1905
 __do_sys_bind net/socket.c:1910 [inline]
 __se_sys_bind net/socket.c:1908 [inline]
 __x64_sys_bind+0x3f/0x50 net/socket.c:1908
 x64_sys_call+0x2ceb/0x3000 arch/x86/include/generated/asm/syscalls_64.h:50
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xc0/0x2a0 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

read to 0xffff88819920381b of 1 bytes by task 18360 on cpu 0:
 memcmp+0x52/0x90 lib/string.c:694
 memcmp include/linux/fortify-string.h:727 [inline]
 bacmp+0x1e/0x30 include/net/bluetooth/bluetooth.h:376
 l2cap_sock_connect+0x25a/0x4c0 net/bluetooth/l2cap_sock.c:218
 __sys_connect_file net/socket.c:2089 [inline]
 __sys_connect+0x1f1/0x2a0 net/socket.c:2108
 __do_sys_connect net/socket.c:2114 [inline]
 __se_sys_connect net/socket.c:2111 [inline]
 __x64_sys_connect+0x3f/0x50 net/socket.c:2111
 x64_sys_call+0x2e09/0x3000 arch/x86/include/generated/asm/syscalls_64.h:43
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xc0/0x2a0 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

value changed: 0x00 -> 0xff

Reported by Kernel Concurrency Sanitizer on:
CPU: 0 UID: 0 PID: 18360 Comm: syz.0.12425 Tainted: G        W           syzkaller #0 PREEMPT(voluntary) 
Tainted: [W]=WARN
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/24/2026
==================================================================


Reply:
The data race occurs between `l2cap_sock_bind()` and `l2cap_sock_connect()` on the same Bluetooth socket. 

In `l2cap_sock_bind()`, the socket lock (`lock_sock(sk)`) is held while the source address (`chan->src`) and its type (`chan->src_type`) are being updated:
```c
132:    bacpy(&chan->src, &la.l2_bdaddr);
133:    chan->src_type = la.l2_bdaddr_type;
```

In `l2cap_sock_connect()`, the socket lock is acquired and then immediately released:
```c
192:    lock_sock(sk);
193:    zapped = sock_flag(sk, SOCK_ZAPPED);
194:    release_sock(sk);
```
Later, it accesses `chan->src` and `chan->src_type` without holding the lock:
```c
218:    if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) &&
219:        bdaddr_type_is_le(la.l2_bdaddr_type)) {
...
236:        chan->src_type = BDADDR_LE_PUBLIC;
237:    }
```
And it calls `l2cap_chan_connect(chan, ...)` which also reads these fields.

Because `l2cap_sock_connect()` does not hold the socket lock during these checks, it can race with a concurrent `l2cap_sock_bind()` call. Since `chan->src` is a 6-byte structure (`bdaddr_t`), a race can result in `l2cap_sock_connect()` reading a partially written or inconsistent address. This inconsistent data is used to make decisions about address type "fix-ups" and is used for routing the connection in `hci_get_route()`.

This race is harmful because:
1. It involves a multi-byte structure that is not accessed atomically.
2. It can lead to incorrect kernel logic and connection failures (e.g., failing to find a route to the Bluetooth device).
3. The fields are intended to be protected by the socket lock, but `l2cap_sock_connect()` fails to maintain that protection during its validation and setup phase.
4. It is not a simple statistic or flag, but core connection parameters.

While it may not lead to a kernel crash or memory corruption, it is a functional bug in the protocol implementation caused by a lack of proper synchronization.

5/2 2026/02/13 13:16 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 3922
							output: 174
							thoughts: 229
						

Thoughts:
**Analyzing a Data Race in Bluetooth Socket Operations**

Okay, so the report indicates a classic data race – `bacpy` writing while `memcmp` reads. That's never good. The write is happening within `l2cap_sock_bind`, and the read is triggered by `l2cap_sock_connect`. The specific addresses are `0xffff888199203818` for the write, 6 bytes, and `0xffff88819920381b` for the read, 1 byte. And it looks like a value flipped from `0x00` to `0xff` during the race.

My immediate thought is to dive into the code. Time to check `include/net/bluetooth/bluetooth.h` for the definitions of `bacpy` and `bacmp`, and trace back the callers, `l2cap_sock_bind` and `l2cap_sock_connect`. I'm betting `bacpy` is some sort of Bluetooth address copy – likely 6 bytes since the report indicates a 6-byte write – and `bacmp` is its comparison. It's almost certainly a Bluetooth address field within some structure that's the culprit here.

Okay, let's get the code up and start digging.



6/2 2026/02/13 13:16 tool codesearch-definition-source
0m Args:
map[ContextFile:include/net/bluetooth/bluetooth.h IncludeLines:true Name:bacpy]

Results:
map[SourceCode: 378:	static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
 379:	{
 380:		memcpy(dst, src, sizeof(bdaddr_t));
 381:	}
 SourceFile:include/net/bluetooth/bluetooth.h]

7/2 2026/02/13 13:16 tool codesearch-definition-source
0m Args:
map[ContextFile:include/net/bluetooth/bluetooth.h IncludeLines:true Name:bacmp]

Results:
map[SourceCode: 373:	/* Copy, swap, convert BD Address */
 374:	static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
 375:	{
 376:		return memcmp(ba1, ba2, sizeof(bdaddr_t));
 377:	}
 SourceFile:include/net/bluetooth/bluetooth.h]

8/2 2026/02/13 13:16 tool codesearch-definition-source
0m Args:
map[ContextFile:net/bluetooth/l2cap_sock.c IncludeLines:true Name:l2cap_sock_bind]

Results:
map[SourceCode:  83:	static int l2cap_sock_bind(struct socket *sock, struct sockaddr_unsized *addr, int alen)
  84:	{
  85:		struct sock *sk = sock->sk;
  86:		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
  87:		struct sockaddr_l2 la;
  88:		int len, err = 0;
  89:	
  90:		BT_DBG("sk %p", sk);
  91:	
  92:		if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
  93:		    addr->sa_family != AF_BLUETOOTH)
  94:			return -EINVAL;
  95:	
  96:		memset(&la, 0, sizeof(la));
  97:		len = min_t(unsigned int, sizeof(la), alen);
  98:		memcpy(&la, addr, len);
  99:	
 100:		if (la.l2_cid && la.l2_psm)
 101:			return -EINVAL;
 102:	
 103:		if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
 104:			return -EINVAL;
 105:	
 106:		if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
 107:			/* We only allow ATT user space socket */
 108:			if (la.l2_cid &&
 109:			    la.l2_cid != cpu_to_le16(L2CAP_CID_ATT))
 110:				return -EINVAL;
 111:		}
 112:	
 113:		lock_sock(sk);
 114:	
 115:		if (sk->sk_state != BT_OPEN) {
 116:			err = -EBADFD;
 117:			goto done;
 118:		}
 119:	
 120:		if (la.l2_psm) {
 121:			__u16 psm = __le16_to_cpu(la.l2_psm);
 122:	
 123:			if (la.l2_bdaddr_type == BDADDR_BREDR)
 124:				err = l2cap_validate_bredr_psm(psm);
 125:			else
 126:				err = l2cap_validate_le_psm(psm);
 127:	
 128:			if (err)
 129:				goto done;
 130:		}
 131:	
 132:		bacpy(&chan->src, &la.l2_bdaddr);
 133:		chan->src_type = la.l2_bdaddr_type;
 134:	
 135:		if (la.l2_cid)
 136:			err = l2cap_add_scid(chan, __le16_to_cpu(la.l2_cid));
 137:		else
 138:			err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm);
 139:	
 140:		if (err < 0)
 141:			goto done;
 142:	
 143:		switch (chan->chan_type) {
 144:		case L2CAP_CHAN_CONN_LESS:
 145:			if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_3DSP)
 146:				chan->sec_level = BT_SECURITY_SDP;
 147:			break;
 148:		case L2CAP_CHAN_CONN_ORIENTED:
 149:			if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_SDP ||
 150:			    __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM)
 151:				chan->sec_level = BT_SECURITY_SDP;
 152:			break;
 153:		case L2CAP_CHAN_RAW:
 154:			chan->sec_level = BT_SECURITY_SDP;
 155:			break;
 156:		case L2CAP_CHAN_FIXED:
 157:			/* Fixed channels default to the L2CAP core not holding a
 158:			 * hci_conn reference for them. For fixed channels mapping to
 159:			 * L2CAP sockets we do want to hold a reference so set the
 160:			 * appropriate flag to request it.
 161:			 */
 162:			set_bit(FLAG_HOLD_HCI_CONN, &chan->flags);
 163:			break;
 164:		}
 165:	
 166:		/* Use L2CAP_MODE_LE_FLOWCTL (CoC) in case of LE address and
 167:		 * L2CAP_MODE_EXT_FLOWCTL (ECRED) has not been set.
 168:		 */
 169:		if (chan->psm && bdaddr_type_is_le(chan->src_type) &&
 170:		    chan->mode != L2CAP_MODE_EXT_FLOWCTL)
 171:			chan->mode = L2CAP_MODE_LE_FLOWCTL;
 172:	
 173:		chan->state = BT_BOUND;
 174:		sk->sk_state = BT_BOUND;
 175:	
 176:	done:
 177:		release_sock(sk);
 178:		return err;
 179:	}
 SourceFile:net/bluetooth/l2cap_sock.c]

9/2 2026/02/13 13:16 tool codesearch-definition-source
0m Args:
map[ContextFile:net/bluetooth/l2cap_sock.c IncludeLines:true Name:l2cap_sock_connect]

Results:
map[SourceCode: 181:	static int l2cap_sock_connect(struct socket *sock, struct sockaddr_unsized *addr,
 182:				      int alen, int flags)
 183:	{
 184:		struct sock *sk = sock->sk;
 185:		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 186:		struct sockaddr_l2 la;
 187:		int len, err = 0;
 188:		bool zapped;
 189:	
 190:		BT_DBG("sk %p", sk);
 191:	
 192:		lock_sock(sk);
 193:		zapped = sock_flag(sk, SOCK_ZAPPED);
 194:		release_sock(sk);
 195:	
 196:		if (zapped)
 197:			return -EINVAL;
 198:	
 199:		if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
 200:		    addr->sa_family != AF_BLUETOOTH)
 201:			return -EINVAL;
 202:	
 203:		memset(&la, 0, sizeof(la));
 204:		len = min_t(unsigned int, sizeof(la), alen);
 205:		memcpy(&la, addr, len);
 206:	
 207:		if (la.l2_cid && la.l2_psm)
 208:			return -EINVAL;
 209:	
 210:		if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
 211:			return -EINVAL;
 212:	
 213:		/* Check that the socket wasn't bound to something that
 214:		 * conflicts with the address given to connect(). If chan->src
 215:		 * is BDADDR_ANY it means bind() was never used, in which case
 216:		 * chan->src_type and la.l2_bdaddr_type do not need to match.
 217:		 */
 218:		if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) &&
 219:		    bdaddr_type_is_le(la.l2_bdaddr_type)) {
 220:			/* Old user space versions will try to incorrectly bind
 221:			 * the ATT socket using BDADDR_BREDR. We need to accept
 222:			 * this and fix up the source address type only when
 223:			 * both the source CID and destination CID indicate
 224:			 * ATT. Anything else is an invalid combination.
 225:			 */
 226:			if (chan->scid != L2CAP_CID_ATT ||
 227:			    la.l2_cid != cpu_to_le16(L2CAP_CID_ATT))
 228:				return -EINVAL;
 229:	
 230:			/* We don't have the hdev available here to make a
 231:			 * better decision on random vs public, but since all
 232:			 * user space versions that exhibit this issue anyway do
 233:			 * not support random local addresses assuming public
 234:			 * here is good enough.
 235:			 */
 236:			chan->src_type = BDADDR_LE_PUBLIC;
 237:		}
 238:	
 239:		if (chan->src_type != BDADDR_BREDR && la.l2_bdaddr_type == BDADDR_BREDR)
 240:			return -EINVAL;
 241:	
 242:		if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
 243:			/* We only allow ATT user space socket */
 244:			if (la.l2_cid &&
 245:			    la.l2_cid != cpu_to_le16(L2CAP_CID_ATT))
 246:				return -EINVAL;
 247:		}
 248:	
 249:		/* Use L2CAP_MODE_LE_FLOWCTL (CoC) in case of LE address and
 250:		 * L2CAP_MODE_EXT_FLOWCTL (ECRED) has not been set.
 251:		 */
 252:		if (chan->psm && bdaddr_type_is_le(chan->src_type) &&
 253:		    chan->mode != L2CAP_MODE_EXT_FLOWCTL)
 254:			chan->mode = L2CAP_MODE_LE_FLOWCTL;
 255:	
 256:		err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid),
 257:					 &la.l2_bdaddr, la.l2_bdaddr_type,
 258:					 READ_ONCE(sk->sk_sndtimeo));
 259:		if (err)
 260:			return err;
 261:	
 262:		lock_sock(sk);
 263:	
 264:		err = bt_sock_wait_state(sk, BT_CONNECTED,
 265:					 sock_sndtimeo(sk, flags & O_NONBLOCK));
 266:	
 267:		release_sock(sk);
 268:	
 269:		return err;
 270:	}
 SourceFile:net/bluetooth/l2cap_sock.c]

10/2 2026/02/13 13:16 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 7905
							output: 47
							thoughts: 913
						

Thoughts:
**Race Condition in L2CAP Socket Binding and Connection**

Okay, so I'm looking at this L2CAP code, specifically `l2cap_sock_bind` and `l2cap_sock_connect`. I'm seeing a potential race condition here, and it's making me a little uneasy.

In `l2cap_sock_bind`, the code writes to `chan->src` and `chan->src_type`, which is fine because it's protected by `lock_sock(sk)`. But in `l2cap_sock_connect`, the code *reads* from `chan->src` *after* releasing the lock. And that's where the problem arises: the read is *not* protected. It releases the lock immediately, then accesses `chan->src`.

It seems that `chan` is part of the `l2cap_pinfo` associated with the socket `sk`. So, if one thread calls `bind` on a socket while another thread calls `connect` on the same socket concurrently, we have a race. A classic bind/connect on the same socket is a bit unusual, but it's valid.

`l2cap_sock_connect` is trying to check if the socket was already bound, looking at `chan->src`. If `bind` is running simultaneously, the write to `chan->src` in `bind` might not be complete when `bacmp` in `connect` reads it. Now `BDADDR_ANY` is all zeros, so if `bacpy` is in the process of writing the source address, `bacmp` might see a partially written address. This is dangerous.

The potential damage here is in the `if` block condition. It checks `chan->src_type` first, which is assigned *after* `chan->src`. If `connect` sees `chan->src_type == BDADDR_BREDR` (which is likely the default) and `bacmp(&chan->src, BDADDR_ANY)` is true, it might try to "fix up" the source address type.

Specifically, if the address starts as `BDADDR_ANY` and `bind` is updating it, `bacmp` might return true, and it enters the block.

My intuition says that if the application does this, it's undefined behavior for the application. The kernel should be robust enough to handle this without crashing or ending up in an inconsistent state, but it still feels wrong. The critical issue is that the socket lock isn't held for the entire duration of the connection attempt. The function calls `l2cap_chan_connect(chan, ...)` later on, and I'd better check what's going on in that function. It is possible that `chan` is protected there, but I need to investigate.



11/2 2026/02/13 13:16 tool codesearch-definition-source
0m Args:
map[ContextFile:net/bluetooth/l2cap_core.c IncludeLines:true Name:l2cap_chan_connect]

Results:
map[SourceCode:6966:	int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
6967:			       bdaddr_t *dst, u8 dst_type, u16 timeout)
6968:	{
6969:		struct l2cap_conn *conn;
6970:		struct hci_conn *hcon;
6971:		struct hci_dev *hdev;
6972:		int err;
6973:	
6974:		BT_DBG("%pMR -> %pMR (type %u) psm 0x%4.4x mode 0x%2.2x", &chan->src,
6975:		       dst, dst_type, __le16_to_cpu(psm), chan->mode);
6976:	
6977:		hdev = hci_get_route(dst, &chan->src, chan->src_type);
6978:		if (!hdev)
6979:			return -EHOSTUNREACH;
6980:	
6981:		hci_dev_lock(hdev);
6982:	
6983:		if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid &&
6984:		    chan->chan_type != L2CAP_CHAN_RAW) {
6985:			err = -EINVAL;
6986:			goto done;
6987:		}
6988:	
6989:		if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !psm) {
6990:			err = -EINVAL;
6991:			goto done;
6992:		}
6993:	
6994:		if (chan->chan_type == L2CAP_CHAN_FIXED && !cid) {
6995:			err = -EINVAL;
6996:			goto done;
6997:		}
6998:	
6999:		switch (chan->mode) {
7000:		case L2CAP_MODE_BASIC:
7001:			break;
7002:		case L2CAP_MODE_LE_FLOWCTL:
7003:			break;
7004:		case L2CAP_MODE_EXT_FLOWCTL:
7005:			if (!enable_ecred) {
7006:				err = -EOPNOTSUPP;
7007:				goto done;
7008:			}
7009:			break;
7010:		case L2CAP_MODE_ERTM:
7011:		case L2CAP_MODE_STREAMING:
7012:			if (!disable_ertm)
7013:				break;
7014:			fallthrough;
7015:		default:
7016:			err = -EOPNOTSUPP;
7017:			goto done;
7018:		}
7019:	
7020:		switch (chan->state) {
7021:		case BT_CONNECT:
7022:		case BT_CONNECT2:
7023:		case BT_CONFIG:
7024:			/* Already connecting */
7025:			err = 0;
7026:			goto done;
7027:	
7028:		case BT_CONNECTED:
7029:			/* Already connected */
7030:			err = -EISCONN;
7031:			goto done;
7032:	
7033:		case BT_OPEN:
7034:		case BT_BOUND:
7035:			/* Can connect */
7036:			break;
7037:	
7038:		default:
7039:			err = -EBADFD;
7040:			goto done;
7041:		}
7042:	
7043:		/* Set destination address and psm */
7044:		bacpy(&chan->dst, dst);
7045:		chan->dst_type = dst_type;
7046:	
7047:		chan->psm = psm;
7048:		chan->dcid = cid;
7049:	
7050:		if (bdaddr_type_is_le(dst_type)) {
7051:			/* Convert from L2CAP channel address type to HCI address type
7052:			 */
7053:			if (dst_type == BDADDR_LE_PUBLIC)
7054:				dst_type = ADDR_LE_DEV_PUBLIC;
7055:			else
7056:				dst_type = ADDR_LE_DEV_RANDOM;
7057:	
7058:			if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
7059:				hcon = hci_connect_le(hdev, dst, dst_type, false,
7060:						      chan->sec_level, timeout,
7061:						      HCI_ROLE_SLAVE, 0, 0);
7062:			else
7063:				hcon = hci_connect_le_scan(hdev, dst, dst_type,
7064:							   chan->sec_level, timeout,
7065:							   CONN_REASON_L2CAP_CHAN);
7066:	
7067:		} else {
7068:			u8 auth_type = l2cap_get_auth_type(chan);
7069:			hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type,
7070:					       CONN_REASON_L2CAP_CHAN, timeout);
7071:		}
7072:	
7073:		if (IS_ERR(hcon)) {
7074:			err = PTR_ERR(hcon);
7075:			goto done;
7076:		}
7077:	
7078:		conn = l2cap_conn_add(hcon);
7079:		if (!conn) {
7080:			hci_conn_drop(hcon);
7081:			err = -ENOMEM;
7082:			goto done;
7083:		}
7084:	
7085:		if (chan->mode == L2CAP_MODE_EXT_FLOWCTL) {
7086:			struct l2cap_chan_data data;
7087:	
7088:			data.chan = chan;
7089:			data.pid = chan->ops->get_peer_pid(chan);
7090:			data.count = 1;
7091:	
7092:			l2cap_chan_list(conn, l2cap_chan_by_pid, &data);
7093:	
7094:			/* Check if there isn't too many channels being connected */
7095:			if (data.count > L2CAP_ECRED_CONN_SCID_MAX) {
7096:				hci_conn_drop(hcon);
7097:				err = -EPROTO;
7098:				goto done;
7099:			}
7100:		}
7101:	
7102:		mutex_lock(&conn->lock);
7103:		l2cap_chan_lock(chan);
7104:	
7105:		if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
7106:			hci_conn_drop(hcon);
7107:			err = -EBUSY;
7108:			goto chan_unlock;
7109:		}
7110:	
7111:		/* Update source addr of the socket */
7112:		bacpy(&chan->src, &hcon->src);
7113:		chan->src_type = bdaddr_src_type(hcon);
7114:	
7115:		__l2cap_chan_add(conn, chan);
7116:	
7117:		/* l2cap_chan_add takes its own ref so we can drop this one */
7118:		hci_conn_drop(hcon);
7119:	
7120:		l2cap_state_change(chan, BT_CONNECT);
7121:		__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
7122:	
7123:		/* Release chan->sport so that it can be reused by other
7124:		 * sockets (as it's only used for listening sockets).
7125:		 */
7126:		write_lock(&chan_list_lock);
7127:		chan->sport = 0;
7128:		write_unlock(&chan_list_lock);
7129:	
7130:		if (hcon->state == BT_CONNECTED) {
7131:			if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
7132:				__clear_chan_timer(chan);
7133:				if (l2cap_chan_check_security(chan, true))
7134:					l2cap_state_change(chan, BT_CONNECTED);
7135:			} else
7136:				l2cap_do_start(chan);
7137:		}
7138:	
7139:		err = 0;
7140:	
7141:	chan_unlock:
7142:		l2cap_chan_unlock(chan);
7143:		mutex_unlock(&conn->lock);
7144:	done:
7145:		hci_dev_unlock(hdev);
7146:		hci_dev_put(hdev);
7147:		return err;
7148:	}
 SourceFile:net/bluetooth/l2cap_core.c]

12/2 2026/02/13 13:16 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 12115
							output: 43
							thoughts: 1728
						

Thoughts:
**Analysis of Potential Race Condition in L2CAP Socket Binding and Connection**

Okay, so I've been looking at this code, and it seems like there's a potential race condition between `l2cap_sock_bind` and `l2cap_sock_connect`. Specifically, the issue revolves around concurrent access to `chan->src` and `chan->src_type`, which are both part of the L2CAP channel structure associated with a socket.

The core of the problem stems from the fact that `l2cap_sock_connect` reads `chan->src` and potentially modifies `chan->src_type` without holding the socket lock. Meanwhile, `l2cap_sock_bind` writes to `chan->src` and `chan->src_type`, and it *does* hold the lock.

Here's the breakdown of what I'm seeing:

*   In `l2cap_sock_bind`, the code writes the local Bluetooth address to `chan->src` and sets the corresponding address type:
    ```c
    bacpy(&chan->src, &la.l2_bdaddr);
    chan->src_type = la.l2_bdaddr_type;
    ```
*   In `l2cap_sock_connect`, the code reads `chan->src` and makes a potentially problematic check:
    ```c
    if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) &&
        bdaddr_type_is_le(la.l2_bdaddr_type)) {
        chan->src_type = BDADDR_LE_PUBLIC;
    }
    ```
    This check is intended to fix up the address type for legacy user space versions, but it's done *without* holding the socket lock. This means if `bind` and `connect` run concurrently, `connect` might read a partially-written value of `chan->src`. The `bacmp` function, which is just `memcmp`, could return true if any part of the address has been written to a non-zero value, leading to incorrect fix-up of `chan->src_type`.

*   Crucially, `l2cap_sock_connect` calls `l2cap_chan_connect` *after* the potentially unsafe check, also without holding the lock. This is worrying because `l2cap_chan_connect` calls `hci_get_route` which uses `chan->src`.

The race manifests because `l2cap_sock_connect` doesn't hold `lock_sock(sk)` during these operations. This is a clear oversight, as `chan` fields should be protected by the socket lock when accessed by multiple socket functions.

Let's examine the potential scenarios:

1.  **Partial Write of `chan->src`:** If `connect` reads `chan->src` while `bind` is in the middle of writing it, the comparison `bacmp(&chan->src, BDADDR_ANY)` could return true prematurely. The KCSAN report indicates a byte changing from `0` to `0xff`, which is a classic symptom of this. This can trigger the "fix up" logic, which might incorrectly set `chan->src_type` to `BDADDR_LE_PUBLIC`.
2.  **Inconsistent State:** If `connect` runs between the `bacpy` and the `chan->src_type` assignment in `bind`, it might see the new source address, but the old source type. This can lead to a similar incorrect fix-up.
3.  **Garbage Address to `hci_get_route`:** If `hci_get_route` is called by `l2cap_chan_connect` while `bind` is changing the address, `hci_get_route` will see a garbage address and route packets incorrectly.

While the user is in "weird" territory if calling bind and connect concurrently, the kernel *must* remain consistent.

The "fix-up" code is designed to handle older user space versions that might incorrectly use `BDADDR_BREDR` for LE connections. However, the race makes the fix-up unreliable.

The key flaw is the missing lock in `l2cap_sock_connect` and the fact that `l2cap_chan_connect` calls `hci_get_route` without the lock. This is a critical bug. It's unsafe because it can lead to incorrect routing and, in certain cases, could lead to security issues if the address is not properly validated.

I need to dig into this more deeply to quantify the risk and find the best way to resolve the race, ideally by adding the necessary locks and ensuring all accesses to `chan` are protected.


13/2 2026/02/13 13:17 tool codesearch-definition-source
0m Args:
map[ContextFile:net/bluetooth/hci_core.c IncludeLines:true Name:hci_get_route]

Results:
map[SourceCode:1240:	struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type)
1241:	{
1242:		int use_src = bacmp(src, BDADDR_ANY);
1243:		struct hci_dev *hdev = NULL, *d;
1244:	
1245:		BT_DBG("%pMR -> %pMR", src, dst);
1246:	
1247:		read_lock(&hci_dev_list_lock);
1248:	
1249:		list_for_each_entry(d, &hci_dev_list, list) {
1250:			if (!test_bit(HCI_UP, &d->flags) ||
1251:			    hci_dev_test_flag(d, HCI_USER_CHANNEL))
1252:				continue;
1253:	
1254:			/* Simple routing:
1255:			 *   No source address - find interface with bdaddr != dst
1256:			 *   Source address    - find interface with bdaddr == src
1257:			 */
1258:	
1259:			if (use_src) {
1260:				bdaddr_t id_addr;
1261:				u8 id_addr_type;
1262:	
1263:				if (src_type == BDADDR_BREDR) {
1264:					if (!lmp_bredr_capable(d))
1265:						continue;
1266:					bacpy(&id_addr, &d->bdaddr);
1267:					id_addr_type = BDADDR_BREDR;
1268:				} else {
1269:					if (!lmp_le_capable(d))
1270:						continue;
1271:	
1272:					hci_copy_identity_address(d, &id_addr,
1273:								  &id_addr_type);
1274:	
1275:					/* Convert from HCI to three-value type */
1276:					if (id_addr_type == ADDR_LE_DEV_PUBLIC)
1277:						id_addr_type = BDADDR_LE_PUBLIC;
1278:					else
1279:						id_addr_type = BDADDR_LE_RANDOM;
1280:				}
1281:	
1282:				if (!bacmp(&id_addr, src) && id_addr_type == src_type) {
1283:					hdev = d; break;
1284:				}
1285:			} else {
1286:				if (bacmp(&d->bdaddr, dst)) {
1287:					hdev = d; break;
1288:				}
1289:			}
1290:		}
1291:	
1292:		if (hdev)
1293:			hdev = hci_dev_hold(hdev);
1294:	
1295:		read_unlock(&hci_dev_list_lock);
1296:		return hdev;
1297:	}
 SourceFile:net/bluetooth/hci_conn.c]

14/2 2026/02/13 13:17 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 15784
							output: 86
							thoughts: 745
						

Thoughts:
**Analyzing a Potential Race Condition in L2CAP Connection Establishment**

Okay, let's break this down. I'm looking at the `hci_get_route` function and I see a potential race condition arising from the way it accesses the `src` address, specifically `&chan->src`. If a concurrent `bind` operation is writing to `chan->src` while `hci_get_route` is reading it, we could end up with a corrupted address. This could lead to `hci_get_route` either failing to find the correct HCI device (`hdev`) or, worse, finding the wrong one. A failure here results in `l2cap_chan_connect` returning `-EHOSTUNREACH`.

The core issue seems to be that `l2cap_sock_connect` doesn't hold `lock_sock(sk)` while calling `l2cap_chan_connect`. This absence of locking exposes several `chan` fields to potential race conditions.

I'm puzzled by the early release of the socket lock in `l2cap_sock_connect`:

```c
 192:		lock_sock(sk);
 193:		zapped = sock_flag(sk, SOCK_ZAPPED);
 194:		release_sock(sk);
```

It looks like the only reason to acquire the lock initially is to check `SOCK_ZAPPED`. Most other `connect` implementations, like `inet_stream_connect`, hold the socket lock for the entire duration of the connection attempt.

I need to investigate if holding the lock throughout `l2cap_sock_connect` is feasible. However, keeping the lock might block for a while if `l2cap_chan_connect` blocks, and `l2cap_chan_connect` does call `hci_connect_le` or `hci_connect_acl`, which may involve sending HCI commands.

But, `l2cap_chan_connect` itself doesn't seem to block on network I/O; it just *initiates* the connection. The actual waiting for the connection to complete happens later in `l2cap_sock_connect`:

```c
 264:		err = bt_sock_wait_state(sk, BT_CONNECTED,
 265:					 sock_sndtimeo(sk, flags & O_NONBLOCK));
```

And `bt_sock_wait_state` *does* handle the lock. So, why release it so early?

Looking at `l2cap_sock_bind`, it holds the lock throughout, which is what I would expect. If `l2cap_sock_connect` were to hold the lock from line 192 until line 262 (when it reacquires it), this race condition would be eliminated.

However, a critical point, I need to check for potential deadlocks. `l2cap_chan_connect` also takes `hci_dev_lock(hdev)` and `l2cap_chan_lock(chan)`. If `l2cap_sock_connect` held `lock_sock(sk)` the whole time, would this create a deadlock scenario? `lock_sock(sk)` is a mutex (at least in its behavior).

I think I need to look at other Bluetooth socket types, `rfcomm_sock_connect`, `sco_sock_connect`, to see if they follow the same locking strategy or if they provide any useful insight to avoid the potential deadlock. I'll get back to this after that investigation.



15/2 2026/02/13 13:17 tool codesearch-definition-source
0m Error:
requested entity does not exist

Args:
map[ContextFile:net/bluetooth/rfcomm/sock.c IncludeLines:true Name:rfcomm_sock_connect]

Results:
map[SourceCode: SourceFile:]

16/2 2026/02/13 13:17 tool codesearch-definition-source
0m Args:
map[ContextFile:net/bluetooth/sco.c IncludeLines:true Name:sco_sock_connect]

Results:
map[SourceCode: 642:	static int sco_sock_connect(struct socket *sock, struct sockaddr_unsized *addr, int alen, int flags)
 643:	{
 644:		struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
 645:		struct sock *sk = sock->sk;
 646:		int err;
 647:	
 648:		BT_DBG("sk %p", sk);
 649:	
 650:		if (alen < sizeof(struct sockaddr_sco) ||
 651:		    addr->sa_family != AF_BLUETOOTH)
 652:			return -EINVAL;
 653:	
 654:		if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
 655:			return -EBADFD;
 656:	
 657:		if (sk->sk_type != SOCK_SEQPACKET)
 658:			err = -EINVAL;
 659:	
 660:		lock_sock(sk);
 661:		/* Set destination address and psm */
 662:		bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr);
 663:		release_sock(sk);
 664:	
 665:		err = sco_connect(sk);
 666:		if (err)
 667:			return err;
 668:	
 669:		lock_sock(sk);
 670:	
 671:		err = bt_sock_wait_state(sk, BT_CONNECTED,
 672:					 sock_sndtimeo(sk, flags & O_NONBLOCK));
 673:	
 674:		release_sock(sk);
 675:		return err;
 676:	}
 SourceFile:net/bluetooth/sco.c]

17/2 2026/02/13 13:17 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 17919
							output: 25
							thoughts: 73
						

Thoughts:
Here's my take on the situation:

**Reflecting on Bluetooth Socket Connection Logic**

Okay, so `sco_sock_connect` is releasing the lock *before* it calls `sco_connect`. That's a good thing, keeps the connection process nimble, but it makes me wonder if there's a broader pattern here I should review. Now, I have to mentally re-calibrate. I *think* I saw something similar with `l2cap_sock_connect` recently, didn't I? Or was it something related? Hmm... need to double-check my mental map here.

Let's not take anything for granted. I'm going to revisit `rfcomm_sock_connect`. Best to confirm the code path and ensure my understanding is spot on. I’m pretty sure it’s in `net/bluetooth/rfcomm/sock.c`, but let’s just verify before diving in. Need to have all my ducks in a row for this investigation.



18/2 2026/02/13 13:17 tool codesearch-dir-index
0m Args:
map[Dir:net/bluetooth/rfcomm/]

Results:
map[Files:[core.c sock.c tty.c] Subdirs:<nil>]

19/2 2026/02/13 13:17 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 18263
							output: 45
							thoughts: 21
						

Thoughts:
Okay, here's the summary, assuming I'm a seasoned expert working on `net/bluetooth/rfcomm/sock.c`:

**RFCOMM Socket Source Code Analysis - Attempt #2**

Alright, back at it. Looks like I'm taking another look at `net/bluetooth/rfcomm/sock.c`. Let's see if I can get this figured out. I need to understand what's happening here, specifically related to… well, everything, frankly. Time to dive back in and refresh my understanding of the data flow and how the RFCOMM socket interacts with the lower layers. Perhaps a fresh perspective will reveal the issue this time around.



20/2 2026/02/13 13:17 tool codesearch-definition-source
0m Error:
requested entity does not exist

Args:
map[ContextFile:net/bluetooth/rfcomm/sock.c IncludeLines:true Name:rfcomm_sock_connect]

Results:
map[SourceCode: SourceFile:]

21/2 2026/02/13 13:17 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 18490
							output: 29
							thoughts: 21
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Debugging a Potential RFCOMM Socket Connection Issue**

Alright, so I'm digging into this `rfcomm_sock_connect` function. It *feels* off, like maybe that's not the actual name of the function I'm dealing with. My initial gut feeling is that something about the naming convention doesn't align with what I'd expect given the context. Given my experience, I'm already starting to think about potential variations in naming that might be used internally, or perhaps an abstraction layer that's hiding the underlying implementation detail. The point is, I need to verify that I'm referencing the right thing. Therefore, rather than jumping to assumptions I should go directly to the source. Right now, I'm heading over to the relevant source file to double-check the actual function definition and ensure that the name aligns with my mental model. Time to go spelunking in the code.



22/2 2026/02/13 13:17 tool codesearch-file-index
0m Args:
map[SourceFile:net/bluetooth/rfcomm/sock.c]

Results:
map[Entities:<nil>]

23/2 2026/02/13 13:17 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 18763
							output: 25
							thoughts: 37
						

Thoughts:
Okay, here's my interpretation of those thoughts, tailored for an expert audience, as if they were my own:

**Investigating a Bluetooth Socket Search Anomaly**

Well, that's peculiar. I was expecting `codesearch-file-index` to flag something in `net/bluetooth/rfcomm/sock.c`, but it's returning a blank result. That's not right. This is usually my go-to for a quick file lookup. Something's clearly off with the indexing.

Alright, time to get more direct. Let me try `read-file` directly on the target file. Bypass the index and see if there's an actual problem with the file's contents, or if the indexing tool just has an issue. Let's see if the file is where I expect it to be and what its contents are. This suggests either a search index corruption, or a location mismatch.



24/2 2026/02/13 13:17 tool read-file
0m Args:
map[File:net/bluetooth/rfcomm/sock.c]

Results:
map[Contents:/*
   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 2 as
   published by the Free Software Foundation;

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
   SOFTWARE IS DISCLAIMED.
*/

/*
 * RFCOMM sockets.
 */
#include <linux/compat.h>
#include <linux/export.h>
#include <linux/debugfs.h>
#include <linux/sched/signal.h>

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/rfcomm.h>

static const struct proto_ops rfcomm_sock_ops;

static struct bt_sock_list rfcomm_sk_list = {
	.lock = __RW_LOCK_UNLOCKED(rfcomm_sk_list.lock)
};

static void rfcomm_sock_close(struct sock *sk);
static void rfcomm_sock_kill(struct sock *sk);

/* ---- DLC callbacks ----
 *
 * called under rfcomm_dlc_lock()
 */
static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
{
	struct sock *sk = d->owner;
	if (!sk)
		return;

	atomic_add(skb->len, &sk->sk_rmem_alloc);
	skb_queue_tail(&sk->sk_receive_queue, skb);
	sk->sk_data_ready(sk);

	if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
		rfcomm_dlc_throttle(d);
}

static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
{
	struct sock *sk = d->owner, *parent;

	if (!sk)
		return;

	BT_DBG("dlc %p state %ld err %d", d, d->state, err);

	lock_sock(sk);

	if (err)
		sk->sk_err = err;

	sk->sk_state = d->state;

	parent = bt_sk(sk)->parent;
	if (parent) {
		if (d->state == BT_CLOSED) {
			sock_set_flag(sk, SOCK_ZAPPED);
			bt_accept_unlink(sk);
		}
		parent->sk_data_ready(parent);
	} else {
		if (d->state == BT_CONNECTED)
			rfcomm_session_getaddr(d->session,
					       &rfcomm_pi(sk)->src, NULL);
		sk->sk_state_change(sk);
	}

	release_sock(sk);

	if (parent && sock_flag(sk, SOCK_ZAPPED)) {
		/* We have to drop DLC lock here, otherwise
		 * rfcomm_sock_destruct() will dead lock. */
		rfcomm_dlc_unlock(d);
		rfcomm_sock_kill(sk);
		rfcomm_dlc_lock(d);
	}
}

/* ---- Socket functions ---- */
static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src)
{
	struct sock *sk = NULL;

	sk_for_each(sk, &rfcomm_sk_list.head) {
		if (rfcomm_pi(sk)->channel != channel)
			continue;

		if (bacmp(&rfcomm_pi(sk)->src, src))
			continue;

		if (sk->sk_state == BT_BOUND || sk->sk_state == BT_LISTEN)
			break;
	}

	return sk ? sk : NULL;
}

/* Find socket with channel and source bdaddr.
 * Returns closest match.
 */
static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
{
	struct sock *sk = NULL, *sk1 = NULL;

	read_lock(&rfcomm_sk_list.lock);

	sk_for_each(sk, &rfcomm_sk_list.head) {
		if (state && sk->sk_state != state)
			continue;

		if (rfcomm_pi(sk)->channel == channel) {
			/* Exact match. */
			if (!bacmp(&rfcomm_pi(sk)->src, src))
				break;

			/* Closest match */
			if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY))
				sk1 = sk;
		}
	}

	read_unlock(&rfcomm_sk_list.lock);

	return sk ? sk : sk1;
}

static void rfcomm_sock_destruct(struct sock *sk)
{
	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;

	BT_DBG("sk %p dlc %p", sk, d);

	skb_queue_purge(&sk->sk_receive_queue);
	skb_queue_purge(&sk->sk_write_queue);

	rfcomm_dlc_lock(d);
	rfcomm_pi(sk)->dlc = NULL;

	/* Detach DLC if it's owned by this socket */
	if (d->owner == sk)
		d->owner = NULL;
	rfcomm_dlc_unlock(d);

	rfcomm_dlc_put(d);
}

static void rfcomm_sock_cleanup_listen(struct sock *parent)
{
	struct sock *sk;

	BT_DBG("parent %p", parent);

	/* Close not yet accepted dlcs */
	while ((sk = bt_accept_dequeue(parent, NULL))) {
		rfcomm_sock_close(sk);
		rfcomm_sock_kill(sk);
	}

	parent->sk_state  = BT_CLOSED;
	sock_set_flag(parent, SOCK_ZAPPED);
}

/* Kill socket (only if zapped and orphan)
 * Must be called on unlocked socket.
 */
static void rfcomm_sock_kill(struct sock *sk)
{
	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
		return;

	BT_DBG("sk %p state %d refcnt %d", sk, sk->sk_state, refcount_read(&sk->sk_refcnt));

	/* Kill poor orphan */
	bt_sock_unlink(&rfcomm_sk_list, sk);
	sock_set_flag(sk, SOCK_DEAD);
	sock_put(sk);
}

static void __rfcomm_sock_close(struct sock *sk)
{
	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;

	BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);

	switch (sk->sk_state) {
	case BT_LISTEN:
		rfcomm_sock_cleanup_listen(sk);
		break;

	case BT_CONNECT:
	case BT_CONNECT2:
	case BT_CONFIG:
	case BT_CONNECTED:
		rfcomm_dlc_close(d, 0);
		fallthrough;

	default:
		sock_set_flag(sk, SOCK_ZAPPED);
		break;
	}
}

/* Close socket.
 * Must be called on unlocked socket.
 */
static void rfcomm_sock_close(struct sock *sk)
{
	lock_sock(sk);
	__rfcomm_sock_close(sk);
	release_sock(sk);
}

static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
{
	struct rfcomm_pinfo *pi = rfcomm_pi(sk);

	BT_DBG("sk %p", sk);

	if (parent) {
		sk->sk_type = parent->sk_type;
		pi->dlc->defer_setup = test_bit(BT_SK_DEFER_SETUP,
						&bt_sk(parent)->flags);

		pi->sec_level = rfcomm_pi(parent)->sec_level;
		pi->role_switch = rfcomm_pi(parent)->role_switch;

		security_sk_clone(parent, sk);
	} else {
		pi->dlc->defer_setup = 0;

		pi->sec_level = BT_SECURITY_LOW;
		pi->role_switch = 0;
	}

	pi->dlc->sec_level = pi->sec_level;
	pi->dlc->role_switch = pi->role_switch;
}

static struct proto rfcomm_proto = {
	.name		= "RFCOMM",
	.owner		= THIS_MODULE,
	.obj_size	= sizeof(struct rfcomm_pinfo)
};

static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock,
				      int proto, gfp_t prio, int kern)
{
	struct rfcomm_dlc *d;
	struct sock *sk;

	d = rfcomm_dlc_alloc(prio);
	if (!d)
		return NULL;

	sk = bt_sock_alloc(net, sock, &rfcomm_proto, proto, prio, kern);
	if (!sk) {
		rfcomm_dlc_free(d);
		return NULL;
	}

	d->data_ready   = rfcomm_sk_data_ready;
	d->state_change = rfcomm_sk_state_change;

	rfcomm_pi(sk)->dlc = d;
	d->owner = sk;

	sk->sk_destruct = rfcomm_sock_destruct;
	sk->sk_sndtimeo = RFCOMM_CONN_TIMEOUT;

	sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
	sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;

	bt_sock_link(&rfcomm_sk_list, sk);

	BT_DBG("sk %p", sk);
	return sk;
}

static int rfcomm_sock_create(struct net *net, struct socket *sock,
			      int protocol, int kern)
{
	struct sock *sk;

	BT_DBG("sock %p", sock);

	sock->state = SS_UNCONNECTED;

	if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW)
		return -ESOCKTNOSUPPORT;

	sock->ops = &rfcomm_sock_ops;

	sk = rfcomm_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern);
	if (!sk)
		return -ENOMEM;

	rfcomm_sock_init(sk, NULL);
	return 0;
}

static int rfcomm_sock_bind(struct socket *sock, struct sockaddr_unsized *addr, int addr_len)
{
	struct sockaddr_rc sa;
	struct sock *sk = sock->sk;
	int len, err = 0;

	if (!addr || addr_len < offsetofend(struct sockaddr, sa_family) ||
	    addr->sa_family != AF_BLUETOOTH)
		return -EINVAL;

	memset(&sa, 0, sizeof(sa));
	len = min_t(unsigned int, sizeof(sa), addr_len);
	memcpy(&sa, addr, len);

	BT_DBG("sk %p %pMR", sk, &sa.rc_bdaddr);

	lock_sock(sk);

	if (sk->sk_state != BT_OPEN) {
		err = -EBADFD;
		goto done;
	}

	if (sk->sk_type != SOCK_STREAM) {
		err = -EINVAL;
		goto done;
	}

	write_lock(&rfcomm_sk_list.lock);

	if (sa.rc_channel &&
	    __rfcomm_get_listen_sock_by_addr(sa.rc_channel, &sa.rc_bdaddr)) {
		err = -EADDRINUSE;
	} else {
		/* Save source address */
		bacpy(&rfcomm_pi(sk)->src, &sa.rc_bdaddr);
		rfcomm_pi(sk)->channel = sa.rc_channel;
		sk->sk_state = BT_BOUND;
	}

	write_unlock(&rfcomm_sk_list.lock);

done:
	release_sock(sk);
	return err;
}

static int rfcomm_sock_connect(struct socket *sock, struct sockaddr_unsized *addr,
			       int alen, int flags)
{
	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
	struct sock *sk = sock->sk;
	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
	int err = 0;

	BT_DBG("sk %p", sk);

	if (alen < sizeof(struct sockaddr_rc) ||
	    addr->sa_family != AF_BLUETOOTH)
		return -EINVAL;

	sock_hold(sk);
	lock_sock(sk);

	if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
		err = -EBADFD;
		goto done;
	}

	if (sk->sk_type != SOCK_STREAM) {
		err = -EINVAL;
		goto done;
	}

	sk->sk_state = BT_CONNECT;
	bacpy(&rfcomm_pi(sk)->dst, &sa->rc_bdaddr);
	rfcomm_pi(sk)->channel = sa->rc_channel;

	d->sec_level = rfcomm_pi(sk)->sec_level;
	d->role_switch = rfcomm_pi(sk)->role_switch;

	/* Drop sock lock to avoid potential deadlock with the RFCOMM lock */
	release_sock(sk);
	err = rfcomm_dlc_open(d, &rfcomm_pi(sk)->src, &sa->rc_bdaddr,
			      sa->rc_channel);
	lock_sock(sk);
	if (!err && !sock_flag(sk, SOCK_ZAPPED))
		err = bt_sock_wait_state(sk, BT_CONNECTED,
				sock_sndtimeo(sk, flags & O_NONBLOCK));

done:
	release_sock(sk);
	sock_put(sk);
	return err;
}

static int rfcomm_sock_listen(struct socket *sock, int backlog)
{
	struct sock *sk = sock->sk;
	int err = 0;

	BT_DBG("sk %p backlog %d", sk, backlog);

	lock_sock(sk);

	if (sk->sk_state != BT_BOUND) {
		err = -EBADFD;
		goto done;
	}

	if (sk->sk_type != SOCK_STREAM) {
		err = -EINVAL;
		goto done;
	}

	if (!rfcomm_pi(sk)->channel) {
		bdaddr_t *src = &rfcomm_pi(sk)->src;
		u8 channel;

		err = -EINVAL;

		write_lock(&rfcomm_sk_list.lock);

		for (channel = 1; channel < 31; channel++)
			if (!__rfcomm_get_listen_sock_by_addr(channel, src)) {
				rfcomm_pi(sk)->channel = channel;
				err = 0;
				break;
			}

		write_unlock(&rfcomm_sk_list.lock);

		if (err < 0)
			goto done;
	}

	sk->sk_max_ack_backlog = backlog;
	sk->sk_ack_backlog = 0;
	sk->sk_state = BT_LISTEN;

done:
	release_sock(sk);
	return err;
}

static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock,
			      struct proto_accept_arg *arg)
{
	DEFINE_WAIT_FUNC(wait, woken_wake_function);
	struct sock *sk = sock->sk, *nsk;
	long timeo;
	int err = 0;

	lock_sock_nested(sk, SINGLE_DEPTH_NESTING);

	if (sk->sk_type != SOCK_STREAM) {
		err = -EINVAL;
		goto done;
	}

	timeo = sock_rcvtimeo(sk, arg->flags & O_NONBLOCK);

	BT_DBG("sk %p timeo %ld", sk, timeo);

	/* Wait for an incoming connection. (wake-one). */
	add_wait_queue_exclusive(sk_sleep(sk), &wait);
	while (1) {
		if (sk->sk_state != BT_LISTEN) {
			err = -EBADFD;
			break;
		}

		nsk = bt_accept_dequeue(sk, newsock);
		if (nsk)
			break;

		if (!timeo) {
			err = -EAGAIN;
			break;
		}

		if (signal_pending(current)) {
			err = sock_intr_errno(timeo);
			break;
		}

		release_sock(sk);

		timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);

		lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
	}
	remove_wait_queue(sk_sleep(sk), &wait);

	if (err)
		goto done;

	newsock->state = SS_CONNECTED;

	BT_DBG("new socket %p", nsk);

done:
	release_sock(sk);
	return err;
}

static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int peer)
{
	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
	struct sock *sk = sock->sk;

	BT_DBG("sock %p, sk %p", sock, sk);

	if (peer && sk->sk_state != BT_CONNECTED &&
	    sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2)
		return -ENOTCONN;

	memset(sa, 0, sizeof(*sa));
	sa->rc_family  = AF_BLUETOOTH;
	sa->rc_channel = rfcomm_pi(sk)->channel;
	if (peer)
		bacpy(&sa->rc_bdaddr, &rfcomm_pi(sk)->dst);
	else
		bacpy(&sa->rc_bdaddr, &rfcomm_pi(sk)->src);

	return sizeof(struct sockaddr_rc);
}

static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg,
			       size_t len)
{
	struct sock *sk = sock->sk;
	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
	struct sk_buff *skb;
	int sent;

	if (test_bit(RFCOMM_DEFER_SETUP, &d->flags))
		return -ENOTCONN;

	if (msg->msg_flags & MSG_OOB)
		return -EOPNOTSUPP;

	if (sk->sk_shutdown & SEND_SHUTDOWN)
		return -EPIPE;

	BT_DBG("sock %p, sk %p", sock, sk);

	lock_sock(sk);

	sent = bt_sock_wait_ready(sk, msg->msg_flags);

	release_sock(sk);

	if (sent)
		return sent;

	skb = bt_skb_sendmmsg(sk, msg, len, d->mtu, RFCOMM_SKB_HEAD_RESERVE,
			      RFCOMM_SKB_TAIL_RESERVE);
	if (IS_ERR(skb))
		return PTR_ERR(skb);

	sent = rfcomm_dlc_send(d, skb);
	if (sent < 0)
		kfree_skb(skb);

	return sent;
}

static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg,
			       size_t size, int flags)
{
	struct sock *sk = sock->sk;
	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
	int len;

	if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
		rfcomm_dlc_accept(d);
		return 0;
	}

	len = bt_sock_stream_recvmsg(sock, msg, size, flags);

	lock_sock(sk);
	if (!(flags & MSG_PEEK) && len > 0)
		atomic_sub(len, &sk->sk_rmem_alloc);

	if (atomic_read(&sk->sk_rmem_alloc) <= (sk->sk_rcvbuf >> 2))
		rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
	release_sock(sk);

	return len;
}

static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname,
		sockptr_t optval, unsigned int optlen)
{
	struct sock *sk = sock->sk;
	int err = 0;
	u32 opt;

	BT_DBG("sk %p", sk);

	lock_sock(sk);

	switch (optname) {
	case RFCOMM_LM:
		err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
		if (err)
			break;

		if (opt & RFCOMM_LM_FIPS) {
			err = -EINVAL;
			break;
		}

		if (opt & RFCOMM_LM_AUTH)
			rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
		if (opt & RFCOMM_LM_ENCRYPT)
			rfcomm_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
		if (opt & RFCOMM_LM_SECURE)
			rfcomm_pi(sk)->sec_level = BT_SECURITY_HIGH;

		rfcomm_pi(sk)->role_switch = (opt & RFCOMM_LM_MASTER);
		break;

	default:
		err = -ENOPROTOOPT;
		break;
	}

	release_sock(sk);
	return err;
}

static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname,
		sockptr_t optval, unsigned int optlen)
{
	struct sock *sk = sock->sk;
	struct bt_security sec;
	int err = 0;
	u32 opt;

	BT_DBG("sk %p", sk);

	if (level == SOL_RFCOMM)
		return rfcomm_sock_setsockopt_old(sock, optname, optval, optlen);

	if (level != SOL_BLUETOOTH)
		return -ENOPROTOOPT;

	lock_sock(sk);

	switch (optname) {
	case BT_SECURITY:
		if (sk->sk_type != SOCK_STREAM) {
			err = -EINVAL;
			break;
		}

		sec.level = BT_SECURITY_LOW;

		err = copy_safe_from_sockptr(&sec, sizeof(sec), optval, optlen);
		if (err)
			break;

		if (sec.level > BT_SECURITY_HIGH) {
			err = -EINVAL;
			break;
		}

		rfcomm_pi(sk)->sec_level = sec.level;
		break;

	case BT_DEFER_SETUP:
		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
			err = -EINVAL;
			break;
		}

		err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
		if (err)
			break;

		if (opt)
			set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
		else
			clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);

		break;

	default:
		err = -ENOPROTOOPT;
		break;
	}

	release_sock(sk);
	return err;
}

static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
{
	struct sock *sk = sock->sk;
	struct sock *l2cap_sk;
	struct l2cap_conn *conn;
	struct rfcomm_conninfo cinfo;
	int err = 0;
	size_t len;
	u32 opt;

	BT_DBG("sk %p", sk);

	if (get_user(len, optlen))
		return -EFAULT;

	lock_sock(sk);

	switch (optname) {
	case RFCOMM_LM:
		switch (rfcomm_pi(sk)->sec_level) {
		case BT_SECURITY_LOW:
			opt = RFCOMM_LM_AUTH;
			break;
		case BT_SECURITY_MEDIUM:
			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
			break;
		case BT_SECURITY_HIGH:
			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
			      RFCOMM_LM_SECURE;
			break;
		case BT_SECURITY_FIPS:
			opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
			      RFCOMM_LM_SECURE | RFCOMM_LM_FIPS;
			break;
		default:
			opt = 0;
			break;
		}

		if (rfcomm_pi(sk)->role_switch)
			opt |= RFCOMM_LM_MASTER;

		if (put_user(opt, (u32 __user *) optval))
			err = -EFAULT;

		break;

	case RFCOMM_CONNINFO:
		if (sk->sk_state != BT_CONNECTED &&
					!rfcomm_pi(sk)->dlc->defer_setup) {
			err = -ENOTCONN;
			break;
		}

		l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
		conn = l2cap_pi(l2cap_sk)->chan->conn;

		memset(&cinfo, 0, sizeof(cinfo));
		cinfo.hci_handle = conn->hcon->handle;
		memcpy(cinfo.dev_class, conn->hcon->dev_class, 3);

		len = min(len, sizeof(cinfo));
		if (copy_to_user(optval, (char *) &cinfo, len))
			err = -EFAULT;

		break;

	default:
		err = -ENOPROTOOPT;
		break;
	}

	release_sock(sk);
	return err;
}

static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
{
	struct sock *sk = sock->sk;
	struct bt_security sec;
	int err = 0;
	size_t len;

	BT_DBG("sk %p", sk);

	if (level == SOL_RFCOMM)
		return rfcomm_sock_getsockopt_old(sock, optname, optval, optlen);

	if (level != SOL_BLUETOOTH)
		return -ENOPROTOOPT;

	if (get_user(len, optlen))
		return -EFAULT;

	lock_sock(sk);

	switch (optname) {
	case BT_SECURITY:
		if (sk->sk_type != SOCK_STREAM) {
			err = -EINVAL;
			break;
		}

		sec.level = rfcomm_pi(sk)->sec_level;
		sec.key_size = 0;

		len = min(len, sizeof(sec));
		if (copy_to_user(optval, (char *) &sec, len))
			err = -EFAULT;

		break;

	case BT_DEFER_SETUP:
		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
			err = -EINVAL;
			break;
		}

		if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
			     (u32 __user *) optval))
			err = -EFAULT;

		break;

	default:
		err = -ENOPROTOOPT;
		break;
	}

	release_sock(sk);
	return err;
}

static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
	struct sock *sk __maybe_unused = sock->sk;
	int err;

	BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg);

	err = bt_sock_ioctl(sock, cmd, arg);

	if (err == -ENOIOCTLCMD) {
#ifdef CONFIG_BT_RFCOMM_TTY
		err = rfcomm_dev_ioctl(sk, cmd, (void __user *) arg);
#else
		err = -EOPNOTSUPP;
#endif
	}

	return err;
}

#ifdef CONFIG_COMPAT
static int rfcomm_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
	return rfcomm_sock_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
}
#endif

static int rfcomm_sock_shutdown(struct socket *sock, int how)
{
	struct sock *sk = sock->sk;
	int err = 0;

	BT_DBG("sock %p, sk %p", sock, sk);

	if (!sk)
		return 0;

	lock_sock(sk);
	if (!sk->sk_shutdown) {
		sk->sk_shutdown = SHUTDOWN_MASK;

		release_sock(sk);
		__rfcomm_sock_close(sk);
		lock_sock(sk);

		if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
		    !(current->flags & PF_EXITING))
			err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
	}
	release_sock(sk);
	return err;
}

static int rfcomm_sock_release(struct socket *sock)
{
	struct sock *sk = sock->sk;
	int err;

	BT_DBG("sock %p, sk %p", sock, sk);

	if (!sk)
		return 0;

	err = rfcomm_sock_shutdown(sock, 2);

	sock_orphan(sk);
	rfcomm_sock_kill(sk);
	return err;
}

/* ---- RFCOMM core layer callbacks ----
 *
 * called under rfcomm_lock()
 */
int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d)
{
	struct sock *sk, *parent;
	bdaddr_t src, dst;
	int result = 0;

	BT_DBG("session %p channel %d", s, channel);

	rfcomm_session_getaddr(s, &src, &dst);

	/* Check if we have socket listening on channel */
	parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
	if (!parent)
		return 0;

	lock_sock(parent);

	/* Check for backlog size */
	if (sk_acceptq_is_full(parent)) {
		BT_DBG("backlog full %d", parent->sk_ack_backlog);
		goto done;
	}

	sk = rfcomm_sock_alloc(sock_net(parent), NULL, BTPROTO_RFCOMM, GFP_ATOMIC, 0);
	if (!sk)
		goto done;

	bt_sock_reclassify_lock(sk, BTPROTO_RFCOMM);

	rfcomm_sock_init(sk, parent);
	bacpy(&rfcomm_pi(sk)->src, &src);
	bacpy(&rfcomm_pi(sk)->dst, &dst);
	rfcomm_pi(sk)->channel = channel;

	sk->sk_state = BT_CONFIG;
	bt_accept_enqueue(parent, sk, true);

	/* Accept connection and return socket DLC */
	*d = rfcomm_pi(sk)->dlc;
	result = 1;

done:
	release_sock(parent);

	if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
		parent->sk_state_change(parent);

	return result;
}

static int rfcomm_sock_debugfs_show(struct seq_file *f, void *p)
{
	struct sock *sk;

	read_lock(&rfcomm_sk_list.lock);

	sk_for_each(sk, &rfcomm_sk_list.head) {
		seq_printf(f, "%pMR %pMR %d %d\n",
			   &rfcomm_pi(sk)->src, &rfcomm_pi(sk)->dst,
			   sk->sk_state, rfcomm_pi(sk)->channel);
	}

	read_unlock(&rfcomm_sk_list.lock);

	return 0;
}

DEFINE_SHOW_ATTRIBUTE(rfcomm_sock_debugfs);

static struct dentry *rfcomm_sock_debugfs;

static const struct proto_ops rfcomm_sock_ops = {
	.family		= PF_BLUETOOTH,
	.owner		= THIS_MODULE,
	.release	= rfcomm_sock_release,
	.bind		= rfcomm_sock_bind,
	.connect	= rfcomm_sock_connect,
	.listen		= rfcomm_sock_listen,
	.accept		= rfcomm_sock_accept,
	.getname	= rfcomm_sock_getname,
	.sendmsg	= rfcomm_sock_sendmsg,
	.recvmsg	= rfcomm_sock_recvmsg,
	.shutdown	= rfcomm_sock_shutdown,
	.setsockopt	= rfcomm_sock_setsockopt,
	.getsockopt	= rfcomm_sock_getsockopt,
	.ioctl		= rfcomm_sock_ioctl,
	.gettstamp	= sock_gettstamp,
	.poll		= bt_sock_poll,
	.socketpair	= sock_no_socketpair,
	.mmap		= sock_no_mmap,
#ifdef CONFIG_COMPAT
	.compat_ioctl	= rfcomm_sock_compat_ioctl,
#endif
};

static const struct net_proto_family rfcomm_sock_family_ops = {
	.family		= PF_BLUETOOTH,
	.owner		= THIS_MODULE,
	.create		= rfcomm_sock_create
};

int __init rfcomm_init_sockets(void)
{
	int err;

	BUILD_BUG_ON(sizeof(struct sockaddr_rc) > sizeof(struct sockaddr));

	err = proto_register(&rfcomm_proto, 0);
	if (err < 0)
		return err;

	err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops);
	if (err < 0) {
		BT_ERR("RFCOMM socket layer registration failed");
		goto error;
	}

	err = bt_procfs_init(&init_net, "rfcomm", &rfcomm_sk_list, NULL);
	if (err < 0) {
		BT_ERR("Failed to create RFCOMM proc file");
		bt_sock_unregister(BTPROTO_RFCOMM);
		goto error;
	}

	BT_INFO("RFCOMM socket layer initialized");

	if (IS_ERR_OR_NULL(bt_debugfs))
		return 0;

	rfcomm_sock_debugfs = debugfs_create_file("rfcomm", 0444,
						  bt_debugfs, NULL,
						  &rfcomm_sock_debugfs_fops);

	return 0;

error:
	proto_unregister(&rfcomm_proto);
	return err;
}

void __exit rfcomm_cleanup_sockets(void)
{
	bt_procfs_cleanup(&init_net, "rfcomm");

	debugfs_remove(rfcomm_sock_debugfs);

	bt_sock_unregister(BTPROTO_RFCOMM);

	proto_unregister(&rfcomm_proto);
}
]

25/2 2026/02/13 13:17 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 28146
							output: 24
							thoughts: 3502
						

Thoughts:
**Analysis of Potential Data Race in L2CAP Socket Connection**

Okay, so I've been digging into this code, specifically the `l2cap_sock_connect` function in the Bluetooth L2CAP stack, and I'm seeing a potential data race when a socket is being bound concurrently. The issue centers around the socket lock and how it's handled during connection establishment.

Here's the breakdown of my thinking:

1.  **Lock Dropping:** The code, similar to RFCOMM, drops the socket lock (`sk_lock`) early, which is a design choice to avoid potential deadlocks. This is done before calling `rfcomm_dlc_open` in the RFCOMM case, and even earlier in L2CAP. In L2CAP, the lock is dropped right after checking `SOCK_ZAPPED`. This seems to be where the trouble starts.

2.  **Concurrent Operations:** The problem arises if a `bind` operation is running concurrently with a `connect` operation on the same socket. `bind` acquires the socket lock, copies the source address (`chan->src`) using `bacpy` (which is effectively a memcpy for a Bluetooth address), and then releases the lock. `connect`, on the other hand, acquires the lock briefly, releases it, and then checks the source address with `bacmp` (a memcmp).

3.  **The Race Condition:** The critical point is that `connect` releases the socket lock *before* checking the source address. If `bind` is running concurrently, there's a window where `connect` might read a partially updated `chan->src` value, leading to inconsistent data.

4.  **KCSAN Report:** The Kernel Concurrency Sanitizer (KCSAN) confirms this, reporting a read-write race on `chan->src`. The stack traces confirm that `bind` is writing to the address while `connect` is reading it. This race is real.

5.  **Impact:** The consequences of this race are not necessarily kernel crashes or memory corruption in the strict sense. The primary concern is that `connect` might end up with an incorrect source address. This could lead to a failed connection attempt (e.g., `-EHOSTUNREACH`) or, worse, a connection using an unintended source address. Furthermore, `l2cap_chan_connect` will also read this data and can lead to inconsistent state.

6.  **Why the Lock Isn't Held:** The design choice of releasing the socket lock early stems from a desire to avoid deadlocks with other locking mechanisms, like the `hci_dev_lock` and `l2cap_chan_lock` which are taken later in `l2cap_chan_connect`. A potential deadlock scenario could arise if a reverse lock order happens.

7.  **Is it "Benign"?:** While a user calling `bind` and `connect` concurrently on the same socket is likely an application error, the kernel still shouldn't have data races.

8.  **The Fix?:** Holding the socket lock for the duration of source address access would resolve the race. However, this could introduce deadlocks. The "right" fix might involve alternative synchronization mechanisms or careful ordering of lock acquisitions to avoid the deadlock while protecting the source address.

In summary, this data race, while not catastrophic, can lead to unpredictable behavior in connection establishment due to the potential for the read of the source Bluetooth address to happen while the write is in progress. The root cause is the early release of the socket lock to prevent deadlocks, but this comes at the cost of this data race. While the concurrency is likely an application bug, the kernel still shouldn't have a race.



26/2 2026/02/13 13:18 tool grepper
0m Error:
no matches

Args:
map[Expression:l2cap_sock_connect.*bacmp]

Results:
map[Output:]

27/2 2026/02/13 13:18 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 32466
							output: 39
							thoughts: 68
						

Thoughts:
Here's my summary, as though I'm thinking through this code snippet:

**Debugging a Potential Bluetooth Connection Issue**

Okay, so I'm looking at this `if` statement, and I need to figure out what's going on here. The goal is likely to diagnose why a connection isn't working as expected. Let's see... the `chan` struct seems to be crucial here; it probably holds connection information. I'm going to quickly parse what these conditions mean and why they are tested.

`chan->src_type == BDADDR_BREDR`: This checks if the source address type is Bluetooth BR/EDR. That seems reasonable, as a lot of my work focuses on this type of connection. The next part, `bacmp(&chan->src, BDADDR_ANY)`, I recognize the standard library function `bacmp` – that's a direct comparison of Bluetooth addresses. The check here is basically ensuring that the source address is *not* a wildcard or "any" address. Makes sense; we need a specific source.

Finally, `bdaddr_type_is_le(la.l2_bdaddr_type)` is interesting. I'm seeing this comparison of an L2 address type - this probably indicates we're dealing with Low Energy in some form or another. I'm going to have to dive deeper into the structure to be sure. It suggests a check that the link layer address type is defined as a Low Energy address, which seems a sensible sanity check. I need to understand the relationship between BR/EDR and LE in this context. Maybe we're seeing an unexpected mismatch or setting a BR/EDR link with LE specific parameters or something. I can already see that this has the potential to become a confusing debug, but I can see how it relates to my current problem, it might be the key to understanding the issue. I will keep this in mind as I continue looking at the code.



28/2 2026/02/13 13:18 tool grepper
0m Args:
map[Expression:chan->src_type == BDADDR_BREDR && bacmp\(&chan->src, BDADDR_ANY\)]

Results:
map[Output:net/bluetooth/l2cap_sock.c=181=static int l2cap_sock_connect(struct socket *sock, struct sockaddr_unsized *addr,
--
net/bluetooth/l2cap_sock.c-217-	 */
net/bluetooth/l2cap_sock.c:218:	if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) &&
net/bluetooth/l2cap_sock.c-219-	    bdaddr_type_is_le(la.l2_bdaddr_type)) {
]

29/2 2026/02/13 13:18 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 33141
							output: 48
							thoughts: 1350
						

Thoughts:
**Analyzing a Potential Data Race in L2CAP Socket Binding and Connection**

Okay, so I'm looking at this L2CAP code, and I see a potential race condition between `l2cap_sock_bind` and `l2cap_sock_connect`. `l2cap_sock_bind` holds the socket lock, which is good, but `l2cap_sock_connect` *doesn't*. Specifically, the issue seems to center around how the source Bluetooth address (`chan->src`) and its type (`chan->src_type`) are handled.

I can see that `l2cap_sock_bind` writes to `chan->src` and `chan->src_type`:

```c
 132:		bacpy(&chan->src, &la.l2_bdaddr);
 133:		chan->src_type = la.l2_bdaddr_type;
```

And `l2cap_sock_connect` checks this data using `bacmp` and potentially changes `chan->src_type` based on its value:

```c
 218:		if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) &&
```

My concern is that if these functions are called concurrently on the same socket, `bacmp` might read a partially written `chan->src`. While kernel developers often consider races on "state" variables benign if they don't lead to crashes, this is a 6-byte structure, which makes it a bit more worrying.  A "false positive" or "false negative" from `bacmp` could lead to incorrect execution of the `if` block and a potential change of `chan->src_type` to incorrect value.

However, if `bind` and `connect` *are* called concurrently, the state is already non-deterministic, isn't it? If `connect` happens before `bind`, it uses `BDADDR_ANY`, and if `connect` happens after `bind`, it uses the address from `bind`. In the worst-case scenario, if they happen *exactly* at the same time, it might use a partially initialized address.

The likely outcome of a partially initialized address is that `hci_get_route` will fail to find a Bluetooth adapter, leading to `-EHOSTUNREACH` in `connect`. This doesn't seem like a critical issue for a racing application, right?

But, wait... the `connect` "fix up" logic could change `chan->src_type` to `BDADDR_LE_PUBLIC`. If `bind` then runs, it might overwrite that with a different `src_type`. If `bind` sets it to `BDADDR_BREDR` or `BDADDR_LE_PUBLIC`, that should be fine. But what if `bind` sets it to `BDADDR_LE_RANDOM`, and then `connect` incorrectly sets it to `BDADDR_LE_PUBLIC`? Ultimately, `bind` will *eventually* finish because it holds the socket lock. The state will be what `bind` sets. However, the connection attempt might have already started with an invalid `src_type`.

Then again, the source address and type are updated *again* within `l2cap_chan_connect`.

```c
7112:		bacpy(&chan->src, &hcon->src);
7113:		chan->src_type = bdaddr_src_type(hcon);
```

Okay, so the real source of truth for the adapter is `hcon`, so even if there's a problem, `l2cap_chan_connect` will update the channel to the correct values from the adapter's configuration.

The biggest issue is `hci_get_route`. If `src` is partially written, it might not find any adapter. This race doesn't seem to corrupt kernel memory, which is a good thing.

`chan->src` is a 6-byte `bdaddr_t`.  `bacmp` does a `memcmp`.  I need to make sure that `memcmp` doesn't do an out-of-bounds read, but I am fairly certain that `bdaddr_t` is always 6 bytes, and `memcmp` is safe. Likewise, `memcpy` is safe. `chan->src_type` is a `u8`, and those accesses should be atomic.

The real race is on the 6 bytes of `bdaddr_t`. Typical kernel practice is to ignore these types of races if it's a single value or to address them with `READ_ONCE`/`WRITE_ONCE`. But `READ_ONCE` doesn't


30/2 2026/02/13 13:18 tool codesearch-definition-source
0m Args:
map[ContextFile:net/bluetooth/l2cap_sock.c IncludeLines:true Name:l2cap_sock_getname]

Results:
map[SourceCode: 385:	static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
 386:				      int peer)
 387:	{
 388:		struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
 389:		struct sock *sk = sock->sk;
 390:		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
 391:	
 392:		BT_DBG("sock %p, sk %p", sock, sk);
 393:	
 394:		if (peer && sk->sk_state != BT_CONNECTED &&
 395:		    sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2 &&
 396:		    sk->sk_state != BT_CONFIG)
 397:			return -ENOTCONN;
 398:	
 399:		memset(la, 0, sizeof(struct sockaddr_l2));
 400:		addr->sa_family = AF_BLUETOOTH;
 401:	
 402:		la->l2_psm = chan->psm;
 403:	
 404:		if (peer) {
 405:			bacpy(&la->l2_bdaddr, &chan->dst);
 406:			la->l2_cid = cpu_to_le16(chan->dcid);
 407:			la->l2_bdaddr_type = chan->dst_type;
 408:		} else {
 409:			bacpy(&la->l2_bdaddr, &chan->src);
 410:			la->l2_cid = cpu_to_le16(chan->scid);
 411:			la->l2_bdaddr_type = chan->src_type;
 412:		}
 413:	
 414:		return sizeof(struct sockaddr_l2);
 415:	}
 SourceFile:net/bluetooth/l2cap_sock.c]

31/2 2026/02/13 13:18 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 36119
							output: 25
							thoughts: 498
						

Thoughts:
**Analyzing Potential Data Races in the Bluetooth L2CAP Socket Layer**

Okay, so I'm digging into this `l2cap_sock_getname` function, and the first thing that jumps out is that it doesn't hold `lock_sock(sk)`. This is a classic data race scenario. It's accessing `chan->src`, `chan->dst`, and other address-related fields without any protection, which means `getname` could be racing with `bind` or `connect`.

My initial thought is, are the Bluetooth folks just okay with these races on address fields, or have they just not gotten around to fixing them because it would be a bit of a lock-fest? But, I have to say, `l2cap_sock_getname` is a textbook example of where data races are likely to happen.

Wait, if `l2cap_sock_getname` doesn't hold the socket lock, then any concurrent `bind` operation is going to be racing with it. This is not good.

The question then becomes, is this actually harmful? If `getname` just returns a partially written address, at least it's just garbage data, right? It's not like it's a pointer to memory that can be dereferenced, it's just the address itself.

Hold on, though. `l2cap_sock_connect` actually uses these values to make decisions, and passes it to `l2cap_chan_connect`.

```c
 218:		if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) &&
```
If `l2cap_chan_connect` gets a corrupted `src` address, the whole thing could just fail.

Actually, I recall a known issue in the Bluetooth stack where `lock_sock` is often missing where it should be, likely because of some of those tricky deadlock issues I've seen.

Let's circle back to `l2cap_chan_connect`. It calls `l2cap_chan_lock(chan)`. Perhaps `bind` also needs to acquire that lock? In `l2cap_sock_bind` I see:

```c
 113:		lock_sock(sk);
...
 132:		bacpy(&chan->src, &la.l2_bdaddr);
```

Nope, `bind` *doesn't* take `l2cap_chan_lock(chan)`.

Hang on a second… `l2cap_chan` has its own lock! I need to trace where that lock is actually being used. It seems this could be a source of problems.



32/2 2026/02/13 13:18 tool codesearch-find-references
0m Args:
map[Name:l2cap_chan_lock]

Results:
map[References:<nil> TruncatedOutput:false]

33/2 2026/02/13 13:18 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 37247
							output: 45
							thoughts: 39
						

Thoughts:
Okay, here's my interpretation of those thoughts, tailored for an expert audience:

**Debugging a Potential Concurrency Issue in Bluetooth L2CAP**

Right, this smells like a concurrency issue. I'm immediately leaning towards a macro, or potentially a misplaced lock. My first instinct is to scan for calls to `mutex_lock(&chan->lock)`. I need to figure out which part of the code is being protected. Let's start by digging into the `l2cap_chan` structure definition. I need to understand what data members are protected by that lock, and how they are being accessed. Knowing the data in the `l2cap_chan` struct and how it's used is key to diagnosing the race condition.



34/2 2026/02/13 13:18 tool codesearch-definition-source
0m Args:
map[ContextFile:include/net/bluetooth/l2cap.h IncludeLines:true Name:l2cap_chan]

Results:
map[SourceCode: 512:	struct l2cap_chan {
 513:		struct l2cap_conn	*conn;
 514:		struct kref	kref;
 515:		atomic_t	nesting;
 516:	
 517:		__u8		state;
 518:	
 519:		bdaddr_t	dst;
 520:		__u8		dst_type;
 521:		bdaddr_t	src;
 522:		__u8		src_type;
 523:		__le16		psm;
 524:		__le16		sport;
 525:		__u16		dcid;
 526:		__u16		scid;
 527:	
 528:		__u16		imtu;
 529:		__u16		omtu;
 530:		__u16		flush_to;
 531:		__u8		mode;
 532:		__u8		chan_type;
 533:		__u8		chan_policy;
 534:	
 535:		__u8		sec_level;
 536:	
 537:		__u8		ident;
 538:	
 539:		__u8		conf_req[64];
 540:		__u8		conf_len;
 541:		__u8		num_conf_req;
 542:		__u8		num_conf_rsp;
 543:	
 544:		__u8		fcs;
 545:	
 546:		__u16		tx_win;
 547:		__u16		tx_win_max;
 548:		__u16		ack_win;
 549:		__u8		max_tx;
 550:		__u16		retrans_timeout;
 551:		__u16		monitor_timeout;
 552:		__u16		mps;
 553:	
 554:		__u16		tx_credits;
 555:		__u16		rx_credits;
 556:	
 557:		/* estimated available receive buffer space or -1 if unknown */
 558:		ssize_t		rx_avail;
 559:	
 560:		__u8		tx_state;
 561:		__u8		rx_state;
 562:	
 563:		unsigned long	conf_state;
 564:		unsigned long	conn_state;
 565:		unsigned long	flags;
 566:	
 567:		__u16		next_tx_seq;
 568:		__u16		expected_ack_seq;
 569:		__u16		expected_tx_seq;
 570:		__u16		buffer_seq;
 571:		__u16		srej_save_reqseq;
 572:		__u16		last_acked_seq;
 573:		__u16		frames_sent;
 574:		__u16		unacked_frames;
 575:		__u8		retry_count;
 576:		__u16		sdu_len;
 577:		struct sk_buff	*sdu;
 578:		struct sk_buff	*sdu_last_frag;
 579:	
 580:		__u16		remote_tx_win;
 581:		__u8		remote_max_tx;
 582:		__u16		remote_mps;
 583:	
 584:		__u8		local_id;
 585:		__u8		local_stype;
 586:		__u16		local_msdu;
 587:		__u32		local_sdu_itime;
 588:		__u32		local_acc_lat;
 589:		__u32		local_flush_to;
 590:	
 591:		__u8		remote_id;
 592:		__u8		remote_stype;
 593:		__u16		remote_msdu;
 594:		__u32		remote_sdu_itime;
 595:		__u32		remote_acc_lat;
 596:		__u32		remote_flush_to;
 597:	
 598:		struct delayed_work	chan_timer;
 599:		struct delayed_work	retrans_timer;
 600:		struct delayed_work	monitor_timer;
 601:		struct delayed_work	ack_timer;
 602:	
 603:		struct sk_buff		*tx_send_head;
 604:		struct sk_buff_head	tx_q;
 605:		struct sk_buff_head	srej_q;
 606:		struct l2cap_seq_list	srej_list;
 607:		struct l2cap_seq_list	retrans_list;
 608:	
 609:		struct list_head	list;
 610:		struct list_head	global_l;
 611:	
 612:		void			*data;
 613:		const struct l2cap_ops	*ops;
 614:		struct mutex		lock;
 615:	};
 SourceFile:include/net/bluetooth/l2cap.h]

35/2 2026/02/13 13:18 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 39005
							output: 23
							thoughts: 71
						

Thoughts:
**Analyzing the L2CAP Channel Lock**

Okay, so I'm looking at the `struct l2cap_chan` definition. Right, line 614... yes, it contains a `struct mutex lock`. That's the key. Now, the `l2cap_chan_lock` macro… I'm betting it's something along the lines of a simple `mutex_lock` call. Let me check my assumptions...
```c
#define l2cap_chan_lock(c) mutex_lock(&c->lock)
```
...Yup, as expected. Clean and straightforward.



36/2 2026/02/13 13:18 tool grepper
0m Error:
no matches

Args:
map[Expression:#define l2cap_chan_lock]

Results:
map[Output:]

37/2 2026/02/13 13:18 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 39245
							output: 47
							thoughts: 20
						

Thoughts:
Here's my thought process, summarized as you requested:

**Debugging Strategy: Locating a Definition**

Okay, so I need to understand what `l2cap_chan_lock` is. It's obviously a crucial element in this code, likely a mutex or some other synchronization primitive, but I don't know the exact context. The first thing I'm going to do is use my tools, a quick search, to pinpoint the definition of `l2cap_chan_lock`. I need to see exactly how it's declared and where it lives. This will give me immediate insight into its data type, its scope, and how it's likely being used. Knowing that definition is the foundational piece to understanding its function.



38/2 2026/02/13 13:18 tool codesearch-definition-source
0m Args:
map[ContextFile:include/net/bluetooth/l2cap.h IncludeLines:true Name:l2cap_chan_lock]

Results:
map[SourceCode: 825:	static inline void l2cap_chan_lock(struct l2cap_chan *chan)
 826:	{
 827:		mutex_lock_nested(&chan->lock, atomic_read(&chan->nesting));
 828:	}
 SourceFile:include/net/bluetooth/l2cap.h]

39/2 2026/02/13 13:18 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 39570
							output: 26
							thoughts: 542
						

Thoughts:
**Analyzing a Potential Race Condition in L2CAP Socket Connection**

Alright, let's break this down. I've noticed a potential race condition within the L2CAP socket code, and it's bugging me. Specifically, I'm focusing on the interaction between `l2cap_sock_bind` and `l2cap_sock_connect`.

Okay, so I see that the `l2cap_chan_lock` exists, and now I see that `l2cap_sock_bind` *doesn't* take that `l2cap_chan_lock(chan)`. That's fine, I can see why. Now, `l2cap_sock_connect` *also* doesn't take that `l2cap_chan_lock(chan)` *before* the race condition. Instead it calls `l2cap_chan_connect`, which *does* grab the `l2cap_chan_lock(chan)`, but that happens at line 7103, which is after the interesting stuff. That race happens at line 218 of `l2cap_sock_connect`, so too late.

Even if `bind` *did* take that channel lock, it wouldn't matter because `connect` isn't holding it at the point of the race.

So, the race is between `bind` (holding `lock_sock(sk)`) and `connect` (holding nothing at that crucial moment). Now, if `connect` *did* hold `lock_sock(sk)` during that specific check, the race would be gone. But, as I saw earlier, the code intentionally releases it!

Now, the question is, is this harmful? I don't think it causes kernel panics or instability. It's probably just causing incorrect connection parameters, which is a problem. But is it a security issue? Probably not, since the race involves operations on the same socket, usually within the same process.

Hang on... what if a socket is *shared* between processes? Then we have a race condition! That adds a dimension of complexity.

Thinking broader here: many Bluetooth data races get reported by KCSAN. Often, `READ_ONCE`/`WRITE_ONCE` or improved locking fix these. Let's see if we can apply something similar to `src` or `dst`. I'll start with `bacpy` and then see how `READ_ONCE` might apply (wait, it's a `memcpy`, so that's not directly applicable).

Oh, I found a past related issue! There was a patch, "Bluetooth: Fix data races in l2cap_sock_getname," which added `lock_sock`. Good, that's what I'm looking for! Let me check if `l2cap_sock_getname` has `lock_sock` in the version I'm looking at. I just checked and it doesn't appear to have it. Let me re-read `l2cap_sock_getname`.



40/2 2026/02/13 13:19 tool read-file
0m Args:
map[File:net/bluetooth/l2cap_sock.c]

Results:
map[Contents:/*
   BlueZ - Bluetooth protocol stack for Linux
   Copyright (C) 2000-2001 Qualcomm Incorporated
   Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
   Copyright (C) 2010 Google Inc.
   Copyright (C) 2011 ProFUSION Embedded Systems

   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 2 as
   published by the Free Software Foundation;

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
   SOFTWARE IS DISCLAIMED.
*/

/* Bluetooth L2CAP sockets. */

#include <linux/module.h>
#include <linux/export.h>
#include <linux/filter.h>
#include <linux/sched/signal.h>

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>

#include "smp.h"

static struct bt_sock_list l2cap_sk_list = {
	.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
};

static const struct proto_ops l2cap_sock_ops;
static void l2cap_sock_init(struct sock *sk, struct sock *parent);
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
				     int proto, gfp_t prio, int kern);
static void l2cap_sock_cleanup_listen(struct sock *parent);

bool l2cap_is_socket(struct socket *sock)
{
	return sock && sock->ops == &l2cap_sock_ops;
}
EXPORT_SYMBOL(l2cap_is_socket);

static int l2cap_validate_bredr_psm(u16 psm)
{
	/* PSM must be odd and lsb of upper byte must be 0 */
	if ((psm & 0x0101) != 0x0001)
		return -EINVAL;

	/* Restrict usage of well-known PSMs */
	if (psm < L2CAP_PSM_DYN_START && !capable(CAP_NET_BIND_SERVICE))
		return -EACCES;

	return 0;
}

static int l2cap_validate_le_psm(u16 psm)
{
	/* Valid LE_PSM ranges are defined only until 0x00ff */
	if (psm > L2CAP_PSM_LE_DYN_END)
		return -EINVAL;

	/* Restrict fixed, SIG assigned PSM values to CAP_NET_BIND_SERVICE */
	if (psm < L2CAP_PSM_LE_DYN_START && !capable(CAP_NET_BIND_SERVICE))
		return -EACCES;

	return 0;
}

static int l2cap_sock_bind(struct socket *sock, struct sockaddr_unsized *addr, int alen)
{
	struct sock *sk = sock->sk;
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
	struct sockaddr_l2 la;
	int len, err = 0;

	BT_DBG("sk %p", sk);

	if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
	    addr->sa_family != AF_BLUETOOTH)
		return -EINVAL;

	memset(&la, 0, sizeof(la));
	len = min_t(unsigned int, sizeof(la), alen);
	memcpy(&la, addr, len);

	if (la.l2_cid && la.l2_psm)
		return -EINVAL;

	if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
		return -EINVAL;

	if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
		/* We only allow ATT user space socket */
		if (la.l2_cid &&
		    la.l2_cid != cpu_to_le16(L2CAP_CID_ATT))
			return -EINVAL;
	}

	lock_sock(sk);

	if (sk->sk_state != BT_OPEN) {
		err = -EBADFD;
		goto done;
	}

	if (la.l2_psm) {
		__u16 psm = __le16_to_cpu(la.l2_psm);

		if (la.l2_bdaddr_type == BDADDR_BREDR)
			err = l2cap_validate_bredr_psm(psm);
		else
			err = l2cap_validate_le_psm(psm);

		if (err)
			goto done;
	}

	bacpy(&chan->src, &la.l2_bdaddr);
	chan->src_type = la.l2_bdaddr_type;

	if (la.l2_cid)
		err = l2cap_add_scid(chan, __le16_to_cpu(la.l2_cid));
	else
		err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm);

	if (err < 0)
		goto done;

	switch (chan->chan_type) {
	case L2CAP_CHAN_CONN_LESS:
		if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_3DSP)
			chan->sec_level = BT_SECURITY_SDP;
		break;
	case L2CAP_CHAN_CONN_ORIENTED:
		if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_SDP ||
		    __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM)
			chan->sec_level = BT_SECURITY_SDP;
		break;
	case L2CAP_CHAN_RAW:
		chan->sec_level = BT_SECURITY_SDP;
		break;
	case L2CAP_CHAN_FIXED:
		/* Fixed channels default to the L2CAP core not holding a
		 * hci_conn reference for them. For fixed channels mapping to
		 * L2CAP sockets we do want to hold a reference so set the
		 * appropriate flag to request it.
		 */
		set_bit(FLAG_HOLD_HCI_CONN, &chan->flags);
		break;
	}

	/* Use L2CAP_MODE_LE_FLOWCTL (CoC) in case of LE address and
	 * L2CAP_MODE_EXT_FLOWCTL (ECRED) has not been set.
	 */
	if (chan->psm && bdaddr_type_is_le(chan->src_type) &&
	    chan->mode != L2CAP_MODE_EXT_FLOWCTL)
		chan->mode = L2CAP_MODE_LE_FLOWCTL;

	chan->state = BT_BOUND;
	sk->sk_state = BT_BOUND;

done:
	release_sock(sk);
	return err;
}

static int l2cap_sock_connect(struct socket *sock, struct sockaddr_unsized *addr,
			      int alen, int flags)
{
	struct sock *sk = sock->sk;
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
	struct sockaddr_l2 la;
	int len, err = 0;
	bool zapped;

	BT_DBG("sk %p", sk);

	lock_sock(sk);
	zapped = sock_flag(sk, SOCK_ZAPPED);
	release_sock(sk);

	if (zapped)
		return -EINVAL;

	if (!addr || alen < offsetofend(struct sockaddr, sa_family) ||
	    addr->sa_family != AF_BLUETOOTH)
		return -EINVAL;

	memset(&la, 0, sizeof(la));
	len = min_t(unsigned int, sizeof(la), alen);
	memcpy(&la, addr, len);

	if (la.l2_cid && la.l2_psm)
		return -EINVAL;

	if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
		return -EINVAL;

	/* Check that the socket wasn't bound to something that
	 * conflicts with the address given to connect(). If chan->src
	 * is BDADDR_ANY it means bind() was never used, in which case
	 * chan->src_type and la.l2_bdaddr_type do not need to match.
	 */
	if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) &&
	    bdaddr_type_is_le(la.l2_bdaddr_type)) {
		/* Old user space versions will try to incorrectly bind
		 * the ATT socket using BDADDR_BREDR. We need to accept
		 * this and fix up the source address type only when
		 * both the source CID and destination CID indicate
		 * ATT. Anything else is an invalid combination.
		 */
		if (chan->scid != L2CAP_CID_ATT ||
		    la.l2_cid != cpu_to_le16(L2CAP_CID_ATT))
			return -EINVAL;

		/* We don't have the hdev available here to make a
		 * better decision on random vs public, but since all
		 * user space versions that exhibit this issue anyway do
		 * not support random local addresses assuming public
		 * here is good enough.
		 */
		chan->src_type = BDADDR_LE_PUBLIC;
	}

	if (chan->src_type != BDADDR_BREDR && la.l2_bdaddr_type == BDADDR_BREDR)
		return -EINVAL;

	if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
		/* We only allow ATT user space socket */
		if (la.l2_cid &&
		    la.l2_cid != cpu_to_le16(L2CAP_CID_ATT))
			return -EINVAL;
	}

	/* Use L2CAP_MODE_LE_FLOWCTL (CoC) in case of LE address and
	 * L2CAP_MODE_EXT_FLOWCTL (ECRED) has not been set.
	 */
	if (chan->psm && bdaddr_type_is_le(chan->src_type) &&
	    chan->mode != L2CAP_MODE_EXT_FLOWCTL)
		chan->mode = L2CAP_MODE_LE_FLOWCTL;

	err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid),
				 &la.l2_bdaddr, la.l2_bdaddr_type,
				 READ_ONCE(sk->sk_sndtimeo));
	if (err)
		return err;

	lock_sock(sk);

	err = bt_sock_wait_state(sk, BT_CONNECTED,
				 sock_sndtimeo(sk, flags & O_NONBLOCK));

	release_sock(sk);

	return err;
}

static int l2cap_sock_listen(struct socket *sock, int backlog)
{
	struct sock *sk = sock->sk;
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
	int err = 0;

	BT_DBG("sk %p backlog %d", sk, backlog);

	lock_sock(sk);

	if (sk->sk_state != BT_BOUND) {
		err = -EBADFD;
		goto done;
	}

	if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) {
		err = -EINVAL;
		goto done;
	}

	switch (chan->mode) {
	case L2CAP_MODE_BASIC:
	case L2CAP_MODE_LE_FLOWCTL:
		break;
	case L2CAP_MODE_EXT_FLOWCTL:
		if (!enable_ecred) {
			err = -EOPNOTSUPP;
			goto done;
		}
		break;
	case L2CAP_MODE_ERTM:
	case L2CAP_MODE_STREAMING:
		if (!disable_ertm)
			break;
		fallthrough;
	default:
		err = -EOPNOTSUPP;
		goto done;
	}

	sk->sk_max_ack_backlog = backlog;
	sk->sk_ack_backlog = 0;

	/* Listening channels need to use nested locking in order not to
	 * cause lockdep warnings when the created child channels end up
	 * being locked in the same thread as the parent channel.
	 */
	atomic_set(&chan->nesting, L2CAP_NESTING_PARENT);

	chan->state = BT_LISTEN;
	sk->sk_state = BT_LISTEN;

done:
	release_sock(sk);
	return err;
}

static int l2cap_sock_accept(struct socket *sock, struct socket *newsock,
			     struct proto_accept_arg *arg)
{
	DEFINE_WAIT_FUNC(wait, woken_wake_function);
	struct sock *sk = sock->sk, *nsk;
	long timeo;
	int err = 0;

	lock_sock_nested(sk, L2CAP_NESTING_PARENT);

	timeo = sock_rcvtimeo(sk, arg->flags & O_NONBLOCK);

	BT_DBG("sk %p timeo %ld", sk, timeo);

	/* Wait for an incoming connection. (wake-one). */
	add_wait_queue_exclusive(sk_sleep(sk), &wait);
	while (1) {
		if (sk->sk_state != BT_LISTEN) {
			err = -EBADFD;
			break;
		}

		nsk = bt_accept_dequeue(sk, newsock);
		if (nsk)
			break;

		if (!timeo) {
			err = -EAGAIN;
			break;
		}

		if (signal_pending(current)) {
			err = sock_intr_errno(timeo);
			break;
		}

		release_sock(sk);

		timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);

		lock_sock_nested(sk, L2CAP_NESTING_PARENT);
	}
	remove_wait_queue(sk_sleep(sk), &wait);

	if (err)
		goto done;

	newsock->state = SS_CONNECTED;

	BT_DBG("new socket %p", nsk);

done:
	release_sock(sk);
	return err;
}

static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
			      int peer)
{
	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
	struct sock *sk = sock->sk;
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;

	BT_DBG("sock %p, sk %p", sock, sk);

	if (peer && sk->sk_state != BT_CONNECTED &&
	    sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2 &&
	    sk->sk_state != BT_CONFIG)
		return -ENOTCONN;

	memset(la, 0, sizeof(struct sockaddr_l2));
	addr->sa_family = AF_BLUETOOTH;

	la->l2_psm = chan->psm;

	if (peer) {
		bacpy(&la->l2_bdaddr, &chan->dst);
		la->l2_cid = cpu_to_le16(chan->dcid);
		la->l2_bdaddr_type = chan->dst_type;
	} else {
		bacpy(&la->l2_bdaddr, &chan->src);
		la->l2_cid = cpu_to_le16(chan->scid);
		la->l2_bdaddr_type = chan->src_type;
	}

	return sizeof(struct sockaddr_l2);
}

static int l2cap_get_mode(struct l2cap_chan *chan)
{
	switch (chan->mode) {
	case L2CAP_MODE_BASIC:
		return BT_MODE_BASIC;
	case L2CAP_MODE_ERTM:
		return BT_MODE_ERTM;
	case L2CAP_MODE_STREAMING:
		return BT_MODE_STREAMING;
	case L2CAP_MODE_LE_FLOWCTL:
		return BT_MODE_LE_FLOWCTL;
	case L2CAP_MODE_EXT_FLOWCTL:
		return BT_MODE_EXT_FLOWCTL;
	}

	return -EINVAL;
}

static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
				     char __user *optval, int __user *optlen)
{
	struct sock *sk = sock->sk;
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
	struct l2cap_options opts;
	struct l2cap_conninfo cinfo;
	int err = 0;
	size_t len;
	u32 opt;

	BT_DBG("sk %p", sk);

	if (get_user(len, optlen))
		return -EFAULT;

	lock_sock(sk);

	switch (optname) {
	case L2CAP_OPTIONS:
		/* LE sockets should use BT_SNDMTU/BT_RCVMTU, but since
		 * legacy ATT code depends on getsockopt for
		 * L2CAP_OPTIONS we need to let this pass.
		 */
		if (bdaddr_type_is_le(chan->src_type) &&
		    chan->scid != L2CAP_CID_ATT) {
			err = -EINVAL;
			break;
		}

		/* Only BR/EDR modes are supported here */
		switch (chan->mode) {
		case L2CAP_MODE_BASIC:
		case L2CAP_MODE_ERTM:
		case L2CAP_MODE_STREAMING:
			break;
		default:
			err = -EINVAL;
			break;
		}

		if (err < 0)
			break;

		memset(&opts, 0, sizeof(opts));
		opts.imtu     = chan->imtu;
		opts.omtu     = chan->omtu;
		opts.flush_to = chan->flush_to;
		opts.mode     = chan->mode;
		opts.fcs      = chan->fcs;
		opts.max_tx   = chan->max_tx;
		opts.txwin_size = chan->tx_win;

		BT_DBG("mode 0x%2.2x", chan->mode);

		len = min(len, sizeof(opts));
		if (copy_to_user(optval, (char *) &opts, len))
			err = -EFAULT;

		break;

	case L2CAP_LM:
		switch (chan->sec_level) {
		case BT_SECURITY_LOW:
			opt = L2CAP_LM_AUTH;
			break;
		case BT_SECURITY_MEDIUM:
			opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT;
			break;
		case BT_SECURITY_HIGH:
			opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
			      L2CAP_LM_SECURE;
			break;
		case BT_SECURITY_FIPS:
			opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
			      L2CAP_LM_SECURE | L2CAP_LM_FIPS;
			break;
		default:
			opt = 0;
			break;
		}

		if (test_bit(FLAG_ROLE_SWITCH, &chan->flags))
			opt |= L2CAP_LM_MASTER;

		if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
			opt |= L2CAP_LM_RELIABLE;

		if (put_user(opt, (u32 __user *) optval))
			err = -EFAULT;

		break;

	case L2CAP_CONNINFO:
		if (sk->sk_state != BT_CONNECTED &&
		    !(sk->sk_state == BT_CONNECT2 &&
		      test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) {
			err = -ENOTCONN;
			break;
		}

		memset(&cinfo, 0, sizeof(cinfo));
		cinfo.hci_handle = chan->conn->hcon->handle;
		memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3);

		len = min(len, sizeof(cinfo));
		if (copy_to_user(optval, (char *) &cinfo, len))
			err = -EFAULT;

		break;

	default:
		err = -ENOPROTOOPT;
		break;
	}

	release_sock(sk);
	return err;
}

static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
				 char __user *optval, int __user *optlen)
{
	struct sock *sk = sock->sk;
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
	struct bt_security sec;
	struct bt_power pwr;
	u32 phys;
	int len, mode, err = 0;

	BT_DBG("sk %p", sk);

	if (level == SOL_L2CAP)
		return l2cap_sock_getsockopt_old(sock, optname, optval, optlen);

	if (level != SOL_BLUETOOTH)
		return -ENOPROTOOPT;

	if (get_user(len, optlen))
		return -EFAULT;

	lock_sock(sk);

	switch (optname) {
	case BT_SECURITY:
		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
		    chan->chan_type != L2CAP_CHAN_FIXED &&
		    chan->chan_type != L2CAP_CHAN_RAW) {
			err = -EINVAL;
			break;
		}

		memset(&sec, 0, sizeof(sec));
		if (chan->conn) {
			sec.level = chan->conn->hcon->sec_level;

			if (sk->sk_state == BT_CONNECTED)
				sec.key_size = chan->conn->hcon->enc_key_size;
		} else {
			sec.level = chan->sec_level;
		}

		len = min_t(unsigned int, len, sizeof(sec));
		if (copy_to_user(optval, (char *) &sec, len))
			err = -EFAULT;

		break;

	case BT_DEFER_SETUP:
		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
			err = -EINVAL;
			break;
		}

		if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
			     (u32 __user *) optval))
			err = -EFAULT;

		break;

	case BT_FLUSHABLE:
		if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags),
			     (u32 __user *) optval))
			err = -EFAULT;

		break;

	case BT_POWER:
		if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
		    && sk->sk_type != SOCK_RAW) {
			err = -EINVAL;
			break;
		}

		pwr.force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);

		len = min_t(unsigned int, len, sizeof(pwr));
		if (copy_to_user(optval, (char *) &pwr, len))
			err = -EFAULT;

		break;

	case BT_CHANNEL_POLICY:
		if (put_user(chan->chan_policy, (u32 __user *) optval))
			err = -EFAULT;
		break;

	case BT_SNDMTU:
		if (!bdaddr_type_is_le(chan->src_type)) {
			err = -EINVAL;
			break;
		}

		if (sk->sk_state != BT_CONNECTED) {
			err = -ENOTCONN;
			break;
		}

		if (put_user(chan->omtu, (u16 __user *) optval))
			err = -EFAULT;
		break;

	case BT_RCVMTU:
		if (!bdaddr_type_is_le(chan->src_type)) {
			err = -EINVAL;
			break;
		}

		if (put_user(chan->imtu, (u16 __user *) optval))
			err = -EFAULT;
		break;

	case BT_PHY:
		if (sk->sk_state != BT_CONNECTED) {
			err = -ENOTCONN;
			break;
		}

		phys = hci_conn_get_phy(chan->conn->hcon);

		if (put_user(phys, (u32 __user *) optval))
			err = -EFAULT;
		break;

	case BT_MODE:
		if (!enable_ecred) {
			err = -ENOPROTOOPT;
			break;
		}

		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
			err = -EINVAL;
			break;
		}

		mode = l2cap_get_mode(chan);
		if (mode < 0) {
			err = mode;
			break;
		}

		if (put_user(mode, (u8 __user *) optval))
			err = -EFAULT;
		break;

	default:
		err = -ENOPROTOOPT;
		break;
	}

	release_sock(sk);
	return err;
}

static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu)
{
	switch (chan->scid) {
	case L2CAP_CID_ATT:
		if (mtu && mtu < L2CAP_LE_MIN_MTU)
			return false;
		break;

	default:
		if (mtu && mtu < L2CAP_DEFAULT_MIN_MTU)
			return false;
	}

	return true;
}

static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
				     sockptr_t optval, unsigned int optlen)
{
	struct sock *sk = sock->sk;
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
	struct l2cap_options opts;
	int err = 0;
	u32 opt;

	BT_DBG("sk %p", sk);

	lock_sock(sk);

	switch (optname) {
	case L2CAP_OPTIONS:
		if (bdaddr_type_is_le(chan->src_type)) {
			err = -EINVAL;
			break;
		}

		if (sk->sk_state == BT_CONNECTED) {
			err = -EINVAL;
			break;
		}

		opts.imtu     = chan->imtu;
		opts.omtu     = chan->omtu;
		opts.flush_to = chan->flush_to;
		opts.mode     = chan->mode;
		opts.fcs      = chan->fcs;
		opts.max_tx   = chan->max_tx;
		opts.txwin_size = chan->tx_win;

		err = copy_safe_from_sockptr(&opts, sizeof(opts), optval,
					     optlen);
		if (err)
			break;

		if (opts.txwin_size > L2CAP_DEFAULT_EXT_WINDOW) {
			err = -EINVAL;
			break;
		}

		if (!l2cap_valid_mtu(chan, opts.imtu)) {
			err = -EINVAL;
			break;
		}

		/* Only BR/EDR modes are supported here */
		switch (opts.mode) {
		case L2CAP_MODE_BASIC:
			clear_bit(CONF_STATE2_DEVICE, &chan->conf_state);
			break;
		case L2CAP_MODE_ERTM:
		case L2CAP_MODE_STREAMING:
			if (!disable_ertm)
				break;
			fallthrough;
		default:
			err = -EINVAL;
			break;
		}

		if (err < 0)
			break;

		chan->mode = opts.mode;

		BT_DBG("mode 0x%2.2x", chan->mode);

		chan->imtu = opts.imtu;
		chan->omtu = opts.omtu;
		chan->fcs  = opts.fcs;
		chan->max_tx = opts.max_tx;
		chan->tx_win = opts.txwin_size;
		chan->flush_to = opts.flush_to;
		break;

	case L2CAP_LM:
		err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
		if (err)
			break;

		if (opt & L2CAP_LM_FIPS) {
			err = -EINVAL;
			break;
		}

		if (opt & L2CAP_LM_AUTH)
			chan->sec_level = BT_SECURITY_LOW;
		if (opt & L2CAP_LM_ENCRYPT)
			chan->sec_level = BT_SECURITY_MEDIUM;
		if (opt & L2CAP_LM_SECURE)
			chan->sec_level = BT_SECURITY_HIGH;

		if (opt & L2CAP_LM_MASTER)
			set_bit(FLAG_ROLE_SWITCH, &chan->flags);
		else
			clear_bit(FLAG_ROLE_SWITCH, &chan->flags);

		if (opt & L2CAP_LM_RELIABLE)
			set_bit(FLAG_FORCE_RELIABLE, &chan->flags);
		else
			clear_bit(FLAG_FORCE_RELIABLE, &chan->flags);
		break;

	default:
		err = -ENOPROTOOPT;
		break;
	}

	release_sock(sk);
	return err;
}

static int l2cap_set_mode(struct l2cap_chan *chan, u8 mode)
{
	switch (mode) {
	case BT_MODE_BASIC:
		if (bdaddr_type_is_le(chan->src_type))
			return -EINVAL;
		mode = L2CAP_MODE_BASIC;
		clear_bit(CONF_STATE2_DEVICE, &chan->conf_state);
		break;
	case BT_MODE_ERTM:
		if (!disable_ertm || bdaddr_type_is_le(chan->src_type))
			return -EINVAL;
		mode = L2CAP_MODE_ERTM;
		break;
	case BT_MODE_STREAMING:
		if (!disable_ertm || bdaddr_type_is_le(chan->src_type))
			return -EINVAL;
		mode = L2CAP_MODE_STREAMING;
		break;
	case BT_MODE_LE_FLOWCTL:
		if (!bdaddr_type_is_le(chan->src_type))
			return -EINVAL;
		mode = L2CAP_MODE_LE_FLOWCTL;
		break;
	case BT_MODE_EXT_FLOWCTL:
		/* TODO: Add support for ECRED PDUs to BR/EDR */
		if (!bdaddr_type_is_le(chan->src_type))
			return -EINVAL;
		mode = L2CAP_MODE_EXT_FLOWCTL;
		break;
	default:
		return -EINVAL;
	}

	chan->mode = mode;

	return 0;
}

static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
				 sockptr_t optval, unsigned int optlen)
{
	struct sock *sk = sock->sk;
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
	struct bt_security sec;
	struct bt_power pwr;
	struct l2cap_conn *conn;
	int err = 0;
	u32 opt;
	u16 mtu;
	u8 mode;

	BT_DBG("sk %p", sk);

	if (level == SOL_L2CAP)
		return l2cap_sock_setsockopt_old(sock, optname, optval, optlen);

	if (level != SOL_BLUETOOTH)
		return -ENOPROTOOPT;

	lock_sock(sk);

	switch (optname) {
	case BT_SECURITY:
		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
		    chan->chan_type != L2CAP_CHAN_FIXED &&
		    chan->chan_type != L2CAP_CHAN_RAW) {
			err = -EINVAL;
			break;
		}

		sec.level = BT_SECURITY_LOW;

		err = copy_safe_from_sockptr(&sec, sizeof(sec), optval, optlen);
		if (err)
			break;

		if (sec.level < BT_SECURITY_LOW ||
		    sec.level > BT_SECURITY_FIPS) {
			err = -EINVAL;
			break;
		}

		chan->sec_level = sec.level;

		if (!chan->conn)
			break;

		conn = chan->conn;

		/* change security for LE channels */
		if (chan->scid == L2CAP_CID_ATT) {
			if (smp_conn_security(conn->hcon, sec.level)) {
				err = -EINVAL;
				break;
			}

			set_bit(FLAG_PENDING_SECURITY, &chan->flags);
			sk->sk_state = BT_CONFIG;
			chan->state = BT_CONFIG;

		/* or for ACL link */
		} else if ((sk->sk_state == BT_CONNECT2 &&
			    test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) ||
			   sk->sk_state == BT_CONNECTED) {
			if (!l2cap_chan_check_security(chan, true))
				set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
			else
				sk->sk_state_change(sk);
		} else {
			err = -EINVAL;
		}
		break;

	case BT_DEFER_SETUP:
		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
			err = -EINVAL;
			break;
		}

		err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
		if (err)
			break;

		if (opt) {
			set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
			set_bit(FLAG_DEFER_SETUP, &chan->flags);
		} else {
			clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
			clear_bit(FLAG_DEFER_SETUP, &chan->flags);
		}
		break;

	case BT_FLUSHABLE:
		err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
		if (err)
			break;

		if (opt > BT_FLUSHABLE_ON) {
			err = -EINVAL;
			break;
		}

		if (opt == BT_FLUSHABLE_OFF) {
			conn = chan->conn;
			/* proceed further only when we have l2cap_conn and
			   No Flush support in the LM */
			if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) {
				err = -EINVAL;
				break;
			}
		}

		if (opt)
			set_bit(FLAG_FLUSHABLE, &chan->flags);
		else
			clear_bit(FLAG_FLUSHABLE, &chan->flags);
		break;

	case BT_POWER:
		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
		    chan->chan_type != L2CAP_CHAN_RAW) {
			err = -EINVAL;
			break;
		}

		pwr.force_active = BT_POWER_FORCE_ACTIVE_ON;

		err = copy_safe_from_sockptr(&pwr, sizeof(pwr), optval, optlen);
		if (err)
			break;

		if (pwr.force_active)
			set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
		else
			clear_bit(FLAG_FORCE_ACTIVE, &chan->flags);
		break;

	case BT_CHANNEL_POLICY:
		err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
		if (err)
			break;

		err = -EOPNOTSUPP;
		break;

	case BT_SNDMTU:
		if (!bdaddr_type_is_le(chan->src_type)) {
			err = -EINVAL;
			break;
		}

		/* Setting is not supported as it's the remote side that
		 * decides this.
		 */
		err = -EPERM;
		break;

	case BT_RCVMTU:
		if (!bdaddr_type_is_le(chan->src_type)) {
			err = -EINVAL;
			break;
		}

		if (chan->mode == L2CAP_MODE_LE_FLOWCTL &&
		    sk->sk_state == BT_CONNECTED) {
			err = -EISCONN;
			break;
		}

		err = copy_safe_from_sockptr(&mtu, sizeof(mtu), optval, optlen);
		if (err)
			break;

		if (chan->mode == L2CAP_MODE_EXT_FLOWCTL &&
		    sk->sk_state == BT_CONNECTED)
			err = l2cap_chan_reconfigure(chan, mtu);
		else
			chan->imtu = mtu;

		break;

	case BT_MODE:
		if (!enable_ecred) {
			err = -ENOPROTOOPT;
			break;
		}

		BT_DBG("sk->sk_state %u", sk->sk_state);

		if (sk->sk_state != BT_BOUND) {
			err = -EINVAL;
			break;
		}

		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
			err = -EINVAL;
			break;
		}

		err = copy_safe_from_sockptr(&mode, sizeof(mode), optval,
					     optlen);
		if (err)
			break;

		BT_DBG("mode %u", mode);

		err = l2cap_set_mode(chan, mode);
		if (err)
			break;

		BT_DBG("mode 0x%2.2x", chan->mode);

		break;

	default:
		err = -ENOPROTOOPT;
		break;
	}

	release_sock(sk);
	return err;
}

static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg,
			      size_t len)
{
	struct sock *sk = sock->sk;
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
	struct sockcm_cookie sockc;
	int err;

	BT_DBG("sock %p, sk %p", sock, sk);

	err = sock_error(sk);
	if (err)
		return err;

	if (msg->msg_flags & MSG_OOB)
		return -EOPNOTSUPP;

	if (sk->sk_state != BT_CONNECTED)
		return -ENOTCONN;

	hci_sockcm_init(&sockc, sk);

	if (msg->msg_controllen) {
		err = sock_cmsg_send(sk, msg, &sockc);
		if (err)
			return err;
	}

	lock_sock(sk);
	err = bt_sock_wait_ready(sk, msg->msg_flags);
	release_sock(sk);
	if (err)
		return err;

	l2cap_chan_lock(chan);
	err = l2cap_chan_send(chan, msg, len, &sockc);
	l2cap_chan_unlock(chan);

	return err;
}

static void l2cap_publish_rx_avail(struct l2cap_chan *chan)
{
	struct sock *sk = chan->data;
	ssize_t avail = sk->sk_rcvbuf - atomic_read(&sk->sk_rmem_alloc);
	int expected_skbs, skb_overhead;

	if (avail <= 0) {
		l2cap_chan_rx_avail(chan, 0);
		return;
	}

	if (!chan->mps) {
		l2cap_chan_rx_avail(chan, -1);
		return;
	}

	/* Correct available memory by estimated sk_buff overhead.
	 * This is significant due to small transfer sizes. However, accept
	 * at least one full packet if receive space is non-zero.
	 */
	expected_skbs = DIV_ROUND_UP(avail, chan->mps);
	skb_overhead = expected_skbs * sizeof(struct sk_buff);
	if (skb_overhead < avail)
		l2cap_chan_rx_avail(chan, avail - skb_overhead);
	else
		l2cap_chan_rx_avail(chan, -1);
}

static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
			      size_t len, int flags)
{
	struct sock *sk = sock->sk;
	struct l2cap_pinfo *pi = l2cap_pi(sk);
	int err;

	if (unlikely(flags & MSG_ERRQUEUE))
		return sock_recv_errqueue(sk, msg, len, SOL_BLUETOOTH,
					  BT_SCM_ERROR);

	lock_sock(sk);

	if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP,
						    &bt_sk(sk)->flags)) {
		if (pi->chan->mode == L2CAP_MODE_EXT_FLOWCTL) {
			sk->sk_state = BT_CONNECTED;
			pi->chan->state = BT_CONNECTED;
			__l2cap_ecred_conn_rsp_defer(pi->chan);
		} else if (bdaddr_type_is_le(pi->chan->src_type)) {
			sk->sk_state = BT_CONNECTED;
			pi->chan->state = BT_CONNECTED;
			__l2cap_le_connect_rsp_defer(pi->chan);
		} else {
			sk->sk_state = BT_CONFIG;
			pi->chan->state = BT_CONFIG;
			__l2cap_connect_rsp_defer(pi->chan);
		}

		err = 0;
		goto done;
	}

	release_sock(sk);

	if (sock->type == SOCK_STREAM)
		err = bt_sock_stream_recvmsg(sock, msg, len, flags);
	else
		err = bt_sock_recvmsg(sock, msg, len, flags);

	if (pi->chan->mode != L2CAP_MODE_ERTM &&
	    pi->chan->mode != L2CAP_MODE_LE_FLOWCTL &&
	    pi->chan->mode != L2CAP_MODE_EXT_FLOWCTL)
		return err;

	lock_sock(sk);

	l2cap_publish_rx_avail(pi->chan);

	/* Attempt to put pending rx data in the socket buffer */
	while (!list_empty(&pi->rx_busy)) {
		struct l2cap_rx_busy *rx_busy =
			list_first_entry(&pi->rx_busy,
					 struct l2cap_rx_busy,
					 list);
		if (__sock_queue_rcv_skb(sk, rx_busy->skb) < 0)
			goto done;
		list_del(&rx_busy->list);
		kfree(rx_busy);
	}

	/* Restore data flow when half of the receive buffer is
	 * available.  This avoids resending large numbers of
	 * frames.
	 */
	if (test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state) &&
	    atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1)
		l2cap_chan_busy(pi->chan, 0);

done:
	release_sock(sk);
	return err;
}

/* Kill socket (only if zapped and orphan)
 * Must be called on unlocked socket, with l2cap channel lock.
 */
static void l2cap_sock_kill(struct sock *sk)
{
	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
		return;

	BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));

	/* Sock is dead, so set chan data to NULL, avoid other task use invalid
	 * sock pointer.
	 */
	l2cap_pi(sk)->chan->data = NULL;
	/* Kill poor orphan */

	l2cap_chan_put(l2cap_pi(sk)->chan);
	sock_set_flag(sk, SOCK_DEAD);
	sock_put(sk);
}

static int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan)
{
	DECLARE_WAITQUEUE(wait, current);
	int err = 0;
	int timeo = L2CAP_WAIT_ACK_POLL_PERIOD;
	/* Timeout to prevent infinite loop */
	unsigned long timeout = jiffies + L2CAP_WAIT_ACK_TIMEOUT;

	add_wait_queue(sk_sleep(sk), &wait);
	set_current_state(TASK_INTERRUPTIBLE);
	do {
		BT_DBG("Waiting for %d ACKs, timeout %04d ms",
		       chan->unacked_frames, time_after(jiffies, timeout) ? 0 :
		       jiffies_to_msecs(timeout - jiffies));

		if (!timeo)
			timeo = L2CAP_WAIT_ACK_POLL_PERIOD;

		if (signal_pending(current)) {
			err = sock_intr_errno(timeo);
			break;
		}

		release_sock(sk);
		timeo = schedule_timeout(timeo);
		lock_sock(sk);
		set_current_state(TASK_INTERRUPTIBLE);

		err = sock_error(sk);
		if (err)
			break;

		if (time_after(jiffies, timeout)) {
			err = -ENOLINK;
			break;
		}

	} while (chan->unacked_frames > 0 &&
		 chan->state == BT_CONNECTED);

	set_current_state(TASK_RUNNING);
	remove_wait_queue(sk_sleep(sk), &wait);
	return err;
}

static int l2cap_sock_shutdown(struct socket *sock, int how)
{
	struct sock *sk = sock->sk;
	struct l2cap_chan *chan;
	struct l2cap_conn *conn;
	int err = 0;

	BT_DBG("sock %p, sk %p, how %d", sock, sk, how);

	/* 'how' parameter is mapped to sk_shutdown as follows:
	 * SHUT_RD   (0) --> RCV_SHUTDOWN  (1)
	 * SHUT_WR   (1) --> SEND_SHUTDOWN (2)
	 * SHUT_RDWR (2) --> SHUTDOWN_MASK (3)
	 */
	how++;

	if (!sk)
		return 0;

	lock_sock(sk);

	if ((sk->sk_shutdown & how) == how)
		goto shutdown_already;

	BT_DBG("Handling sock shutdown");

	/* prevent sk structure from being freed whilst unlocked */
	sock_hold(sk);

	/* prevent chan structure from being freed whilst unlocked */
	chan = l2cap_chan_hold_unless_zero(l2cap_pi(sk)->chan);
	if (!chan)
		goto shutdown_already;

	BT_DBG("chan %p state %s", chan, state_to_string(chan->state));

	if (chan->mode == L2CAP_MODE_ERTM &&
	    chan->unacked_frames > 0 &&
	    chan->state == BT_CONNECTED) {
		err = __l2cap_wait_ack(sk, chan);

		/* After waiting for ACKs, check whether shutdown
		 * has already been actioned to close the L2CAP
		 * link such as by l2cap_disconnection_req().
		 */
		if ((sk->sk_shutdown & how) == how)
			goto shutdown_matched;
	}

	/* Try setting the RCV_SHUTDOWN bit, return early if SEND_SHUTDOWN
	 * is already set
	 */
	if ((how & RCV_SHUTDOWN) && !(sk->sk_shutdown & RCV_SHUTDOWN)) {
		sk->sk_shutdown |= RCV_SHUTDOWN;
		if ((sk->sk_shutdown & how) == how)
			goto shutdown_matched;
	}

	sk->sk_shutdown |= SEND_SHUTDOWN;
	release_sock(sk);

	l2cap_chan_lock(chan);
	/* prevent conn structure from being freed */
	conn = l2cap_conn_hold_unless_zero(chan->conn);
	l2cap_chan_unlock(chan);

	if (conn)
		/* mutex lock must be taken before l2cap_chan_lock() */
		mutex_lock(&conn->lock);

	l2cap_chan_lock(chan);
	l2cap_chan_close(chan, 0);
	l2cap_chan_unlock(chan);

	if (conn) {
		mutex_unlock(&conn->lock);
		l2cap_conn_put(conn);
	}

	lock_sock(sk);

	if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
	    !(current->flags & PF_EXITING))
		err = bt_sock_wait_state(sk, BT_CLOSED,
					 sk->sk_lingertime);

shutdown_matched:
	l2cap_chan_put(chan);
	sock_put(sk);

shutdown_already:
	if (!err && sk->sk_err)
		err = -sk->sk_err;

	release_sock(sk);

	BT_DBG("Sock shutdown complete err: %d", err);

	return err;
}

static int l2cap_sock_release(struct socket *sock)
{
	struct sock *sk = sock->sk;
	int err;
	struct l2cap_chan *chan;

	BT_DBG("sock %p, sk %p", sock, sk);

	if (!sk)
		return 0;

	lock_sock_nested(sk, L2CAP_NESTING_PARENT);
	l2cap_sock_cleanup_listen(sk);
	release_sock(sk);

	bt_sock_unlink(&l2cap_sk_list, sk);

	err = l2cap_sock_shutdown(sock, SHUT_RDWR);
	chan = l2cap_pi(sk)->chan;

	l2cap_chan_hold(chan);
	l2cap_chan_lock(chan);

	sock_orphan(sk);
	l2cap_sock_kill(sk);

	l2cap_chan_unlock(chan);
	l2cap_chan_put(chan);

	return err;
}

static void l2cap_sock_cleanup_listen(struct sock *parent)
{
	struct sock *sk;

	BT_DBG("parent %p state %s", parent,
	       state_to_string(parent->sk_state));

	/* Close not yet accepted channels */
	while ((sk = bt_accept_dequeue(parent, NULL))) {
		struct l2cap_chan *chan = l2cap_pi(sk)->chan;

		BT_DBG("child chan %p state %s", chan,
		       state_to_string(chan->state));

		l2cap_chan_hold(chan);
		l2cap_chan_lock(chan);

		__clear_chan_timer(chan);
		l2cap_chan_close(chan, ECONNRESET);
		l2cap_sock_kill(sk);

		l2cap_chan_unlock(chan);
		l2cap_chan_put(chan);
	}
}

static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
{
	struct sock *sk, *parent = chan->data;

	lock_sock(parent);

	/* Check for backlog size */
	if (sk_acceptq_is_full(parent)) {
		BT_DBG("backlog full %d", parent->sk_ack_backlog);
		release_sock(parent);
		return NULL;
	}

	sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
			      GFP_ATOMIC, 0);
	if (!sk) {
		release_sock(parent);
		return NULL;
        }

	bt_sock_reclassify_lock(sk, BTPROTO_L2CAP);

	l2cap_sock_init(sk, parent);

	bt_accept_enqueue(parent, sk, false);

	release_sock(parent);

	return l2cap_pi(sk)->chan;
}

static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
{
	struct sock *sk;
	struct l2cap_pinfo *pi;
	int err;

	sk = chan->data;
	if (!sk)
		return -ENXIO;

	pi = l2cap_pi(sk);
	lock_sock(sk);
	if (chan->mode == L2CAP_MODE_ERTM && !list_empty(&pi->rx_busy)) {
		err = -ENOMEM;
		goto done;
	}

	if (chan->mode != L2CAP_MODE_ERTM &&
	    chan->mode != L2CAP_MODE_STREAMING &&
	    chan->mode != L2CAP_MODE_LE_FLOWCTL &&
	    chan->mode != L2CAP_MODE_EXT_FLOWCTL) {
		/* Even if no filter is attached, we could potentially
		 * get errors from security modules, etc.
		 */
		err = sk_filter(sk, skb);
		if (err)
			goto done;
	}

	err = __sock_queue_rcv_skb(sk, skb);

	l2cap_publish_rx_avail(chan);

	/* For ERTM and LE, handle a skb that doesn't fit into the recv
	 * buffer.  This is important to do because the data frames
	 * have already been acked, so the skb cannot be discarded.
	 *
	 * Notify the l2cap core that the buffer is full, so the
	 * LOCAL_BUSY state is entered and no more frames are
	 * acked and reassembled until there is buffer space
	 * available.
	 */
	if (err < 0 &&
	    (chan->mode == L2CAP_MODE_ERTM ||
	     chan->mode == L2CAP_MODE_LE_FLOWCTL ||
	     chan->mode == L2CAP_MODE_EXT_FLOWCTL)) {
		struct l2cap_rx_busy *rx_busy =
			kmalloc(sizeof(*rx_busy), GFP_KERNEL);
		if (!rx_busy) {
			err = -ENOMEM;
			goto done;
		}
		rx_busy->skb = skb;
		list_add_tail(&rx_busy->list, &pi->rx_busy);
		l2cap_chan_busy(chan, 1);
		err = 0;
	}

done:
	release_sock(sk);

	return err;
}

static void l2cap_sock_close_cb(struct l2cap_chan *chan)
{
	struct sock *sk = chan->data;

	if (!sk)
		return;

	l2cap_sock_kill(sk);
}

static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
{
	struct sock *sk = chan->data;
	struct sock *parent;

	if (!sk)
		return;

	BT_DBG("chan %p state %s", chan, state_to_string(chan->state));

	/* This callback can be called both for server (BT_LISTEN)
	 * sockets as well as "normal" ones. To avoid lockdep warnings
	 * with child socket locking (through l2cap_sock_cleanup_listen)
	 * we need separation into separate nesting levels. The simplest
	 * way to accomplish this is to inherit the nesting level used
	 * for the channel.
	 */
	lock_sock_nested(sk, atomic_read(&chan->nesting));

	parent = bt_sk(sk)->parent;

	switch (chan->state) {
	case BT_OPEN:
	case BT_BOUND:
	case BT_CLOSED:
		break;
	case BT_LISTEN:
		l2cap_sock_cleanup_listen(sk);
		sk->sk_state = BT_CLOSED;
		chan->state = BT_CLOSED;

		break;
	default:
		sk->sk_state = BT_CLOSED;
		chan->state = BT_CLOSED;

		sk->sk_err = err;

		if (parent) {
			bt_accept_unlink(sk);
			parent->sk_data_ready(parent);
		} else {
			sk->sk_state_change(sk);
		}

		break;
	}
	release_sock(sk);

	/* Only zap after cleanup to avoid use after free race */
	sock_set_flag(sk, SOCK_ZAPPED);

}

static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state,
				       int err)
{
	struct sock *sk = chan->data;

	sk->sk_state = state;

	if (err)
		sk->sk_err = err;
}

static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
					       unsigned long hdr_len,
					       unsigned long len, int nb)
{
	struct sock *sk = chan->data;
	struct sk_buff *skb;
	int err;

	l2cap_chan_unlock(chan);
	skb = bt_skb_send_alloc(sk, hdr_len + len, nb, &err);
	l2cap_chan_lock(chan);

	if (!skb)
		return ERR_PTR(err);

	/* Channel lock is released before requesting new skb and then
	 * reacquired thus we need to recheck channel state.
	 */
	if (chan->state != BT_CONNECTED) {
		kfree_skb(skb);
		return ERR_PTR(-ENOTCONN);
	}

	skb->priority = READ_ONCE(sk->sk_priority);

	bt_cb(skb)->l2cap.chan = chan;

	return skb;
}

static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
{
	struct sock *sk = chan->data;
	struct sock *parent;

	lock_sock(sk);

	parent = bt_sk(sk)->parent;

	BT_DBG("sk %p, parent %p", sk, parent);

	sk->sk_state = BT_CONNECTED;
	sk->sk_state_change(sk);

	if (parent)
		parent->sk_data_ready(parent);

	release_sock(sk);
}

static void l2cap_sock_defer_cb(struct l2cap_chan *chan)
{
	struct sock *parent, *sk = chan->data;

	lock_sock(sk);

	parent = bt_sk(sk)->parent;
	if (parent)
		parent->sk_data_ready(parent);

	release_sock(sk);
}

static void l2cap_sock_resume_cb(struct l2cap_chan *chan)
{
	struct sock *sk = chan->data;

	if (!sk)
		return;

	if (test_and_clear_bit(FLAG_PENDING_SECURITY, &chan->flags)) {
		sk->sk_state = BT_CONNECTED;
		chan->state = BT_CONNECTED;
	}

	clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
	sk->sk_state_change(sk);
}

static void l2cap_sock_set_shutdown_cb(struct l2cap_chan *chan)
{
	struct sock *sk = chan->data;

	lock_sock(sk);
	sk->sk_shutdown = SHUTDOWN_MASK;
	release_sock(sk);
}

static long l2cap_sock_get_sndtimeo_cb(struct l2cap_chan *chan)
{
	struct sock *sk = chan->data;

	return READ_ONCE(sk->sk_sndtimeo);
}

static struct pid *l2cap_sock_get_peer_pid_cb(struct l2cap_chan *chan)
{
	struct sock *sk = chan->data;

	return sk->sk_peer_pid;
}

static void l2cap_sock_suspend_cb(struct l2cap_chan *chan)
{
	struct sock *sk = chan->data;

	set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
	sk->sk_state_change(sk);
}

static int l2cap_sock_filter(struct l2cap_chan *chan, struct sk_buff *skb)
{
	struct sock *sk = chan->data;

	switch (chan->mode) {
	case L2CAP_MODE_ERTM:
	case L2CAP_MODE_STREAMING:
		return sk_filter(sk, skb);
	}

	return 0;
}

static const struct l2cap_ops l2cap_chan_ops = {
	.name			= "L2CAP Socket Interface",
	.new_connection		= l2cap_sock_new_connection_cb,
	.recv			= l2cap_sock_recv_cb,
	.close			= l2cap_sock_close_cb,
	.teardown		= l2cap_sock_teardown_cb,
	.state_change		= l2cap_sock_state_change_cb,
	.ready			= l2cap_sock_ready_cb,
	.defer			= l2cap_sock_defer_cb,
	.resume			= l2cap_sock_resume_cb,
	.suspend		= l2cap_sock_suspend_cb,
	.set_shutdown		= l2cap_sock_set_shutdown_cb,
	.get_sndtimeo		= l2cap_sock_get_sndtimeo_cb,
	.get_peer_pid		= l2cap_sock_get_peer_pid_cb,
	.alloc_skb		= l2cap_sock_alloc_skb_cb,
	.filter			= l2cap_sock_filter,
};

static void l2cap_sock_destruct(struct sock *sk)
{
	struct l2cap_rx_busy *rx_busy, *next;

	BT_DBG("sk %p", sk);

	if (l2cap_pi(sk)->chan) {
		l2cap_pi(sk)->chan->data = NULL;
		l2cap_chan_put(l2cap_pi(sk)->chan);
	}

	list_for_each_entry_safe(rx_busy, next, &l2cap_pi(sk)->rx_busy, list) {
		kfree_skb(rx_busy->skb);
		list_del(&rx_busy->list);
		kfree(rx_busy);
	}

	skb_queue_purge(&sk->sk_receive_queue);
	skb_queue_purge(&sk->sk_write_queue);
}

static void l2cap_skb_msg_name(struct sk_buff *skb, void *msg_name,
			       int *msg_namelen)
{
	DECLARE_SOCKADDR(struct sockaddr_l2 *, la, msg_name);

	memset(la, 0, sizeof(struct sockaddr_l2));
	la->l2_family = AF_BLUETOOTH;
	la->l2_psm = bt_cb(skb)->l2cap.psm;
	bacpy(&la->l2_bdaddr, &bt_cb(skb)->l2cap.bdaddr);

	*msg_namelen = sizeof(struct sockaddr_l2);
}

static void l2cap_sock_init(struct sock *sk, struct sock *parent)
{
	struct l2cap_chan *chan = l2cap_pi(sk)->chan;

	BT_DBG("sk %p", sk);

	if (parent) {
		struct l2cap_chan *pchan = l2cap_pi(parent)->chan;

		sk->sk_type = parent->sk_type;
		bt_sk(sk)->flags = bt_sk(parent)->flags;

		chan->chan_type = pchan->chan_type;
		chan->imtu = pchan->imtu;
		chan->omtu = pchan->omtu;
		chan->conf_state = pchan->conf_state;
		chan->mode = pchan->mode;
		chan->fcs  = pchan->fcs;
		chan->max_tx = pchan->max_tx;
		chan->tx_win = pchan->tx_win;
		chan->tx_win_max = pchan->tx_win_max;
		chan->sec_level = pchan->sec_level;
		chan->flags = pchan->flags;
		chan->tx_credits = pchan->tx_credits;
		chan->rx_credits = pchan->rx_credits;

		if (chan->chan_type == L2CAP_CHAN_FIXED) {
			chan->scid = pchan->scid;
			chan->dcid = pchan->scid;
		}

		security_sk_clone(parent, sk);
	} else {
		switch (sk->sk_type) {
		case SOCK_RAW:
			chan->chan_type = L2CAP_CHAN_RAW;
			break;
		case SOCK_DGRAM:
			chan->chan_type = L2CAP_CHAN_CONN_LESS;
			bt_sk(sk)->skb_msg_name = l2cap_skb_msg_name;
			break;
		case SOCK_SEQPACKET:
		case SOCK_STREAM:
			chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
			break;
		}

		chan->imtu = L2CAP_DEFAULT_MTU;
		chan->omtu = 0;
		if (!disable_ertm && sk->sk_type == SOCK_STREAM) {
			chan->mode = L2CAP_MODE_ERTM;
			set_bit(CONF_STATE2_DEVICE, &chan->conf_state);
		} else {
			chan->mode = L2CAP_MODE_BASIC;
		}

		l2cap_chan_set_defaults(chan);
	}

	/* Default config options */
	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;

	chan->data = sk;
	chan->ops = &l2cap_chan_ops;

	l2cap_publish_rx_avail(chan);
}

static struct proto l2cap_proto = {
	.name		= "L2CAP",
	.owner		= THIS_MODULE,
	.obj_size	= sizeof(struct l2cap_pinfo)
};

static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
				     int proto, gfp_t prio, int kern)
{
	struct sock *sk;
	struct l2cap_chan *chan;

	sk = bt_sock_alloc(net, sock, &l2cap_proto, proto, prio, kern);
	if (!sk)
		return NULL;

	sk->sk_destruct = l2cap_sock_destruct;
	sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;

	INIT_LIST_HEAD(&l2cap_pi(sk)->rx_busy);

	chan = l2cap_chan_create();
	if (!chan) {
		sk_free(sk);
		if (sock)
			sock->sk = NULL;
		return NULL;
	}

	l2cap_chan_hold(chan);

	l2cap_pi(sk)->chan = chan;

	return sk;
}

static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
			     int kern)
{
	struct sock *sk;

	BT_DBG("sock %p", sock);

	sock->state = SS_UNCONNECTED;

	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
	    sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
		return -ESOCKTNOSUPPORT;

	if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
		return -EPERM;

	sock->ops = &l2cap_sock_ops;

	sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern);
	if (!sk)
		return -ENOMEM;

	l2cap_sock_init(sk, NULL);
	bt_sock_link(&l2cap_sk_list, sk);
	return 0;
}

static const struct proto_ops l2cap_sock_ops = {
	.family		= PF_BLUETOOTH,
	.owner		= THIS_MODULE,
	.release	= l2cap_sock_release,
	.bind		= l2cap_sock_bind,
	.connect	= l2cap_sock_connect,
	.listen		= l2cap_sock_listen,
	.accept		= l2cap_sock_accept,
	.getname	= l2cap_sock_getname,
	.sendmsg	= l2cap_sock_sendmsg,
	.recvmsg	= l2cap_sock_recvmsg,
	.poll		= bt_sock_poll,
	.ioctl		= bt_sock_ioctl,
	.gettstamp	= sock_gettstamp,
	.mmap		= sock_no_mmap,
	.socketpair	= sock_no_socketpair,
	.shutdown	= l2cap_sock_shutdown,
	.setsockopt	= l2cap_sock_setsockopt,
	.getsockopt	= l2cap_sock_getsockopt
};

static const struct net_proto_family l2cap_sock_family_ops = {
	.family	= PF_BLUETOOTH,
	.owner	= THIS_MODULE,
	.create	= l2cap_sock_create,
};

int __init l2cap_init_sockets(void)
{
	int err;

	BUILD_BUG_ON(sizeof(struct sockaddr_l2) > sizeof(struct sockaddr));

	err = proto_register(&l2cap_proto, 0);
	if (err < 0)
		return err;

	err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
	if (err < 0) {
		BT_ERR("L2CAP socket registration failed");
		goto error;
	}

	err = bt_procfs_init(&init_net, "l2cap", &l2cap_sk_list,
			     NULL);
	if (err < 0) {
		BT_ERR("Failed to create L2CAP proc file");
		bt_sock_unregister(BTPROTO_L2CAP);
		goto error;
	}

	BT_INFO("L2CAP socket layer initialized");

	return 0;

error:
	proto_unregister(&l2cap_proto);
	return err;
}

void l2cap_cleanup_sockets(void)
{
	bt_procfs_cleanup(&init_net, "l2cap");
	bt_sock_unregister(BTPROTO_L2CAP);
	proto_unregister(&l2cap_proto);
}
]

41/2 2026/02/13 13:19 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 58905
							output: 45
							thoughts: 5456
						

Thoughts:
**Analysis of L2CAP Socket Data Race**

Okay, so I've been reviewing this code, specifically `l2cap_sock_getname`, and it's confirmed: the socket lock isn't held when accessing `chan->src` and `chan->dst`. That's not ideal. The obvious fix would be to add `lock_sock(sk)` in all the relevant spots like `getname` and `connect`, but that's potentially expensive and risks deadlocks.

The race in `l2cap_sock_connect` is particularly interesting because the value of `chan->src` is being used to make a decision. I see `READ_ONCE` is used on `sk->sk_sndtimeo`, which indicates *some* awareness of potential data races. But nothing similar for `chan->src` and if `chan->src` is 6 bytes `READ_ONCE` can't be used anyway.

So, is this a benign race? The usual rule of thumb is that if it doesn't cause a crash and the resulting behavior is acceptable (like a slightly stale counter), then it's fine. Here, a race could lead to `connect` failing or using a wrong source address, which is probably okay since the application is buggy if it's concurrently calling `bind` and `connect`. However, KCSAN is flagging it, because, well, it's a *real* data race.

No risk of memory corruption, no crash risk directly. Wait, *could* `bacmp` or `bacpy` (which are just `memcmp` and `memcpy`) be implemented in a way that causes issues? Nope, they're fine. On some architectures, `memcpy` might use instructions that could cause alignment faults. But that's unlikely for 6 bytes on x86.

There's a similar report for `rfcomm_sock_getname` and `rfcomm_sock_bind` which was marked as "benign" or "to be fixed".

Let's see: are there any other writes to `chan->src`? In `l2cap_chan_connect`, there's a `bacpy` write, but that happens while `l2cap_chan_lock` is held. So, if `l2cap_sock_getname` is called while `l2cap_chan_connect` is updating `chan->src`, we have a race.

This seems pervasive in the Bluetooth stack.

Now, according to the instructions, the definition of "benign" centers around simple variables and effective atomicity. A 6-byte array isn't a "simple int/bool", and it's not "effectively atomic." However, a `bdaddr_t` isn't a complex container either. If the race doesn't crash or corrupt memory, maybe it's fine considering the prevalence of races in this stack? The value changed from 0x00 to 0xff, so if it sees a "mixed" address, it's just wrong.

I *have* seen Bluetooth races being fixed recently, I'll check.

Let's look at `l2cap_sock_bind` again. It sets `chan->src` and `chan->src_type`. If `connect` reads these in between the two lines, there's a race. This is definitely an issue.

Now, is this harmful? If it fails a connection it is still a bug, but is it a *harmful* data race according to KCSAN? KCSAN is trying to find bugs and this leads to incorrect behavior, so it *is* a bug.

According to the instructions, if it doesn't cause memory corruption/crash with a conservative compiler that compiles accesses to primitive types as atomic, then it's benign. But this is *not* a "simple int/bool variable". If you look at how other kernel developers treat these: If it's a race that's only triggered by an application bug (concurrent `bind` and `connect`), it's often considered low priority or benign.

However, if it's shared by two processes, then it can still be triggered and it can affect logic. Here, it affects "fix up" logic and routing (`hci_get_route`). If `hci_get_route` returns a wrong `hdev`, it fails the connection.

But the application is already buggy.

Aha! In `l2cap_sock_connect` there is a `lock_sock` section, but it *doesn't* hold the lock throughout the entire function. They likely didn't hold the lock the whole time to avoid deadlocks. If I have to decide: It's a race on a 6-byte address, but it doesn'


42/2 2026/02/13 13:19 tool grepper
0m Error:
no matches

Args:
map[Expression:lock_sock\(sk\);.*zapped = sock_flag\(sk, SOCK_ZAPPED\);.*release_sock\(sk\);]

Results:
map[Output:]

43/2 2026/02/13 13:19 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 65445
							output: 29
							thoughts: 10
						

Thoughts:
Okay, here's my attempt at summarizing that thought process, tailored for an expert audience:

**Refining the Search Strategy**

Alright, I'm at a point where the complexity of the current approach is starting to bog me down. It's time to take a step back and reassess. Instead of getting lost in a maze of intricate commands, I'm going to try something fundamentally simpler, a basic 'grep'. It's about stripping away unnecessary layers and getting back to the core of the problem. Perhaps a more direct approach will be more productive. I can always build back complexity later if necessary, but this seems like the best starting point.



44/2 2026/02/13 13:19 tool grepper
0m Args:
map[Expression:zapped = sock_flag\(sk, SOCK_ZAPPED\);]

Results:
map[Output:net/bluetooth/l2cap_sock.c=181=static int l2cap_sock_connect(struct socket *sock, struct sockaddr_unsized *addr,
--
net/bluetooth/l2cap_sock.c-192-	lock_sock(sk);
net/bluetooth/l2cap_sock.c:193:	zapped = sock_flag(sk, SOCK_ZAPPED);
net/bluetooth/l2cap_sock.c-194-	release_sock(sk);
]

45/2 2026/02/13 13:19 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 65755
							output: 19
							thoughts: 732
						

Thoughts:
**My Assessment of the Data Race in `l2cap_sock_bind`**

Okay, so I've re-examined the code. It's exactly as I initially saw it in `l2cap_sock_bind`. Looking back at the `read-file` output for `l2cap_sock_bind`, specifically lines 132-138, I noticed this:

```c
	bacpy(&chan->src, &la.l2_bdaddr);
	chan->src_type = la.l2_bdaddr_type;

	if (la.l2_cid)
		err = l2cap_add_scid(chan, __le16_to_cpu(la.l2_cid));
	else
		err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm);
```

The race condition is definitely present. Now, the question is, is it harmful or benign? I need to analyze this very carefully.

My initial thought is that it *is* harmful. I have to be completely objective in this. My instinct is that it's a bug, and that I must judge it to be harmful. I must assess the reasoning behind calling it "benign".

I need to apply the definition of "benign" to this specific data race.  If I consider it benign, am I implicitly saying that this race is acceptable. I can't do that.

Many KCSAN reports flag races that are technically bugs but practically harmless. Is that the case here? The only potential consequence I'm seeing is a connection failure for a racing application. That *could* be considered practically harmless. But practically harmless is not the same as saying "this is not a bug."

The definition of a benign race is pretty specific: it should be on a simple int/bool variable or similar field, and the accesses are *not* protected by any mutual exclusion primitives. Here, the accesses *are* supposed to be protected by `lock_sock(sk)`. `bind` *should* protect them, but `connect` does not.  So, this doesn't fit the benign definition.

A non-benign (or 'harmful') data race, as per the definition, can lead to corruption or a crash.  This particular one might not lead to a crash, but...

The definition of "benign" also mentions flags, statistics counters, and similar fields.  This is *not* a flag or counter.

Therefore, I'm going to classify this as harmful.

Just to be absolutely certain, I'll quickly check if `l2cap_chan_connect` is ever called with the socket lock held in other places. No, it is a core function.

As a final check, I will see if there was a recent change where `l2cap_sock_connect` was modified to release the lock. I will check for any comments about it, in the absence of version history access.
There are no comments.

I'm confident in my assessment. I'll set the results.



46/2 2026/02/13 13:20 tool set-results
0m Args:
map[Benign:false Confident:true]

Results:
map[Benign:false Confident:true]

47/2 2026/02/13 13:20 llm expert
0m Model:
gemini-3-flash-preview

Tokens:
							input: 67198
							output: 584
							thoughts: 303
						

Thoughts:
**My Analysis of the L2CAP Socket Data Race**

Okay, so I've been looking at this L2CAP socket code and I think I've spotted a nasty little race condition. It's happening specifically between `l2cap_sock_bind()` and `l2cap_sock_connect()` on the same Bluetooth socket. The core issue is the protection around access to the `chan->src` Bluetooth address.

Essentially, `l2cap_sock_bind()` *holds* the socket lock, `lock_sock(sk)`, while it's writing that `chan->src` address. That seems correct, good practice. However, `l2cap_sock_connect()` prematurely *releases* that lock and then proceeds to read `chan->src` (using `bacmp()`, which seems fine on its own) *without* re-acquiring any protection.

This is where things get dicey. If `l2cap_sock_bind()` and `l2cap_sock_connect()` are running concurrently – which, knowing this kind of environment, is entirely possible – `l2cap_sock_connect()` might read a partially written or inconsistent Bluetooth address from `chan->src`. We're talking about a multi-byte structure, so there's a real possibility of it being in a transitional state.

This isn't just some benign race; this is a logic bug. That inconsistent `chan->src` value is then fed into logic that decides whether to "fix up" the source address type, and then it's *also* passed to `l2cap_chan_connect()`, which subsequently uses it for routing via `hci_get_route()`. A corrupted source address has all sorts of implications. This could lead to connection failures, like `-EHOSTUNREACH`, or, even worse, connections established with incorrect parameters.

While I don't see any immediate risk of kernel panic or memory corruption here, the fact that the race involves a multi-byte structure, directly impacts the outcome of a system call, and *should* be protected by that socket lock (because `bind()` shows intent) makes it a critical synchronization issue. It's a clear logic flaw introduced by insufficient synchronization in the code, and it needs to be addressed. This isn't just an inefficiency; it's a potential source of intermittent and hard-to-debug connection problems.



LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)