2024-04-30 17:09:12

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v2 0/3] Bluetooth: qca: generalise device address check

The QCA default device address apparently comes from the NVM
configuration file and can differ quite a bit between controllers.

This series adds support for storing the default address when parsing
the configuration file and using it to determine whether the controller
has been provisioned with an address.

This makes sure that devices without a unique address start as
unconfigured unless a valid address has been provided in the devicetree.

Included in v2 are two preparatory but otherwise independent fixes that
adds the missing sanity checks when parsing the firmware files and makes
sure that the parser can handle configuration files for WCN3xxx.

Johan


Changes in v2:
- add missing firmware sanity checks (new patch)
- fix nvm configuration parsing (new patch)
- make sure to set the BD_ADDR quirk flag also when the controller
returns BDADDR_ANY


Johan Hovold (3):
Bluetooth: qca: add missing firmware sanity checks
Bluetooth: qca: fix NVM configuration parsing
Bluetooth: qca: generalise device address check

drivers/bluetooth/btqca.c | 83 +++++++++++++++++++++++++++++++--------
drivers/bluetooth/btqca.h | 2 +
2 files changed, 68 insertions(+), 17 deletions(-)

--
2.43.2



2024-04-30 17:09:13

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v2 1/3] Bluetooth: qca: add missing firmware sanity checks

Add the missing sanity checks when parsing the firmware files before
downloading them to avoid accessing and corrupting memory beyond the
vmalloced buffer.

Fixes: 83e81961ff7e ("Bluetooth: btqca: Introduce generic QCA ROME support")
Cc: [email protected] # 4.10
Signed-off-by: Johan Hovold <[email protected]>
---
drivers/bluetooth/btqca.c | 38 ++++++++++++++++++++++++++++++++------
1 file changed, 32 insertions(+), 6 deletions(-)

diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index cfa71708397b..6743b0a79d7a 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -268,9 +268,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;
@@ -286,6 +287,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev,

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;

@@ -294,6 +298,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;
@@ -333,6 +340,9 @@ 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);
@@ -341,17 +351,26 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff);
BT_DBG("Length\t\t : %d bytes", length);

+ 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_HCI:
+ if (tag_len < 3)
+ return -EINVAL;
+
/* HCI transport layer parameters
* enabling software inband sleep
* onto controller side.
@@ -367,6 +386,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.
*/
@@ -375,14 +397,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,
@@ -532,7 +556,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)
+ return ret;

segment = data;
remain = size;
--
2.43.2


2024-04-30 17:09:13

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v2 3/3] Bluetooth: qca: generalise device address check

The default device address apparently comes from the NVM configuration
file and can differ quite a bit between controllers.

Store the default address when parsing the configuration file and use it
to determine whether the controller has been provisioned with an
address.

This makes sure that devices without a unique address start as
unconfigured unless a valid address has been provided in the devicetree.

Fixes: 00567f70051a ("Bluetooth: qca: fix invalid device address check")
Cc: [email protected] # 6.5
Cc: Doug Anderson <[email protected]>
Cc: Janaki Ramaiah Thota <[email protected]>
Signed-off-by: Johan Hovold <[email protected]>
---
drivers/bluetooth/btqca.c | 21 ++++++++++++---------
drivers/bluetooth/btqca.h | 2 ++
2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index f6c9f89a6311..c6b2dd4d1716 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -15,9 +15,6 @@

#define VERSION "0.1"

