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 -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmV8mvcZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKcFTEACQRFdK50+kKekfzNoFe4SA CEDQqPyoR59Q12zc/sZmVVdWKCLjHT3yx9/3UPOPhz4LWQl0juvpPhNE/WSIh+Dx eozOZViebOfh9DstOSnjDKg7qGrybEjmtpVJn+jcFfzJedDVHF+POM97SleGSj50 EgJ8j3Qe8KNVQqhT0beJUE/Ku5f6zDBxZ3gcgphIU2CVnWQwrR36yaY/psDRn3oz YXcSz/Un4gWpIw0pwby8kViFjcnt8c65xJLX0o+WL+2rJecTiikDvSPtVHhI3F9W 1dmZ9rNg+mBYc+Lw/LkpDpj051+A+dINa71jLS/XCZyj4MMQw3uH/8D2diHwLxX8 Nst3ZF/xDZsEjFEbJEfDamM6M7DtqmltQ8A28Lmp90+AMIczNlrU2ZYAnRd+zK/H pbzTNddbVEj7gSSJb2OrymN45i1unX7dHZ9ASDAzBDxgQEdsrM0W1Qp0YW+7qefa ihvQOGM52ZdGNM6C73rvSYXssGKTp8G/illIQkHg4szs1H96Yw4x2ArXo5S1KANC 5c/k4qQEsr7vgDgkfORtJZ6BKFBb6p6/toyf2GizAiGfcsKCUwHvd7i8/AeGznj3 bCkLnL5v9nOSEeIqvBe9hIFsL6a3k1CbpTF4U/tK33Ybqqp8eiGrQY35+1EESdY4 Cy5fz5AgONuLAiOoypmN5A== =JAze -----END PGP SIGNATURE----- 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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
498444e390
@ -11,6 +11,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
@ -44,6 +45,7 @@ struct vhci_data {
|
||||
bool wakeup;
|
||||
__u16 msft_opcode;
|
||||
bool aosp_capable;
|
||||
atomic_t initialized;
|
||||
};
|
||||
|
||||
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)
|
||||
|
||||
memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
|
||||
|
||||
mutex_lock(&data->open_mutex);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -464,7 +465,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
|
||||
skb_put_u8(skb, 0xff);
|
||||
skb_put_u8(skb, opcode);
|
||||
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);
|
||||
return 0;
|
||||
|
@ -189,6 +189,7 @@ struct blocked_key {
|
||||
struct smp_csrk {
|
||||
bdaddr_t bdaddr;
|
||||
u8 bdaddr_type;
|
||||
u8 link_type;
|
||||
u8 type;
|
||||
u8 val[16];
|
||||
};
|
||||
@ -198,6 +199,7 @@ struct smp_ltk {
|
||||
struct rcu_head rcu;
|
||||
bdaddr_t bdaddr;
|
||||
u8 bdaddr_type;
|
||||
u8 link_type;
|
||||
u8 authenticated;
|
||||
u8 type;
|
||||
u8 enc_size;
|
||||
@ -212,6 +214,7 @@ struct smp_irk {
|
||||
bdaddr_t rpa;
|
||||
bdaddr_t bdaddr;
|
||||
u8 addr_type;
|
||||
u8 link_type;
|
||||
u8 val[16];
|
||||
};
|
||||
|
||||
@ -219,6 +222,8 @@ struct link_key {
|
||||
struct list_head list;
|
||||
struct rcu_head rcu;
|
||||
bdaddr_t bdaddr;
|
||||
u8 bdaddr_type;
|
||||
u8 link_type;
|
||||
u8 type;
|
||||
u8 val[HCI_LINK_KEY_SIZE];
|
||||
u8 pin_len;
|
||||
@ -1227,11 +1232,11 @@ static inline struct hci_conn *hci_conn_hash_lookup_cis(struct hci_dev *hdev,
|
||||
continue;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Match destination address if set */
|
||||
|
@ -309,11 +309,14 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
||||
if (flags & MSG_OOB)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
skb = skb_recv_datagram(sk, flags, &err);
|
||||
if (!skb) {
|
||||
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
||||
return 0;
|
||||
err = 0;
|
||||
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -343,6 +346,8 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
||||
|
||||
skb_free_datagram(sk, skb);
|
||||
|
||||
release_sock(sk);
|
||||
|
||||
if (flags & MSG_TRUNC)
|
||||
copied = skblen;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
if (WARN_ON(!hdev))
|
||||
return HCI_ERROR_UNSPECIFIED;
|
||||
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
|
||||
|
||||
if (rp->status)
|
||||
@ -747,9 +750,23 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data,
|
||||
} else {
|
||||
conn->enc_key_size = rp->key_size;
|
||||
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:
|
||||
hci_dev_unlock(hdev);
|
||||
@ -820,8 +837,6 @@ static u8 hci_cc_write_auth_payload_timeout(struct hci_dev *hdev, void *data,
|
||||
if (!rp->status)
|
||||
conn->auth_payload_timeout = get_unaligned_le16(sent + 2);
|
||||
|
||||
hci_encrypt_cfm(conn, 0);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
@ -2304,7 +2319,8 @@ static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
|
||||
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)
|
||||
@ -3683,12 +3699,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.timeout = cpu_to_le16(hdev->auth_payload_timeout);
|
||||
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");
|
||||
goto notify;
|
||||
}
|
||||
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
notify:
|
||||
|
@ -6492,6 +6492,14 @@ drop:
|
||||
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,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@ -6517,23 +6525,24 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
|
||||
|
||||
if (len > skb->len || !cmd->ident) {
|
||||
BT_DBG("corrupted command");
|
||||
l2cap_sig_send_rej(conn, cmd->ident);
|
||||
break;
|
||||
}
|
||||
|
||||
err = l2cap_bredr_sig_cmd(conn, cmd, len, skb->data);
|
||||
if (err) {
|
||||
struct l2cap_cmd_rej_unk rej;
|
||||
|
||||
BT_ERR("Wrong link type (%d)", err);
|
||||
|
||||
rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
|
||||
l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
|
||||
sizeof(rej), &rej);
|
||||
l2cap_sig_send_rej(conn, cmd->ident);
|
||||
}
|
||||
|
||||
skb_pull(skb, len);
|
||||
}
|
||||
|
||||
if (skb->len > 0) {
|
||||
BT_DBG("corrupted command");
|
||||
l2cap_sig_send_rej(conn, 0);
|
||||
}
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
@ -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++) {
|
||||
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,
|
||||
MGMT_OP_LOAD_LINK_KEYS,
|
||||
MGMT_STATUS_INVALID_PARAMS);
|
||||
@ -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++) {
|
||||
struct mgmt_irk_info *irk = &cp->irks[i];
|
||||
u8 addr_type = le_addr_type(irk->addr.type);
|
||||
|
||||
if (hci_is_blocked_key(hdev,
|
||||
HCI_BLOCKED_KEY_TYPE_IRK,
|
||||
@ -7139,8 +7141,12 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
|
||||
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,
|
||||
le_addr_type(irk->addr.type), irk->val,
|
||||
addr_type, irk->val,
|
||||
BDADDR_ANY);
|
||||
}
|
||||
|
||||
@ -7221,6 +7227,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
|
||||
for (i = 0; i < key_count; i++) {
|
||||
struct mgmt_ltk_info *key = &cp->keys[i];
|
||||
u8 type, authenticated;
|
||||
u8 addr_type = le_addr_type(key->addr.type);
|
||||
|
||||
if (hci_is_blocked_key(hdev,
|
||||
HCI_BLOCKED_KEY_TYPE_LTK,
|
||||
@ -7255,8 +7262,12 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
|
||||
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,
|
||||
le_addr_type(key->addr.type), type, authenticated,
|
||||
addr_type, type, authenticated,
|
||||
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,
|
||||
|
||||
ev.store_hint = persistent;
|
||||
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;
|
||||
memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
|
||||
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)
|
||||
ev.store_hint = persistent;
|
||||
|
||||
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.enc_size = key->enc_size;
|
||||
ev.key.ediv = key->ediv;
|
||||
@ -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.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));
|
||||
|
||||
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,
|
||||
ev.store_hint = persistent;
|
||||
|
||||
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;
|
||||
memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
|
||||
|
||||
|
@ -1059,6 +1059,7 @@ static void smp_notify_keys(struct l2cap_conn *conn)
|
||||
}
|
||||
|
||||
if (smp->remote_irk) {
|
||||
smp->remote_irk->link_type = hcon->type;
|
||||
mgmt_new_irk(hdev, smp->remote_irk, persistent);
|
||||
|
||||
/* Now that user space can be considered to know the
|
||||
@ -1078,24 +1079,28 @@ static void smp_notify_keys(struct l2cap_conn *conn)
|
||||
}
|
||||
|
||||
if (smp->csrk) {
|
||||
smp->csrk->link_type = hcon->type;
|
||||
smp->csrk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->csrk->bdaddr, &hcon->dst);
|
||||
mgmt_new_csrk(hdev, smp->csrk, persistent);
|
||||
}
|
||||
|
||||
if (smp->responder_csrk) {
|
||||
smp->responder_csrk->link_type = hcon->type;
|
||||
smp->responder_csrk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->responder_csrk->bdaddr, &hcon->dst);
|
||||
mgmt_new_csrk(hdev, smp->responder_csrk, persistent);
|
||||
}
|
||||
|
||||
if (smp->ltk) {
|
||||
smp->ltk->link_type = hcon->type;
|
||||
smp->ltk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->ltk->bdaddr, &hcon->dst);
|
||||
mgmt_new_ltk(hdev, smp->ltk, persistent);
|
||||
}
|
||||
|
||||
if (smp->responder_ltk) {
|
||||
smp->responder_ltk->link_type = hcon->type;
|
||||
smp->responder_ltk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->responder_ltk->bdaddr, &hcon->dst);
|
||||
mgmt_new_ltk(hdev, smp->responder_ltk, persistent);
|
||||
@ -1115,6 +1120,8 @@ static void smp_notify_keys(struct l2cap_conn *conn)
|
||||
key = hci_add_link_key(hdev, smp->conn->hcon, &hcon->dst,
|
||||
smp->link_key, type, 0, &persistent);
|
||||
if (key) {
|
||||
key->link_type = hcon->type;
|
||||
key->bdaddr_type = hcon->dst_type;
|
||||
mgmt_new_link_key(hdev, key, persistent);
|
||||
|
||||
/* Don't keep debug keys around if the relevant
|
||||
|
Loading…
x
Reference in New Issue
Block a user