Linux bluetooth development
 help / color / mirror / Atom feed
* [bluez/bluez] 83e927: device: fix inverted NULL check in gatt_db clone
From: github-actions[bot] @ 2026-05-18  5:52 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1096236
  Home:   https://github.com/bluez/bluez
  Commit: 83e92707b9831b25a4de0b66f5b6cea4509c63c2
      https://github.com/bluez/bluez/commit/83e92707b9831b25a4de0b66f5b6cea4509c63c2
  Author: Zhao Dongdong <zhaodongdong@kylinos.cn>
  Date:   2026-05-18 (Mon, 18 May 2026)

  Changed paths:
    M src/device.c

  Log Message:
  -----------
  device: fix inverted NULL check in gatt_db clone

gatt_db_clone() returns NULL on failure so the condition was inverted.
With the old check a successful clone (non-NULL) would return false and
skip swapping the device's GATT database, while a failure (NULL) would
fall through and dereference a NULL pointer a few lines below.

Fix by negating the condition: only bail out early if the clone failed;
proceed with the swap when the clone actually succeeds.

Fixes: cbe4144 ("set: Attempt to use existing set gatt-db")
Signed-off-by: Zhao Dongdong <zhaodongdong@kylinos.cn>



To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* Re: [PATCH] Bluetooth: HIDP: fix missing length checks in hidp_input_report()
From: Greg KH @ 2026-05-18  5:18 UTC (permalink / raw)
  To: Muhammad Bilal
  Cc: linux-bluetooth, linux-kernel, marcel, luiz.dentz, johan.hedberg,
	stable
In-Reply-To: <20260517234805.116570-1-meatuni001@gmail.com>

On Sun, May 17, 2026 at 07:48:05PM -0400, Muhammad Bilal wrote:
> hidp_input_report() reads keyboard and mouse payload data from an skb
> without first verifying that skb->len contains enough data.
> 
> hidp_recv_intr_frame() pulls the 1-byte HIDP header before dispatching
> to hidp_input_report(). If a paired device sends a truncated packet,
> the handler reads beyond the valid skb data, resulting in
> an out-of-bounds read of skb data.
> The OOB bytes may be interpreted as phantom key presses or
> spurious mouse movement.
> 
> Add a check that skb->len is non-zero before the type switch, and
> per-report-type minimum length checks before accessing the payload.
> 
> Signed-off-by: Muhammad Bilal <meatuni001@gmail.com>
> ---
>  net/bluetooth/hidp/core.c | 19 ++++++++++++++++---
>  1 file changed, 16 insertions(+), 3 deletions(-)
> 
> diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
> index 976f91eeb..03838a6ff 100644
> --- a/net/bluetooth/hidp/core.c
> +++ b/net/bluetooth/hidp/core.c
> @@ -179,12 +179,22 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
>  {
>  	struct input_dev *dev = session->input;
>  	unsigned char *keys = session->keys;
> -	unsigned char *udata = skb->data + 1;
> -	signed char *sdata = skb->data + 1;
> -	int i, size = skb->len - 1;
> +	unsigned char *udata;
> +	signed char *sdata;
> +	int i, size;
> +
> +	if (!skb->len)
> +		return;
> +
> +	udata = skb->data + 1;
> +	sdata = skb->data + 1;
> +	size = skb->len - 1;
>  
>  	switch (skb->data[0]) {
>  	case 0x01:	/* Keyboard report */
> +		if (size < 8)
> +			break;
> +
>  		for (i = 0; i < 8; i++)
>  			input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
>  
> @@ -213,6 +223,9 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
>  		break;
>  
>  	case 0x02:	/* Mouse report */
> +		if (size < 3)
> +			break;
> +
>  		input_report_key(dev, BTN_LEFT,   sdata[0] & 0x01);
>  		input_report_key(dev, BTN_RIGHT,  sdata[0] & 0x02);
>  		input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
> -- 
> 2.54.0
> 
> 

<formletter>

This is not the correct way to submit patches for inclusion in the
stable kernel tree.  Please read:
    https://www.kernel.org/doc/html/latest/process/stable-kernel-rules.html
for how to do this properly.

</formletter>

^ permalink raw reply

* Re: [REGRESSION] Bluetooth: btmtk: MT7922 "Failed to send wmt func ctrl (-22)" after 634a4408c0615c ("validate WMT event SKB length before struct access")
From: Thorsten Leemhuis @ 2026-05-18  4:39 UTC (permalink / raw)
  To: Brandon Arnold, linux-bluetooth
  Cc: luiz.von.dentz, tristan, chris.lu, linux-mediatek, gregkh, stable,
	regressions
In-Reply-To: <CAM07e=vYJE8khJmbsn75SOYye44o8YV8TZsRyF1mFRuUTMCgUw@mail.gmail.com>

On 5/18/26 01:25, Brandon Arnold wrote:
> #regzbot introduced: 634a4408c0615c206885e60ea05f489c426f64b6
> #regzbot title: MT7922 BT controller never registers (wmt func ctrl
> -22) after btmtk WMT SKB-length validation

Thx for the reports, there are quite a few similar ones already; the
problem is known and the fix (see the link below) should be heading to
mainline this week and from there go to stable.

Ciao, Thorsten

#regzbot dup:
https://lore.kernel.org/linux-bluetooth/770d36b07311bf88210c187923f243fb9f126f04.1777058551.git.pav@iki.fi/

> Hello there.
> 
> I wanted to report the below information about a commit that I
> confirmed broke my MediaTek MT7922 adapter. The commit is also built
> into the main Arch Linux package, so it affected me during a routine
> update (see the BBS link in the report below). This adapter is the one
> that came with my Framework Laptop 16 system.
> 
> Apologies for Claude's verbosity and language but I can confirm I
> attended the bisect and revert of the offending diff. Thank you!
> 
> Workaround in use: pinned to the Arch Linux pre-7.0.7 kernel.
> 
> Thanks,
> Brandon Arnold
> 
> Commit 634a4408c0615c ("Bluetooth: btmtk: validate WMT event SKB
> length before struct access"), backported to 7.0.x stable and shipped
> in v7.0.7, breaks Bluetooth on the MediaTek MT7922: the WMT function
> control step fails with -EINVAL and the HCI controller never
> registers. WiFi on the same chip (mt7921e) is unaffected.
> 
> This is NOT a v6.19->v7.0 mainline regression -- mainline v7.0 is
> GOOD. The regression is the above commit specifically; it is absent
> from v7.0 and v7.0.6 and present in v7.0.7.
> 
> Scope / affected versions
> -------------------------
> - GOOD: mainline v7.0, linux-stable v7.0.6 (commit absent)
> - BAD: linux-stable v7.0.7 (commit present)
> - Independently reported on Arch (different machine -- Lenovo
> IdeaPad, MT7922 USB [0489:e0d8]): BROKEN on linux 7.0.7.arch2-1,
> WORKING on 7.0.6.arch1-1, identical symptom.
> https://bbs.archlinux.org/viewtopic.php?id=313561
> 
> Hardware / firmware (primary reporter)
> --------------------------------------
> - Framework Laptop 16 (AMD Ryzen AI 300 Series), board FRANMHCP09 A9
> - BIOS: INSYDE/Framework 03.04, 2025-11-06
> - MT7922, PCI [14c3:0616] subsys [14c3:e616]; BT side USB, driver
> btusb/btmtk; WiFi side mt7921e (works)
> - linux-firmware 20260410; BT firmware BT_RAM_CODE_MT7922_1_1,
> HW/SW Version 0x008a008a, Build Time 20260224103448
> - bluez 5.86
> 
> Symptom
> -------
> The firmware download and version handshake still succeed (identical
> HW/SW version line before and after), then:
> 
> Bluetooth: hci0: HW/SW Version: 0x008a008a, Build Time: 20260224103448
> Bluetooth: hci0: Failed to send wmt func ctrl (-22)
> 
> No "Device setup in N usecs" follows; BlueZ reports "No default
> controller available". hci0 exists in /sys/class/bluetooth and is not
> rfkill-blocked. Reproducible deterministically on cold boot,
> `modprobe -r btusb; modprobe btusb`, and full USB unbind/rebind. It
> fails even with btusb enable_autosuspend=0, so this is distinct from
> the known func-ctrl/autosuspend race.
> 
> Analysis
> --------
> 634a4408c0615c reworks btmtk_usb_hci_wmt_sync() to validate length
> with skb_pull_data() before casting the WMT event:
> 
> - wmt_evt = (struct btmtk_hci_wmt_evt *)data->evt_skb->data;
> + wmt_evt = skb_pull_data(data->evt_skb, sizeof(*wmt_evt));
> + if (!wmt_evt) { ... err = -EINVAL; goto err_free_skb; }
> ...
> case BTMTK_WMT_FUNC_CTRL:
> + if (!skb_pull_data(data->evt_skb,
> + sizeof(wmt_evt_funcc->status))) {
> + err = -EINVAL; goto err_free_skb;
> + }
> wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
> 
> For the FUNC_CTRL response from the MT7922, one of these
> skb_pull_data() calls returns NULL and the function returns -EINVAL
> (surfaced as "Failed to send wmt func ctrl (-22)"). In effect the
> length the driver now requires
> (sizeof(struct btmtk_hci_wmt_evt) + sizeof(status)) exceeds what this
> controller actually sends for FUNC_CTRL, so a valid handshake is now
> rejected. The pre-patch code cast and read the same bytes without the
> strict length gate and worked on this hardware.
> 
> Empirical confirmation (mainline, no distro patches)
> ----------------------------------------------------
> Built faithfully from the running Arch config (only LOCALVERSION
> added); no out-of-tree changes.
> 
> - mainline v7.0 : GOOD (commit absent)
> - linux-stable v7.0.7 : BAD (kernel 7.0.7-bisect; WMT func ctrl -22
> count = 1; hci0 device setup never completes; bluetoothctl shows 0
> controllers)
> - v7.0.7 + revert of
> 70d37a8b9229 (the 7.0.7
> backport of 634a4408c0615c): GOOD (kernel
> 7.0.7-bisect-00001-ge33bfb5d7480; WMT func ctrl -22 count = 0; hci0
> device setup OK; bluetoothctl shows 1 controller)
> 
> The reverted tree's drivers/bluetooth/btmtk.c is byte-identical to
> v7.0.6 (git diff v7.0.6 -- drivers/bluetooth/btmtk.c is empty), so the
> v7.0.7-vs-revert pair isolates exactly this one commit.
> 
> Reproduction
> ------------
> 1. Boot a kernel >= v7.0.7-equivalent on MT7922 hardware.
> 2. `bluetoothctl list` -> no controller.
> 3. `journalctl -k -b | grep 'wmt func ctrl'` -> -22.
> 4. Revert 634a4408c0615c (or boot v7.0.6) -> controller registers.
> 
> A straight revert restores operation and is offered as the candidate
> fix; alternatively the length checks should be relaxed to match the
> MT7922's actual FUNC_CTRL WMT event length. I can test patches, or
> provide full bad/good kernel logs, btmon/hci traces, and the exact
> short SKB length on request.


^ permalink raw reply

* Re: [PATCH v3] Bluetooth: btintel: Use skb_pull_data return for bounds check
From: Quan Sun @ 2026-05-18  4:01 UTC (permalink / raw)
  To: Paul Menzel; +Cc: marcel, luiz.dentz, kiran.k, linux-bluetooth
In-Reply-To: <e12a170f-5340-4f45-8550-127039de805a@molgen.mpg.de>

Dear Paul,

Thanks for your review and feedback!

> How did you find this? Manual review, or some tool?

This was found via manual code review. I noticed that skb_pull_data(skb, 
4) is actually called 18 times, meaning the function consumes 74 bytes 
in total, but the initial check only verified that skb->len was at least 
66 bytes.

> Where you able to test the new code on hardware?

Unfortunately, I wasn't able to test this on actual hardware as I don't
have access to this specific Intel Bluetooth chip. However, the fix
strictly ensures that we don't dereference a NULL pointer returned by
skb_pull_data() when the packet is shorter than expected.

> It’d be great to log more information, wouldn’t it?

That's a very good point. I'm planning to update the malformed label to 
log the remaining length, like this:

     bt_dev_dbg(hdev, "Malformed packet received, remaining len %u", 
skb->len);

Does this look good to you, or would you prefer logging some other details?

Kind regards,
Quan Sun


^ permalink raw reply

* RE: Bluetooth: HIDP: fix missing length checks in hidp_input_report()
From: bluez.test.bot @ 2026-05-18  2:56 UTC (permalink / raw)
  To: linux-bluetooth, meatuni001
In-Reply-To: <20260517234805.116570-1-meatuni001@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1482 bytes --]

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=1096211

---Test result---

Test Summary:
CheckPatch                    PASS      0.61 seconds
GitLint                       PASS      0.25 seconds
SubjectPrefix                 PASS      0.09 seconds
BuildKernel                   PASS      25.57 seconds
CheckAllWarning               PASS      27.88 seconds
CheckSparse                   PASS      26.78 seconds
BuildKernel32                 PASS      24.79 seconds
TestRunnerSetup               PASS      530.22 seconds
TestRunner_l2cap-tester       PASS      378.32 seconds
TestRunner_iso-tester         PASS      596.24 seconds
TestRunner_bnep-tester        PASS      18.62 seconds
TestRunner_mgmt-tester        PASS      2023.70 seconds
TestRunner_rfcomm-tester      PASS      63.42 seconds
TestRunner_sco-tester         PASS      141.24 seconds
TestRunner_ioctl-tester       PASS      133.47 seconds
TestRunner_mesh-tester        PASS      59.92 seconds
TestRunner_smp-tester         PASS      17.98 seconds
TestRunner_userchan-tester    PASS      19.13 seconds
TestRunner_6lowpan-tester     PASS      51.17 seconds
IncrementalBuild              PASS      23.75 seconds



https://github.com/bluez/bluetooth-next/pull/206

---
Regards,
Linux Bluetooth


^ permalink raw reply

* [PATCH v9] Bluetooth: hci_uart: fix UAFs and race conditions in close and init paths
From: w15303746062 @ 2026-05-18  2:49 UTC (permalink / raw)
  To: luiz.dentz, pmenzel, marcel, linux-bluetooth
  Cc: linux-serial, linux-kernel, greg, stable, Mingyu Wang
In-Reply-To: <CABBYNZ+r3gm37FW5WqE79bRp+x9UZsaCtyvfz_FdixqEucAxGw@mail.gmail.com>

From: Mingyu Wang <25181214217@stu.xidian.edu.cn>

Vulnerabilities leading to Use-After-Free (UAF) and Null Pointer
Dereference (NPD) conditions were observed in the lifecycle management
of hci_uart.

The primary issue arises because the workqueues (init_ready and
write_work) are only flushed/cancelled if the HCI_UART_PROTO_READY
flag is set during TTY close. If a hangup occurs before setup completes,
hci_uart_tty_close() skips the teardown of these workqueues and
proceeds to free the `hu` struct. When the scheduled work executes
later, it blindly dereferences the freed `hu` struct.

Furthermore, several data races and UAFs were identified in the teardown
sequence:
1. Calling hci_uart_flush() from hci_uart_close() without effectively
   disabling write_work causes a race condition where both can concurrently
   double-free hu->tx_skb. This happens because protocol timers can
   concurrently invoke hci_uart_tx_wakeup() and requeue write_work.
2. Calling hci_free_dev(hdev) before hu->proto->close(hu) causes a UAF
   when vendor specific protocol close callbacks dereference hu->hdev.
3. In the initialization error paths, failing to take the proto_lock
   write lock before clearing PROTO_READY leads to races with active
   readers. Additionally, hci_uart_tty_receive() accesses hu->hdev
   outside the read lock, leading to UAFs if the initialization error
   path frees hdev concurrently.

Fix these synchronization and lifecycle issues by:
1. Re-ordering hci_uart_tty_close() to clear HCI_UART_PROTO_READY first,
   followed immediately by a cancel_work_sync(&hu->write_work). Clearing
   the flag locks out concurrent protocol timers from successfully invoking
   hci_uart_tx_wakeup(), effectively rendering the cancellation permanent
   and preventing the tx_skb double-free.
2. Note: Clearing PROTO_READY early causes hci_uart_close() to skip
   hu->proto->flush(). This is perfectly safe in the tty_close path
   because hu->proto->close() executes shortly after, which intrinsically
   purges all protocol SKB queues and tears down the state.
3. Relocating hu->proto->close(hu) strictly prior to hci_free_dev(hdev)
   across all close and error paths to prevent vendor-level UAFs.
4. Moving the hdev->stat.byte_rx increment in hci_uart_tty_receive()
   inside the proto_lock read-side critical section to safely synchronize
   with device unregistration.
5. Adding cancel_work_sync(&hu->write_work) to hci_uart_close() to safely
   flush the workqueue before hci_uart_flush() is invoked via the HCI core.
6. Utilizing cancel_work_sync() instead of disable_work_sync() across
   all paths to prevent permanently breaking user-space retry capabilities.

Fixes: 3b799254cf6f ("Bluetooth: hci_uart: Cancel init work before unregistering")
Cc: stable@vger.kernel.org
Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>
---
Changes in v9:
- Addressed a critical flaw identified in v8 where premature cancellation of write_work allowed active protocol timers to immediately reschedule it. The teardown sequence in hci_uart_tty_close() now strictly clears HCI_UART_PROTO_READY *before* calling cancel_work_sync(&hu->write_work). This permanently locks out hci_uart_tx_wakeup(), completely resolving the lingering UAF and double-free races.
- Documented that skipping hu->proto->flush() via early flag clearance is intrinsically safe, as hu->proto->close() executes subsequently to purge all unacked/rel queues.

Changes in v8:
- Corrected the teardown sequence in hci_uart_tty_close() by unconditionally canceling write_work BEFORE hci_uart_close().
- Moved hu->hdev->stat.byte_rx increment inside the proto_lock read-side critical section in hci_uart_tty_receive() to prevent read-side UAF against concurrent registration failures.
- Added cancel_work_sync(&hu->write_work) inside hci_uart_close() to eliminate the race condition between write_work and hci_uart_flush() when the interface is brought down via the HCI core.

Changes in v7:
- Reverted disable_work_sync() back to cancel_work_sync() across all error and close paths to preserve user-space retry capabilities.
- Synchronized workqueue teardown safely by atomically clearing PROTO_READY / PROTO_INIT under proto_lock prior to calling cancel_work_sync().
- Fixed a Use-After-Free (UAF) vulnerability in the teardown sequence by relocating hu->proto->close(hu) strictly prior to hci_free_dev(hdev).
- Added cancel_work_sync(&hu->init_ready) at the very beginning of hci_uart_tty_close() to serialize teardown against active asynchronous registration.

Changes in v6:
- Fixed missing `hu->proto_lock` write lock in hci_uart_init_work() error path to prevent race with readers (reported by Sashiko).
- Added disable_work_sync() instead of cancel_work_sync() for `hu->write_work` in hci_uart_init_work() and hci_uart_register_dev() error paths.

Changes in v5:
- Relocated disable_work_sync() to the very top of hci_uart_tty_close(), 
  before hci_uart_close(), to ensure no new work is submitted during device teardown.

Changes in v4:
- Adopted Luiz's suggestion to use disable_work_sync() instead of 
  cancel_work_sync() in close path to prevent new work submissions.

Changes in v3:
- Added 'Cc: stable' tag as requested by the stable bot.

Changes in v2:
- Added KASAN/ODEBUG crash trace.

 drivers/bluetooth/hci_ldisc.c | 48 +++++++++++++++++++++++++++++------
 1 file changed, 40 insertions(+), 8 deletions(-)

diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 275ea865bc29..47f4902b40b4 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -194,7 +194,15 @@ void hci_uart_init_work(struct work_struct *work)
 	err = hci_register_dev(hu->hdev);
 	if (err < 0) {
 		BT_ERR("Can't register HCI device");
+
+		percpu_down_write(&hu->proto_lock);
 		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
+		percpu_up_write(&hu->proto_lock);
+
+		/* Safely cancel work after clearing flags */
+		cancel_work_sync(&hu->write_work);
+
+		/* Close protocol before freeing hdev */
 		hu->proto->close(hu);
 		hdev = hu->hdev;
 		hu->hdev = NULL;
@@ -263,8 +271,12 @@ static int hci_uart_open(struct hci_dev *hdev)
 /* Close device */
 static int hci_uart_close(struct hci_dev *hdev)
 {
+	struct hci_uart *hu = hci_get_drvdata(hdev);
+
 	BT_DBG("hdev %p", hdev);
 
+	cancel_work_sync(&hu->write_work);
+
 	hci_uart_flush(hdev);
 	hdev->flush = NULL;
 	return 0;
@@ -531,6 +543,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
 {
 	struct hci_uart *hu = tty->disc_data;
 	struct hci_dev *hdev;
+	bool proto_ready;
 
 	BT_DBG("tty %p", tty);
 
@@ -540,24 +553,38 @@ static void hci_uart_tty_close(struct tty_struct *tty)
 	if (!hu)
 		return;
 
-	hdev = hu->hdev;
-	if (hdev)
-		hci_uart_close(hdev);
+	/* Wait for init_ready to finish to prevent registration races */
+	cancel_work_sync(&hu->init_ready);
 
-	if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
+	proto_ready = test_bit(HCI_UART_PROTO_READY, &hu->flags);
+	if (proto_ready) {
 		percpu_down_write(&hu->proto_lock);
 		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
 		percpu_up_write(&hu->proto_lock);
+	}
 
-		cancel_work_sync(&hu->init_ready);
-		cancel_work_sync(&hu->write_work);
+	/*
+	 * Unconditionally cancel write_work AFTER clearing PROTO_READY.
+	 * This ensures that concurrent protocol timers cannot requeue
+	 * write_work via hci_uart_tx_wakeup(), permanently preventing
+	 * double-free races and UAFs.
+	 */
+	cancel_work_sync(&hu->write_work);
+
+	hdev = hu->hdev;
+	if (hdev)
+		hci_uart_close(hdev); /* proto->flush is safely skipped */
 
+	if (proto_ready) {
 		if (hdev) {
 			if (test_bit(HCI_UART_REGISTERED, &hu->flags))
 				hci_unregister_dev(hdev);
-			hci_free_dev(hdev);
 		}
+		/* Close protocol before freeing hdev (intrinsically purges queues) */
 		hu->proto->close(hu);
+
+		if (hdev)
+			hci_free_dev(hdev);
 	}
 	clear_bit(HCI_UART_PROTO_SET, &hu->flags);
 
@@ -625,11 +652,12 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
 	 * tty caller
 	 */
 	hu->proto->recv(hu, data, count);
-	percpu_up_read(&hu->proto_lock);
 
 	if (hu->hdev)
 		hu->hdev->stat.byte_rx += count;
 
+	percpu_up_read(&hu->proto_lock);
+
 	tty_unthrottle(tty);
 }
 
@@ -695,6 +723,10 @@ static int hci_uart_register_dev(struct hci_uart *hu)
 		percpu_down_write(&hu->proto_lock);
 		clear_bit(HCI_UART_PROTO_INIT, &hu->flags);
 		percpu_up_write(&hu->proto_lock);
+		/* Cancel work after clearing flags */
+		cancel_work_sync(&hu->write_work);
+
+		/* Close protocol before freeing hdev */
 		hu->proto->close(hu);
 		hu->hdev = NULL;
 		hci_free_dev(hdev);
-- 
2.34.1


^ permalink raw reply related

* [PATCH] Bluetooth: btmtk: fix urb->setup_packet leak in error paths
From: Jiajia Liu @ 2026-05-18  2:24 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz, Matthias Brugger,
	AngeloGioacchino Del Regno, Sean Wang
  Cc: linux-bluetooth, linux-kernel, linux-arm-kernel, linux-mediatek,
	Jiajia Liu

The setup_packet of control urb is not freed if usb_submit_urb fails or
the submitted urb is killed. Add free in these two paths.

Fixes: a1c49c434e150 ("Bluetooth: btusb: Add protocol support for MediaTek MT7668U USB devices")
Signed-off-by: Jiajia Liu <liujiajia@kylinos.cn>
---
 drivers/bluetooth/btmtk.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index f70c1b0f8990..5330f06f000a 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -537,6 +537,7 @@ static void btmtk_usb_wmt_recv(struct urb *urb)
 		return;
 	} else if (urb->status == -ENOENT) {
 		/* Avoid suspend failed when usb_kill_urb */
+		kfree(urb->setup_packet);
 		return;
 	}
 
@@ -610,6 +611,7 @@ static int btmtk_usb_submit_wmt_recv_urb(struct hci_dev *hdev)
 		if (err != -EPERM && err != -ENODEV)
 			bt_dev_err(hdev, "urb %p submission failed (%d)",
 				   urb, -err);
+		kfree(dr);
 		usb_unanchor_urb(urb);
 	}
 
-- 
2.53.0


^ permalink raw reply related

* [PATCH BlueZ] device: fix inverted NULL check in gatt_db clone
From: Zhao Dongdong @ 2026-05-18  2:12 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Zhao Dongdong

From: Zhao Dongdong <zhaodongdong@kylinos.cn>

gatt_db_clone() returns NULL on failure so the condition was inverted.
With the old check a successful clone (non-NULL) would return false and
skip swapping the device's GATT database, while a failure (NULL) would
fall through and dereference a NULL pointer a few lines below.

Fix by negating the condition: only bail out early if the clone failed;
proceed with the swap when the clone actually succeeds.

Fixes: cbe4144 ("set: Attempt to use existing set gatt-db")
Signed-off-by: Zhao Dongdong <zhaodongdong@kylinos.cn>
---
 src/device.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/device.c b/src/device.c
index 28515054c..bea893301 100644
--- a/src/device.c
+++ b/src/device.c
@@ -7896,7 +7896,7 @@ bool btd_device_set_gatt_db(struct btd_device *device, struct gatt_db *db)
 		return false;
 
 	clone = gatt_db_clone(db);
-	if (clone)
+	if (!clone)
 		return false;
 
 	gatt_db_unregister(device->db, device->db_id);
-- 
2.25.1


^ permalink raw reply related

* RE: Bluetooth: L2CAP: rate-limit ECHO_RSP per signaling PDU
From: bluez.test.bot @ 2026-05-18  2:04 UTC (permalink / raw)
  To: linux-bluetooth, michael.bommarito
In-Reply-To: <20260518002800.1361430-1-michael.bommarito@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 937 bytes --]

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=1096214

---Test result---

Test Summary:
CheckPatch                    PASS      0.76 seconds
GitLint                       PASS      0.34 seconds
SubjectPrefix                 PASS      0.13 seconds
BuildKernel                   PASS      25.56 seconds
CheckAllWarning               PASS      27.84 seconds
CheckSparse                   PASS      26.36 seconds
BuildKernel32                 PASS      24.38 seconds
TestRunnerSetup               PASS      533.67 seconds
TestRunner_l2cap-tester       PASS      378.52 seconds
IncrementalBuild              PASS      25.29 seconds



https://github.com/bluez/bluetooth-next/pull/207

---
Regards,
Linux Bluetooth


^ permalink raw reply

* [PATCH v8] Bluetooth: hci_uart: fix UAFs and race conditions in close and init paths
From: w15303746062 @ 2026-05-18  1:36 UTC (permalink / raw)
  To: luiz.dentz, pmenzel, marcel, linux-bluetooth
  Cc: linux-serial, linux-kernel, greg, stable, Mingyu Wang
In-Reply-To: <CABBYNZ+r3gm37FW5WqE79bRp+x9UZsaCtyvfz_FdixqEucAxGw@mail.gmail.com>

From: Mingyu Wang <25181214217@stu.xidian.edu.cn>

Vulnerabilities leading to Use-After-Free (UAF) and Null Pointer
Dereference (NPD) conditions were observed in the lifecycle management
of hci_uart.

