VYPR
Unrated severityNVD Advisory· Published May 28, 2026

CVE-2026-46140

CVE-2026-46140

Description

In the Linux kernel, the following vulnerability has been resolved:

Bluetooth: btmtk: validate WMT event SKB length before struct access

btmtk_usb_hci_wmt_sync() casts the WMT event response SKB data to struct btmtk_hci_wmt_evt (7 bytes) and struct btmtk_hci_wmt_evt_funcc (9 bytes) without first checking that the SKB contains enough data. A short firmware response causes out-of-bounds reads from SKB tailroom.

Use skb_pull_data() to validate and advance past the base WMT event header. For the FUNC_CTRL case, pull the additional status field bytes before accessing them.

Affected products

1
  • Linux/Kernelllm-fuzzy
    Range: <= 5.10-rc1 (fixed in stable commits)

Patches

8
c411cf1bfde9

Bluetooth: btmtk: validate WMT event SKB length before struct access

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitTristan MadaniApr 21, 2026Fixed in 6.12.88via kernel-cna
1 file changed · +13 3
  • drivers/bluetooth/btmtk.c+13 3 modified
    diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
    index 07979d47eb76e0..ca3e730feddaa9 100644
    --- a/drivers/bluetooth/btmtk.c
    +++ b/drivers/bluetooth/btmtk.c
    @@ -654,8 +654,13 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     	if (data->evt_skb == NULL)
     		goto err_free_wc;
     
    -	/* Parse and handle the return 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) {
    +		bt_dev_err(hdev, "WMT event too short (%u bytes)",
    +			   data->evt_skb->len);
    +		err = -EINVAL;
    +		goto err_free_skb;
    +	}
     	if (wmt_evt->whdr.op != hdr->op) {
     		bt_dev_err(hdev, "Wrong op received %d expected %d",
     			   wmt_evt->whdr.op, hdr->op);
    @@ -671,6 +676,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     			status = BTMTK_WMT_PATCH_DONE;
     		break;
     	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;
     		if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
     			status = BTMTK_WMT_ON_DONE;
    -- 
    cgit 1.3-korg
    
    
    
624fb79dadc1

Bluetooth: btmtk: validate WMT event SKB length before struct access

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitTristan MadaniApr 21, 2026Fixed in 6.18.30via kernel-cna
1 file changed · +13 3
  • drivers/bluetooth/btmtk.c+13 3 modified
    diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
    index a8c520dc09e19c..7b4aa8e7a495b8 100644
    --- a/drivers/bluetooth/btmtk.c
    +++ b/drivers/bluetooth/btmtk.c
    @@ -654,8 +654,13 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     	if (data->evt_skb == NULL)
     		goto err_free_wc;
     
    -	/* Parse and handle the return 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) {
    +		bt_dev_err(hdev, "WMT event too short (%u bytes)",
    +			   data->evt_skb->len);
    +		err = -EINVAL;
    +		goto err_free_skb;
    +	}
     	if (wmt_evt->whdr.op != hdr->op) {
     		bt_dev_err(hdev, "Wrong op received %d expected %d",
     			   wmt_evt->whdr.op, hdr->op);
    @@ -671,6 +676,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     			status = BTMTK_WMT_PATCH_DONE;
     		break;
     	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;
     		if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
     			status = BTMTK_WMT_ON_DONE;
    -- 
    cgit 1.3-korg
    
    
    
70d37a8b9229

Bluetooth: btmtk: validate WMT event SKB length before struct access

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitTristan MadaniApr 21, 2026Fixed in 7.0.7via kernel-cna
1 file changed · +13 3
  • drivers/bluetooth/btmtk.c+13 3 modified
    diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
    index fa7533578f85c9..31ff133b6159ff 100644
    --- a/drivers/bluetooth/btmtk.c
    +++ b/drivers/bluetooth/btmtk.c
    @@ -654,8 +654,13 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     	if (data->evt_skb == NULL)
     		goto err_free_wc;
     
    -	/* Parse and handle the return 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) {
    +		bt_dev_err(hdev, "WMT event too short (%u bytes)",
    +			   data->evt_skb->len);
    +		err = -EINVAL;
    +		goto err_free_skb;
    +	}
     	if (wmt_evt->whdr.op != hdr->op) {
     		bt_dev_err(hdev, "Wrong op received %d expected %d",
     			   wmt_evt->whdr.op, hdr->op);
    @@ -671,6 +676,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     			status = BTMTK_WMT_PATCH_DONE;
     		break;
     	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;
     		if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
     			status = BTMTK_WMT_ON_DONE;
    -- 
    cgit 1.3-korg
    
    
    
634a4408c061

Bluetooth: btmtk: validate WMT event SKB length before struct access

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitTristan MadaniApr 21, 2026Fixed in 7.1-rc3via kernel-cna
1 file changed · +13 3
  • drivers/bluetooth/btmtk.c+13 3 modified
    diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
    index 6fb6ca2748086e..f70c1b0f899035 100644
    --- a/drivers/bluetooth/btmtk.c
    +++ b/drivers/bluetooth/btmtk.c
    @@ -695,8 +695,13 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     	if (data->evt_skb == NULL)
     		goto err_free_wc;
     
    -	/* Parse and handle the return 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) {
    +		bt_dev_err(hdev, "WMT event too short (%u bytes)",
    +			   data->evt_skb->len);
    +		err = -EINVAL;
    +		goto err_free_skb;
    +	}
     	if (wmt_evt->whdr.op != hdr->op) {
     		bt_dev_err(hdev, "Wrong op received %d expected %d",
     			   wmt_evt->whdr.op, hdr->op);
    @@ -712,6 +717,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     			status = BTMTK_WMT_PATCH_DONE;
     		break;
     	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;
     		if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
     			status = BTMTK_WMT_ON_DONE;
    -- 
    cgit 1.3-korg
    
    
    
624fb79dadc1

Bluetooth: btmtk: validate WMT event SKB length before struct access

1 file changed · +13 3
  • drivers/bluetooth/btmtk.c+13 3 modified
    diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
    index a8c520dc09e19c..7b4aa8e7a495b8 100644
    --- a/drivers/bluetooth/btmtk.c
    +++ b/drivers/bluetooth/btmtk.c
    @@ -654,8 +654,13 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     	if (data->evt_skb == NULL)
     		goto err_free_wc;
     
    -	/* Parse and handle the return 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) {
    +		bt_dev_err(hdev, "WMT event too short (%u bytes)",
    +			   data->evt_skb->len);
    +		err = -EINVAL;
    +		goto err_free_skb;
    +	}
     	if (wmt_evt->whdr.op != hdr->op) {
     		bt_dev_err(hdev, "Wrong op received %d expected %d",
     			   wmt_evt->whdr.op, hdr->op);
    @@ -671,6 +676,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     			status = BTMTK_WMT_PATCH_DONE;
     		break;
     	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;
     		if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
     			status = BTMTK_WMT_ON_DONE;
    -- 
    cgit 1.3-korg
    
    
    
70d37a8b9229

Bluetooth: btmtk: validate WMT event SKB length before struct access

1 file changed · +13 3
  • drivers/bluetooth/btmtk.c+13 3 modified
    diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
    index fa7533578f85c9..31ff133b6159ff 100644
    --- a/drivers/bluetooth/btmtk.c
    +++ b/drivers/bluetooth/btmtk.c
    @@ -654,8 +654,13 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     	if (data->evt_skb == NULL)
     		goto err_free_wc;
     
    -	/* Parse and handle the return 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) {
    +		bt_dev_err(hdev, "WMT event too short (%u bytes)",
    +			   data->evt_skb->len);
    +		err = -EINVAL;
    +		goto err_free_skb;
    +	}
     	if (wmt_evt->whdr.op != hdr->op) {
     		bt_dev_err(hdev, "Wrong op received %d expected %d",
     			   wmt_evt->whdr.op, hdr->op);
    @@ -671,6 +676,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     			status = BTMTK_WMT_PATCH_DONE;
     		break;
     	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;
     		if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
     			status = BTMTK_WMT_ON_DONE;
    -- 
    cgit 1.3-korg
    
    
    
c411cf1bfde9

Bluetooth: btmtk: validate WMT event SKB length before struct access

1 file changed · +13 3
  • drivers/bluetooth/btmtk.c+13 3 modified
    diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
    index 07979d47eb76e0..ca3e730feddaa9 100644
    --- a/drivers/bluetooth/btmtk.c
    +++ b/drivers/bluetooth/btmtk.c
    @@ -654,8 +654,13 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     	if (data->evt_skb == NULL)
     		goto err_free_wc;
     
    -	/* Parse and handle the return 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) {
    +		bt_dev_err(hdev, "WMT event too short (%u bytes)",
    +			   data->evt_skb->len);
    +		err = -EINVAL;
    +		goto err_free_skb;
    +	}
     	if (wmt_evt->whdr.op != hdr->op) {
     		bt_dev_err(hdev, "Wrong op received %d expected %d",
     			   wmt_evt->whdr.op, hdr->op);
    @@ -671,6 +676,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     			status = BTMTK_WMT_PATCH_DONE;
     		break;
     	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;
     		if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
     			status = BTMTK_WMT_ON_DONE;
    -- 
    cgit 1.3-korg
    
    
    
634a4408c061

Bluetooth: btmtk: validate WMT event SKB length before struct access

1 file changed · +13 3
  • drivers/bluetooth/btmtk.c+13 3 modified
    diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
    index 6fb6ca2748086e..f70c1b0f899035 100644
    --- a/drivers/bluetooth/btmtk.c
    +++ b/drivers/bluetooth/btmtk.c
    @@ -695,8 +695,13 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     	if (data->evt_skb == NULL)
     		goto err_free_wc;
     
    -	/* Parse and handle the return 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) {
    +		bt_dev_err(hdev, "WMT event too short (%u bytes)",
    +			   data->evt_skb->len);
    +		err = -EINVAL;
    +		goto err_free_skb;
    +	}
     	if (wmt_evt->whdr.op != hdr->op) {
     		bt_dev_err(hdev, "Wrong op received %d expected %d",
     			   wmt_evt->whdr.op, hdr->op);
    @@ -712,6 +717,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
     			status = BTMTK_WMT_PATCH_DONE;
     		break;
     	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;
     		if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
     			status = BTMTK_WMT_ON_DONE;
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Missing length validation before casting SKB data to struct btmtk_hci_wmt_evt (7 bytes) and struct btmtk_hci_wmt_evt_funcc (9 bytes) allows out-of-bounds reads from SKB tailroom when a short firmware response is received."

Attack vector

An attacker who can control or influence the firmware response sent over USB to a MediaTek Bluetooth controller can craft a WMT event response shorter than the expected struct sizes (7 bytes for btmtk_hci_wmt_evt, 9 bytes for btmtk_hci_wmt_evt_funcc). The function btmtk_usb_hci_wmt_sync() in drivers/bluetooth/btmtk.c casts the SKB data pointer to these structs without first verifying the SKB contains enough data, causing out-of-bounds reads from SKB tailroom. The attacker does not need authentication; the vulnerability is reachable via a malicious or compromised Bluetooth firmware endpoint.

Affected code

The vulnerable function is `btmtk_usb_hci_wmt_sync()` in `drivers/bluetooth/btmtk.c`. The code casts `data->evt_skb->data` to `struct btmtk_hci_wmt_evt` (7 bytes) and, in the `BTMTK_WMT_FUNC_CTRL` case, to `struct btmtk_hci_wmt_evt_funcc` (9 bytes) without length validation [patch_id=2898349].

What the fix does

The patch replaces the direct cast `(struct btmtk_hci_wmt_evt *)data->evt_skb->data` with `skb_pull_data(data->evt_skb, sizeof(*wmt_evt))`, which returns NULL if the SKB does not contain at least 7 bytes. A new error check logs the short length and jumps to err_free_skb. For the FUNC_CTRL case, an additional `skb_pull_data()` validates that the 2-byte status field is present before the cast to `struct btmtk_hci_wmt_evt_funcc`. This ensures all struct accesses are backed by valid SKB data, closing the out-of-bounds read.

Preconditions

  • networkAttacker must be able to deliver a crafted WMT event response to the host over USB from the Bluetooth firmware endpoint.
  • inputThe firmware response SKB must be shorter than the expected struct sizes (less than 7 bytes for the base event, or less than 9 bytes for the FUNC_CTRL case).

Generated on May 28, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.