From: Jia Jia <physicalmtea@gmail.com>
To: "Martin K . Petersen" <mkp@kernel.org>
Cc: Jan Engelhardt <jengelh@inai.de>, Hannes Reinecke <hare@suse.de>,
Paolo Bonzini <pbonzini@redhat.com>,
Akinobu Mita <akinobu.mita@gmail.com>,
James Bottomley <James.Bottomley@suse.de>,
linux-scsi@vger.kernel.org, target-devel@vger.kernel.org,
linux-kernel@vger.kernel.org, Jia Jia <physicalmtea@gmail.com>
Subject: [PATCH 6/8] scsi: target: limit DIF block CRC to each data sg
Date: Tue, 6 Oct 2026 17:33:36 +0800 [thread overview]
Message-ID: <20261006093338.27342-7-physicalmtea@gmail.com> (raw)
In-Reply-To: <20261006093338.27342-1-physicalmtea@gmail.com>
sbc_dif_generate() and sbc_dif_verify() CRC one logical block from the
data sg. When the first entry is shorter than the block, the remainder
is read from the next entry with
crc_t10dif_update(crc, daddr, block_size - avail)
That length is not limited to the next sg->length. A 512 byte block
split 256 + 100 + 156, with the 100 byte entry ending on a page, reads
156 bytes into the next physical page.
vhost-scsi can build that layout from one guest data buffer. Software
verify and software INSERT both use this CRC. Walk later entries and
read only the bytes each one actually holds. The helper unmaps the
current data page and may leave a later one mapped, with the same
kmap_local_page() calls as the rest of the walk.
KASAN reports:
BUG: KASAN: use-after-free in crc_t10dif_update+0x91/0xf0
Read of size 1
crc_t10dif_update
sbc_dif_verify
target_execute_cmd
vhost_scsi_write_pending
transport_generic_new_cmd
__target_submit
target_queued_submit_work
process_one_work
worker_thread
kthread
ret_from_fork
ret_from_fork_asm
Fixes: 18213afbd8ce ("target: handle odd SG mapping for data transfer memory")
Signed-off-by: Jia Jia <physicalmtea@gmail.com>
---
drivers/target/target_core_sbc.c | 54 +++++++++++++++++++++++++-------
1 file changed, 42 insertions(+), 12 deletions(-)
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index c0aeb8886743..76dbc986e887 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -1310,6 +1310,44 @@ sbc_dif_prot_copy(struct scatterlist **psgp, void **paddrp,
return true;
}
+/*
+ * CRC the rest of one logical block. @need is the byte count still
+ * unread. Take only what each following data sg holds.
+ */
+static bool
+sbc_dif_crc_rest(struct scatterlist **dsgp, void **daddrp, int *offp,
+ unsigned int need, __u16 *crc)
+{
+ struct scatterlist *dsg = *dsgp;
+ void *daddr = *daddrp;
+
+ kunmap_local(daddr - dsg->offset);
+ while (need) {
+ unsigned int take;
+
+ dsg = sg_next(dsg);
+ if (!dsg)
+ return false;
+
+ daddr = kmap_local_page(sg_page(dsg)) + dsg->offset;
+ if (!dsg->length) {
+ kunmap_local(daddr - dsg->offset);
+ return false;
+ }
+
+ take = min_t(unsigned int, need, dsg->length);
+ *crc = crc_t10dif_update(*crc, daddr, take);
+ need -= take;
+ *offp = take;
+ if (need)
+ kunmap_local(daddr - dsg->offset);
+ }
+
+ *dsgp = dsg;
+ *daddrp = daddr;
+ return true;
+}
+
void
sbc_dif_generate(struct se_cmd *cmd)
{
@@ -1358,15 +1396,11 @@ sbc_dif_generate(struct se_cmd *cmd)
avail = min(block_size, dsg->length - offset);
crc = crc_t10dif(daddr + offset, avail);
if (avail < block_size) {
- kunmap_local(daddr - dsg->offset);
- dsg = sg_next(dsg);
- if (!dsg) {
+ if (!sbc_dif_crc_rest(&dsg, &daddr, &offset,
+ block_size - avail, &crc)) {
kunmap_local(paddr - psg->offset);
return;
}
- daddr = kmap_local_page(sg_page(dsg)) + dsg->offset;
- offset = block_size - avail;
- crc = crc_t10dif_update(crc, daddr, offset);
} else {
offset += block_size;
}
@@ -1543,15 +1577,11 @@ sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors,
avail = min(block_size, dsg->length - dsg_off);
crc = crc_t10dif(daddr + dsg_off, avail);
if (avail < block_size) {
- kunmap_local(daddr - dsg->offset);
- dsg = sg_next(dsg);
- if (!dsg) {
+ if (!sbc_dif_crc_rest(&dsg, &daddr, &dsg_off,
+ block_size - avail, &crc)) {
kunmap_local(paddr - psg->offset);
return 0;
}
- daddr = kmap_local_page(sg_page(dsg)) + dsg->offset;
- dsg_off = block_size - avail;
- crc = crc_t10dif_update(crc, daddr, dsg_off);
} else {
dsg_off += block_size;
}
--
2.34.1
next prev parent reply other threads:[~2026-10-06 9:34 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-06 9:33 [PATCH 0/8] scsi: target: keep command bytes inside the sg Jia Jia
2026-10-06 9:33 ` [PATCH 1/8] scsi: target: take COMPARE AND WRITE data from the write half Jia Jia
2026-10-06 9:33 ` [PATCH 2/8] scsi: target: keep REPORT REFERRALS stores inside the buffer Jia Jia
2026-10-06 9:33 ` [PATCH 3/8] scsi: target: reject a short SET TARGET PORT GROUPS list Jia Jia
2026-10-06 9:33 ` [PATCH 4/8] scsi: target: copy a DIF insert tuple across prot sgs Jia Jia
2026-10-06 9:33 ` [PATCH 5/8] scsi: target: copy a DIF verify " Jia Jia
2026-10-06 9:33 ` Jia Jia [this message]
2026-10-06 9:33 ` [PATCH 7/8] scsi: target: keep pscsi mode bytes inside the data sgs Jia Jia
2026-10-06 9:33 ` [PATCH 8/8] scsi: target: skip an escaped DIF block inside the data sg Jia Jia
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261006093338.27342-7-physicalmtea@gmail.com \
--to=physicalmtea@gmail.com \
--cc=James.Bottomley@suse.de \
--cc=akinobu.mita@gmail.com \
--cc=hare@suse.de \
--cc=jengelh@inai.de \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=mkp@kernel.org \
--cc=pbonzini@redhat.com \
--cc=target-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®