Commit 498444e3 authored by David S. Miller's avatar David S. Miller

Merge tag 'for-net-2023-12-15' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth

Luiz Augusto von Dentz says:

====================
bluetooth pull request for net:

 - Add encryption key size check when acting as peripheral
 - Shut up false-positive build warning
 - Send reject if L2CAP command request is corrupted
 - Fix Use-After-Free in bt_sock_recvmsg
 - Fix not notifying when connection encryption changes
 - Fix not checking if HCI_OP_INQUIRY has been sent
 - Fix address type send over to the MGMT interface
 - Fix deadlock in vhci_send_frame
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8353c2ab 2e07e834
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <linux/atomic.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -44,6 +45,7 @@ struct vhci_data { ...@@ -44,6 +45,7 @@ struct vhci_data {
bool wakeup; bool wakeup;
__u16 msft_opcode; __u16 msft_opcode;
bool aosp_capable; bool aosp_capable;
atomic_t initialized;
}; };
static int vhci_open_dev(struct hci_dev *hdev) static int vhci_open_dev(struct hci_dev *hdev)
...@@ -75,11 +77,10 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -75,11 +77,10 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
mutex_lock(&data->open_mutex);
skb_queue_tail(&data->readq, skb); skb_queue_tail(&data->readq, skb);
mutex_unlock(&data->open_mutex);
wake_up_interruptible(&data->read_wait); if (atomic_read(&data->initialized))
wake_up_interruptible(&data->read_wait);
return 0; return 0;
} }
...@@ -464,7 +465,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) ...@@ -464,7 +465,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
skb_put_u8(skb, 0xff); skb_put_u8(skb, 0xff);
skb_put_u8(skb, opcode); skb_put_u8(skb, opcode);
put_unaligned_le16(hdev->id, skb_put(skb, 2)); put_unaligned_le16(hdev->id, skb_put(skb, 2));
skb_queue_tail(&data->readq, skb); skb_queue_head(&data->readq, skb);
atomic_inc(&data->initialized);
wake_up_interruptible(&data->read_wait); wake_up_interruptible(&data->read_wait);
return 0; return 0;
......
...@@ -189,6 +189,7 @@ struct blocked_key { ...@@ -189,6 +189,7 @@ struct blocked_key {
struct smp_csrk { struct smp_csrk {
bdaddr_t bdaddr; bdaddr_t bdaddr;
u8 bdaddr_type; u8 bdaddr_type;
u8 link_type;
u8 type; u8 type;
u8 val[16]; u8 val[16];
}; };
...@@ -198,6 +199,7 @@ struct smp_ltk { ...@@ -198,6 +199,7 @@ struct smp_ltk {
struct rcu_head rcu; struct rcu_head rcu;
bdaddr_t bdaddr; bdaddr_t bdaddr;
u8 bdaddr_type; u8 bdaddr_type;
u8 link_type;
u8 authenticated; u8 authenticated;
u8 type; u8 type;
u8 enc_size; u8 enc_size;
...@@ -212,6 +214,7 @@ struct smp_irk { ...@@ -212,6 +214,7 @@ struct smp_irk {
bdaddr_t rpa; bdaddr_t rpa;
bdaddr_t bdaddr; bdaddr_t bdaddr;
u8 addr_type; u8 addr_type;
u8 link_type;
u8 val[16]; u8 val[16];
}; };
...@@ -219,6 +222,8 @@ struct link_key { ...@@ -219,6 +222,8 @@ struct link_key {
struct list_head list; struct list_head list;
struct rcu_head rcu; struct rcu_head rcu;
bdaddr_t bdaddr; bdaddr_t bdaddr;
u8 bdaddr_type;
u8 link_type;
u8 type; u8 type;
u8 val[HCI_LINK_KEY_SIZE]; u8 val[HCI_LINK_KEY_SIZE];
u8 pin_len; u8 pin_len;
...@@ -1227,11 +1232,11 @@ static inline struct hci_conn *hci_conn_hash_lookup_cis(struct hci_dev *hdev, ...@@ -1227,11 +1232,11 @@ static inline struct hci_conn *hci_conn_hash_lookup_cis(struct hci_dev *hdev,
continue; continue;
/* Match CIG ID if set */ /* Match CIG ID if set */
if (cig != BT_ISO_QOS_CIG_UNSET && cig != c->iso_qos.ucast.cig) if (cig != c->iso_qos.ucast.cig)
continue; continue;
/* Match CIS ID if set */ /* Match CIS ID if set */
if (id != BT_ISO_QOS_CIS_UNSET && id != c->iso_qos.ucast.cis) if (id != c->iso_qos.ucast.cis)
continue; continue;
/* Match destination address if set */ /* Match destination address if set */
......
...@@ -309,11 +309,14 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, ...@@ -309,11 +309,14 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
if (flags & MSG_OOB) if (flags & MSG_OOB)
return -EOPNOTSUPP; return -EOPNOTSUPP;
lock_sock(sk);
skb = skb_recv_datagram(sk, flags, &err); skb = skb_recv_datagram(sk, flags, &err);
if (!skb) { if (!skb) {
if (sk->sk_shutdown & RCV_SHUTDOWN) if (sk->sk_shutdown & RCV_SHUTDOWN)
return 0; err = 0;
release_sock(sk);
return err; return err;
} }
...@@ -343,6 +346,8 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, ...@@ -343,6 +346,8 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
skb_free_datagram(sk, skb); skb_free_datagram(sk, skb);
release_sock(sk);
if (flags & MSG_TRUNC) if (flags & MSG_TRUNC)
copied = skblen; copied = skblen;
......
...@@ -516,6 +516,9 @@ static u8 hci_cc_read_class_of_dev(struct hci_dev *hdev, void *data, ...@@ -516,6 +516,9 @@ static u8 hci_cc_read_class_of_dev(struct hci_dev *hdev, void *data,
{ {
struct hci_rp_read_class_of_dev *rp = data; struct hci_rp_read_class_of_dev *rp = data;
if (WARN_ON(!hdev))
return HCI_ERROR_UNSPECIFIED;
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
if (rp->status) if (rp->status)
...@@ -747,9 +750,23 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data, ...@@ -747,9 +750,23 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data,
} else { } else {
conn->enc_key_size = rp->key_size; conn->enc_key_size = rp->key_size;
status = 0; status = 0;
if (conn->enc_key_size < hdev->min_enc_key_size) {
/* As slave role, the conn->state has been set to
* BT_CONNECTED and l2cap conn req might not be received
* yet, at this moment the l2cap layer almost does
* nothing with the non-zero status.
* So we also clear encrypt related bits, and then the
* handler of l2cap conn req will get the right secure
* state at a later time.
*/
status = HCI_ERROR_AUTH_FAILURE;
clear_bit(HCI_CONN_ENCRYPT, &conn->flags);
clear_bit(HCI_CONN_AES_CCM, &conn->flags);
}
} }
hci_encrypt_cfm(conn, 0); hci_encrypt_cfm(conn, status);
done: done:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -820,8 +837,6 @@ static u8 hci_cc_write_auth_payload_timeout(struct hci_dev *hdev, void *data, ...@@ -820,8 +837,6 @@ static u8 hci_cc_write_auth_payload_timeout(struct hci_dev *hdev, void *data,
if (!rp->status) if (!rp->status)
conn->auth_payload_timeout = get_unaligned_le16(sent + 2); conn->auth_payload_timeout = get_unaligned_le16(sent + 2);
hci_encrypt_cfm(conn, 0);
unlock: unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -2304,7 +2319,8 @@ static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) ...@@ -2304,7 +2319,8 @@ static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
return; return;
} }
set_bit(HCI_INQUIRY, &hdev->flags); if (hci_sent_cmd_data(hdev, HCI_OP_INQUIRY))
set_bit(HCI_INQUIRY, &hdev->flags);
} }
static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
...@@ -3683,12 +3699,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data, ...@@ -3683,12 +3699,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
cp.timeout = cpu_to_le16(hdev->auth_payload_timeout); cp.timeout = cpu_to_le16(hdev->auth_payload_timeout);
if (hci_send_cmd(conn->hdev, HCI_OP_WRITE_AUTH_PAYLOAD_TO, if (hci_send_cmd(conn->hdev, HCI_OP_WRITE_AUTH_PAYLOAD_TO,
sizeof(cp), &cp)) { sizeof(cp), &cp))
bt_dev_err(hdev, "write auth payload timeout failed"); bt_dev_err(hdev, "write auth payload timeout failed");
goto notify;
}
goto unlock;
} }
notify: notify:
......
...@@ -6492,6 +6492,14 @@ static inline void l2cap_le_sig_channel(struct l2cap_conn *conn, ...@@ -6492,6 +6492,14 @@ static inline void l2cap_le_sig_channel(struct l2cap_conn *conn,
kfree_skb(skb); kfree_skb(skb);
} }
static inline void l2cap_sig_send_rej(struct l2cap_conn *conn, u16 ident)
{
struct l2cap_cmd_rej_unk rej;
rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
}
static inline void l2cap_sig_channel(struct l2cap_conn *conn, static inline void l2cap_sig_channel(struct l2cap_conn *conn,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -6517,23 +6525,24 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, ...@@ -6517,23 +6525,24 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
if (len > skb->len || !cmd->ident) { if (len > skb->len || !cmd->ident) {
BT_DBG("corrupted command"); BT_DBG("corrupted command");
l2cap_sig_send_rej(conn, cmd->ident);
break; break;
} }
err = l2cap_bredr_sig_cmd(conn, cmd, len, skb->data); err = l2cap_bredr_sig_cmd(conn, cmd, len, skb->data);
if (err) { if (err) {
struct l2cap_cmd_rej_unk rej;
BT_ERR("Wrong link type (%d)", err); BT_ERR("Wrong link type (%d)", err);
l2cap_sig_send_rej(conn, cmd->ident);
rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
sizeof(rej), &rej);
} }
skb_pull(skb, len); skb_pull(skb, len);
} }
if (skb->len > 0) {
BT_DBG("corrupted command");
l2cap_sig_send_rej(conn, 0);
}
drop: drop:
kfree_skb(skb); kfree_skb(skb);
} }
......
...@@ -2897,7 +2897,8 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -2897,7 +2897,8 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
for (i = 0; i < key_count; i++) { for (i = 0; i < key_count; i++) {
struct mgmt_link_key_info *key = &cp->keys[i]; struct mgmt_link_key_info *key = &cp->keys[i];
if (key->addr.type != BDADDR_BREDR || key->type > 0x08) /* Considering SMP over BREDR/LE, there is no need to check addr_type */
if (key->type > 0x08)
return mgmt_cmd_status(sk, hdev->id, return mgmt_cmd_status(sk, hdev->id,
MGMT_OP_LOAD_LINK_KEYS, MGMT_OP_LOAD_LINK_KEYS,
MGMT_STATUS_INVALID_PARAMS); MGMT_STATUS_INVALID_PARAMS);
...@@ -7130,6 +7131,7 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data, ...@@ -7130,6 +7131,7 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
for (i = 0; i < irk_count; i++) { for (i = 0; i < irk_count; i++) {
struct mgmt_irk_info *irk = &cp->irks[i]; struct mgmt_irk_info *irk = &cp->irks[i];
u8 addr_type = le_addr_type(irk->addr.type);
if (hci_is_blocked_key(hdev, if (hci_is_blocked_key(hdev,
HCI_BLOCKED_KEY_TYPE_IRK, HCI_BLOCKED_KEY_TYPE_IRK,
...@@ -7139,8 +7141,12 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data, ...@@ -7139,8 +7141,12 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
continue; continue;
} }
/* When using SMP over BR/EDR, the addr type should be set to BREDR */
if (irk->addr.type == BDADDR_BREDR)
addr_type = BDADDR_BREDR;
hci_add_irk(hdev, &irk->addr.bdaddr, hci_add_irk(hdev, &irk->addr.bdaddr,
le_addr_type(irk->addr.type), irk->val, addr_type, irk->val,
BDADDR_ANY); BDADDR_ANY);
} }
...@@ -7221,6 +7227,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, ...@@ -7221,6 +7227,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
for (i = 0; i < key_count; i++) { for (i = 0; i < key_count; i++) {
struct mgmt_ltk_info *key = &cp->keys[i]; struct mgmt_ltk_info *key = &cp->keys[i];
u8 type, authenticated; u8 type, authenticated;
u8 addr_type = le_addr_type(key->addr.type);
if (hci_is_blocked_key(hdev, if (hci_is_blocked_key(hdev,
HCI_BLOCKED_KEY_TYPE_LTK, HCI_BLOCKED_KEY_TYPE_LTK,
...@@ -7255,8 +7262,12 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, ...@@ -7255,8 +7262,12 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
continue; continue;
} }
/* When using SMP over BR/EDR, the addr type should be set to BREDR */
if (key->addr.type == BDADDR_BREDR)
addr_type = BDADDR_BREDR;
hci_add_ltk(hdev, &key->addr.bdaddr, hci_add_ltk(hdev, &key->addr.bdaddr,
le_addr_type(key->addr.type), type, authenticated, addr_type, type, authenticated,
key->val, key->enc_size, key->ediv, key->rand); key->val, key->enc_size, key->ediv, key->rand);
} }
...@@ -9523,7 +9534,7 @@ void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, ...@@ -9523,7 +9534,7 @@ void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
ev.store_hint = persistent; ev.store_hint = persistent;
bacpy(&ev.key.addr.bdaddr, &key->bdaddr); bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
ev.key.addr.type = BDADDR_BREDR; ev.key.addr.type = link_to_bdaddr(key->link_type, key->bdaddr_type);
ev.key.type = key->type; ev.key.type = key->type;
memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE); memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
ev.key.pin_len = key->pin_len; ev.key.pin_len = key->pin_len;
...@@ -9574,7 +9585,7 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent) ...@@ -9574,7 +9585,7 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
ev.store_hint = persistent; ev.store_hint = persistent;
bacpy(&ev.key.addr.bdaddr, &key->bdaddr); bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type); ev.key.addr.type = link_to_bdaddr(key->link_type, key->bdaddr_type);
ev.key.type = mgmt_ltk_type(key); ev.key.type = mgmt_ltk_type(key);
ev.key.enc_size = key->enc_size; ev.key.enc_size = key->enc_size;
ev.key.ediv = key->ediv; ev.key.ediv = key->ediv;
...@@ -9603,7 +9614,7 @@ void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent) ...@@ -9603,7 +9614,7 @@ void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent)
bacpy(&ev.rpa, &irk->rpa); bacpy(&ev.rpa, &irk->rpa);
bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr); bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type); ev.irk.addr.type = link_to_bdaddr(irk->link_type, irk->addr_type);
memcpy(ev.irk.val, irk->val, sizeof(irk->val)); memcpy(ev.irk.val, irk->val, sizeof(irk->val));
mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL); mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
...@@ -9632,7 +9643,7 @@ void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk, ...@@ -9632,7 +9643,7 @@ void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
ev.store_hint = persistent; ev.store_hint = persistent;
bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr); bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type); ev.key.addr.type = link_to_bdaddr(csrk->link_type, csrk->bdaddr_type);
ev.key.type = csrk->type; ev.key.type = csrk->type;
memcpy(ev.key.val, csrk->val, sizeof(csrk->val)); memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
......
...@@ -1059,6 +1059,7 @@ static void smp_notify_keys(struct l2cap_conn *conn) ...@@ -1059,6 +1059,7 @@ static void smp_notify_keys(struct l2cap_conn *conn)
} }
if (smp->remote_irk) { if (smp->remote_irk) {
smp->remote_irk->link_type = hcon->type;
mgmt_new_irk(hdev, smp->remote_irk, persistent); mgmt_new_irk(hdev, smp->remote_irk, persistent);
/* Now that user space can be considered to know the /* Now that user space can be considered to know the
...@@ -1078,24 +1079,28 @@ static void smp_notify_keys(struct l2cap_conn *conn) ...@@ -1078,24 +1079,28 @@ static void smp_notify_keys(struct l2cap_conn *conn)
} }
if (smp->csrk) { if (smp->csrk) {
smp->csrk->link_type = hcon->type;
smp->csrk->bdaddr_type = hcon->dst_type; smp->csrk->bdaddr_type = hcon->dst_type;
bacpy(&smp->csrk->bdaddr, &hcon->dst); bacpy(&smp->csrk->bdaddr, &hcon->dst);
mgmt_new_csrk(hdev, smp->csrk, persistent); mgmt_new_csrk(hdev, smp->csrk, persistent);
} }
if (smp->responder_csrk) { if (smp->responder_csrk) {
smp->responder_csrk->link_type = hcon->type;
smp->responder_csrk->bdaddr_type = hcon->dst_type; smp->responder_csrk->bdaddr_type = hcon->dst_type;
bacpy(&smp->responder_csrk->bdaddr, &hcon->dst); bacpy(&smp->responder_csrk->bdaddr, &hcon->dst);
mgmt_new_csrk(hdev, smp->responder_csrk, persistent); mgmt_new_csrk(hdev, smp->responder_csrk, persistent);
} }
if (smp->ltk) { if (smp->ltk) {
smp->ltk->link_type = hcon->type;
smp->ltk->bdaddr_type = hcon->dst_type; smp->ltk->bdaddr_type = hcon->dst_type;
bacpy(&smp->ltk->bdaddr, &hcon->dst); bacpy(&smp->ltk->bdaddr, &hcon->dst);
mgmt_new_ltk(hdev, smp->ltk, persistent); mgmt_new_ltk(hdev, smp->ltk, persistent);
} }
if (smp->responder_ltk) { if (smp->responder_ltk) {
smp->responder_ltk->link_type = hcon->type;
smp->responder_ltk->bdaddr_type = hcon->dst_type; smp->responder_ltk->bdaddr_type = hcon->dst_type;
bacpy(&smp->responder_ltk->bdaddr, &hcon->dst); bacpy(&smp->responder_ltk->bdaddr, &hcon->dst);
mgmt_new_ltk(hdev, smp->responder_ltk, persistent); mgmt_new_ltk(hdev, smp->responder_ltk, persistent);
...@@ -1115,6 +1120,8 @@ static void smp_notify_keys(struct l2cap_conn *conn) ...@@ -1115,6 +1120,8 @@ static void smp_notify_keys(struct l2cap_conn *conn)
key = hci_add_link_key(hdev, smp->conn->hcon, &hcon->dst, key = hci_add_link_key(hdev, smp->conn->hcon, &hcon->dst,
smp->link_key, type, 0, &persistent); smp->link_key, type, 0, &persistent);
if (key) { if (key) {
key->link_type = hcon->type;
key->bdaddr_type = hcon->dst_type;
mgmt_new_link_key(hdev, key, persistent); mgmt_new_link_key(hdev, key, persistent);
/* Don't keep debug keys around if the relevant /* Don't keep debug keys around if the relevant
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment