Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6f0381a authored by Balvinder Singh's avatar Balvinder Singh Committed by Nitin Shivpure
Browse files

Bluetooth: Fix for checking proper user-supplied buffers



During patch download procedure, size validation and zero
allocation of buffers are done to ensure values passed are
in permissible range.

CRs-fixed: 2082452
Change-Id: I16a46f8c8860296919bf11021143ae36f2964363
Signed-off-by: default avatarBalvinder Singh <bpsingh@codeaurora.org>
parent 94f816cc
Loading
Loading
Loading
Loading
+52 −12
Original line number Original line Diff line number Diff line
/*
/*
 *  Bluetooth supports for Qualcomm Atheros chips
 *  Bluetooth supports for Qualcomm Atheros chips
 *
 *
 *  Copyright (c) 2015 The Linux Foundation. All rights reserved.
 *  Copyright (c) 2017 The Linux Foundation. All rights reserved.
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2
 *  it under the terms of the GNU General Public License version 2
@@ -27,6 +27,9 @@


#define VERSION "0.1"
#define VERSION "0.1"


#define MAX_PATCH_FILE_SIZE (100*1024)
#define MAX_NVM_FILE_SIZE   (10*1024)

static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version)
static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version)
{
{
	struct sk_buff *skb;
	struct sk_buff *skb;
@@ -285,27 +288,63 @@ static int rome_download_firmware(struct hci_dev *hdev,
				  struct rome_config *config)
				  struct rome_config *config)
{
{
	const struct firmware *fw;
	const struct firmware *fw;
	u32 type_len, length;
	struct tlv_type_hdr *tlv;
	int ret;
	int ret;


	BT_INFO("%s: ROME Downloading %s", hdev->name, config->fwname);
	BT_INFO("%s: ROME Downloading file: %s", hdev->name, config->fwname);

	ret = request_firmware(&fw, config->fwname, &hdev->dev);
	ret = request_firmware(&fw, config->fwname, &hdev->dev);
	if (ret) {

		BT_ERR("%s: Failed to request file: %s (%d)", hdev->name,
	if (ret || !fw || !fw->data || fw->size <= 0) {
		       config->fwname, ret);
		BT_ERR("Failed to request file: err = (%d)", ret);
		ret = ret ? ret : -EINVAL;
		return ret;
		return ret;
	}
	}


	rome_tlv_check_data(config, fw);
	if (config->type != TLV_TYPE_NVM &&
		config->type != TLV_TYPE_PATCH) {
		ret = -EINVAL;
		BT_ERR("TLV_NVM dload: wrong config type selected");
		goto exit;
	}

	if (config->type == TLV_TYPE_PATCH &&
		(fw->size > MAX_PATCH_FILE_SIZE)) {
		ret = -EINVAL;
		BT_ERR("TLV_PATCH dload: wrong patch file sizes");
		goto exit;
	} else if (config->type == TLV_TYPE_NVM &&
		(fw->size > MAX_NVM_FILE_SIZE)) {
		ret = -EINVAL;
		BT_ERR("TLV_NVM dload: wrong NVM file sizes");
		goto exit;
	}

	if (fw->size < sizeof(struct tlv_type_hdr)) {
		ret = -EINVAL;
		BT_ERR("Firware size smaller to fit minimum value");
		goto exit;
	}

	tlv = (struct tlv_type_hdr *)fw->data;
	type_len = le32_to_cpu(tlv->type_len);
	length = (type_len >> 8) & 0x00ffffff;


	if (fw->size - 4 != length) {
		ret = -EINVAL;
		BT_ERR("Requested size not matching size in header");
		goto exit;
	}

	rome_tlv_check_data(config, fw);
	ret = rome_tlv_download_request(hdev, fw);
	ret = rome_tlv_download_request(hdev, fw);

	if (ret) {
	if (ret) {
		BT_ERR("%s: Failed to download file: %s (%d)", hdev->name,
		BT_ERR("Failed to download FW: error = (%d)", ret);
		       config->fwname, ret);
	}
	}


exit:
	release_firmware(fw);
	release_firmware(fw);

	return ret;
	return ret;
}
}


@@ -316,8 +355,9 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
	int err;
	int err;


	cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD;
	cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD;
	cmd[1] = 0x02; 			/* TAG ID */
	/* Set the TAG ID of 0x02 for NVM set and size of tag */
	cmd[2] = sizeof(bdaddr_t);	/* size */
	cmd[1] = 0x02;
	cmd[2] = sizeof(bdaddr_t);
	memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t));
	memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t));
	skb = __hci_cmd_sync_ev(hdev, EDL_NVM_ACCESS_OPCODE, sizeof(cmd), cmd,
	skb = __hci_cmd_sync_ev(hdev, EDL_NVM_ACCESS_OPCODE, sizeof(cmd), cmd,
				HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
				HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);