[PATCH] nvmet-tcp: add bounds checks in nvmet_tcp_build_pdu_iovec

yunje shin yjshin0438 at gmail.com
Mon Feb 2 19:47:32 PST 2026


Just a gentle ping on this patch.

This fixes a crash/GPF observed in _copy_to_iter() when
nvmet_tcp_build_pdu_iovec() walks past cmd->req.sg or uses invalid
sg->length/offset, triggered by malformed PDU length/offset. The patch
adds bounds checks on sg_idx/remaining entries and validates
sg->length/offset before building the bvec.

Also, the Reviewed-by tags in the original posting were obtained via
private discussion; I’d appreciate an on-list re-review (or I can
resend a v2 without those tags if preferred).

Thanks,
YunJe Shin

On Fri, Jan 30, 2026 at 12:44 PM yunje shin <yjshin0438 at gmail.com> wrote:
>
> The Reviewed-by tags mentioned in the earlier thread were obtained
> through private discussion, which kbusch likely wasn't aware of. Could
> the maintainers please re-review this patch?
>
> On Fri, Jan 30, 2026 at 12:43 PM yunje shin <yjshin0438 at gmail.com> wrote:
> >
> > The Reviewed-by tags mentioned in the earlier thread were obtained
> > through private discussion, which Keith likely wasn't aware of. Could
> > the maintainers please re-review this patch?
> >
> > On Fri, Jan 30, 2026 at 12:39 PM yunje shin <yjshin0438 at gmail.com> wrote:
> > >
> > > [  104.528480] BUG: unable to handle page fault for address: ffff888002b42660
> > > [  104.528773] #PF: supervisor write access in kernel mode
> > > [  104.528938] #PF: error_code(0x0003) - permissions violation
> > > [  104.529151] PGD 3a01067 P4D 3a01067 PUD 3a02067 PMD 4f24063 PTE
> > > 8000000002b42121
> > > [  104.529476] Oops: Oops: 0003 [#1] SMP NOPTI
> > > [  104.529817] CPU: 0 UID: 0 PID: 63 Comm: kworker/0:1H Not tainted
> > > 6.19.0-rc7 #1 PREEMPT(voluntary
> > > [  104.530090] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX,
> > > 1996), BIOS 1.16.3-debian-1.16.34
> > > [  104.530440] Workqueue: nvmet_tcp_wq nvmet_tcp_io_work
> > > [  104.530849] RIP: 0010:_copy_to_iter+0x27e/0x7a0
> > > [  104.531077] Code: 01 48 2b 05 a4 2a 2f 01 48 c1 f8 06 48 c1 e0 0c
> > > 48 03 05 a5 2a 2f 01 48 01 f0 7
> > > [  104.531620] RSP: 0018:ffffc9000021bba8 EFLAGS: 00000246
> > > [  104.531805] RAX: ffff888002b42660 RBX: 0000000000000008 RCX: 305c782f706d742f
> > > [  104.532019] RDX: 0000000000000008 RSI: ffff88800515c078 RDI: 00000000000009a0
> > > [  104.532243] RBP: ffff888005070218 R08: 0000000000000000 R09: ffff888004ed5300
> > > [  104.532428] R10: 0000000000001000 R11: ffff888003e032e0 R12: ffff88800515c078
> > > [  104.532615] R13: 0000000000000000 R14: 0000000000000008 R15: 0000000000004080
> > > [  104.532821] FS:  0000000000000000(0000) GS:ffff8880fa4a4000(0000)
> > > knlGS:0000000000000000
> > > [  104.533048] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > > [  104.533222] CR2: ffff888002b42660 CR3: 0000000004fec000 CR4: 00000000000006f0
> > > [  104.533483] Call Trace:
> > > [  104.533957]  <TASK>
> > > [  104.534195]  ? __pfx_simple_copy_to_iter+0x10/0x10
> > > [  104.534381]  __skb_datagram_iter+0x1a7/0x2e0
> > > [  104.534541]  ? __pfx_simple_copy_to_iter+0x10/0x10
> > > [  104.534671]  skb_copy_datagram_iter+0x2f/0x90
> > > [  104.534811]  tcp_recvmsg_locked+0x784/0x9d0
> > > [  104.534936]  tcp_recvmsg+0x81/0x1e0
> > > [  104.535045]  inet_recvmsg+0x50/0x130
> > > [  104.535166]  ? security_socket_recvmsg+0x43/0x60
> > > [  104.535294]  sock_recvmsg+0xa1/0xc0
> > > [  104.535381]  nvmet_tcp_io_work+0xdb/0x720
> > > [  104.535476]  process_one_work+0x15b/0x380
> > > [  104.535570]  worker_thread+0x2a5/0x3c0
> > > [  104.535653]  ? __pfx_worker_thread+0x10/0x10
> > > [  104.535747]  kthread+0xf6/0x1f0
> > > [  104.535839]  ? __pfx_kthread+0x10/0x10
> > > [  104.535949]  ? __pfx_kthread+0x10/0x10
> > > [  104.536060]  ret_from_fork+0x131/0x190
> > > [  104.536182]  ? __pfx_kthread+0x10/0x10
> > > [  104.536296]  ret_from_fork_asm+0x1a/0x30
> > > [  104.536451]  </TASK>
> > > [  104.536545] Modules linked in:
> > > [  104.536764] CR2: ffff888002b42660
> > > [  104.537046] ---[ end trace 0000000000000000 ]---
> > > [  104.537291] RIP: 0010:_copy_to_iter+0x27e/0x7a0
> > > [  104.537412] Code: 01 48 2b 05 a4 2a 2f 01 48 c1 f8 06 48 c1 e0 0c
> > > 48 03 05 a5 2a 2f 01 48 01 f0 7
> > > [  104.537848] RSP: 0018:ffffc9000021bba8 EFLAGS: 00000246
> > > [  104.538005] RAX: ffff888002b42660 RBX: 0000000000000008 RCX: 305c782f706d742f
> > > [  104.538229] RDX: 0000000000000008 RSI: ffff88800515c078 RDI: 00000000000009a0
> > > [  104.538416] RBP: ffff888005070218 R08: 0000000000000000 R09: ffff888004ed5300
> > > [  104.538617] R10: 0000000000001000 R11: ffff888003e032e0 R12: ffff88800515c078
> > > [  104.538825] R13: 0000000000000000 R14: 0000000000000008 R15: 0000000000004080
> > > [  104.538999] FS:  0000000000000000(0000) GS:ffff8880fa4a4000(0000)
> > > knlGS:0000000000000000
> > > [  104.539209] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > > [  104.539340] CR2: ffff888002b42660 CR3: 0000000004fec000 CR4: 00000000000006f0
> > > [  104.539553] note: kworker/0:1H[63] exited with irqs disabled
> > > [  104.540201] kworker/0:1H (63) used greatest stack depth: 12976 bytes left
> > > ~ $ uname -a
> > > Linux (none) 6.19.0-rc7 #1 SMP PREEMPT_DYNAMIC Fri Jan 30 09:36:44 KST
> > > 2026 x86_64 GNU/Linux
> > >
> > > On Wed, Jan 28, 2026 at 9:41 AM YunJe Shin <yjshin0438 at gmail.com> wrote:
> > > >
> > > > nvmet_tcp_build_pdu_iovec() could walk past cmd->req.sg when a PDU
> > > > length or offset exceeds sg_cnt and then use bogus sg->length/offset
> > > > values, leading to _copy_to_iter() GPF/KASAN. Guard sg_idx, remaining
> > > > entries, and sg->length/offset before building the bvec.
> > > >
> > > > Fixes: 872d26a391da ("nvmet-tcp: add NVMe over TCP target driver")
> > > > Signed-off-by: YunJe Shin <ioerts at kookmin.ac.kr>
> > > > Reviewed-by: Sagi Grimberg <sagi at grimberg.me>
> > > > Reviewed-by: Joonkyo Jung <joonkyoj at yonsei.ac.kr>
> > > > ---
> > > >  drivers/nvme/target/tcp.c | 17 +++++++++++++++++
> > > >  1 file changed, 17 insertions(+)
> > > >
> > > > diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
> > > > index 15416ff0eac4..1a62b405d8e6 100644
> > > > --- a/drivers/nvme/target/tcp.c
> > > > +++ b/drivers/nvme/target/tcp.c
> > > > @@ -349,11 +349,14 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd)
> > > >         cmd->req.sg = NULL;
> > > >  }
> > > >
> > > > +static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue);
> > > > +
> > > >  static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
> > > >  {
> > > >         struct bio_vec *iov = cmd->iov;
> > > >         struct scatterlist *sg;
> > > >         u32 length, offset, sg_offset;
> > > > +       unsigned int sg_remaining;
> > > >         int nr_pages;
> > > >
> > > >         length = cmd->pdu_len;
> > > > @@ -361,9 +364,22 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
> > > >         offset = cmd->rbytes_done;
> > > >         cmd->sg_idx = offset / PAGE_SIZE;
> > > >         sg_offset = offset % PAGE_SIZE;
> > > > +       if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) {
> > > > +               nvmet_tcp_fatal_error(cmd->queue);
> > > > +               return;
> > > > +       }
> > > >         sg = &cmd->req.sg[cmd->sg_idx];
> > > > +       sg_remaining = cmd->req.sg_cnt - cmd->sg_idx;
> > > >
> > > >         while (length) {
> > > > +               if (!sg_remaining) {
> > > > +                       nvmet_tcp_fatal_error(cmd->queue);
> > > > +                       return;
> > > > +               }
> > > > +               if (!sg->length || sg->length <= sg_offset) {
> > > > +                       nvmet_tcp_fatal_error(cmd->queue);
> > > > +                       return;
> > > > +               }
> > > >                 u32 iov_len = min_t(u32, length, sg->length - sg_offset);
> > > >
> > > >                 bvec_set_page(iov, sg_page(sg), iov_len,
> > > > @@ -371,6 +387,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
> > > >
> > > >                 length -= iov_len;
> > > >                 sg = sg_next(sg);
> > > > +               sg_remaining--;
> > > >                 iov++;
> > > >                 sg_offset = 0;
> > > >         }
> > > > --
> > > > 2.43.0
> > > >



More information about the Linux-nvme mailing list