-#define QCA_BDADDR_DEFAULT (&(bdaddr_t) {{ 0xad, 0x5a, 0x00, 0x00, 0x00, 0x00 }})
-#define QCA_BDADDR_WCN3991 (&(bdaddr_t) {{ 0xad, 0x5a, 0x00, 0x00, 0x98, 0x39 }})
-
int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver,
enum qca_btsoc_type soc_type)
{
@@ -387,6 +384,14 @@ static int qca_tlv_check_data(struct hci_dev *hdev,

/* 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;
@@ -661,7 +666,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;
@@ -685,10 +690,8 @@ 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) ||
- !bacmp(&bda->bdaddr, QCA_BDADDR_WCN3991)) {
+ if (!bacmp(&bda->bdaddr, &config->bdaddr))
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
- }

kfree_skb(skb);

@@ -716,7 +719,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;
@@ -901,7 +904,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;

diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
index dc31984f71dc..49ad668d0d0b 100644
--- a/drivers/bluetooth/btqca.h
+++ b/drivers/bluetooth/btqca.h
@@ -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)

@@ -94,6 +95,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 {
--
2.43.2


2024-04-30 17:09:14

by Johan Hovold

[permalink] [raw]
Subject: [PATCH v2 2/3] Bluetooth: qca: fix NVM configuration parsing

The NVM configuration files used by WCN3988 and WCN3990/1/8 have two
sets of configuration tags that are enclosed by a type-length header of
type four which the current parser fails to account for.

Instead the driver happily parses random data as if it were valid tags,
something which can lead to the configuration data being corrupted if it
ever encounters the words 0x0011 or 0x001b.

As is clear from commit b63882549b2b ("Bluetooth: btqca: Fix the NVM
baudrate tag offcet for wcn3991") the intention has always been to
process the configuration data also for WCN3991 and WCN3998 which
encodes the baud rate at a different offset.

Fix the parser so that it can handle the WCN3xxx configuration files,
which has an enclosing type-length header of type four and two sets of
TLV tags enclosed by a type-length header of type two and three,
respectively.

Note that only the first set, which contains the tags the driver is
currently looking for, will be parsed for now.

With the parser fixed, the software in-band sleep bit will now be set
for WCN3991 and WCN3998 (as it is for later controllers) and the default
baud rate 3200000 may be updated by the driver also for WCN3xxx
controllers.

Notably the deep-sleep feature bit is already set by default in all
configuration files in linux-firmware.

Fixes: 4219d4686875 ("Bluetooth: btqca: Add wcn3990 firmware download support.")
Cc: [email protected] # 4.19
Cc: Matthias Kaehlcke <[email protected]>
Signed-off-by: Johan Hovold <[email protected]>
---
drivers/bluetooth/btqca.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 6743b0a79d7a..f6c9f89a6311 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -281,6 +281,7 @@ static int 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;
@@ -346,11 +347,30 @@ static int qca_tlv_check_data(struct hci_dev *hdev,
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;

--
2.43.2


2024-04-30 17:43:27

by bluez.test.bot

[permalink] [raw]
Subject: RE: Bluetooth: qca: generalise device address check

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=849404

---Test result---

Test Summary:
CheckPatch PASS 1.83 seconds
GitLint FAIL 1.01 seconds
SubjectPrefix PASS 0.25 seconds
BuildKernel PASS 32.71 seconds
CheckAllWarning PASS 33.33 seconds
CheckSparse PASS 39.16 seconds
CheckSmatch FAIL 36.83 seconds
BuildKernel32 PASS 29.51 seconds
TestRunnerSetup PASS 534.15 seconds
TestRunner_l2cap-tester PASS 18.55 seconds
TestRunner_iso-tester FAIL 33.93 seconds
TestRunner_bnep-tester PASS 4.68 seconds
TestRunner_mgmt-tester FAIL 112.65 seconds
TestRunner_rfcomm-tester PASS 7.35 seconds
TestRunner_sco-tester PASS 15.05 seconds
TestRunner_ioctl-tester PASS 7.93 seconds
TestRunner_mesh-tester PASS 5.89 seconds
TestRunner_smp-tester PASS 6.91 seconds
TestRunner_userchan-tester PASS 4.97 seconds
IncrementalBuild PASS 38.57 seconds

Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[v2,1/3] Bluetooth: qca: add missing firmware sanity checks

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
7: B3 Line contains hard tab characters (\t): "Cc: [email protected] # 4.10"
[v2,2/3] Bluetooth: qca: fix NVM configuration parsing

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
32: B3 Line contains hard tab characters (\t): "Cc: [email protected] # 4.19"
##############################
Test: CheckSmatch - FAIL
Desc: Run smatch tool with source
Output:

Segmentation fault (core dumped)
make[4]: *** [scripts/Makefile.build:244: net/bluetooth/hci_core.o] Error 139
make[4]: *** Deleting file 'net/bluetooth/hci_core.o'
make[3]: *** [scripts/Makefile.build:485: net/bluetooth] Error 2
make[2]: *** [scripts/Makefile.build:485: net] Error 2
make[2]: *** Waiting for unfinished jobs....
Segmentation fault (core dumped)
make[4]: *** [scripts/Makefile.build:244: drivers/bluetooth/bcm203x.o] Error 139
make[4]: *** Deleting file 'drivers/bluetooth/bcm203x.o'
make[4]: *** Waiting for unfinished jobs....
Segmentation fault (core dumped)
make[4]: *** [scripts/Makefile.build:244: drivers/bluetooth/bpa10x.o] Error 139
make[4]: *** Deleting file 'drivers/bluetooth/bpa10x.o'
make[3]: *** [scripts/Makefile.build:485: drivers/bluetooth] Error 2
make[2]: *** [scripts/Makefile.build:485: drivers] Error 2
make[1]: *** [/github/workspace/src/src/Makefile:1919: .] Error 2
make: *** [Makefile:240: __sub-make] Error 2
##############################
Test: TestRunner_iso-tester - FAIL
Desc: Run iso-tester with test-runner
Output:
Total: 122, Passed: 121 (99.2%), Failed: 1, Not Run: 0

Failed Test Cases
ISO Connect2 Suspend - Success Failed 4.235 seconds
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 492, Passed: 489 (99.4%), Failed: 1, Not Run: 2

Failed Test Cases
LL Privacy - Add Device 5 (2 Devices to RL) Failed 0.162 seconds


---
Regards,
Linux Bluetooth

2024-04-30 21:22:23

by Doug Anderson

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] Bluetooth: qca: generalise device address check

Hi,

On Tue, Apr 30, 2024 at 10:08 AM Johan Hovold <[email protected]> wrote:
>
> The default device address apparently comes from the NVM configuration
> file and can differ quite a bit between controllers.
>
> Store the default address when parsing the configuration file and use it
> to determine whether the controller has been provisioned with an
> address.
>
> This makes sure that devices without a unique address start as
> unconfigured unless a valid address has been provided in the devicetree.
>
> Fixes: 00567f70051a ("Bluetooth: qca: fix invalid device address check")
> Cc: [email protected] # 6.5
> Cc: Doug Anderson <[email protected]>
> Cc: Janaki Ramaiah Thota <[email protected]>
> Signed-off-by: Johan Hovold <[email protected]>
> ---
> drivers/bluetooth/btqca.c | 21 ++++++++++++---------
> drivers/bluetooth/btqca.h | 2 ++
> 2 files changed, 14 insertions(+), 9 deletions(-)

I can confirm that my sc7180-trogdor-based devices manage to detect
the default address after this series and thus still look to the
device-tree for their address. Thus:

Tested-by: Douglas Anderson <[email protected]>

I'll continue to note that I still wish that detecting the default
address wasn't important for trogdor. I still feel that the fact that
they have a valid BT address stored in their device tree (populated by
firmware) should take precedence. ...but I won't insist.

I'm happy to let Bluetooth/Qualcomm folks decide if they like this
implementation and I don't have tons of Bluetooth context, so I'll not
add a Reviewed-by tag.

-Doug

2024-04-30 21:52:17

by patchwork-bot+bluetooth

[permalink] [raw]
Subject: Re: [PATCH v2 0/3] Bluetooth: qca: generalise device address check

Hello:

This series was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <[email protected]>:

On Tue, 30 Apr 2024 19:07:38 +0200 you wrote:
> The QCA default device address apparently comes from the NVM
> configuration file and can differ quite a bit between controllers.
>
> This series adds support for storing the default address when parsing
> the configuration file and using it to determine whether the controller
> has been provisioned with an address.
>
> [...]

Here is the summary with links:
- [v2,1/3] Bluetooth: qca: add missing firmware sanity checks
https://git.kernel.org/bluetooth/bluetooth-next/c/fd10f4fe66a1
- [v2,2/3] Bluetooth: qca: fix NVM configuration parsing
https://git.kernel.org/bluetooth/bluetooth-next/c/882125a9cdb9
- [v2,3/3] Bluetooth: qca: generalise device address check
https://git.kernel.org/bluetooth/bluetooth-next/c/aa63c8b7b1c2

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



2024-05-01 06:27:31

by Johan Hovold

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] Bluetooth: qca: add missing firmware sanity checks

On Tue, Apr 30, 2024 at 07:07:39PM +0200, Johan Hovold wrote:
> Add the missing sanity checks when parsing the firmware files before
> downloading them to avoid accessing and corrupting memory beyond the
> vmalloced buffer.
>
> Fixes: 83e81961ff7e ("Bluetooth: btqca: Introduce generic QCA ROME support")
> Cc: [email protected] # 4.10
> Signed-off-by: Johan Hovold <[email protected]>
> ---
> drivers/bluetooth/btqca.c | 38 ++++++++++++++++++++++++++++++++------
> 1 file changed, 32 insertions(+), 6 deletions(-)

> static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size,
> @@ -532,7 +556,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)
> + return ret;

Bah, I realised late last night that I had forgotten to fix this error
path before posting v2. This was supposed to say

goto out;

to make sure the firmware buffer is released in case we ever encounter
malformed firmware.

I'll send a follow-up patch.

Johan

2024-05-01 06:31:37

by Johan Hovold

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] Bluetooth: qca: generalise device address check

On Tue, Apr 30, 2024 at 02:21:47PM -0700, Doug Anderson wrote:
> On Tue, Apr 30, 2024 at 10:08 AM Johan Hovold <[email protected]> wrote:
> >
> > The default device address apparently comes from the NVM configuration
> > file and can differ quite a bit between controllers.
> >
> > Store the default address when parsing the configuration file and use it
> > to determine whether the controller has been provisioned with an
> > address.
> >
> > This makes sure that devices without a unique address start as
> > unconfigured unless a valid address has been provided in the devicetree.
> >
> > Fixes: 00567f70051a ("Bluetooth: qca: fix invalid device address check")
> > Cc: [email protected] # 6.5
> > Cc: Doug Anderson <[email protected]>
> > Cc: Janaki Ramaiah Thota <[email protected]>
> > Signed-off-by: Johan Hovold <[email protected]>

> I can confirm that my sc7180-trogdor-based devices manage to detect
> the default address after this series and thus still look to the
> device-tree for their address. Thus:
>
> Tested-by: Douglas Anderson <[email protected]>

Thanks for testing, Doug.

> I'll continue to note that I still wish that detecting the default
> address wasn't important for trogdor. I still feel that the fact that
> they have a valid BT address stored in their device tree (populated by
> firmware) should take precedence. ...but I won't insist.

When I can find the time, I'll look into at least dropping the BD_ADDR
quirk in favour of always looking in the devicetree when we do not have
a valid address. That may be a good time to revisit the question whether
the devicetree should always override the controller's address too.

Johan