The primary issue arises because the workqueues (init_ready and
write_work) are only flushed/cancelled if the HCI_UART_PROTO_READY
flag is set during TTY close. If a hangup occurs before setup completes,
hci_uart_tty_close() skips the teardown of these workqueues and
proceeds to free the `hu` struct. When the scheduled work executes
later, it blindly dereferences the freed `hu` struct.

Furthermore, several data races and UAFs were identified in the teardown
sequence:
1. Calling hci_uart_flush() from hci_uart_close() without canceling
   write_work causes a race condition where both can concurrently
   double-free hu->tx_skb. This occurs both in TTY hangup and when the
   HCI device is closed via the HCI core.
2. Calling hci_free_dev(hdev) before hu->proto->close(hu) causes a UAF
   when vendor specific protocol close callbacks dereference hu->hdev.
3. In the initialization error paths, failing to take the proto_lock
   write lock before clearing PROTO_READY leads to races with active
   readers. Additionally, hci_uart_tty_receive() accesses hu->hdev
   outside the read lock, leading to UAFs if the initialization error
   path frees hdev concurrently.

Fix these synchronization and lifecycle issues by:
1. Re-ordering hci_uart_tty_close() to unconditionally cancel init_ready
   and write_work first. This prevents the double-free race in
   hci_uart_flush(), while preserving the HCI_UART_PROTO_READY flag so
   underlying hu->proto->flush() callbacks can still execute safely.
2. Relocating hu->proto->close(hu) strictly prior to hci_free_dev(hdev)
   across all close and error paths to prevent vendor-level UAFs.
3. Moving the hdev->stat.byte_rx increment in hci_uart_tty_receive()
   inside the proto_lock read-side critical section to safely synchronize
   with device unregistration.
4. Adding cancel_work_sync(&hu->write_work) to hci_uart_close() to safely
   flush the workqueue before hci_uart_flush() is invoked.
5. Utilizing cancel_work_sync() instead of disable_work_sync() after
   flags are cleared to safely flush workqueues without permanently
   breaking user-space retry capabilities.

Fixes: 3b799254cf6f ("Bluetooth: hci_uart: Cancel init work before unregistering")
Cc: stable@vger.kernel.org
Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>
---
Changes in v8:
- Corrected the teardown sequence in hci_uart_tty_close() by unconditionally canceling write_work BEFORE hci_uart_close(). This completely prevents the tx_skb double-free without prematurely clearing PROTO_READY, ensuring underlying hu->proto->flush(hu) runs correctly.
- Moved hu->hdev->stat.byte_rx increment inside the proto_lock read-side critical section in hci_uart_tty_receive() to prevent read-side UAF against concurrent registration failures.
- Added cancel_work_sync(&hu->write_work) inside hci_uart_close() to eliminate the race condition between write_work and hci_uart_flush() when the interface is brought down via the HCI core.

Changes in v7:
- Reverted disable_work_sync() back to cancel_work_sync() across all error and close paths to preserve user-space retry capabilities.
- Synchronized workqueue teardown safely by atomically clearing PROTO_READY / PROTO_INIT under proto_lock prior to calling cancel_work_sync().
- Fixed a Use-After-Free (UAF) vulnerability in the teardown sequence by relocating hu->proto->close(hu) strictly prior to hci_free_dev(hdev).
- Added cancel_work_sync(&hu->init_ready) at the very beginning of hci_uart_tty_close() to serialize teardown against active asynchronous registration.

Changes in v6:
- Fixed missing `hu->proto_lock` write lock in hci_uart_init_work() error path to prevent race with readers (reported by Sashiko).
- Added disable_work_sync() instead of cancel_work_sync() for `hu->write_work` in hci_uart_init_work() and hci_uart_register_dev() error paths.

Changes in v5:
- Relocated disable_work_sync() to the very top of hci_uart_tty_close(), 
  before hci_uart_close(), to ensure no new work is submitted during device teardown.

Changes in v4:
- Adopted Luiz's suggestion to use disable_work_sync() instead of 
  cancel_work_sync() in close path to prevent new work submissions.

Changes in v3:
- Added 'Cc: stable' tag as requested by the stable bot.

Changes in v2:
- Added KASAN/ODEBUG crash trace.

 drivers/bluetooth/hci_ldisc.c | 33 ++++++++++++++++++++++++++++-----
 1 file changed, 28 insertions(+), 5 deletions(-)

diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 275ea865bc29..cb56194daad1 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -194,7 +194,15 @@ void hci_uart_init_work(struct work_struct *work)
 	err = hci_register_dev(hu->hdev);
 	if (err < 0) {
 		BT_ERR("Can't register HCI device");
+
+		percpu_down_write(&hu->proto_lock);
 		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
+		percpu_up_write(&hu->proto_lock);
+
+		/* Safely cancel work after clearing flags */
+		cancel_work_sync(&hu->write_work);
+
+		/* Close protocol before freeing hdev */
 		hu->proto->close(hu);
 		hdev = hu->hdev;
 		hu->hdev = NULL;
@@ -263,8 +271,12 @@ static int hci_uart_open(struct hci_dev *hdev)
 /* Close device */
 static int hci_uart_close(struct hci_dev *hdev)
 {
+	struct hci_uart *hu = hci_get_drvdata(hdev);
+
 	BT_DBG("hdev %p", hdev);
 
+	cancel_work_sync(&hu->write_work);
+
 	hci_uart_flush(hdev);
 	hdev->flush = NULL;
 	return 0;
@@ -540,6 +552,12 @@ static void hci_uart_tty_close(struct tty_struct *tty)
 	if (!hu)
 		return;
 
+	/* Wait for init_ready to finish to prevent registration races */
+	cancel_work_sync(&hu->init_ready);
+
+	/* Unconditionally cancel write_work BEFORE hci_uart_close() to prevent double-free */
+	cancel_work_sync(&hu->write_work);
+
 	hdev = hu->hdev;
 	if (hdev)
 		hci_uart_close(hdev);
@@ -549,15 +567,15 @@ static void hci_uart_tty_close(struct tty_struct *tty)
 		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
 		percpu_up_write(&hu->proto_lock);
 
-		cancel_work_sync(&hu->init_ready);
-		cancel_work_sync(&hu->write_work);
-
 		if (hdev) {
 			if (test_bit(HCI_UART_REGISTERED, &hu->flags))
 				hci_unregister_dev(hdev);
-			hci_free_dev(hdev);
 		}
+		/* Close protocol before freeing hdev */
 		hu->proto->close(hu);
+
+		if (hdev)
+			hci_free_dev(hdev);
 	}
 	clear_bit(HCI_UART_PROTO_SET, &hu->flags);
 
@@ -625,11 +643,12 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
 	 * tty caller
 	 */
 	hu->proto->recv(hu, data, count);
-	percpu_up_read(&hu->proto_lock);
 
 	if (hu->hdev)
 		hu->hdev->stat.byte_rx += count;
 
+	percpu_up_read(&hu->proto_lock);
+
 	tty_unthrottle(tty);
 }
 
@@ -695,6 +714,10 @@ static int hci_uart_register_dev(struct hci_uart *hu)
 		percpu_down_write(&hu->proto_lock);
 		clear_bit(HCI_UART_PROTO_INIT, &hu->flags);
 		percpu_up_write(&hu->proto_lock);
+		/* Cancel work after clearing flags */
+		cancel_work_sync(&hu->write_work);
+
+		/* Close protocol before freeing hdev */
 		hu->proto->close(hu);
 		hu->hdev = NULL;
 		hci_free_dev(hdev);
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH] Bluetooth: L2CAP: rate-limit ECHO_RSP per signaling PDU
From: Michael Bommarito @ 2026-05-18  1:03 UTC (permalink / raw)
  To: Muhammad Bilal
  Cc: linux-bluetooth, linux-kernel, marcel, luiz.dentz, johan.hedberg
In-Reply-To: <20260518010019.121323-1-meatuni001@gmail.com>

On Sun, May 17, 2026 at 9:00 PM Muhammad Bilal <meatuni001@gmail.com> wrote:
> A response counter covering all outbound responses generated per PDU
> would close both paths. Something like:
>
>         int resp_count = 0;
>
>         /* in the error path: */
>         if (err) {
>                 if (++resp_count <= L2CAP_SIG_ECHO_BURST) {
>                         BT_ERR("Wrong link type (%d)", err);
>                         l2cap_sig_send_rej(conn, cmd->ident);
>                 }
>                 continue;
>         }
>
>         /* existing echo path: */
>         if (cmd->code == L2CAP_ECHO_REQ &&
>             ++resp_count > L2CAP_SIG_ECHO_BURST) {
>                 skb_pull(skb, len);
>                 continue;
>         }
>
> Using pr_warn_ratelimited() instead of BT_ERR() in the loop would
> also reduce log amplification independent of the skb path.

