339 lines
19 KiB
JSON
339 lines
19 KiB
JSON
{
|
|
"dataType": "CVE_RECORD",
|
|
"dataVersion": "5.2",
|
|
"cveMetadata": {
|
|
"cveId": "CVE-2026-99239",
|
|
"assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
|
|
"state": "PUBLISHED",
|
|
"assignerShortName": "Linux",
|
|
"dateReserved": "2026-09-25T10:25:14.403Z",
|
|
"datePublished": "2026-11-02T16:06:43.262Z",
|
|
"dateUpdated": "2026-11-03T19:13:06.554Z"
|
|
},
|
|
"containers": {
|
|
"cna": {
|
|
"providerMetadata": {
|
|
"orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
|
|
"shortName": "Linux",
|
|
"dateUpdated": "2026-11-03T19:13:06.554Z"
|
|
},
|
|
"descriptions": [
|
|
{
|
|
"lang": "en",
|
|
"value": "In the Linux kernel, the following vulnerability has been resolved:\n\nBluetooth: L2CAP: refuse __l2cap_chan_add if chan already has conn\n\nl2cap_chan may be linked to l2cap_conn at most once. This is assumed in\nseveral places, eg l2cap_chan_del cleanup.\n\nThere is a TOCTOU race where the invariant is violated:\n\n [Task 1] [Task 2]\n l2cap_chan_connect l2cap_sock_bind\n l2cap_chan_lock lock_sock\n l2cap_state_change if (sk->sk_state != BT_OPEN)\n chan->state = BT_CONNECT\n l2cap_sock_state_change_cb chan->state = BT_BOUND\n sk->sk_state = BT_BOUND\n lock_sock <------------------ release_sock\n sk->sk_state = BT_CONNECT\n\nl2cap_sock_connect() does not check sk->sk_state, so since chan->state\nis now BT_BOUND, subsequent connect() ends up with second\n__l2cap_chan_add.\n\nExplicitly document and check the invariant in __l2cap_chan_add with\nWARN_ON_ONCE. The only callsite where it could be hit is\nl2cap_chan_connect, so add pre-check there to avoid relying on\nchan->state. chan->state read/write is not properly guarded currently so\nthere can be other TOCTOUC problems.\n\nAdd l2cap_lock_chan in l2cap_sock_bind() to guard chan->state write."
|
|
}
|
|
],
|
|
"metrics": [
|
|
{
|
|
"cvssV3_1": {
|
|
"version": "3.1",
|
|
"vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
|
|
"baseScore": 7.8,
|
|
"baseSeverity": "HIGH"
|
|
},
|
|
"scenarios": [
|
|
{
|
|
"lang": "en",
|
|
"value": "AV:L - The double add is a local TOCTOU: l2cap_sock_connect()→l2cap_chan_connect()→__l2cap_chan_add() races l2cap_sock_bind(), which overwrites chan->state to BT_BOUND so a later connect() links the same l2cap_chan again. No received L2CAP/HCI PDU carries that state; a radio peer cannot issue those syscalls.\nAC:L - The attacker owns both threads. bind() holds lock_sock while l2cap_state_change() blocks in l2cap_sock_state_change_cb(); bind() then sets chan->state=BT_BOUND. l2cap_sock_connect() never checks sk->sk_state, so a later connect() observes BT_BOUND and calls __l2cap_chan_add() again. The race is attacker-driven and retryable.\nPR:L - l2cap_sock_create() requires capable(CAP_NET_RAW) only for SOCK_RAW; SOCK_SEQPACKET/STREAM used here have no capability gate. l2cap_add_psm() auto-picks a dynamic PSM (BR/EDR >=0x1001) without CAP_NET_BIND_SERVICE. bt_sock_create() is init_net-only, so this is an ordinary unprivileged local user.\nUI:N - The attacker opens their own AF_BLUETOOTH/BTPROTO_L2CAP socket and issues bind()/connect(). hci_connect_acl() creates the hci_conn, l2cap_conn_add() publishes l2cap_data, and __l2cap_chan_add() runs before any remote Connection Complete or pairing prompt.\nS:U - __l2cap_chan_add() corrupts the host kernel l2cap_chan.list linked into l2cap_conn.chan_l, which l2cap_chan_del() and l2cap_conn_del() then walk; the impact stays in the kernel L2CAP/HCI authority and does not cross a VM, IOMMU, or sandbox boundary.\nC:H - A second __l2cap_chan_add() to another l2cap_conn list_add_tail()s the same chan->list without unlinking it from the first conn->chan_l. l2cap_conn_del()'s list_for_each_entry_safe then follows those stale pointers and treats the other conn's list head as an l2cap_chan, an adjacent-slab type confusion that can be sprayed for a kernel read.\nI:H - l2cap_chan_del() list_del()s the twice-inserted chan->list, writing next/prev of the other connection's nodes, and l2cap_conn_del() calls chan->ops->teardown/close on the type-confused object. That unlink write plus ops-pointer invocation is a write/control-flow primitive.\nA:H - Inserting chan->list into the same conn->chan_l twice makes a self-loop, so __l2cap_get_chan_by_scid(), l2cap_conn_start(), and l2cap_conn_del() hang in list_for_each_entry; after list_del() the leftover head still points at the poisoned node and oopses."
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"affected": [
|
|
{
|
|
"product": "Linux",
|
|
"vendor": "Linux",
|
|
"defaultStatus": "unaffected",
|
|
"repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
|
|
"programFiles": [
|
|
"net/bluetooth/l2cap_core.c",
|
|
"net/bluetooth/l2cap_sock.c"
|
|
],
|
|
"versions": [
|
|
{
|
|
"version": "8f90405a4a6f1f1880dc07996b47bf57c712bd8a",
|
|
"lessThan": "85cc289eb08afa975375f838187369e68b429ee0",
|
|
"status": "affected",
|
|
"versionType": "git"
|
|
},
|
|
{
|
|
"version": "32d783cafb46ff3ca58e6f9fd62c9c5f35eaf26b",
|
|
"lessThan": "820579652b24ce277e0097cd65b42bd9b7b8bf07",
|
|
"status": "affected",
|
|
"versionType": "git"
|
|
},
|
|
{
|
|
"version": "8922c7940bae9ce4b1736dddb6362370793835c2",
|
|
"lessThan": "e618d928ec7f88cbeadfa3542adcac40f474e629",
|
|
"status": "affected",
|
|
"versionType": "git"
|
|
},
|
|
{
|
|
"version": "91047a4396a8b1857a6f712a90cf33ec0012b189",
|
|
"lessThan": "fabaff1c59ff2cc89cb7e5bd0186a5e15f0c73b2",
|
|
"status": "affected",
|
|
"versionType": "git"
|
|
},
|
|
{
|
|
"version": "0b0e2bf39cf99e458d991b9df253727e036a7d7d",
|
|
"lessThan": "52fe88e4ef87311eee32b45c65603e7c69e75e7d",
|
|
"status": "affected",
|
|
"versionType": "git"
|
|
},
|
|
{
|
|
"version": "d3b739db5dc6f688a60d56da872fabaf65246032",
|
|
"lessThan": "10c705dd706aa93164ba41f2566f15206d6c178e",
|
|
"status": "affected",
|
|
"versionType": "git"
|
|
},
|
|
{
|
|
"version": "b66774b48dd98f07254951f74ea6f513efe7ff8b",
|
|
"lessThan": "73820561d8cbfd3364a29b8fa77f1707f26029da",
|
|
"status": "affected",
|
|
"versionType": "git"
|
|
},
|
|
{
|
|
"version": "b66774b48dd98f07254951f74ea6f513efe7ff8b",
|
|
"lessThan": "d3afd7803f9bc2a8c4270199497b60158b2fc647",
|
|
"status": "affected",
|
|
"versionType": "git"
|
|
},
|
|
{
|
|
"version": "b66774b48dd98f07254951f74ea6f513efe7ff8b",
|
|
"lessThan": "86b55991d3cd690e73c5ef8d20b75ae4905b357a",
|
|
"status": "affected",
|
|
"versionType": "git"
|
|
},
|
|
{
|
|
"version": "50c38d9f42a529691e4e67ea9cedf4f0bfc8d277",
|
|
"status": "affected",
|
|
"versionType": "git"
|
|
},
|
|
{
|
|
"version": "5.10.265",
|
|
"lessThan": "5.10.273",
|
|
"status": "affected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "5.15.216",
|
|
"lessThan": "5.15.224",
|
|
"status": "affected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "6.1.183",
|
|
"lessThan": "6.1.191",
|
|
"status": "affected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "6.6.145",
|
|
"lessThan": "6.6.161",
|
|
"status": "affected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "6.12.97",
|
|
"lessThan": "6.12.115",
|
|
"status": "affected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "6.18.39",
|
|
"lessThan": "6.18.60",
|
|
"status": "affected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "7.1.4",
|
|
"lessThan": "7.2",
|
|
"status": "affected",
|
|
"versionType": "semver"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"product": "Linux",
|
|
"vendor": "Linux",
|
|
"defaultStatus": "affected",
|
|
"repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
|
|
"programFiles": [
|
|
"net/bluetooth/l2cap_core.c",
|
|
"net/bluetooth/l2cap_sock.c"
|
|
],
|
|
"versions": [
|
|
{
|
|
"version": "7.2",
|
|
"status": "affected"
|
|
},
|
|
{
|
|
"version": "0",
|
|
"lessThan": "7.2",
|
|
"status": "unaffected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "5.10.273",
|
|
"lessThanOrEqual": "5.10.*",
|
|
"status": "unaffected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "5.15.224",
|
|
"lessThanOrEqual": "5.15.*",
|
|
"status": "unaffected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "6.1.191",
|
|
"lessThanOrEqual": "6.1.*",
|
|
"status": "unaffected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "6.6.161",
|
|
"lessThanOrEqual": "6.6.*",
|
|
"status": "unaffected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "6.12.115",
|
|
"lessThanOrEqual": "6.12.*",
|
|
"status": "unaffected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "6.18.60",
|
|
"lessThanOrEqual": "6.18.*",
|
|
"status": "unaffected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "7.2.14",
|
|
"lessThanOrEqual": "7.2.*",
|
|
"status": "unaffected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "7.3.1",
|
|
"lessThanOrEqual": "7.3.*",
|
|
"status": "unaffected",
|
|
"versionType": "semver"
|
|
},
|
|
{
|
|
"version": "7.4-rc1",
|
|
"lessThanOrEqual": "*",
|
|
"status": "unaffected",
|
|
"versionType": "original_commit_for_fix"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"cpeApplicability": [
|
|
{
|
|
"nodes": [
|
|
{
|
|
"operator": "OR",
|
|
"negate": false,
|
|
"cpeMatch": [
|
|
{
|
|
"vulnerable": true,
|
|
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
|
"versionStartIncluding": "5.10.265",
|
|
"versionEndExcluding": "5.10.273"
|
|
},
|
|
{
|
|
"vulnerable": true,
|
|
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
|
"versionStartIncluding": "5.15.216",
|
|
"versionEndExcluding": "5.15.224"
|
|
},
|
|
{
|
|
"vulnerable": true,
|
|
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
|
"versionStartIncluding": "6.1.183",
|
|
"versionEndExcluding": "6.1.191"
|
|
},
|
|
{
|
|
"vulnerable": true,
|
|
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
|
"versionStartIncluding": "6.6.145",
|
|
"versionEndExcluding": "6.6.161"
|
|
},
|
|
{
|
|
"vulnerable": true,
|
|
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
|
"versionStartIncluding": "6.12.97",
|
|
"versionEndExcluding": "6.12.115"
|
|
},
|
|
{
|
|
"vulnerable": true,
|
|
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
|
"versionStartIncluding": "6.18.39",
|
|
"versionEndExcluding": "6.18.60"
|
|
},
|
|
{
|
|
"vulnerable": true,
|
|
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
|
"versionStartIncluding": "7.2",
|
|
"versionEndExcluding": "7.2.14"
|
|
},
|
|
{
|
|
"vulnerable": true,
|
|
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
|
"versionStartIncluding": "7.2",
|
|
"versionEndExcluding": "7.3.1"
|
|
},
|
|
{
|
|
"vulnerable": true,
|
|
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
|
"versionStartIncluding": "7.2",
|
|
"versionEndExcluding": "7.4-rc1"
|
|
},
|
|
{
|
|
"vulnerable": true,
|
|
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
|
"versionStartIncluding": "7.1.4"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"references": [
|
|
{
|
|
"url": "https://git.kernel.org/stable/c/85cc289eb08afa975375f838187369e68b429ee0"
|
|
},
|
|
{
|
|
"url": "https://git.kernel.org/stable/c/820579652b24ce277e0097cd65b42bd9b7b8bf07"
|
|
},
|
|
{
|
|
"url": "https://git.kernel.org/stable/c/e618d928ec7f88cbeadfa3542adcac40f474e629"
|
|
},
|
|
{
|
|
"url": "https://git.kernel.org/stable/c/fabaff1c59ff2cc89cb7e5bd0186a5e15f0c73b2"
|
|
},
|
|
{
|
|
"url": "https://git.kernel.org/stable/c/52fe88e4ef87311eee32b45c65603e7c69e75e7d"
|
|
},
|
|
{
|
|
"url": "https://git.kernel.org/stable/c/10c705dd706aa93164ba41f2566f15206d6c178e"
|
|
},
|
|
{
|
|
"url": "https://git.kernel.org/stable/c/73820561d8cbfd3364a29b8fa77f1707f26029da"
|
|
},
|
|
{
|
|
"url": "https://git.kernel.org/stable/c/d3afd7803f9bc2a8c4270199497b60158b2fc647"
|
|
},
|
|
{
|
|
"url": "https://git.kernel.org/stable/c/86b55991d3cd690e73c5ef8d20b75ae4905b357a"
|
|
}
|
|
],
|
|
"title": "Bluetooth: L2CAP: refuse __l2cap_chan_add if chan already has conn",
|
|
"x_generator": {
|
|
"engine": "bippy-1.2.0"
|
|
}
|
|
}
|
|
}
|
|
} |