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

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

CVE-2026-89973

nvme-tcp: check the data direction of a C2HData PDU

8.2 EPSS 0.6% 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-89973 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

nvme_tcp_handle_c2h_data() finds the request by command id and checks that it has a payload, but it does not check that the command asked for data to be read. A controller that answers a write command with C2HData therefore reaches nvme_tcp_recv_data(), where _copy_to_iter() hits WARN_ON_ONCE(i->data_source) and returns 0. The receive path turns that into -EFAULT and resets the controller. No data is copied, so this is not memory corruption. What a controller gets is a kernel warning it can raise at will, which is fatal on a host booted with panic_on_warn. The send path already knows the direction - it consults rq_data_dir() when it builds a command - and nvme_tcp_handle_r2t() checks the length and the offset of the request it names. The C2HData path does not check the direction at all. Reject a C2HData PDU whose command is not a read. Rejecting it fails the command and resets the controller, as the neighbouring check in this function does; what goes away is the warning. [ 6.885580] ------------[ cut here ]------------ [ 6.886457] WARNING: lib/iov_iter.c:193 at _copy_to_iter+0x289/0x1330, CPU#0: kworker/0:1H/71 [ 6.888137] CPU: 0 UID: 0 PID: 71 Comm: kworker/0:1H Not tainted 7.2.0-rc5-NVMETCP-gf5098b6bae76 #1 PREEMPT(lazy) [ 6.891165] Workqueue: nvme_tcp_wq nvme_tcp_io_work [ 6.891875] RIP: 0010:_copy_to_iter+0x289/0x1330 [ 6.903739] Call Trace: [ 6.904085] <TASK> [ 6.909254] __skb_datagram_iter+0x433/0x820 [ 6.911026] skb_copy_datagram_iter+0x37/0x120 [ 6.911622] nvme_tcp_recv_skb+0xa07/0x4320 [ 6.913378] __tcp_read_sock+0x1ab/0x810 [ 6.915788] nvme_tcp_try_recv+0x152/0x1e0 [ 6.918222] nvme_tcp_io_work+0x1e4/0x6c0 [ 6.926906] </TASK> [ 6.927226] ---[ end trace 0000000000000000 ]--- [ 6.927878] nvme nvme0: queue 1 failed to copy request 0x71 data [ 6.928709] nvme nvme0: receive failed: -14

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/host/tcp.c

What this is
NVM EXPRESS DRIVERMAINTAINERS section matched on drivers/nvme/host/ · linux-nvme@lists.infradead.org · Supported
Kernel module
nvme_tcp

Check it on the machine

grep -w CONFIG_NVME_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 nvme_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_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
8.2 high
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:Hsource recompute it
Attack vector
network (AV:N)source
EPSS
0.60%, higher than 47.6% 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.270df74950ba600
5.05.15.221980d990f3c05
5.06.1.1885b115d932f6e
5.06.6.1570673a2affe45
5.06.12.11080d56202fbdf
5.06.18.51b4af7999a998
5.07.2.5a0c389b8a495
5.07.3f83af377c148

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
The nvme-tcp host receive path (nvme_tcp_data_ready -> nvme_tcp_try_recv -> nvme_tcp_recv_skb -> nvme_tcp_handle_c2h_data) parses C2HData PDUs from a remote NVMe/TCP target over routable TCP (typically port 4420); a malicious or compromised target, or an on-path injector into the default-unencrypted stream, triggers the bug from the network.
AC:LAttack complexity, low
A malicious controller that replies to any in-flight write-direction command with a well-formed C2HData PDU always hits WARN_ON_ONCE(i->data_source) in _copy_to_iter; writes occur from writeback, discards, and init-time Set Features. No race, special memory layout, or rare config beyond CONFIG_NVME_TCP is required.
PR:NPrivileges required, none
NVMe/TCP authentication (TLS and DH-HMAC-CHAP) is optional and off by default, so the connected fabric peer needs no credentials or privileges on the victim host; it simply answers I/O the host is already sending.
UI:NUser interaction, none
No victim action is required at exploit time; once the host is connected (including nvmf-autoconnect at boot), ordinary writeback, journal I/O, and controller-init Set Features with a data buffer issue write-direction commands that the malicious target answers with C2HData.
S:UScope, unchanged
The WARN splat, NVMe controller reset, and any panic_on_warn crash remain inside the host kernel. This is not a VM escape, IOMMU bypass, or sandbox boundary crossing.
C:LConfidentiality impact, low
WARN_ON_ONCE in _copy_to_iter calls __warn()/dump_stack(), disclosing kernel text addresses in dmesg. No data is copied (the write iterator is ITER_SOURCE and copy_to_iter returns 0), so there is no use-after-free or arbitrary kernel read.
I:NIntegrity impact, none
The receive path turns the failed copy into -EFAULT and resets the controller; _copy_to_iter returns 0 without writing, so there is no memory corruption, write primitive, or control-flow hijack.
A:HAvailability impact, high
The reporter reproduced WARNING in _copy_to_iter from nvme_tcp_io_work, which panics hosts with panic_on_warn or warn_limit. Independently, every C2HData-for-write returns -EFAULT and runs nvme_tcp_error_recovery(), so a malicious target can repeatedly take down NVMe-oF storage.