Commit b1235d79611e78a07629b4cbe53291c9cffd1834
1 parent
7cb127d5b0
Exists in
master
and in
7 other branches
[Bluetooth] Allow security for outgoing L2CAP connections
When requested the L2CAP layer will now enforce authentication and encryption on outgoing connections. The usefulness of this feature is kinda limited since it will not allow proper connection ownership tracking until the authentication procedure has been finished. This is a limitation of Bluetooth 2.0 and before and can only be fixed by using Simple Pairing. Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Showing 1 changed file with 108 additions and 64 deletions Side-by-side Diff
net/bluetooth/l2cap.c
... | ... | @@ -76,11 +76,21 @@ |
76 | 76 | static void l2cap_sock_timeout(unsigned long arg) |
77 | 77 | { |
78 | 78 | struct sock *sk = (struct sock *) arg; |
79 | + int reason; | |
79 | 80 | |
80 | 81 | BT_DBG("sock %p state %d", sk, sk->sk_state); |
81 | 82 | |
82 | 83 | bh_lock_sock(sk); |
83 | - __l2cap_sock_close(sk, ETIMEDOUT); | |
84 | + | |
85 | + if (sk->sk_state == BT_CONNECT && | |
86 | + (l2cap_pi(sk)->link_mode & (L2CAP_LM_AUTH | | |
87 | + L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE))) | |
88 | + reason = ECONNREFUSED; | |
89 | + else | |
90 | + reason = ETIMEDOUT; | |
91 | + | |
92 | + __l2cap_sock_close(sk, reason); | |
93 | + | |
84 | 94 | bh_unlock_sock(sk); |
85 | 95 | |
86 | 96 | l2cap_sock_kill(sk); |
... | ... | @@ -240,7 +250,7 @@ |
240 | 250 | hci_conn_put(conn->hcon); |
241 | 251 | } |
242 | 252 | |
243 | - sk->sk_state = BT_CLOSED; | |
253 | + sk->sk_state = BT_CLOSED; | |
244 | 254 | sock_set_flag(sk, SOCK_ZAPPED); |
245 | 255 | |
246 | 256 | if (err) |
247 | 257 | |
248 | 258 | |
249 | 259 | |
... | ... | @@ -307,14 +317,16 @@ |
307 | 317 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; |
308 | 318 | |
309 | 319 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { |
310 | - struct l2cap_conn_req req; | |
311 | - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); | |
312 | - req.psm = l2cap_pi(sk)->psm; | |
320 | + if (l2cap_check_link_mode(sk)) { | |
321 | + struct l2cap_conn_req req; | |
322 | + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); | |
323 | + req.psm = l2cap_pi(sk)->psm; | |
313 | 324 | |
314 | - l2cap_pi(sk)->ident = l2cap_get_ident(conn); | |
325 | + l2cap_pi(sk)->ident = l2cap_get_ident(conn); | |
315 | 326 | |
316 | - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | |
327 | + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | |
317 | 328 | L2CAP_CONN_REQ, sizeof(req), &req); |
329 | + } | |
318 | 330 | } else { |
319 | 331 | struct l2cap_info_req req; |
320 | 332 | req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); |
321 | 333 | |
322 | 334 | |
323 | 335 | |
... | ... | @@ -349,14 +361,16 @@ |
349 | 361 | } |
350 | 362 | |
351 | 363 | if (sk->sk_state == BT_CONNECT) { |
352 | - struct l2cap_conn_req req; | |
353 | - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); | |
354 | - req.psm = l2cap_pi(sk)->psm; | |
364 | + if (l2cap_check_link_mode(sk)) { | |
365 | + struct l2cap_conn_req req; | |
366 | + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); | |
367 | + req.psm = l2cap_pi(sk)->psm; | |
355 | 368 | |
356 | - l2cap_pi(sk)->ident = l2cap_get_ident(conn); | |
369 | + l2cap_pi(sk)->ident = l2cap_get_ident(conn); | |
357 | 370 | |
358 | - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | |
371 | + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | |
359 | 372 | L2CAP_CONN_REQ, sizeof(req), &req); |
373 | + } | |
360 | 374 | } else if (sk->sk_state == BT_CONNECT2) { |
361 | 375 | struct l2cap_conn_rsp rsp; |
362 | 376 | rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); |
... | ... | @@ -455,7 +469,8 @@ |
455 | 469 | |
456 | 470 | conn->feat_mask = 0; |
457 | 471 | |
458 | - setup_timer(&conn->info_timer, l2cap_info_timeout, (unsigned long)conn); | |
472 | + setup_timer(&conn->info_timer, l2cap_info_timeout, | |
473 | + (unsigned long) conn); | |
459 | 474 | |
460 | 475 | spin_lock_init(&conn->lock); |
461 | 476 | rwlock_init(&conn->chan_list.lock); |
... | ... | @@ -567,7 +582,7 @@ |
567 | 582 | while ((sk = bt_accept_dequeue(parent, NULL))) |
568 | 583 | l2cap_sock_close(sk); |
569 | 584 | |
570 | - parent->sk_state = BT_CLOSED; | |
585 | + parent->sk_state = BT_CLOSED; | |
571 | 586 | sock_set_flag(parent, SOCK_ZAPPED); |
572 | 587 | } |
573 | 588 | |
574 | 589 | |
... | ... | @@ -610,9 +625,8 @@ |
610 | 625 | req.scid = cpu_to_le16(l2cap_pi(sk)->scid); |
611 | 626 | l2cap_send_cmd(conn, l2cap_get_ident(conn), |
612 | 627 | L2CAP_DISCONN_REQ, sizeof(req), &req); |
613 | - } else { | |
628 | + } else | |
614 | 629 | l2cap_chan_del(sk, reason); |
615 | - } | |
616 | 630 | break; |
617 | 631 | |
618 | 632 | case BT_CONNECT: |
619 | 633 | |
... | ... | @@ -681,9 +695,9 @@ |
681 | 695 | sock_reset_flag(sk, SOCK_ZAPPED); |
682 | 696 | |
683 | 697 | sk->sk_protocol = proto; |
684 | - sk->sk_state = BT_OPEN; | |
698 | + sk->sk_state = BT_OPEN; | |
685 | 699 | |
686 | - setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long)sk); | |
700 | + setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk); | |
687 | 701 | |
688 | 702 | bt_sock_link(&l2cap_sk_list, sk); |
689 | 703 | return sk; |
... | ... | @@ -1201,7 +1215,8 @@ |
1201 | 1215 | __l2cap_sock_close(sk, 0); |
1202 | 1216 | |
1203 | 1217 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) |
1204 | - err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); | |
1218 | + err = bt_sock_wait_state(sk, BT_CLOSED, | |
1219 | + sk->sk_lingertime); | |
1205 | 1220 | } |
1206 | 1221 | release_sock(sk); |
1207 | 1222 | return err; |
... | ... | @@ -1245,6 +1260,11 @@ |
1245 | 1260 | */ |
1246 | 1261 | parent->sk_data_ready(parent, 0); |
1247 | 1262 | } |
1263 | + | |
1264 | + if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) { | |
1265 | + struct l2cap_conn *conn = l2cap_pi(sk)->conn; | |
1266 | + hci_conn_change_link_key(conn->hcon); | |
1267 | + } | |
1248 | 1268 | } |
1249 | 1269 | |
1250 | 1270 | /* Copy frame to all raw sockets on that connection */ |
... | ... | @@ -1778,7 +1798,7 @@ |
1778 | 1798 | |
1779 | 1799 | default: |
1780 | 1800 | sk->sk_state = BT_DISCONN; |
1781 | - sk->sk_err = ECONNRESET; | |
1801 | + sk->sk_err = ECONNRESET; | |
1782 | 1802 | l2cap_sock_set_timer(sk, HZ * 5); |
1783 | 1803 | { |
1784 | 1804 | struct l2cap_disconn_req req; |
1785 | 1805 | |
... | ... | @@ -2151,9 +2171,7 @@ |
2151 | 2171 | { |
2152 | 2172 | struct l2cap_chan_list *l; |
2153 | 2173 | struct l2cap_conn *conn = hcon->l2cap_data; |
2154 | - struct l2cap_conn_rsp rsp; | |
2155 | 2174 | struct sock *sk; |
2156 | - int result; | |
2157 | 2175 | |
2158 | 2176 | if (!conn) |
2159 | 2177 | return 0; |
2160 | 2178 | |
2161 | 2179 | |
2162 | 2180 | |
2163 | 2181 | |
2164 | 2182 | |
... | ... | @@ -2169,37 +2187,53 @@ |
2169 | 2187 | |
2170 | 2188 | bh_lock_sock(sk); |
2171 | 2189 | |
2172 | - if (sk->sk_state != BT_CONNECT2) { | |
2173 | - bh_unlock_sock(sk); | |
2174 | - continue; | |
2175 | - } | |
2176 | - | |
2177 | 2190 | if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) && |
2178 | - !(hcon->link_mode & HCI_LM_ENCRYPT)) { | |
2191 | + !(hcon->link_mode & HCI_LM_ENCRYPT) && | |
2192 | + !status) { | |
2179 | 2193 | bh_unlock_sock(sk); |
2180 | 2194 | continue; |
2181 | 2195 | } |
2182 | 2196 | |
2183 | - if (!status) { | |
2184 | - sk->sk_state = BT_CONFIG; | |
2185 | - result = 0; | |
2186 | - } else { | |
2187 | - sk->sk_state = BT_DISCONN; | |
2188 | - l2cap_sock_set_timer(sk, HZ/10); | |
2189 | - result = L2CAP_CR_SEC_BLOCK; | |
2190 | - } | |
2197 | + if (sk->sk_state == BT_CONNECT) { | |
2198 | + if (!status) { | |
2199 | + struct l2cap_conn_req req; | |
2200 | + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); | |
2201 | + req.psm = l2cap_pi(sk)->psm; | |
2191 | 2202 | |
2192 | - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); | |
2193 | - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); | |
2194 | - rsp.result = cpu_to_le16(result); | |
2195 | - rsp.status = cpu_to_le16(0); | |
2196 | - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | |
2197 | - L2CAP_CONN_RSP, sizeof(rsp), &rsp); | |
2203 | + l2cap_pi(sk)->ident = l2cap_get_ident(conn); | |
2198 | 2204 | |
2205 | + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | |
2206 | + L2CAP_CONN_REQ, sizeof(req), &req); | |
2207 | + } else { | |
2208 | + l2cap_sock_clear_timer(sk); | |
2209 | + l2cap_sock_set_timer(sk, HZ / 10); | |
2210 | + } | |
2211 | + } else if (sk->sk_state == BT_CONNECT2) { | |
2212 | + struct l2cap_conn_rsp rsp; | |
2213 | + __u16 result; | |
2214 | + | |
2215 | + if (!status) { | |
2216 | + sk->sk_state = BT_CONFIG; | |
2217 | + result = L2CAP_CR_SUCCESS; | |
2218 | + } else { | |
2219 | + sk->sk_state = BT_DISCONN; | |
2220 | + l2cap_sock_set_timer(sk, HZ / 10); | |
2221 | + result = L2CAP_CR_SEC_BLOCK; | |
2222 | + } | |
2223 | + | |
2224 | + rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); | |
2225 | + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); | |
2226 | + rsp.result = cpu_to_le16(result); | |
2227 | + rsp.status = cpu_to_le16(0); | |
2228 | + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | |
2229 | + L2CAP_CONN_RSP, sizeof(rsp), &rsp); | |
2230 | + } | |
2231 | + | |
2199 | 2232 | bh_unlock_sock(sk); |
2200 | 2233 | } |
2201 | 2234 | |
2202 | 2235 | read_unlock(&l->lock); |
2236 | + | |
2203 | 2237 | return 0; |
2204 | 2238 | } |
2205 | 2239 | |
2206 | 2240 | |
... | ... | @@ -2207,9 +2241,7 @@ |
2207 | 2241 | { |
2208 | 2242 | struct l2cap_chan_list *l; |
2209 | 2243 | struct l2cap_conn *conn = hcon->l2cap_data; |
2210 | - struct l2cap_conn_rsp rsp; | |
2211 | 2244 | struct sock *sk; |
2212 | - int result; | |
2213 | 2245 | |
2214 | 2246 | if (!conn) |
2215 | 2247 | return 0; |
2216 | 2248 | |
2217 | 2249 | |
2218 | 2250 | |
2219 | 2251 | |
2220 | 2252 | |
... | ... | @@ -2234,34 +2266,46 @@ |
2234 | 2266 | continue; |
2235 | 2267 | } |
2236 | 2268 | |
2237 | - if (sk->sk_state != BT_CONNECT2) { | |
2238 | - bh_unlock_sock(sk); | |
2239 | - continue; | |
2240 | - } | |
2269 | + if (sk->sk_state == BT_CONNECT) { | |
2270 | + if (!status) { | |
2271 | + struct l2cap_conn_req req; | |
2272 | + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); | |
2273 | + req.psm = l2cap_pi(sk)->psm; | |
2241 | 2274 | |
2242 | - if (!status) { | |
2243 | - sk->sk_state = BT_CONFIG; | |
2244 | - result = 0; | |
2245 | - } else { | |
2246 | - sk->sk_state = BT_DISCONN; | |
2247 | - l2cap_sock_set_timer(sk, HZ/10); | |
2248 | - result = L2CAP_CR_SEC_BLOCK; | |
2249 | - } | |
2275 | + l2cap_pi(sk)->ident = l2cap_get_ident(conn); | |
2250 | 2276 | |
2251 | - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); | |
2252 | - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); | |
2253 | - rsp.result = cpu_to_le16(result); | |
2254 | - rsp.status = cpu_to_le16(0); | |
2255 | - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | |
2256 | - L2CAP_CONN_RSP, sizeof(rsp), &rsp); | |
2277 | + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | |
2278 | + L2CAP_CONN_REQ, sizeof(req), &req); | |
2279 | + } else { | |
2280 | + l2cap_sock_clear_timer(sk); | |
2281 | + l2cap_sock_set_timer(sk, HZ / 10); | |
2282 | + } | |
2283 | + } else if (sk->sk_state == BT_CONNECT2) { | |
2284 | + struct l2cap_conn_rsp rsp; | |
2285 | + __u16 result; | |
2257 | 2286 | |
2258 | - if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) | |
2259 | - hci_conn_change_link_key(hcon); | |
2287 | + if (!status) { | |
2288 | + sk->sk_state = BT_CONFIG; | |
2289 | + result = L2CAP_CR_SUCCESS; | |
2290 | + } else { | |
2291 | + sk->sk_state = BT_DISCONN; | |
2292 | + l2cap_sock_set_timer(sk, HZ / 10); | |
2293 | + result = L2CAP_CR_SEC_BLOCK; | |
2294 | + } | |
2260 | 2295 | |
2296 | + rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); | |
2297 | + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); | |
2298 | + rsp.result = cpu_to_le16(result); | |
2299 | + rsp.status = cpu_to_le16(0); | |
2300 | + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | |
2301 | + L2CAP_CONN_RSP, sizeof(rsp), &rsp); | |
2302 | + } | |
2303 | + | |
2261 | 2304 | bh_unlock_sock(sk); |
2262 | 2305 | } |
2263 | 2306 | |
2264 | 2307 | read_unlock(&l->lock); |
2308 | + | |
2265 | 2309 | return 0; |
2266 | 2310 | } |
2267 | 2311 |