Commit 2b10740c authored by Jakub Kicinski's avatar Jakub Kicinski

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

Luiz Augusto von Dentz says:

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

 - Fix race when opening vhci device
 - Avoid memcmp() out of bounds warning
 - Correctly bounds check and pad HCI_MON_NEW_INDEX name
 - Fix using memcmp when comparing keys
 - Ignore error return for hci_devcd_register() in btrtl
 - Always check if connection is alive before deleting
 - Fix a refcnt underflow problem for hci_conn

* tag 'for-net-2023-10-13' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: hci_sock: Correctly bounds check and pad HCI_MON_NEW_INDEX name
  Bluetooth: avoid memcmp() out of bounds warning
  Bluetooth: hci_sock: fix slab oob read in create_monitor_event
  Bluetooth: btrtl: Ignore error return for hci_devcd_register()
  Bluetooth: hci_event: Fix coding style
  Bluetooth: hci_event: Fix using memcmp when comparing keys
  Bluetooth: Fix a refcnt underflow problem for hci_conn
  Bluetooth: hci_sync: always check if connection is alive before deleting
  Bluetooth: Reject connection with the device which has same BD_ADDR
  Bluetooth: hci_event: Ignore NULL link key
  Bluetooth: ISO: Fix invalid context error
  Bluetooth: vhci: Fix race when opening vhci device
====================