Thanks, good catch on both!  Luiz reminded me about
pr_warn_ratelimited before and I missed that again.

I'll give others an opportunity to weigh in and then send an updated v2.

Thanks,
Mike

^ permalink raw reply

* Re: [PATCH] Bluetooth: L2CAP: rate-limit ECHO_RSP per signaling PDU
From: Muhammad Bilal @ 2026-05-18  1:00 UTC (permalink / raw)
  To: michael.bommarito
  Cc: linux-bluetooth, linux-kernel, marcel, luiz.dentz, johan.hedberg
In-Reply-To: <20260518002800.1361430-1-michael.bommarito@gmail.com>

Hi Michael,

Thanks for the patch. The ECHO_REQ cap addresses one amplification
vector, but the same N:1 amplification appears reachable via the
unknown-command path in the same loop.

When l2cap_bredr_sig_cmd() returns an error for an unrecognised command
code, the loop calls l2cap_sig_send_rej() unconditionally:

        err = l2cap_bredr_sig_cmd(conn, cmd, len, skb->data);
        if (err) {
                BT_ERR("Wrong link type (%d)", err);
                l2cap_sig_send_rej(conn, cmd->ident);
        }

A peer that packs N commands with an unknown code (e.g. 0xFF, len = 0)
into a single signaling PDU would trigger N calls to
l2cap_sig_send_rej(), sending N COMMAND_REJ responses,
bypassing the new L2CAP_SIG_ECHO_BURST limit entirely. This produces
the same TX queue saturation the patch intends to prevent, and also
floods the kernel log with N BT_ERR() writes per PDU.

A response counter covering all outbound responses generated per PDU
would close both paths. Something like:

        int resp_count = 0;

        /* in the error path: */
        if (err) {
                if (++resp_count <= L2CAP_SIG_ECHO_BURST) {
                        BT_ERR("Wrong link type (%d)", err);
                        l2cap_sig_send_rej(conn, cmd->ident);
                }
                continue;
        }

        /* existing echo path: */
        if (cmd->code == L2CAP_ECHO_REQ &&
            ++resp_count > L2CAP_SIG_ECHO_BURST) {
                skb_pull(skb, len);
                continue;
        }

Using pr_warn_ratelimited() instead of BT_ERR() in the loop would
also reduce log amplification independent of the skb path.

Regards,
Muhammad Bilal

^ permalink raw reply

* [PATCH] Bluetooth: L2CAP: rate-limit ECHO_RSP per signaling PDU
From: Michael Bommarito @ 2026-05-18  0:28 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz; +Cc: linux-bluetooth, linux-kernel

l2cap_sig_channel() walks every L2CAP signaling command packed in
one inbound ACL frame and dispatches each to l2cap_bredr_sig_cmd().
The L2CAP_ECHO_REQ handler unconditionally calls

  l2cap_send_cmd(conn, ident, L2CAP_ECHO_RSP, cmd_len, data);

per request, with no per-PDU cap and no per-connection rate limit
anywhere in the path (HCI -> hci_conn -> l2cap_sig_channel ->
l2cap_bredr_sig_cmd).

A peer that packs N L2CAP_ECHO_REQ commands (4 bytes each) into a
single inbound signaling PDU forces the kernel to emit N separate
ACL frames carrying L2CAP_ECHO_RSP.  Measured between two
unmodified upstream kernels over real radio (Intel AX210 attacker,
Intel BE200 target):

  N=1   :    13 B in,    13 B out,  1 ACL frame back,  23 ms wall
  N=4   :    25 B in,    52 B out,  4 ACL frames back, 12 ms wall
  N=16  :    73 B in,   208 B out, 16 ACL frames back, 28 ms wall
  N=48  :   201 B in,   624 B out, 48 ACL frames back, 67 ms wall
  N=168 :   681 B in,  2184 B out, 168 ACL frames back, 220 ms wall

The 10x latency growth at N=168 vs N=1 (220ms vs 23ms) is the
target's signaling work-queue and radio TX queue saturating on the
burst.  A sustained flood (50 inbound PDUs of 168 packed echoes
each) drives ~840 ECHO_RSPs/sec from the target until the kernel's
input ACL queue back-pressures the attacker; during the attack
window the target's BT radio is fully occupied answering echoes
and any other ongoing BT traffic (audio, HID, file transfer) is
starved.  bluetoothd CPU stays at 0% throughout -- the entire path
is kernel-side.

L2CAP signaling channel CID 0x0001 is pre-auth, so no pairing is
required to reach the bug.  Reproducible from any device with a
programmable Bluetooth radio within range of a target running an
unpatched kernel with CONFIG_BT_BREDR=y (effectively every
Linux distribution that ships Bluetooth).

Cap the number of echoes answered per inbound signaling PDU to
L2CAP_SIG_ECHO_BURST (4).  Subsequent ECHO_REQs in the same PDU
are silently dropped.  Legitimate clients (l2ping, BlueZ test
suite, specification-compliant L2CAP) send one ECHO_REQ per PDU
and are unaffected.  Worst-case amplification ratio is now 4:1
per PDU, bounded.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-7
---
 net/bluetooth/l2cap_core.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 77dec104a9c36..1c1179fddb8ba 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -5626,11 +5626,25 @@ static inline void l2cap_sig_send_rej(struct l2cap_conn *conn, u16 ident)
 	l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
 }
 
+/*
+ * Maximum L2CAP_ECHO_REQ commands handled in a single inbound
+ * signaling PDU.  An inbound PDU may legitimately pack multiple
+ * commands, but a peer that packs many L2CAP_ECHO_REQs into one
+ * PDU triggers an N:1 outbound ECHO_RSP storm that saturates the
+ * link's signaling and ACL TX paths.  Cap the number of echoes
+ * answered per inbound PDU to a small burst.  Subsequent ECHO_REQs
+ * in the same PDU are silently dropped; the peer can pace itself
+ * with one ECHO_REQ per PDU (the l2ping shape and the only legit
+ * use that has ever been observed in the wild).
+ */
+#define L2CAP_SIG_ECHO_BURST	4
+
 static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 				     struct sk_buff *skb)
 {
 	struct hci_conn *hcon = conn->hcon;
 	struct l2cap_cmd_hdr *cmd;
+	unsigned int echo_count = 0;
 	int err;
 
 	l2cap_raw_recv(conn, skb);
@@ -5656,6 +5670,13 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 			continue;
 		}
 
+		if (cmd->code == L2CAP_ECHO_REQ &&
+		    ++echo_count > L2CAP_SIG_ECHO_BURST) {
+			/* Drop excess echoes packed into one PDU. */
+			skb_pull(skb, len);
+			continue;
+		}
+
 		err = l2cap_bredr_sig_cmd(conn, cmd, len, skb->data);
 		if (err) {
 			BT_ERR("Wrong link type (%d)", err);
-- 
2.53.0


^ permalink raw reply related

* [PATCH] Bluetooth: HIDP: fix missing length checks in hidp_input_report()
From: Muhammad Bilal @ 2026-05-17 23:48 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: linux-kernel, marcel, luiz.dentz, johan.hedberg, stable,
	Muhammad Bilal

hidp_input_report() reads keyboard and mouse payload data from an skb
without first verifying that skb->len contains enough data.

hidp_recv_intr_frame() pulls the 1-byte HIDP header before dispatching
to hidp_input_report(). If a paired device sends a truncated packet,
the handler reads beyond the valid skb data, resulting in
an out-of-bounds read of skb data.
The OOB bytes may be interpreted as phantom key presses or
spurious mouse movement.

Add a check that skb->len is non-zero before the type switch, and
per-report-type minimum length checks before accessing the payload.

Signed-off-by: Muhammad Bilal <meatuni001@gmail.com>
---
 net/bluetooth/hidp/core.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 976f91eeb..03838a6ff 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -179,12 +179,22 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
 {
 	struct input_dev *dev = session->input;
 	unsigned char *keys = session->keys;
-	unsigned char *udata = skb->data + 1;
-	signed char *sdata = skb->data + 1;
-	int i, size = skb->len - 1;
+	unsigned char *udata;
+	signed char *sdata;
+	int i, size;
+
+	if (!skb->len)
+		return;
+
+	udata = skb->data + 1;
+	sdata = skb->data + 1;
+	size = skb->len - 1;
 
 	switch (skb->data[0]) {
 	case 0x01:	/* Keyboard report */
+		if (size < 8)
+			break;
+
 		for (i = 0; i < 8; i++)
 			input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1);
 
@@ -213,6 +223,9 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
 		break;
 
 	case 0x02:	/* Mouse report */
+		if (size < 3)
+			break;
+
 		input_report_key(dev, BTN_LEFT,   sdata[0] & 0x01);
 		input_report_key(dev, BTN_RIGHT,  sdata[0] & 0x02);
 		input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04);
-- 
2.54.0


^ permalink raw reply related

* [REGRESSION] Bluetooth: btmtk: MT7922 "Failed to send wmt func ctrl (-22)" after 634a4408c0615c ("validate WMT event SKB length before struct access")
From: Brandon Arnold @ 2026-05-17 23:25 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: luiz.von.dentz, tristan, chris.lu, linux-mediatek, gregkh, stable,
	regressions

#regzbot introduced: 634a4408c0615c206885e60ea05f489c426f64b6
#regzbot title: MT7922 BT controller never registers (wmt func ctrl
-22) after btmtk WMT SKB-length validation

