Commit f2d85904 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'for-net-2024-05-03' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth

Luiz Augusto von Dentz says:

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

 - mediatek: mt8183-pico6: Fix bluetooth node
 - sco: Fix use-after-free bugs caused by sco_sock_timeout
 - l2cap: fix null-ptr-deref in l2cap_chan_timeout
 - qca: Various fixes
 - l2cap: Fix slab-use-after-free in l2cap_connect()
 - msft: fix slab-use-after-free in msft_do_close()
 - HCI: Fix potential null-ptr-deref

* tag 'for-net-2024-05-03' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: qca: fix firmware check error path
  Bluetooth: l2cap: fix null-ptr-deref in l2cap_chan_timeout
  Bluetooth: HCI: Fix potential null-ptr-deref
  arm64: dts: mediatek: mt8183-pico6: Fix bluetooth node
  Bluetooth: qca: fix info leak when fetching board id
  Bluetooth: qca: fix info leak when fetching fw build id
  Bluetooth: qca: generalise device address check
  Bluetooth: qca: fix NVM configuration parsing
  Bluetooth: qca: add missing firmware sanity checks
  Bluetooth: msft: fix slab-use-after-free in msft_do_close()
  Bluetooth: L2CAP: Fix slab-use-after-free in l2cap_connect()
  Bluetooth: qca: fix wcn3991 device address check
  Bluetooth: Fix use-after-free bugs caused by sco_sock_timeout
====================

