Skip to content

Commit 52a0a98

Browse files
YunJe Shinkeithbusch
authored andcommitted
nvmet-tcp: add bounds checks in nvmet_tcp_build_pdu_iovec
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: 872d26a ("nvmet-tcp: add NVMe over TCP target driver") Signed-off-by: YunJe Shin <[email protected]> Reviewed-by: Sagi Grimberg <[email protected]> Reviewed-by: Joonkyo Jung <[email protected]> Signed-off-by: Keith Busch <[email protected]>
1 parent 071be3b commit 52a0a98

1 file changed

Lines changed: 17 additions & 0 deletions

File tree

drivers/nvme/target/tcp.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,28 +349,45 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd)
349349
cmd->req.sg = NULL;
350350
}
351351

352+
static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue);
353+
352354
static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
353355
{
354356
struct bio_vec *iov = cmd->iov;
355357
struct scatterlist *sg;
356358
u32 length, offset, sg_offset;
359+
unsigned int sg_remaining;
357360
int nr_pages;
358361

359362
length = cmd->pdu_len;
360363
nr_pages = DIV_ROUND_UP(length, PAGE_SIZE);
361364
offset = cmd->rbytes_done;
362365
cmd->sg_idx = offset / PAGE_SIZE;
363366
sg_offset = offset % PAGE_SIZE;
367+
if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) {
368+
nvmet_tcp_fatal_error(cmd->queue);
369+
return;
370+
}
364371
sg = &cmd->req.sg[cmd->sg_idx];
372+
sg_remaining = cmd->req.sg_cnt - cmd->sg_idx;
365373

366374
while (length) {
375+
if (!sg_remaining) {
376+
nvmet_tcp_fatal_error(cmd->queue);
377+
return;
378+
}
379+
if (!sg->length || sg->length <= sg_offset) {
380+
nvmet_tcp_fatal_error(cmd->queue);
381+
return;
382+
}
367383
u32 iov_len = min_t(u32, length, sg->length - sg_offset);
368384

369385
bvec_set_page(iov, sg_page(sg), iov_len,
370386
sg->offset + sg_offset);
371387

372388
length -= iov_len;
373389
sg = sg_next(sg);
390+
sg_remaining--;
374391
iov++;
375392
sg_offset = 0;
376393
}

0 commit comments

Comments
 (0)