Hello there.

I wanted to report the below information about a commit that I
confirmed broke my MediaTek MT7922 adapter. The commit is also built
into the main Arch Linux package, so it affected me during a routine
update (see the BBS link in the report below). This adapter is the one
that came with my Framework Laptop 16 system.

Apologies for Claude's verbosity and language but I can confirm I
attended the bisect and revert of the offending diff. Thank you!

Workaround in use: pinned to the Arch Linux pre-7.0.7 kernel.

Thanks,
Brandon Arnold

Commit 634a4408c0615c ("Bluetooth: btmtk: validate WMT event SKB
length before struct access"), backported to 7.0.x stable and shipped
in v7.0.7, breaks Bluetooth on the MediaTek MT7922: the WMT function
control step fails with -EINVAL and the HCI controller never
registers. WiFi on the same chip (mt7921e) is unaffected.

This is NOT a v6.19->v7.0 mainline regression -- mainline v7.0 is
GOOD. The regression is the above commit specifically; it is absent
from v7.0 and v7.0.6 and present in v7.0.7.

Scope / affected versions
-------------------------
- GOOD: mainline v7.0, linux-stable v7.0.6 (commit absent)
- BAD: linux-stable v7.0.7 (commit present)
- Independently reported on Arch (different machine -- Lenovo
IdeaPad, MT7922 USB [0489:e0d8]): BROKEN on linux 7.0.7.arch2-1,
WORKING on 7.0.6.arch1-1, identical symptom.
https://bbs.archlinux.org/viewtopic.php?id=313561

Hardware / firmware (primary reporter)
--------------------------------------
- Framework Laptop 16 (AMD Ryzen AI 300 Series), board FRANMHCP09 A9
- BIOS: INSYDE/Framework 03.04, 2025-11-06
- MT7922, PCI [14c3:0616] subsys [14c3:e616]; BT side USB, driver
btusb/btmtk; WiFi side mt7921e (works)
- linux-firmware 20260410; BT firmware BT_RAM_CODE_MT7922_1_1,
HW/SW Version 0x008a008a, Build Time 20260224103448
- bluez 5.86

Symptom
-------
The firmware download and version handshake still succeed (identical
HW/SW version line before and after), then:

Bluetooth: hci0: HW/SW Version: 0x008a008a, Build Time: 20260224103448
Bluetooth: hci0: Failed to send wmt func ctrl (-22)

No "Device setup in N usecs" follows; BlueZ reports "No default
controller available". hci0 exists in /sys/class/bluetooth and is not
rfkill-blocked. Reproducible deterministically on cold boot,
`modprobe -r btusb; modprobe btusb`, and full USB unbind/rebind. It
fails even with btusb enable_autosuspend=0, so this is distinct from
the known func-ctrl/autosuspend race.

Analysis
--------
634a4408c0615c reworks btmtk_usb_hci_wmt_sync() to validate length
with skb_pull_data() before casting the WMT event:

- wmt_evt = (struct btmtk_hci_wmt_evt *)data->evt_skb->data;
+ wmt_evt = skb_pull_data(data->evt_skb, sizeof(*wmt_evt));
+ if (!wmt_evt) { ... err = -EINVAL; goto err_free_skb; }
...
case BTMTK_WMT_FUNC_CTRL:
+ if (!skb_pull_data(data->evt_skb,
+ sizeof(wmt_evt_funcc->status))) {
+ err = -EINVAL; goto err_free_skb;
+ }
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;

For the FUNC_CTRL response from the MT7922, one of these
skb_pull_data() calls returns NULL and the function returns -EINVAL
(surfaced as "Failed to send wmt func ctrl (-22)"). In effect the
length the driver now requires
(sizeof(struct btmtk_hci_wmt_evt) + sizeof(status)) exceeds what this
controller actually sends for FUNC_CTRL, so a valid handshake is now
rejected. The pre-patch code cast and read the same bytes without the
strict length gate and worked on this hardware.

Empirical confirmation (mainline, no distro patches)
----------------------------------------------------
Built faithfully from the running Arch config (only LOCALVERSION
added); no out-of-tree changes.

- mainline v7.0 : GOOD (commit absent)
- linux-stable v7.0.7 : BAD (kernel 7.0.7-bisect; WMT func ctrl -22
count = 1; hci0 device setup never completes; bluetoothctl shows 0
controllers)
- v7.0.7 + revert of
70d37a8b9229 (the 7.0.7
backport of 634a4408c0615c): GOOD (kernel
7.0.7-bisect-00001-ge33bfb5d7480; WMT func ctrl -22 count = 0; hci0
device setup OK; bluetoothctl shows 1 controller)

The reverted tree's drivers/bluetooth/btmtk.c is byte-identical to
v7.0.6 (git diff v7.0.6 -- drivers/bluetooth/btmtk.c is empty), so the
v7.0.7-vs-revert pair isolates exactly this one commit.

Reproduction
------------
1. Boot a kernel >= v7.0.7-equivalent on MT7922 hardware.
2. `bluetoothctl list` -> no controller.
3. `journalctl -k -b | grep 'wmt func ctrl'` -> -22.
4. Revert 634a4408c0615c (or boot v7.0.6) -> controller registers.

A straight revert restores operation and is offered as the candidate
fix; alternatively the length checks should be relaxed to match the
MT7922's actual FUNC_CTRL WMT event length. I can test patches, or
provide full bad/good kernel logs, btmon/hci traces, and the exact
short SKB length on request.

^ permalink raw reply

* RE: [BlueZ] tester.config: add missing CRYPTO_AES
From: bluez.test.bot @ 2026-05-17 22:05 UTC (permalink / raw)
  To: linux-bluetooth, pav
In-Reply-To: <478a4d370bc0b20b98223507166dfd580ae8477d.1779051031.git.pav@iki.fi>

[-- Attachment #1: Type: text/plain, Size: 4047 bytes --]

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=1096181

---Test result---

Test Summary:
CheckPatch                    FAIL      0.40 seconds
GitLint                       FAIL      0.30 seconds
BuildEll                      PASS      20.76 seconds
BluezMake                     PASS      658.47 seconds
MakeCheck                     FAIL      18.44 seconds
MakeDistcheck                 FAIL      228.35 seconds
CheckValgrind                 FAIL      293.09 seconds
CheckSmatch                   PASS      350.33 seconds
bluezmakeextell               PASS      182.08 seconds
IncrementalBuild              PASS      645.34 seconds
ScanBuild                     PASS      1018.26 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[BlueZ] tester.config: add missing CRYPTO_AES
WARNING:UNKNOWN_COMMIT_ID: Unknown commit id '4a1507625b0', maybe rebased or not pulled?
#81: 
Kernel commit 4a1507625b0 ("Bluetooth: SMP: Use AES-CMAC library

/github/workspace/src/patch/14577648.patch total: 0 errors, 1 warnings, 21 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14577648.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ] tester.config: add missing CRYPTO_AES

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
26: B2 Line has trailing whitespace: "    "
28: B2 Line has trailing whitespace: "    "
30: B2 Line has trailing whitespace: "    "
31: B1 Line exceeds max length (115>80): "    https://github.com/bluez/bluetooth-next/commit/84ebde6f819c06cc1d804a471d9fb60b7986e190/checks/76408920221/logs"
32: B2 Line has trailing whitespace: "    "
33: B1 Line exceeds max length (115>80): "    https://github.com/bluez/bluetooth-next/commit/82f0e0c7d08eb21d0579471a3b5c004cf95dda08/checks/75862464065/logs"
##############################
Test: MakeCheck - FAIL
Desc: Run Bluez Make Check
Output:

make[3]: *** [Makefile:10239: test-suite.log] Error 1
make[2]: *** [Makefile:10347: check-TESTS] Error 2
make[1]: *** [Makefile:10818: check-am] Error 2
make: *** [Makefile:10820: check] Error 2
##############################
Test: MakeDistcheck - FAIL
Desc: Run Bluez Make Distcheck
Output:

make[4]: *** [Makefile:10239: test-suite.log] Error 1
make[3]: *** [Makefile:10347: check-TESTS] Error 2
make[2]: *** [Makefile:10818: check-am] Error 2
make[1]: *** [Makefile:10820: check] Error 2
make: *** [Makefile:10741: distcheck] Error 1
##############################
Test: CheckValgrind - FAIL
Desc: Run Bluez Make Check with Valgrind
Output:

tools/mgmt-tester.c: In function ‘main’:
tools/mgmt-tester.c:12990:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
12990 | int main(int argc, char *argv[])
      |     ^~~~
make[3]: *** [Makefile:10239: test-suite.log] Error 1
make[2]: *** [Makefile:10347: check-TESTS] Error 2
make[1]: *** [Makefile:10818: check-am] Error 2
make: *** [Makefile:10820: check] Error 2


https://github.com/bluez/bluez/pull/2131

---
Regards,
Linux Bluetooth


^ permalink raw reply

* [bluez/bluez] 0ea80f: tester.config: add missing CRYPTO_AES
From: Pauli Virtanen @ 2026-05-17 21:07 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1096181
  Home:   https://github.com/bluez/bluez
  Commit: 0ea80ff50dd4fb09eb7594250336e70943818d99
      https://github.com/bluez/bluez/commit/0ea80ff50dd4fb09eb7594250336e70943818d99
  Author: Pauli Virtanen <pav@iki.fi>
  Date:   2026-05-17 (Sun, 17 May 2026)

  Changed paths:
    M doc/ci.config
    M doc/test-runner.rst
    M doc/tester.config

  Log Message:
  -----------
  tester.config: add missing CRYPTO_AES

Kernel commit 4a1507625b0 ("Bluetooth: SMP: Use AES-CMAC library
API") removed CRYPTO_AES from the default Bluetooth kernel config.

This causes Bluetooth testbots to fail silently with "Not Run" status:

Basic Framework - Success - init
  Read Index List callback
    Status: 0x00
Bluetooth: hci0: Opcode 0x0c03 failed: -110
Bluetooth: hci0: Opcode 0x0c03 failed: -110
  hciemu: Failed to open vhci
  Failed to setup HCI emulation
Basic Framework - Success - pre setup failed
Basic Framework - Success - done
...
SCO CVSD Listen Send - Success                       Not Run
Total: 30, Passed: 0 (0.0%), Failed: 0, Not Run: 30

Fix by explicitly requiring CRYPTO_AES.



To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* [PATCH BlueZ] tester.config: add missing CRYPTO_AES
From: Pauli Virtanen @ 2026-05-17 20:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Pauli Virtanen

Kernel commit 4a1507625b0 ("Bluetooth: SMP: Use AES-CMAC library
API") removed CRYPTO_AES from the default Bluetooth kernel config.

This causes Bluetooth testbots to fail silently with "Not Run" status:

Basic Framework - Success - init
  Read Index List callback
    Status: 0x00
Bluetooth: hci0: Opcode 0x0c03 failed: -110
Bluetooth: hci0: Opcode 0x0c03 failed: -110
  hciemu: Failed to open vhci
  Failed to setup HCI emulation
Basic Framework - Success - pre setup failed
Basic Framework - Success - done
...
SCO CVSD Listen Send - Success                       Not Run
Total: 30, Passed: 0 (0.0%), Failed: 0, Not Run: 30

Fix by explicitly requiring CRYPTO_AES.
---

Notes:
    See any recent CI test log from
    
    https://github.com/bluez/bluetooth-next/pulls
    
    for example
    
    https://github.com/bluez/bluetooth-next/commit/84ebde6f819c06cc1d804a471d9fb60b7986e190/checks/76408920221/logs
    
    https://github.com/bluez/bluetooth-next/commit/82f0e0c7d08eb21d0579471a3b5c004cf95dda08/checks/75862464065/logs

 doc/ci.config       | 1 +
 doc/test-runner.rst | 1 +
 doc/tester.config   | 1 +
 3 files changed, 3 insertions(+)

diff --git a/doc/ci.config b/doc/ci.config
index bb3cb221f..2da3e14c4 100644
--- a/doc/ci.config
+++ b/doc/ci.config
@@ -112,6 +112,7 @@ CONFIG_BT_QCOMSMD=y
 
 CONFIG_BT_VIRTIO=y
 
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_CMAC=y
 CONFIG_CRYPTO_USER_API=y
 CONFIG_CRYPTO_USER_API_HASH=y
diff --git a/doc/test-runner.rst b/doc/test-runner.rst
index 60f18683c..ff2420ea8 100644
--- a/doc/test-runner.rst
+++ b/doc/test-runner.rst
@@ -84,6 +84,7 @@ Bluetooth
 	CONFIG_BT_HCIUART_H4=y
 	CONFIG_BT_HCIVHCI=y
 
+	CONFIG_CRYPTO_AES=y
 	CONFIG_CRYPTO_CMAC=y
 	CONFIG_CRYPTO_USER_API=y
 	CONFIG_CRYPTO_USER_API_HASH=y
diff --git a/doc/tester.config b/doc/tester.config
index 0cf5e2723..b9c5f34bc 100644
--- a/doc/tester.config
+++ b/doc/tester.config
@@ -43,6 +43,7 @@ CONFIG_BT_MSFTEXT=y
 CONFIG_BT_AOSPEXT=y
 CONFIG_BT_FEATURE_DEBUG=y
 
+CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_CMAC=y
 CONFIG_CRYPTO_USER_API=y
 CONFIG_CRYPTO_USER_API_HASH=y
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH] Bluetooth: SMP: add missing skb len check in smp_cmd_keypress_notify
From: Muhammad Bilal @ 2026-05-17 19:03 UTC (permalink / raw)
  To: pmenzel
  Cc: linux-bluetooth, linux-kernel, marcel, luiz.dentz, johan.hedberg,
	stable
In-Reply-To: <860987c6-5a8a-4409-8943-0cba9d3cc2e1@molgen.mpg.de>

Hi Paul,

There is no safe way to access kp->value in the truncated case, since
the payload is not guaranteed to be present when skb->len < sizeof(*kp).

If diagnostic information is still useful, only metadata can be logged:

	if (skb->len < sizeof(*kp)) {
		bt_dev_dbg(conn->hcon->hdev,
			   "truncated keypress notify, len=%u",
			   skb->len);
		return SMP_INVALID_PARAMS;
	}

This keeps visibility into malformed packets without touching unvalidated
memory. Happy to send a v2 if that looks good to you.

Regards,
Muhammad Bilal

^ permalink raw reply

* Re: [PATCH] Bluetooth: SMP: add missing skb len check in smp_cmd_keypress_notify
From: Paul Menzel @ 2026-05-17 18:41 UTC (permalink / raw)
  To: Muhammad Bilal
  Cc: linux-bluetooth, linux-kernel, marcel, luiz.dentz, johan.hedberg,
	stable
In-Reply-To: <20260517180832.52329-1-meatuni001@gmail.com>

Dear Muhammad,


Am 17.05.26 um 20:08 schrieb Muhammad Bilal:

> Thanks for the review.

Thank you for your instant reply.

> Moving the check after bt_dev_dbg() would not be safe since the debug
> statement reads kp->value, which is exactly what the length check is guarding.
> 
> On a truncated SMP_CMD_KEYPRESS_NOTIFY packet, skb->len may be smaller
> than sizeof(*kp) when entering the handler, so evaluating kp->value in
> the debug log would already access out-of-bounds memory before the
> guard is reached.
> 
> Therefore the length check needs to remain before any access to
> kp->value.

Thank you for the explanation. Is there another to log the faulty value?


Kind regards,

Paul

^ permalink raw reply

* Re: [PATCH] Bluetooth: SMP: add missing skb len check in smp_cmd_keypress_notify
From: Muhammad Bilal @ 2026-05-17 18:08 UTC (permalink / raw)
  To: pmenzel
  Cc: linux-bluetooth, linux-kernel, marcel, luiz.dentz, johan.hedberg,
	stable
In-Reply-To: <3a7eaf6e-6e4e-42b1-a136-3ed2befa90e2@molgen.mpg.de>

Hi Paul,

Thanks for the review.

Moving the check after bt_dev_dbg() would not be safe since the debug
statement reads kp->value, which is exactly what the length check is guarding.

On a truncated SMP_CMD_KEYPRESS_NOTIFY packet, skb->len may be smaller
than sizeof(*kp) when entering the handler, so evaluating kp->value in
the debug log would already access out-of-bounds memory before the
guard is reached.

Therefore the length check needs to remain before any access to
kp->value.

Regards,
Muhammad Bilal

^ permalink raw reply

* [Bug 221539] New: MT7925 Bluetooth fails to initialize since kernel 7.0.8 — regression from 7.0.5
From: bugzilla-daemon @ 2026-05-17 18:07 UTC (permalink / raw)
  To: linux-bluetooth

https://bugzilla.kernel.org/show_bug.cgi?id=221539

            Bug ID: 221539
           Summary: MT7925 Bluetooth fails to initialize since kernel
                    7.0.8 — regression from 7.0.5
           Product: Drivers
           Version: 2.5
          Hardware: All
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P3
         Component: Bluetooth
          Assignee: linux-bluetooth@vger.kernel.org
          Reporter: sphinx-rift-sector@duck.com
        Regression: No

**Hardware:**
- Framework Laptop 13 (AMD AI 300 series)
- WiFi/BT chip: MediaTek MT7925 (RZ717)
- PCIe ID: MEDIATEK Corp. MT7925 (RZ717) Wi-Fi 7 160MHz
- BT interface: USB (hci0)

**Working kernel:** 7.0.5
**Broken kernel:** 7.0.8
**Firmware:** linux-firmware 20260410
(mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin)
**Distro:** NixOS 26.05 (unstable)

**Description:**

Bluetooth on the MediaTek MT7925 stopped working after upgrading the kernel
from 7.0.5 to 7.0.8. WiFi continues to work via the mt7925e PCIe driver. The BT
USB device enumerates and hci0 is created, but the WMT firmware handshake fails
with EINVAL (-22). The adapter cannot be brought up.

This is a regression: the same firmware and hardware work on kernel 7.0.5.

**Symptoms:**

- `hciconfig hci0` shows BD Address: 00:00:00:00:00:00, state DOWN
- `hciconfig hci0 up` returns: "Can't init device hci0: Invalid argument (22)"
- `modprobe -r btusb && modprobe btusb` does not resolve the issue
- Rebooting does not resolve the issue
- rfkill shows hci0 not blocked (soft or hard)

**dmesg (relevant lines):**

```
Bluetooth: Core ver 2.22
Bluetooth: HCI device and connection manager initialized
Bluetooth: HCI socket layer initialized
Bluetooth: L2CAP socket layer initialized
Bluetooth: SCO socket layer initialized
usbcore: registered new interface driver btusb
Bluetooth: hci0: HW/SW Version: 0x00000000, Build Time: 20260106153314
Bluetooth: hci0: Failed to send wmt func ctrl (-22)
Bluetooth: hci0: HCI Enhanced Setup Synchronous Connection command is
advertised, but not supported.
mt7925e 0000:c0:00.0: WM Firmware Version: ____000000, Build Time:
20260106153120
```

Note: `HW/SW Version: 0x00000000` indicates the chip is not responding to
version queries during the WMT protocol handshake.

**Steps to reproduce:**

1. Boot a system with MediaTek MT7925 on kernel 7.0.8
2. Check `hciconfig hci0` — adapter is DOWN with null BD address
3. Attempt `hciconfig hci0 up` — fails with EINVAL
4. Downgrade to kernel 7.0.5 — Bluetooth works

**Related:**
- Bug 219sp688 reports MT7925 BT initialization failures on kernels 6.12–6.15,
but with USB enumeration timeouts (-110). This bug is different: USB
enumeration succeeds, but the WMT func ctrl command fails (-22).

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are the assignee for the bug.

^ permalink raw reply

* Re: [PATCH] Bluetooth: SMP: add missing skb len check in smp_cmd_keypress_notify
From: Paul Menzel @ 2026-05-17 17:47 UTC (permalink / raw)
  To: Muhammad Bilal
  Cc: linux-bluetooth, linux-kernel, marcel, luiz.dentz, johan.hedberg,
	stable
In-Reply-To: <20260517145417.31910-1-meatuni001@gmail.com>

Dear Muhammad,


Thank you for patch.

Am 17.05.26 um 16:54 schrieb Muhammad Bilal:
> smp_cmd_keypress_notify() accesses the received payload as
> struct smp_cmd_keypress_notify without verifying that skb->len
> contains enough data.
> 
> smp_sig_channel() removes the opcode byte before dispatching to
> command handlers, so a SMP_CMD_KEYPRESS_NOTIFY packet without a
> payload leaves skb->len equal to zero on entry to the handler,
> causing a 1-byte out-of-bounds read from the heap.
> 
> Add a length check before accessing the payload and return
> SMP_INVALID_PARAMS when the packet is too short, matching the
> pattern used by other SMP command handlers.
> 
> Fixes: 1408bb6efb04 ("Bluetooth: Add dummy handler for LE SC keypress notification")
> Cc: stable@vger.kernel.org
> Signed-off-by: Muhammad Bilal <meatuni001@gmail.com>
> ---
>   net/bluetooth/smp.c | 3 +++
>   1 file changed, 3 insertions(+)
> 
> diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
> index 98f1da4f5..4c98e2a3a 100644
> --- a/net/bluetooth/smp.c
> +++ b/net/bluetooth/smp.c
> @@ -2932,6 +2932,9 @@ static int smp_cmd_keypress_notify(struct l2cap_conn *conn,
>   {
>   	struct smp_cmd_keypress_notify *kp = (void *) skb->data;
>   
> +	if (skb->len < sizeof(*kp))
> +		return SMP_INVALID_PARAMS;
> +
>   	bt_dev_dbg(conn->hcon->hdev, "value 0x%02x", kp->value);

Add the check after the debug log, so it can be inspected?

>   
>   	return 0;


Kind regards,

Paul

^ permalink raw reply

* Re: [PATCH v3] Bluetooth: btintel: Use skb_pull_data return for bounds check
From: Paul Menzel @ 2026-05-17 16:54 UTC (permalink / raw)
  To: Quan Sun; +Cc: marcel, luiz.dentz, kiran.k, linux-bluetooth
In-Reply-To: <20260517060142.24510-1-2022090917019@std.uestc.edu.cn>

Dear Quan,


Thank you for your patch.

Am 17.05.26 um 08:01 schrieb Quan Sun:
> The length check at the top of btintel_print_fseq_info() verifies
> the skb has at least 66 bytes (sizeof(u32) * 16 + 2), but the
> function actually consumes 74 bytes (2 * 1 + 18 * 4). When firmware
> returns a packet of exactly 66 bytes, the last two skb_pull_data()
> calls return NULL, which is passed directly to get_unaligned_le32(),
> resulting in a NULL pointer dereference.

How did you find this? Manual review, or some tool?

> Remove the insufficient length check and instead validate every
> skb_pull_data() return value, branching to a malformed label that
> logs the error and frees the skb.

Where you able to test the new code on hardware?

> Fixes: a7ba218a44aa ("Bluetooth: btintel: Print Firmware Sequencer information")
> Signed-off-by: Quan Sun <2022090917019@std.uestc.edu.cn>
> ---
>   drivers/bluetooth/btintel.c | 106 +++++++++++++++++++++++++++---------
>   1 file changed, 79 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
> index 5e9cac090bd8..0c42ee53fe2e 100644
> --- a/drivers/bluetooth/btintel.c
> +++ b/drivers/bluetooth/btintel.c
> @@ -3358,14 +3358,9 @@ void btintel_print_fseq_info(struct hci_dev *hdev)
>   		return;
>   	}
>   
> -	if (skb->len < (sizeof(u32) * 16 + 2)) {
> -		bt_dev_dbg(hdev, "Malformed packet of length %u received",
> -			   skb->len);
> -		kfree_skb(skb);
> -		return;
> -	}
> -
>   	p = skb_pull_data(skb, 1);
> +	if (!p)
> +		goto malformed;
>   	if (*p) {
>   		bt_dev_dbg(hdev, "Failed to get fseq status (0x%2.2x)", *p);
>   		kfree_skb(skb);
> @@ -3373,6 +3368,8 @@ void btintel_print_fseq_info(struct hci_dev *hdev)
>   	}
>   
>   	p = skb_pull_data(skb, 1);
> +	if (!p)
> +		goto malformed;
>   	switch (*p) {
>   	case 0:
>   		str = "Success";
> @@ -3396,65 +3393,120 @@ void btintel_print_fseq_info(struct hci_dev *hdev)
>   
>   	bt_dev_info(hdev, "Fseq status: %s (0x%2.2x)", str, *p);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Reason: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Global version: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Installed version: 0x%8.8x", val);
>   
> -	p = skb->data;
> -	skb_pull_data(skb, 4);
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
>   	bt_dev_info(hdev, "Fseq executed: %2.2u.%2.2u.%2.2u.%2.2u", p[0], p[1],
>   		    p[2], p[3]);
>   
> -	p = skb->data;
> -	skb_pull_data(skb, 4);
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
>   	bt_dev_info(hdev, "Fseq BT Top: %2.2u.%2.2u.%2.2u.%2.2u", p[0], p[1],
>   		    p[2], p[3]);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq Top init version: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq Cnvio init version: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq MBX Wifi file version: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq BT version: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq Top reset address: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq MBX timeout: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq MBX ack: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq CNVi id: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq CNVr id: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq Error handle: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq Magic noalive indication: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq OTP version: 0x%8.8x", val);
>   
> -	val = get_unaligned_le32(skb_pull_data(skb, 4));
> +	p = skb_pull_data(skb, 4);
> +	if (!p)
> +		goto malformed;
> +	val = get_unaligned_le32(p);
>   	bt_dev_dbg(hdev, "Fseq MBX otp version: 0x%8.8x", val);
>   
>   	kfree_skb(skb);
> +	return;
> +
> +malformed:
> +	bt_dev_dbg(hdev, "Malformed packet received");

It’d be great to log more information, wouldn’t it?

> +	kfree_skb(skb);
>   }
>   EXPORT_SYMBOL_GPL(btintel_print_fseq_info);
>   


Kind regards,

Paul

^ permalink raw reply

* RE: Bluetooth: SMP: add missing skb len check in smp_cmd_keypress_notify
From: bluez.test.bot @ 2026-05-17 16:13 UTC (permalink / raw)
  To: linux-bluetooth, meatuni001
In-Reply-To: <20260517145417.31910-1-meatuni001@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 936 bytes --]

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=1096089

---Test result---

Test Summary:
CheckPatch                    PASS      0.74 seconds
GitLint                       PASS      0.35 seconds
SubjectPrefix                 PASS      0.13 seconds
BuildKernel                   PASS      28.81 seconds
CheckAllWarning               PASS      29.40 seconds
CheckSparse                   PASS      28.55 seconds
BuildKernel32                 PASS      26.07 seconds
TestRunnerSetup               PASS      576.08 seconds
TestRunner_smp-tester         PASS      18.39 seconds
IncrementalBuild              PASS      25.74 seconds



https://github.com/bluez/bluetooth-next/pull/205

---
Regards,
Linux Bluetooth


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox