Look up another CVE · open CVE-2026-89968 in the interactive tracker
CVE-2026-89968
nvmet-tcp: reject unsolicited H2CData PDUs
Published 2026-09-16 (33 days ago) by the Linux kernel CNA. Subsystem drivers/nvme. Debian urgency: not yet assigned.
What to do, per Debian release
Debian's own status for CVE-2026-89968 in every release this site tracks, and what each one means in practice. Every status below is the one the Debian Security Team publishes for this CVE. source
| Release | Status | Version | What this means |
|---|---|---|---|
| Debian 12bookworm | fixedDLA-4841-1 · 2026-10-17 · text | 6.1.190-1 | Update the kernel and reboot. DLA-4841-1 shipped the fix on 2026-10-17, in 6.1.190-1. A running kernel keeps the old code until the machine restarts. |
| Debian 13trixie | fixedDSA-6528-1 · 2026-09-29 · text | 6.12.111-1 | Update the kernel and reboot. DSA-6528-1 shipped the fix on 2026-09-29, in 6.12.111-1. A running kernel keeps the old code until the machine restarts. |
| Debian 14forky | fixed | 7.2.6-1 | Update the kernel and reboot. Fixed in 7.2.6-1. A running kernel keeps the old code until the machine restarts. |
| Debian unstablesid | fixed | 7.2.6-1 | Update the kernel and reboot. Fixed in 7.2.6-1. A running kernel keeps the old code until the machine restarts. |
| Debian 12bookworm · linux-6.12 | fixedDLA-4817-1 · 2026-10-04 · text | 6.12.111-1~deb12u1 | Update the kernel and reboot. DLA-4817-1 shipped the fix on 2026-10-04, in 6.12.111-1~deb12u1. A running kernel keeps the old code until the machine restarts. |
The vulnerability
What the bug is
nvmet_tcp_handle_h2c_data_pdu() accepts an H2CData PDU after only checking that its TTAG is a valid in-range command index and that the command's data buffers are mapped. It never checks that the target has actually solicited that data by sending an R2T for the command. A remote host can abuse this. It submits a write command that takes the R2T path and, before the target transmits the R2T, sends an H2CData PDU for that command's tag. The data completes the command early, and when the command then fails synchronously (e.g. a length mismatch caught by nvmet_check_transfer_len()), it is completed a second time. Each completion calls nvmet_tcp_queue_response(), so the same command is added to queue->resp_list twice while it is still linked; the second llist_add() makes the node point to itself (lentry->next == lentry). nvmet_tcp_process_resp_list() then walks that self-referential node and adds the command to resp_send_list twice. With CONFIG_DEBUG_LIST this trips the "list_add double add" check (kernel BUG); without it the loop never terminates and the nvmet_tcp workqueue wedges (soft-lockup). It is remotely triggerable and needs no authentication on an allow_any_host subsystem. Track whether an R2T has been transmitted for a command and reject an H2CData PDU that arrives before it. The flag is cleared on command reuse (nvmet_tcp_get_cmd() zeroes cmd->flags) and stays set across the multiple H2CData PDUs of a single solicited transfer.
Where it lives
The fix touches these files. If the subsystem is one you do not use, the practical exposure is lower, though the package is still the vulnerable one.
drivers/nvme/target/tcp.c
- What this is
- NVM EXPRESS TARGET DRIVERMAINTAINERS section matched on drivers/nvme/target/ · linux-nvme@lists.infradead.org · Supported
- Kernel module
- nvmet_tcp
Check it on the machine
grep -w CONFIG_NVME_TARGET_TCP /boot/config-$(uname -r)Reads the booted kernel's own configuration, on the machine and nowhere else. =y is built in, =m is a module, and an is not set line means the code is not there.
lsmod | grep -w nvmet_tcpPrints a line if that module is loaded right now, and nothing if it is not. One that is not loaded can still be loaded later by anything that needs it.
Show whether Debian builds this, per release
Debian builds this as a loadable module. Every release below compiles it as a module on every flavour, so whether the code is in the running kernel depends on whether that module is loaded.
- bookworm, trixie, forky, sid, bookworm · linux-6.12m
- m
- a loadable module on every flavour - check lsmod, can be blacklisted
- Build switch
- CONFIG_NVME_TARGET_TCP
From the configuration Debian publishes for every kernel flavour it builds. It covers only the architectures Debian ships a linux-config package for, and nothing about a kernel you built yourself. Debian's own status above stays authoritative about the source package.MAINTAINERS kbuild Makefiles Debian linux-config packages
Signals
- Published
- 2026-09-16 (33 days ago)source
- CVSS
- 7.5 high
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:Hsource recompute it - Attack vector
- network (AV:N)source
- EPSS
- 0.82%, higher than 56.4% of all CVEssource
- CISA KEV
- not listedthe KEV catalogue
- Debian urgency
- not yet assignedsource
- Subsystem
- drivers/nvme
Upstream fixes
The versions the CNA records as introducing and fixing this, and the commit for each. source
| Introduced | Fixed in | Commit |
|---|---|---|
| 5.0 | 5.10.270 | 02341ee424fb |
| 5.0 | 5.15.221 | cade124c06f8 |
| 5.0 | 6.1.188 | 14beef7d4f12 |
| 5.0 | 6.6.157 | 9fb527103e53 |
| 5.0 | 6.12.110 | 2b71f9193e3d |
| 5.0 | 6.18.51 | cf1484d9a75d |
| 5.0 | 7.2.5 | 1cbed7538946 |
| 5.0 | 7.3 | db62b35cbca0 |
Debian advisories
| Advisory | Date | Shipped to | Debian |
|---|---|---|---|
| DLA-4841-1 | 2026-10-17 | bookworm 6.1.190-1 | tracker |
| DLA-4817-1 | 2026-10-04 | bookworm 6.12.111-1~deb12u1 | tracker |
| DSA-6528-1 | 2026-09-29 | trixie 6.12.111-1 | tracker |
Why the CNA scored it this way
Quoted from the kernel CNA's own scoring file, word for word. A highlighted metric carries the most severe value CVSS v3.1 defines for it, which is what pushes the score up. source
- AV:NAttack vector, network
- nvmet-tcp is an in-kernel NVMe-over-TCP target; after kernel_accept() the receive worker parses CapsuleCmd and H2CData PDUs from a listening TCP portal (typically 4420), so a remote initiator on a cloud or storage node can reach the bug over the network.
- AC:LAttack complexity, low
- The attacker sends a write/Connect CapsuleCmd that queues an R2T, then an H2CData PDU for that tag in the same TCP burst; nvmet_tcp_io_work() receives before it sends, so both PDUs are handled before R2T is transmitted, with no condition outside attacker control.
- PR:NPrivileges required, none
- On the unconnected queue after ICReq, Connect with a non-inline SGL takes the R2T path, H2CData is bound to queue->connect while nr_cmds is 0, and nvmet_check_transfer_len() runs before host-NQN allow-list or DH-HMAC-CHAP, so no credentials or Linux privileges are required.
- UI:NUser interaction, none
- Exploitation uses only attacker-sent NVMe/TCP PDUs against an already listening target; no victim action such as mounting a device or opening a file is required.
- S:UScope, unchanged
- The corrupted resp_list, workqueue hang, and optional list_add BUG occur inside the target host kernel's NVMe/TCP worker and do not cross a VM, IOMMU, or other security authority.
- C:NConfidentiality impact, none
- Double llist_add makes the command node self-referential and then livelocks or hits DEBUG_LIST checks; there is no use-after-free, out-of-bounds read, or other primitive that discloses kernel memory.
- I:NIntegrity impact, none
- The second llist_add only points the node at itself rather than creating an attacker-controlled write; there is no use-after-free, OOB write, or type confusion that would allow arbitrary kernel modification or code execution.
- A:HAvailability impact, high
- nvmet_tcp_process_resp_list() walks the self-loop forever, wedging WQ_MEM_RECLAIM nvmet_tcp_wq in a soft lockup; CONFIG_DEBUG_LIST/BUG_ON_DATA_CORRUPTION can BUG on list_add double add, and cancel_work_sync() during teardown deadlocks as well.