]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
vhost-scsi: Validate T10 PI scatterlist counts
authorLinfeng Sun <slf@hdu.edu.cn>
Mon, 27 Jul 2026 08:18:41 +0000 (16:18 +0800)
committerMichael S. Tsirkin <mst@redhat.com>
Tue, 4 Aug 2026 03:08:15 +0000 (23:08 -0400)
When T10 PI is negotiated, vhost-scsi splits protection bytes from
the data iterator before mapping the request scatterlists. A malformed
request can claim protection bytes that cover or exceed the full payload
length. The former leaves no data bytes to map, while the latter
underflows exp_data_len before advancing the iterator. Both cases can let
a zero data SGL count reach sg_alloc_table_chained(), which triggers
BUG_ON(!nents).

Reject protection lengths that cover or exceed the payload before
subtracting prot_bytes and advancing the iterator. Also propagate
negative errors from the protection SGL calculation before calling the
allocator, matching the data SGL path.

Fixes: bca939d5bcd0 ("vhost-scsi: Dynamically allocate scatterlists")
Suggested-by: Jia Jia <physicalmtea@gmail.com>
Signed-off-by: Jia Jia <physicalmtea@gmail.com>
Assisted-by: OpenAI-Codex:GPT-5
Signed-off-by: Linfeng Sun <linfeng.sun.dev@gmail.com>
Message-ID: <20260727081841.923151-1-slf@hdu.edu.cn>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
drivers/vhost/scsi.c

index 9a1253b9d8c50ebcffd06289d0e8aff4d7dc879e..c79197edb16371ce87651afcdd9fac7f5a2d2945 100644 (file)
@@ -972,6 +972,9 @@ vhost_scsi_mapal(struct vhost_scsi *vs, struct vhost_scsi_cmd *cmd,
        if (prot_bytes) {
                sgl_count = vhost_scsi_calc_sgls(prot_iter, prot_bytes,
                                                 VHOST_SCSI_PREALLOC_PROT_SGLS);
+               if (sgl_count < 0)
+                       return sgl_count;
+
                cmd->prot_table.sgl = cmd->prot_sgl;
                ret = sg_alloc_table_chained(&cmd->prot_table, sgl_count,
                                             cmd->prot_table.sgl,
@@ -1416,6 +1419,11 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                         * actual data payload length.
                         */
                        if (prot_bytes) {
+                               if (prot_bytes >= exp_data_len) {
+                                       vq_err(vq, "Protection data exceeds payload length\n");
+                                       goto err;
+                               }
+
                                exp_data_len -= prot_bytes;
                                prot_iter = data_iter;
                                iov_iter_truncate(&prot_iter, prot_bytes);