Link: https://lore.kernel.org/r/20240503171933.3851244-1-luiz.dentz@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents e0863634 40d442f9
......@@ -82,7 +82,8 @@ pins-clk {
};
&mmc1 {
bt_reset: bt-reset {
bluetooth@2 {
reg = <2>;
compatible = "mediatek,mt7921s-bluetooth";
pinctrl-names = "default";
pinctrl-0 = <&bt_pins_reset>;
......
......@@ -15,8 +15,6 @@
#define VERSION "0.1"
#define QCA_BDADDR_DEFAULT (&(bdaddr_t) {{ 0xad, 0x5a, 0x00, 0x00, 0x00, 0x00 }})
int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver,
enum qca_btsoc_type soc_type)
{
......@@ -101,7 +99,8 @@ static int qca_read_fw_build_info(struct hci_dev *hdev)
{
struct sk_buff *skb;
struct edl_event_hdr *edl;
char cmd, build_label[QCA_FW_BUILD_VER_LEN];
char *build_label;
char cmd;
int build_lbl_len, err = 0;
bt_dev_dbg(hdev, "QCA read fw build info");
......@@ -116,6 +115,11 @@ static int qca_read_fw_build_info(struct hci_dev *hdev)
return err;
}
if (skb->len < sizeof(*edl)) {
err = -EILSEQ;
goto out;
}
edl = (struct edl_event_hdr *)(skb->data);
if (!edl) {
bt_dev_err(hdev, "QCA read fw build info with no header");
......@@ -131,14 +135,25 @@ static int qca_read_fw_build_info(struct hci_dev *hdev)
goto out;
}
if (skb->len < sizeof(*edl) + 1) {
err = -EILSEQ;
goto out;
}
build_lbl_len = edl->data[0];
if (build_lbl_len <= QCA_FW_BUILD_VER_LEN - 1) {
memcpy(build_label, edl->data + 1, build_lbl_len);
*(build_label + build_lbl_len) = '\0';
if (skb->len < sizeof(*edl) + 1 + build_lbl_len) {
err = -EILSEQ;
goto out;
}
build_label = kstrndup(&edl->data[1], build_lbl_len, GFP_KERNEL);
if (!build_label)
goto out;
hci_set_fw_info(hdev, "%s", build_label);
kfree(build_label);
out:
kfree_skb(skb);
return err;
......@@ -237,6 +252,11 @@ static int qca_read_fw_board_id(struct hci_dev *hdev, u16 *bid)
goto out;
}
if (skb->len < 3) {
err = -EILSEQ;
goto out;
}
*bid = (edl->data[1] << 8) + edl->data[2];
bt_dev_dbg(hdev, "%s: bid = %x", __func__, *bid);
......@@ -267,9 +287,10 @@ int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
}
EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd);
static void qca_tlv_check_data(struct hci_dev *hdev,
static int qca_tlv_check_data(struct hci_dev *hdev,
struct qca_fw_config *config,
u8 *fw_data, enum qca_btsoc_type soc_type)
u8 *fw_data, size_t fw_size,
enum qca_btsoc_type soc_type)
{
const u8 *data;
u32 type_len;
......@@ -279,12 +300,16 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
struct tlv_type_patch *tlv_patch;
struct tlv_type_nvm *tlv_nvm;
uint8_t nvm_baud_rate = config->user_baud_rate;
u8 type;
config->dnld_mode = QCA_SKIP_EVT_NONE;
config->dnld_type = QCA_SKIP_EVT_NONE;
switch (config->type) {
case ELF_TYPE_PATCH:
if (fw_size < 7)
return -EINVAL;
config->dnld_mode = QCA_SKIP_EVT_VSE_CC;
config->dnld_type = QCA_SKIP_EVT_VSE_CC;
......@@ -293,6 +318,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
bt_dev_dbg(hdev, "File version : 0x%x", fw_data[6]);
break;
case TLV_TYPE_PATCH:
if (fw_size < sizeof(struct tlv_type_hdr) + sizeof(struct tlv_type_patch))
return -EINVAL;
tlv = (struct tlv_type_hdr *)fw_data;
type_len = le32_to_cpu(tlv->type_len);
tlv_patch = (struct tlv_type_patch *)tlv->data;
......@@ -332,25 +360,64 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
break;
case TLV_TYPE_NVM:
if (fw_size < sizeof(struct tlv_type_hdr))
return -EINVAL;
tlv = (struct tlv_type_hdr *)fw_data;
type_len = le32_to_cpu(tlv->type_len);
length = (type_len >> 8) & 0x00ffffff;
length = type_len >> 8;
type = type_len & 0xff;
BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
/* Some NVM files have more than one set of tags, only parse
* the first set when it has type 2 for now. When there is
* more than one set there is an enclosing header of type 4.
*/
if (type == 4) {
if (fw_size < 2 * sizeof(struct tlv_type_hdr))
return -EINVAL;
tlv++;
type_len = le32_to_cpu(tlv->type_len);
length = type_len >> 8;
type = type_len & 0xff;
}
BT_DBG("TLV Type\t\t : 0x%x", type);
BT_DBG("Length\t\t : %d bytes", length);
if (type != 2)
break;
if (fw_size < length + (tlv->data - fw_data))
return -EINVAL;
idx = 0;
data = tlv->data;
while (idx < length) {
while (idx < length - sizeof(struct tlv_type_nvm)) {
tlv_nvm = (struct tlv_type_nvm *)(data + idx);
tag_id = le16_to_cpu(tlv_nvm->tag_id);
tag_len = le16_to_cpu(tlv_nvm->tag_len);
if (length < idx + sizeof(struct tlv_type_nvm) + tag_len)
return -EINVAL;
/* Update NVM tags as needed */
switch (tag_id) {
case EDL_TAG_ID_BD_ADDR:
if (tag_len != sizeof(bdaddr_t))
return -EINVAL;
memcpy(&config->bdaddr, tlv_nvm->data, sizeof(bdaddr_t));
break;
case EDL_TAG_ID_HCI:
if (tag_len < 3)
return -EINVAL;
/* HCI transport layer parameters
* enabling software inband sleep
* onto controller side.
......@@ -366,6 +433,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
break;
case EDL_TAG_ID_DEEP_SLEEP:
if (tag_len < 1)
return -EINVAL;
/* Sleep enable mask
* enabling deep sleep feature on controller.
*/
......@@ -374,14 +444,16 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
break;
}
idx += (sizeof(u16) + sizeof(u16) + 8 + tag_len);
idx += sizeof(struct tlv_type_nvm) + tag_len;
}
break;
default:
BT_ERR("Unknown TLV type %d", config->type);
break;
return -EINVAL;
}
return 0;
}
static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size,
......@@ -531,7 +603,9 @@ static int qca_download_firmware(struct hci_dev *hdev,
memcpy(data, fw->data, size);
release_firmware(fw);
qca_tlv_check_data(hdev, config, data, soc_type);
ret = qca_tlv_check_data(hdev, config, data, size, soc_type);
if (ret)
goto out;
segment = data;
remain = size;
......@@ -614,7 +688,7 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
}
EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
static int qca_check_bdaddr(struct hci_dev *hdev)
static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *config)
{
struct hci_rp_read_bd_addr *bda;
struct sk_buff *skb;
......@@ -638,7 +712,7 @@ static int qca_check_bdaddr(struct hci_dev *hdev)
}
bda = (struct hci_rp_read_bd_addr *)skb->data;
if (!bacmp(&bda->bdaddr, QCA_BDADDR_DEFAULT))
if (!bacmp(&bda->bdaddr, &config->bdaddr))
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
kfree_skb(skb);
......@@ -667,7 +741,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
enum qca_btsoc_type soc_type, struct qca_btsoc_version ver,
const char *firmware_name)
{
struct qca_fw_config config;
struct qca_fw_config config = {};
int err;
u8 rom_ver = 0;
u32 soc_ver;
......@@ -852,7 +926,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
break;
}
err = qca_check_bdaddr(hdev);
err = qca_check_bdaddr(hdev, &config);
if (err)
return err;
......
......@@ -29,6 +29,7 @@
#define EDL_PATCH_CONFIG_RES_EVT (0x00)
#define QCA_DISABLE_LOGGING_SUB_OP (0x14)
#define EDL_TAG_ID_BD_ADDR 2
#define EDL_TAG_ID_HCI (17)
#define EDL_TAG_ID_DEEP_SLEEP (27)
......@@ -47,7 +48,6 @@
#define get_soc_ver(soc_id, rom_ver) \
((le32_to_cpu(soc_id) << 16) | (le16_to_cpu(rom_ver)))
#define QCA_FW_BUILD_VER_LEN 255
#define QCA_HSP_GF_SOC_ID 0x1200
#define QCA_HSP_GF_SOC_MASK 0x0000ff00
......@@ -94,6 +94,7 @@ struct qca_fw_config {
uint8_t user_baud_rate;
enum qca_tlv_dnld_mode dnld_mode;
enum qca_tlv_dnld_mode dnld_type;
bdaddr_t bdaddr;
};
struct edl_event_hdr {
......
......@@ -2768,8 +2768,6 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_unregister_suspend_notifier(hdev);
msft_unregister(hdev);
hci_dev_do_close(hdev);
if (!test_bit(HCI_INIT, &hdev->flags) &&
......@@ -2823,6 +2821,7 @@ void hci_release_dev(struct hci_dev *hdev)
hci_discovery_filter_clear(hdev);
hci_blocked_keys_clear(hdev);
hci_codec_list_clear(&hdev->local_codecs);
msft_release(hdev);
hci_dev_unlock(hdev);
ida_destroy(&hdev->unset_handle_ida);
......
......@@ -7037,6 +7037,8 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
u16 handle = le16_to_cpu(ev->bis[i]);
bis = hci_conn_hash_lookup_handle(hdev, handle);
if (!bis)
continue;
set_bit(HCI_CONN_BIG_SYNC_FAILED, &bis->flags);
hci_connect_cfm(bis, ev->status);
......
......@@ -415,6 +415,9 @@ static void l2cap_chan_timeout(struct work_struct *work)
BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
if (!conn)
return;
mutex_lock(&conn->chan_lock);
/* __set_chan_timer() calls l2cap_chan_hold(chan) while scheduling
* this work. No need to call l2cap_chan_hold(chan) here again.
......@@ -3902,13 +3905,12 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
return 0;
}
static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd,
u8 *data, u8 rsp_code, u8 amp_id)
static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
u8 *data, u8 rsp_code, u8 amp_id)
{
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
struct l2cap_chan *chan = NULL, *pchan;
struct l2cap_chan *chan = NULL, *pchan = NULL;
int result, status = L2CAP_CS_NO_INFO;
u16 dcid = 0, scid = __le16_to_cpu(req->scid);
......@@ -3921,7 +3923,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
&conn->hcon->dst, ACL_LINK);
if (!pchan) {
result = L2CAP_CR_BAD_PSM;
goto sendresp;
goto response;
}
mutex_lock(&conn->chan_lock);
......@@ -4008,17 +4010,15 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
}
response:
l2cap_chan_unlock(pchan);
mutex_unlock(&conn->chan_lock);
l2cap_chan_put(pchan);
sendresp:
rsp.scid = cpu_to_le16(scid);
rsp.dcid = cpu_to_le16(dcid);
rsp.result = cpu_to_le16(result);
rsp.status = cpu_to_le16(status);
l2cap_send_cmd(conn, cmd->ident, rsp_code, sizeof(rsp), &rsp);
if (!pchan)
return;
if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
struct l2cap_info_req info;
info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
......@@ -4041,7 +4041,9 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
chan->num_conf_req++;
}
return chan;
l2cap_chan_unlock(pchan);
mutex_unlock(&conn->chan_lock);
l2cap_chan_put(pchan);
}
static int l2cap_connect_req(struct l2cap_conn *conn,
......
......@@ -769,7 +769,7 @@ void msft_register(struct hci_dev *hdev)
mutex_init(&msft->filter_lock);
}
void msft_unregister(struct hci_dev *hdev)
void msft_release(struct hci_dev *hdev)
{
struct msft_data *msft = hdev->msft_data;
......
......@@ -14,7 +14,7 @@
bool msft_monitor_supported(struct hci_dev *hdev);
void msft_register(struct hci_dev *hdev);
void msft_unregister(struct hci_dev *hdev);
void msft_release(struct hci_dev *hdev);
void msft_do_open(struct hci_dev *hdev);
void msft_do_close(struct hci_dev *hdev);
void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb);
......@@ -35,7 +35,7 @@ static inline bool msft_monitor_supported(struct hci_dev *hdev)
}
static inline void msft_register(struct hci_dev *hdev) {}
static inline void msft_unregister(struct hci_dev *hdev) {}
static inline void msft_release(struct hci_dev *hdev) {}
static inline void msft_do_open(struct hci_dev *hdev) {}
static inline void msft_do_close(struct hci_dev *hdev) {}
static inline void msft_vendor_evt(struct hci_dev *hdev, void *data,
......
......@@ -83,6 +83,10 @@ static void sco_sock_timeout(struct work_struct *work)
struct sock *sk;
sco_conn_lock(conn);
if (!conn->hcon) {
sco_conn_unlock(conn);
return;
}
sk = conn->sk;
if (sk)
sock_hold(sk);
......
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