Link: https://lore.kernel.org/r/20231014031336.1664558-1-luiz.dentz@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 7937609c cb3871b1
...@@ -962,13 +962,10 @@ static void btrtl_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -962,13 +962,10 @@ static void btrtl_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb)
skb_put_data(skb, buf, strlen(buf)); skb_put_data(skb, buf, strlen(buf));
} }
static int btrtl_register_devcoredump_support(struct hci_dev *hdev) static void btrtl_register_devcoredump_support(struct hci_dev *hdev)
{ {
int err; hci_devcd_register(hdev, btrtl_coredump, btrtl_dmp_hdr, NULL);
err = hci_devcd_register(hdev, btrtl_coredump, btrtl_dmp_hdr, NULL);
return err;
} }
void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name) void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name)
...@@ -1255,8 +1252,7 @@ int btrtl_download_firmware(struct hci_dev *hdev, ...@@ -1255,8 +1252,7 @@ int btrtl_download_firmware(struct hci_dev *hdev,
} }
done: done:
if (!err) btrtl_register_devcoredump_support(hdev);
err = btrtl_register_devcoredump_support(hdev);
return err; return err;
} }
......
...@@ -74,7 +74,10 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -74,7 +74,10 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
struct vhci_data *data = hci_get_drvdata(hdev); struct vhci_data *data = hci_get_drvdata(hdev);
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); wake_up_interruptible(&data->read_wait);
return 0; return 0;
......
...@@ -56,7 +56,7 @@ struct hci_mon_new_index { ...@@ -56,7 +56,7 @@ struct hci_mon_new_index {
__u8 type; __u8 type;
__u8 bus; __u8 bus;
bdaddr_t bdaddr; bdaddr_t bdaddr;
char name[8]; char name[8] __nonstring;
} __packed; } __packed;
#define HCI_MON_NEW_INDEX_SIZE 16 #define HCI_MON_NEW_INDEX_SIZE 16
......
...@@ -1627,6 +1627,15 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -1627,6 +1627,15 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
/* Reject outgoing connection to device with same BD ADDR against
* CVE-2020-26555
*/
if (!bacmp(&hdev->bdaddr, dst)) {
bt_dev_dbg(hdev, "Reject connection with same BD_ADDR %pMR\n",
dst);
return ERR_PTR(-ECONNREFUSED);
}
acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
if (!acl) { if (!acl) {
acl = hci_conn_add(hdev, ACL_LINK, dst, HCI_ROLE_MASTER); acl = hci_conn_add(hdev, ACL_LINK, dst, HCI_ROLE_MASTER);
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
/* Bluetooth HCI event handling. */ /* Bluetooth HCI event handling. */
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <linux/crypto.h>
#include <crypto/algapi.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
...@@ -3268,6 +3270,16 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, ...@@ -3268,6 +3270,16 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "bdaddr %pMR type 0x%x", &ev->bdaddr, ev->link_type); bt_dev_dbg(hdev, "bdaddr %pMR type 0x%x", &ev->bdaddr, ev->link_type);
/* Reject incoming connection from device with same BD ADDR against
* CVE-2020-26555
*/
if (hdev && !bacmp(&hdev->bdaddr, &ev->bdaddr)) {
bt_dev_dbg(hdev, "Reject connection with same BD_ADDR %pMR\n",
&ev->bdaddr);
hci_reject_conn(hdev, &ev->bdaddr);
return;
}
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type, mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type,
&flags); &flags);
...@@ -4742,6 +4754,15 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, void *data, ...@@ -4742,6 +4754,15 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, void *data,
if (!conn) if (!conn)
goto unlock; goto unlock;
/* Ignore NULL link key against CVE-2020-26555 */
if (!crypto_memneq(ev->link_key, ZERO_KEY, HCI_LINK_KEY_SIZE)) {
bt_dev_dbg(hdev, "Ignore NULL link key (ZERO KEY) for %pMR",
&ev->bdaddr);
hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
hci_conn_drop(conn);
goto unlock;
}
hci_conn_hold(conn); hci_conn_hold(conn);
conn->disc_timeout = HCI_DISCONN_TIMEOUT; conn->disc_timeout = HCI_DISCONN_TIMEOUT;
hci_conn_drop(conn); hci_conn_drop(conn);
...@@ -5274,8 +5295,8 @@ static u8 bredr_oob_data_present(struct hci_conn *conn) ...@@ -5274,8 +5295,8 @@ static u8 bredr_oob_data_present(struct hci_conn *conn)
* available, then do not declare that OOB data is * available, then do not declare that OOB data is
* present. * present.
*/ */
if (!memcmp(data->rand256, ZERO_KEY, 16) || if (!crypto_memneq(data->rand256, ZERO_KEY, 16) ||
!memcmp(data->hash256, ZERO_KEY, 16)) !crypto_memneq(data->hash256, ZERO_KEY, 16))
return 0x00; return 0x00;
return 0x02; return 0x02;
...@@ -5285,8 +5306,8 @@ static u8 bredr_oob_data_present(struct hci_conn *conn) ...@@ -5285,8 +5306,8 @@ static u8 bredr_oob_data_present(struct hci_conn *conn)
* not supported by the hardware, then check that if * not supported by the hardware, then check that if
* P-192 data values are present. * P-192 data values are present.
*/ */
if (!memcmp(data->rand192, ZERO_KEY, 16) || if (!crypto_memneq(data->rand192, ZERO_KEY, 16) ||
!memcmp(data->hash192, ZERO_KEY, 16)) !crypto_memneq(data->hash192, ZERO_KEY, 16))
return 0x00; return 0x00;
return 0x01; return 0x01;
...@@ -5303,7 +5324,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, void *data, ...@@ -5303,7 +5324,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, void *data,
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (!conn) if (!conn || !hci_conn_ssp_enabled(conn))
goto unlock; goto unlock;
hci_conn_hold(conn); hci_conn_hold(conn);
...@@ -5550,7 +5571,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev, void *data, ...@@ -5550,7 +5571,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev, void *data,
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (!conn) if (!conn || !hci_conn_ssp_enabled(conn))
goto unlock; goto unlock;
/* Reset the authentication requirement to unknown */ /* Reset the authentication requirement to unknown */
...@@ -7021,6 +7042,14 @@ static void hci_le_cis_req_evt(struct hci_dev *hdev, void *data, ...@@ -7021,6 +7042,14 @@ static void hci_le_cis_req_evt(struct hci_dev *hdev, void *data,
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static int hci_iso_term_big_sync(struct hci_dev *hdev, void *data)
{
u8 handle = PTR_UINT(data);
return hci_le_terminate_big_sync(hdev, handle,
HCI_ERROR_LOCAL_HOST_TERM);
}
static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -7065,16 +7094,17 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data, ...@@ -7065,16 +7094,17 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
rcu_read_lock(); rcu_read_lock();
} }
rcu_read_unlock();
if (!ev->status && !i) if (!ev->status && !i)
/* If no BISes have been connected for the BIG, /* If no BISes have been connected for the BIG,
* terminate. This is in case all bound connections * terminate. This is in case all bound connections
* have been closed before the BIG creation * have been closed before the BIG creation
* has completed. * has completed.
*/ */
hci_le_terminate_big_sync(hdev, ev->handle, hci_cmd_sync_queue(hdev, hci_iso_term_big_sync,
HCI_ERROR_LOCAL_HOST_TERM); UINT_PTR(ev->handle), NULL);
rcu_read_unlock();
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
......
...@@ -488,7 +488,8 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event) ...@@ -488,7 +488,8 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event)
ni->type = hdev->dev_type; ni->type = hdev->dev_type;
ni->bus = hdev->bus; ni->bus = hdev->bus;
bacpy(&ni->bdaddr, &hdev->bdaddr); bacpy(&ni->bdaddr, &hdev->bdaddr);
memcpy(ni->name, hdev->name, 8); memcpy_and_pad(ni->name, sizeof(ni->name), hdev->name,
strnlen(hdev->name, sizeof(ni->name)), '\0');
opcode = cpu_to_le16(HCI_MON_NEW_INDEX); opcode = cpu_to_le16(HCI_MON_NEW_INDEX);
break; break;
......
...@@ -5369,6 +5369,7 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason) ...@@ -5369,6 +5369,7 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
{ {
int err = 0; int err = 0;
u16 handle = conn->handle; u16 handle = conn->handle;
bool disconnect = false;
struct hci_conn *c; struct hci_conn *c;
switch (conn->state) { switch (conn->state) {
...@@ -5399,24 +5400,15 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason) ...@@ -5399,24 +5400,15 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
return 0; return 0;
case BT_BOUND: case BT_BOUND:
hci_dev_lock(hdev); break;
hci_conn_failed(conn, reason);
hci_dev_unlock(hdev);
return 0;
default: default:
hci_dev_lock(hdev); disconnect = true;
conn->state = BT_CLOSED; break;
hci_disconn_cfm(conn, reason);
hci_conn_del(conn);
hci_dev_unlock(hdev);
return 0;
} }
hci_dev_lock(hdev); hci_dev_lock(hdev);
/* Check if the connection hasn't been cleanup while waiting /* Check if the connection has been cleaned up concurrently */
* commands to complete.
*/
c = hci_conn_hash_lookup_handle(hdev, handle); c = hci_conn_hash_lookup_handle(hdev, handle);
if (!c || c != conn) { if (!c || c != conn) {
err = 0; err = 0;
...@@ -5428,7 +5420,13 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason) ...@@ -5428,7 +5420,13 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
* or in case of LE it was still scanning so it can be cleanup * or in case of LE it was still scanning so it can be cleanup
* safely. * safely.
*/ */
hci_conn_failed(conn, reason); if (disconnect) {
conn->state = BT_CLOSED;
hci_disconn_cfm(conn, reason);
hci_conn_del(conn);
} else {
hci_conn_failed(conn, reason);
}
unlock: unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
......
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