data built 2026-10-19T13:16:53Z

Look up another CVE · open CVE-2026-89968 in the interactive tracker

CVE-2026-89968

nvmet-tcp: reject unsolicited H2CData PDUs

7.5 EPSS 0.8% AV:N

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

ReleaseStatus VersionWhat this means
Debian 12bookwormfixedDLA-4841-1 · 2026-10-17 · text6.1.190-1Update 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 13trixiefixedDSA-6528-1 · 2026-09-29 · text6.12.111-1Update 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 14forkyfixed7.2.6-1Update the kernel and reboot. Fixed in 7.2.6-1. A running kernel keeps the old code until the machine restarts.
Debian unstablesidfixed7.2.6-1Update 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.12fixedDLA-4817-1 · 2026-10-04 · text6.12.111-1~deb12u1Update 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_tcp

Prints 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

IntroducedFixed inCommit
5.05.10.27002341ee424fb
5.05.15.221cade124c06f8
5.06.1.18814beef7d4f12
5.06.6.1579fb527103e53
5.06.12.1102b71f9193e3d
5.06.18.51cf1484d9a75d
5.07.2.51cbed7538946
5.07.3db62b35cbca0

Debian advisories

AdvisoryDateShipped toDebian
DLA-4841-12026-10-17bookworm 6.1.190-1tracker
DLA-4817-12026-10-04bookworm 6.12.111-1~deb12u1tracker
DSA-6528-12026-09-29trixie 6.12.111-1tracker

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.