Re: [PATCH] nvme-tcp: check the data direction of a C2HData PDU

Sagi Grimberg <[email protected]>
Newsgroups gmane.linux.kernel.stable,gmane.linux.kernel
Message-ID <[email protected]>

On 18/08/2026 14:04, Yehyeong Lee wrote:
> 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
>
> Fixes: 3f2304f8c6d6 ("nvme-tcp: add NVMe over TCP host driver")
> Cc: [email protected]
> Signed-off-by: Yehyeong Lee <[email protected]>
> ---
> Applies on top of "nvme-tcp: do not accept C2HData based on
> blk_rq_payload_bytes() alone".
>
> Measured over a user-space target that answers every write with C2HData.
> The warning appeared in 5 of 5 runs without this patch and in none of 5
> with it, in each of three shapes: a buffered 8 KiB write, a 4 KiB write
> carried in the command capsule, and a discard.  In every run the command
> ids the target answered matched the ones the kernel named.  A conforming
> target is unaffected over 5 runs each way, including writes and a
> passthrough read, which rq_data_dir() classifies as a read.
>
> Those runs were on 7.2-rc5 with this patch as the only change.  Repeating
> the write, the in-capsule write and the conforming-target arms three
> times each on the base this patch applies to - 7.2-rc5 plus that patch
> and its predecessor - gave the same counts.
>
>   drivers/nvme/host/tcp.c | 7 +++++++
>   1 file changed, 7 insertions(+)
>
> diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
> index 85a87ed6df936..a62d6e48f7190 100644
> --- a/drivers/nvme/host/tcp.c
> +++ b/drivers/nvme/host/tcp.c
> @@ -679,6 +679,13 @@ static int nvme_tcp_handle_c2h_data(struct nvme_tcp_queue *queue,
>   		return -ENOENT;
>   	}
>   
> +	if (rq_data_dir(rq) != READ) {
> +		dev_err(queue->ctrl->ctrl.device,
> +			"queue %d tag %#x unexpected data for a write\n",
> +			nvme_tcp_queue_id(queue), rq->tag);
> +		return -EIO;

Minor nit - EPROTO would be more appropriate here (chiming in late here 
- not a really big deal)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.