Bluetooth: MSFT: validate evt_prefix_len against the response length
In the Linux kernel, the following vulnerability has been resolved: Bluetooth: MSFT: validate evt_prefix_len against the response length read_supported_features() only checks that the response covers the fixed part of struct msft_rp_read_supported_features, which is 11 bytes: if (skb->len < sizeof(*rp)) { bt_dev_err(hdev, "MSFT supported features length mismatch"); goto failed; } evt_prefix[] is a flexible array member and rp->evt_prefix_len is an unvalidated u8 taken straight out of that response, so msft->evt_prefix = kmemdup(rp->evt_prefix, rp->evt_prefix_len, GFP_KERNEL); copies up to 255 bytes from a reply that may have carried none of them. What is copied is data the controller never sent, and it is then used to match incoming vendor events in msft_vendor_evt(). This is not an out-of-bounds access. An skb data allocation always has at least SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) bytes past the payload, which is more than the 255 byte maximum, so the read stays inside the allocation and KASAN does not report it. It is still a read of bytes the host was never given, with the length fully controlled by the controller. Reject a response that is too short for the prefix it declares. Verified with an emulated controller over /dev/vhci on a KASAN kernel, with vhci made to advertise an MSFT opcode the way btintel, btqca, btmtk and btrtl do unconditionally. A reply of exactly 11 bytes declaring evt_prefix_len = 255 reaches kmemdup and copies 255 bytes ("skb->len=11 evt_p
- Products
- Kernel
- Affected versions
- Not specified
- Fixed versions
- 5.10.270, 5.15.221, 6.1.188, 6.12.110, 6.18.52, 6.6.157, 7.2.6
- CVEs
- CVE-2026-90251
- Confirmed fixed CVEs
- Not specified
- Updated in this feed
- 4 Nov 2026, 03:59 UTC · Revision 1
Source evidence
Bluetooth: MSFT: validate evt_prefix_len against the response length
core-osv · Original sourcePublished 17 Sept 2026, 16:07 UTC
In the Linux kernel, the following vulnerability has been resolved: Bluetooth: MSFT: validate evt_prefix_len against the response length read_supported_features() only checks that the response covers the fixed part of struct msft_rp_read_supported_features, which is 11 bytes: if (skb->len < sizeof(*rp)) { bt_dev_err(hdev, "MSFT supported features length mismatch"); goto failed; } evt_prefix[] is a flexible array member and rp->evt_prefix_len is an unvalidated u8 taken straight out of that response, so msft->evt_prefix = kmemdup(rp->evt_prefix, rp->evt_prefix_len, GFP_KERNEL); copies up to 255 bytes from a reply that may have carried none of them. What is copied is data the controller never sent, and it is then used to match incoming vendor events in msft_vendor_evt(). This is not an out-of-bounds access. An skb data allocation always has at least SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) bytes past the payload, which is more than the 255 byte maximum, so the read stays inside the allocation and KASAN does not report it. It is still a read of bytes the host was never given, with the length fully controlled by the controller. Reject a response that is too short for the prefix it declares. Verified with an emulated controller over /dev/vhci on a KASAN kernel, with vhci made to advertise an MSFT opcode the way btintel, btqca, btmtk and btrtl do unconditionally. A reply of exactly 11 bytes declaring evt_prefix_len = 255 reaches kmemdup and copies 255 bytes ("skb->len=11 evt_p
osv:CVE-2026-90251
Kernel
Fixed versions: 5.10.270, 5.15.221, 6.1.188, 6.6.157, 6.12.110, 6.18.52, 7.2.6
Complete source record
{
"id": "bd709901b8cfcdc8919cb8829cff852ae53ff34ddd2e5135dd488fc43d86f088",
"url": "https://osv.dev/vulnerability/CVE-2026-90251",
"method": "structured",
"payload": {
"kind": "advisory",
"title": "Bluetooth: MSFT: validate evt_prefix_len against the response length",
"summary": "In the Linux kernel, the following vulnerability has been resolved: Bluetooth: MSFT: validate evt_prefix_len against the response length read_supported_features() only checks that the response covers the fixed part of struct msft_rp_read_supported_features, which is 11 bytes: if (skb->len < sizeof(*rp)) { bt_dev_err(hdev, \"MSFT supported features length mismatch\"); goto failed; } evt_prefix[] is a flexible array member and rp->evt_prefix_len is an unvalidated u8 taken straight out of that response, so msft->evt_prefix = kmemdup(rp->evt_prefix, rp->evt_prefix_len, GFP_KERNEL); copies up to 255 bytes from a reply that may have carried none of them. What is copied is data the controller never sent, and it is then used to match incoming vendor events in msft_vendor_evt(). This is not an out-of-bounds access. An skb data allocation always has at least SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) bytes past the payload, which is more than the 255 byte maximum, so the read stays inside the allocation and KASAN does not report it. It is still a read of bytes the host was never given, with the length fully controlled by the controller. Reject a response that is too short for the prefix it declares. Verified with an emulated controller over /dev/vhci on a KASAN kernel, with vhci made to advertise an MSFT opcode the way btintel, btqca, btmtk and btrtl do unconditionally. A reply of exactly 11 bytes declaring evt_prefix_len = 255 reaches kmemdup and copies 255 bytes (\"skb->len=11 evt_p",
"evidence": "osv:CVE-2026-90251",
"products": [
{
"name": {
"value": "Kernel",
"evidence": "/affected/1/package/name"
},
"prerequisites": [],
"fixed_versions": [
{
"value": "5.10.270",
"evidence": "/affected/1/ranges"
},
{
"value": "5.15.221",
"evidence": "/affected/1/ranges"
},
{
"value": "6.1.188",
"evidence": "/affected/1/ranges"
},
{
"value": "6.6.157",
"evidence": "/affected/1/ranges"
},
{
"value": "6.12.110",
"evidence": "/affected/1/ranges"
},
{
"value": "6.18.52",
"evidence": "/affected/1/ranges"
},
{
"value": "7.2.6",
"evidence": "/affected/1/ranges"
}
],
"affected_versions": []
}
],
"severity": "unknown",
"structured": {
"id": "CVE-2026-90251",
"aliases": [
"CVE-2026-90251"
],
"affected": [
{
"ranges": [
{
"repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
"type": "GIT",
"events": [
{
"introduced": "145373cb1b1fcdba2059e945d0aa2613af2e84d1"
},
{
"fixed": "dce783a10e70f013410f5b583a29fc3286899629"
},
{
"fixed": "21f539c59ed330b671d75fd119c5f659ff92fbd1"
},
{
"fixed": "52b1b3b4d403cbda1b70ce2385e1a71f166a87ba"
},
{
"fixed": "e804d54a5a99d99250490e68093eff7190472e6f"
},
{
"fixed": "620c2631cff490d14d0b9d56f185cc745806d6d7"
},
{
"fixed": "7c2658023d839b651368a5b8b781bf9a817647cb"
},
{
"fixed": "63562cfaea8a650fdb31ee8de21c32e3600be642"
},
{
"fixed": "0079e1a944634ab2dc1c7cdec1144486d096407e"
}
]
}
],
"database_specific": {
"source": "https://storage.googleapis.com/cve-osv-conversion/osv-output/CVE-2026-90251.json"
}
},
{
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "5.8.0"
},
{
"fixed": "5.10.270"
}
]
},
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "5.11.0"
},
{
"fixed": "5.15.221"
}
]
},
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "5.16.0"
},
{
"fixed": "6.1.188"
}
]
},
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "6.2.0"
},
{
"fixed": "6.6.157"
}
]
},
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "6.7.0"
},
{
"fixed": "6.12.110"
}
]
},
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "6.13.0"
},
{
"fixed": "6.18.52"
}
]
},
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "6.19.0"
},
{
"fixed": "7.2.6"
}
]
}
],
"package": {
"name": "Kernel",
"ecosystem": "Linux"
},
"database_specific": {
"source": "https://storage.googleapis.com/cve-osv-conversion/osv-output/CVE-2026-90251.json"
}
}
],
"modified": "2026-10-28T02:30:33.019454103Z",
"provider": "osv",
"references": [
"https://git.kernel.org/stable/c/0079e1a944634ab2dc1c7cdec1144486d096407e",
"https://git.kernel.org/stable/c/21f539c59ed330b671d75fd119c5f659ff92fbd1",
"https://git.kernel.org/stable/c/52b1b3b4d403cbda1b70ce2385e1a71f166a87ba",
"https://git.kernel.org/stable/c/620c2631cff490d14d0b9d56f185cc745806d6d7",
"https://git.kernel.org/stable/c/63562cfaea8a650fdb31ee8de21c32e3600be642",
"https://git.kernel.org/stable/c/7c2658023d839b651368a5b8b781bf9a817647cb",
"https://git.kernel.org/stable/c/dce783a10e70f013410f5b583a29fc3286899629",
"https://git.kernel.org/stable/c/e804d54a5a99d99250490e68093eff7190472e6f",
"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/90xxx/CVE-2026-90251.json",
"https://nvd.nist.gov/vuln/detail/CVE-2026-90251",
"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"
],
"provider_metadata": {
"cna_assigner": "Linux",
"osv_generated_from": "https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/90xxx/CVE-2026-90251.json"
}
},
"related_cves": [
{
"value": "CVE-2026-90251",
"evidence": "/id"
}
],
"security_relevant": true,
"severity_evidence": null
},
"source_id": "core-osv",
"document_id": 500193,
"published_at": "2026-09-17T16:07:52.066+00:00"
}