From 61b433579b6ffecb1d3534fd482dcd48535277c8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 29 May 2014 19:36:53 +0300 Subject: Bluetooth: Fix properly ignoring LTKs of unknown types In case there are new LTK types in the future we shouldn't just blindly assume that != MGMT_LTK_UNAUTHENTICATED means that the key is authenticated. This patch adds explicit checks for each allowed key type in the form of a switch statement and skips any key which has an unknown value. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org --- net/bluetooth/mgmt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5e9c21a5525f..0fce54412ffd 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4546,10 +4546,16 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, else type = HCI_SMP_LTK_SLAVE; - if (key->type == MGMT_LTK_UNAUTHENTICATED) + switch (key->type) { + case MGMT_LTK_UNAUTHENTICATED: authenticated = 0x00; - else + break; + case MGMT_LTK_AUTHENTICATED: authenticated = 0x01; + break; + default: + continue; + } hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type, authenticated, key->val, key->enc_size, key->ediv, -- cgit v1.2.3 From 7e3691e13ab51f3491e996e2edaf99b173621288 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 30 May 2014 14:45:19 +0300 Subject: Bluetooth: Fix authentication check for FIPS security level When checking whether we need to request authentication or not we should include HCI_SECURITY_FIPS to the levels that always need authentication. This patch fixes check for it in the hci_outgoing_auth_needed() function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org --- net/bluetooth/hci_event.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 492d8d5071c7..6cf9596ff69b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1453,6 +1453,7 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, * is requested. */ if (!hci_conn_ssp_enabled(conn) && !(conn->auth_type & 0x01) && + conn->pending_sec_level != BT_SECURITY_FIPS && conn->pending_sec_level != BT_SECURITY_HIGH && conn->pending_sec_level != BT_SECURITY_MEDIUM) return 0; -- cgit v1.2.3 From 62bbd5b35994eaf30519f126765d7f6af9cd3526 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 27 May 2014 11:33:22 +0300 Subject: Bluetooth: 6LoWPAN: Fix MAC address universal/local bit handling The universal/local bit handling was incorrectly done in the code. So when setting EUI address from BD address we do this: - If BD address type is PUBLIC, then we clear the universal bit in EUI address. If the address type is RANDOM, then the universal bit is set (BT 6lowpan draft chapter 3.2.2) - After this we invert the universal/local bit according to RFC 2464 When figuring out BD address we do the reverse: - Take EUI address from stateless IPv6 address, invert the universal/local bit according to RFC 2464 - If universal bit is 1 in this modified EUI address, then address type is set to RANDOM, otherwise it is PUBLIC Note that 6lowpan_iphc.[ch] does the final toggling of U/L bit before sending or receiving the network packet. Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org --- net/bluetooth/6lowpan.c | 65 ++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index adb3ea04adaa..d906016f3c6b 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -420,12 +420,18 @@ static int conn_send(struct l2cap_conn *conn, return 0; } -static void get_dest_bdaddr(struct in6_addr *ip6_daddr, - bdaddr_t *addr, u8 *addr_type) +static u8 get_addr_type_from_eui64(u8 byte) { - u8 *eui64; + /* Is universal(0) or local(1) bit, */ + if (byte & 0x02) + return ADDR_LE_DEV_RANDOM; - eui64 = ip6_daddr->s6_addr + 8; + return ADDR_LE_DEV_PUBLIC; +} + +static void copy_to_bdaddr(struct in6_addr *ip6_daddr, bdaddr_t *addr) +{ + u8 *eui64 = ip6_daddr->s6_addr + 8; addr->b[0] = eui64[7]; addr->b[1] = eui64[6]; @@ -433,16 +439,19 @@ static void get_dest_bdaddr(struct in6_addr *ip6_daddr, addr->b[3] = eui64[2]; addr->b[4] = eui64[1]; addr->b[5] = eui64[0]; +} - addr->b[5] ^= 2; +static void convert_dest_bdaddr(struct in6_addr *ip6_daddr, + bdaddr_t *addr, u8 *addr_type) +{ + copy_to_bdaddr(ip6_daddr, addr); - /* Set universal/local bit to 0 */ - if (addr->b[5] & 1) { - addr->b[5] &= ~1; - *addr_type = ADDR_LE_DEV_PUBLIC; - } else { - *addr_type = ADDR_LE_DEV_RANDOM; - } + /* We need to toggle the U/L bit that we got from IPv6 address + * so that we get the proper address and type of the BD address. + */ + addr->b[5] ^= 0x02; + + *addr_type = get_addr_type_from_eui64(addr->b[5]); } static int header_create(struct sk_buff *skb, struct net_device *netdev, @@ -473,9 +482,11 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, /* Get destination BT device from skb. * If there is no such peer then discard the packet. */ - get_dest_bdaddr(&hdr->daddr, &addr, &addr_type); + convert_dest_bdaddr(&hdr->daddr, &addr, &addr_type); - BT_DBG("dest addr %pMR type %d", &addr, addr_type); + BT_DBG("dest addr %pMR type %s IP %pI6c", &addr, + addr_type == ADDR_LE_DEV_PUBLIC ? "PUBLIC" : "RANDOM", + &hdr->daddr); read_lock_irqsave(&devices_lock, flags); peer = peer_lookup_ba(dev, &addr, addr_type); @@ -556,7 +567,7 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) } else { unsigned long flags; - get_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type); + convert_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type); eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8; dev = lowpan_dev(netdev); @@ -564,8 +575,10 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) peer = peer_lookup_ba(dev, &addr, addr_type); read_unlock_irqrestore(&devices_lock, flags); - BT_DBG("xmit from %s to %pMR (%pI6c) peer %p", netdev->name, - &addr, &lowpan_cb(skb)->addr, peer); + BT_DBG("xmit %s to %pMR type %s IP %pI6c peer %p", + netdev->name, &addr, + addr_type == ADDR_LE_DEV_PUBLIC ? "PUBLIC" : "RANDOM", + &lowpan_cb(skb)->addr, peer); if (peer && peer->conn) err = send_pkt(peer->conn, netdev->dev_addr, @@ -620,13 +633,13 @@ static void set_addr(u8 *eui, u8 *addr, u8 addr_type) eui[6] = addr[1]; eui[7] = addr[0]; - eui[0] ^= 2; - - /* Universal/local bit set, RFC 4291 */ + /* Universal/local bit set, BT 6lowpan draft ch. 3.2.1 */ if (addr_type == ADDR_LE_DEV_PUBLIC) - eui[0] |= 1; + eui[0] &= ~0x02; else - eui[0] &= ~1; + eui[0] |= 0x02; + + BT_DBG("type %d addr %*phC", addr_type, 8, eui); } static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr, @@ -634,7 +647,6 @@ static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr, { netdev->addr_assign_type = NET_ADDR_PERM; set_addr(netdev->dev_addr, addr->b, addr_type); - netdev->dev_addr[0] ^= 2; } static void ifup(struct net_device *netdev) @@ -684,13 +696,6 @@ static int add_peer_conn(struct l2cap_conn *conn, struct lowpan_dev *dev) memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, EUI64_ADDR_LEN); - peer->eui64_addr[0] ^= 2; /* second bit-flip (Universe/Local) - * is done according RFC2464 - */ - - raw_dump_inline(__func__, "peer IPv6 address", - (unsigned char *)&peer->peer_addr, 16); - raw_dump_inline(__func__, "peer EUI64 address", peer->eui64_addr, 8); write_lock_irqsave(&devices_lock, flags); INIT_LIST_HEAD(&peer->list); -- cgit v1.2.3 From 6a5e81650aa8f6e636d9537c7f127c0ee4d55eae Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 28 May 2014 14:43:04 +0300 Subject: Bluetooth: l2cap: Set more channel defaults Default values for various channel settings were missing. This way channel users do not need to set default values themselves. Signed-off-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a1e5bb7d06e8..746848229c85 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -471,8 +471,14 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan) chan->max_tx = L2CAP_DEFAULT_MAX_TX; chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; + chan->remote_max_tx = chan->max_tx; + chan->remote_tx_win = chan->tx_win; chan->ack_win = L2CAP_DEFAULT_TX_WINDOW; chan->sec_level = BT_SECURITY_LOW; + chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; + chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO; + chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO; + chan->conf_state = 0; set_bit(FLAG_FORCE_ACTIVE, &chan->flags); } -- cgit v1.2.3 From 79897d2097a629179e142014ecd3cdce6eac7f0e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 1 Jun 2014 09:45:24 +0300 Subject: Bluetooth: Fix requiring SMP MITM for outgoing connections Due to recent changes to the way that the MITM requirement is set for outgoing pairing attempts we can no longer rely on the hcon->auth_type variable (which is actually good since it was formed from BR/EDR concepts that don't really exist for SMP). To match the logic that BR/EDR now uses simply rely on the local IO capability and/or needed security level to set the MITM requirement for outgoing pairing requests. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org --- net/bluetooth/smp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 4f9662d0fd81..3d1cc164557d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -909,10 +909,11 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) authreq = seclevel_to_authreq(sec_level); - /* hcon->auth_type is set by pair_device in mgmt.c. If the MITM - * flag is set we should also set it for the SMP request. + /* Require MITM if IO Capability allows or the security level + * requires it. */ - if ((hcon->auth_type & 0x01)) + if (hcon->io_capability != HCI_IO_NO_INPUT_OUTPUT || + sec_level > BT_SECURITY_MEDIUM) authreq |= SMP_AUTH_MITM; if (hcon->link_mode & HCI_LM_MASTER) { -- cgit v1.2.3 From f3fb0b58c85666f73139963a7a04d7878f3d22c9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 2 Jun 2014 10:12:44 +0300 Subject: Bluetooth: Fix missing check for FIPS security level When checking whether a legacy link key provides at least HIGH security level we also need to check for FIPS level which is one step above HIGH. This patch fixes a missing check in the hci_link_key_request_evt() function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org --- net/bluetooth/hci_event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 6cf9596ff69b..df7895e8fcc8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3077,7 +3077,8 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) } if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 && - conn->pending_sec_level == BT_SECURITY_HIGH) { + (conn->pending_sec_level == BT_SECURITY_HIGH || + conn->pending_sec_level == BT_SECURITY_FIPS)) { BT_DBG("%s ignoring key unauthenticated for high security", hdev->name); goto not_found; -- cgit v1.2.3 From 8a96f3cd22878fc0bb564a8478a6e17c0b8dca73 Mon Sep 17 00:00:00 2001 From: Jukka Taimisto Date: Thu, 22 May 2014 10:02:39 +0000 Subject: Bluetooth: Fix L2CAP deadlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -[0x01 Introduction We have found a programming error causing a deadlock in Bluetooth subsystem of Linux kernel. The problem is caused by missing release_sock() call when L2CAP connection creation fails due full accept queue. The issue can be reproduced with 3.15-rc5 kernel and is also present in earlier kernels. -[0x02 Details The problem occurs when multiple L2CAP connections are created to a PSM which contains listening socket (like SDP) and left pending, for example, configuration (the underlying ACL link is not disconnected between connections). When L2CAP connection request is received and listening socket is found the l2cap_sock_new_connection_cb() function (net/bluetooth/l2cap_sock.c) is called. This function locks the 'parent' socket and then checks if the accept queue is full. 1178 lock_sock(parent); 1179 1180 /* Check for backlog size */ 1181 if (sk_acceptq_is_full(parent)) { 1182 BT_DBG("backlog full %d", parent->sk_ack_backlog); 1183 return NULL; 1184 } If case the accept queue is full NULL is returned, but the 'parent' socket is not released. Thus when next L2CAP connection request is received the code blocks on lock_sock() since the parent is still locked. Also note that for connections already established and waiting for configuration to complete a timeout will occur and l2cap_chan_timeout() (net/bluetooth/l2cap_core.c) will be called. All threads calling this function will also be blocked waiting for the channel mutex since the thread which is waiting on lock_sock() alread holds the channel mutex. We were able to reproduce this by sending continuously L2CAP connection request followed by disconnection request containing invalid CID. This left the created connections pending configuration. After the deadlock occurs it is impossible to kill bluetoothd, btmon will not get any more data etc. requiring reboot to recover. -[0x03 Fix Releasing the 'parent' socket when l2cap_sock_new_connection_cb() returns NULL seems to fix the issue. Signed-off-by: Jukka Taimisto Reported-by: Tommi Mäkilä Signed-off-by: Johan Hedberg Cc: stable@vger.kernel.org --- net/bluetooth/l2cap_sock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index f59e00c2daa9..34d62348084d 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1180,13 +1180,16 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan) /* 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); - if (!sk) + if (!sk) { + release_sock(parent); return NULL; + } bt_sock_reclassify_lock(sk, BTPROTO_L2CAP); -- cgit v1.2.3