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 5/8] scsi: target: copy a DIF verify tuple across prot sgs
Date: Tue, 6 Oct 2026 17:33:35 +0800 [thread overview]
Message-ID: <20261006093338.27342-6-physicalmtea@gmail.com> (raw)
In-Reply-To: <20261006093338.27342-1-physicalmtea@gmail.com>
sbc_dif_verify() loads an 8 byte t10_pi_tuple while i < psg->length.
A protection sg shorter than 8 bytes still enters the loop.
vhost-scsi keeps each sg inside one page. Eight PI bytes that start
at page offset 4092 are mapped as 4 bytes at that offset and 4 bytes
on the next guest page. The first sg still satisfies i < length, and
the tuple read continues into the next physical page.
Software verify runs when the fabric does not advertise DOUT_STRIP.
vhost-scsi advertises only DIN_PASS and DOUT_PASS. With
fabric_prot_type 1, a WRITE is TARGET_PROT_DOUT_STRIP and
sbc_dif_verify() reads the guest PI buffer.
Copy the 8 byte tuple across protection sg entries before the check.
Four bytes at the end of one entry and four at the start of the next
stay one tuple. A tail with no following entry fails the command.
KASAN reports:
BUG: KASAN: use-after-free in sbc_dif_verify+0x5ab/0x790 [target_core_mod]
Read of size 4
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 | 117 ++++++++++++++++---------------
1 file changed, 60 insertions(+), 57 deletions(-)
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 12275ebad95c..c0aeb8886743 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -1492,81 +1492,84 @@ sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors,
unsigned int ei_lba, struct scatterlist *psg, int psg_off)
{
struct se_device *dev = cmd->se_dev;
- struct t10_pi_tuple *sdt;
struct scatterlist *dsg = cmd->t_data_sg;
sector_t sector = start;
void *daddr, *paddr;
- int i;
sense_reason_t rc;
+ unsigned int poff = psg_off;
int dsg_off = 0;
unsigned int block_size = dev->dev_attrib.block_size;
- for (; psg && sector < start + sectors; psg = sg_next(psg)) {
- paddr = kmap_atomic(sg_page(psg)) + psg->offset;
- daddr = kmap_atomic(sg_page(dsg)) + dsg->offset;
-
- for (i = psg_off; i < psg->length &&
- sector < start + sectors;
- i += sizeof(*sdt)) {
- __u16 crc;
- unsigned int avail;
-
- if (dsg_off >= dsg->length) {
- dsg_off -= dsg->length;
- kunmap_atomic(daddr - dsg->offset);
- dsg = sg_next(dsg);
- if (!dsg) {
- kunmap_atomic(paddr - psg->offset);
- return 0;
- }
- daddr = kmap_atomic(sg_page(dsg)) + dsg->offset;
- }
+ if (!psg || !dsg)
+ return 0;
- sdt = paddr + i;
+ paddr = kmap_local_page(sg_page(psg)) + psg->offset;
+ daddr = kmap_local_page(sg_page(dsg)) + dsg->offset;
- pr_debug("DIF READ sector: %llu guard_tag: 0x%04x"
- " app_tag: 0x%04x ref_tag: %u\n",
- (unsigned long long)sector, sdt->guard_tag,
- sdt->app_tag, be32_to_cpu(sdt->ref_tag));
+ while (sector < start + sectors) {
+ struct t10_pi_tuple sdt;
+ __u16 crc;
+ unsigned int avail;
- if (sdt->app_tag == T10_PI_APP_ESCAPE) {
- dsg_off += block_size;
- goto next;
- }
+ if (poff >= psg->length && !sg_next(psg))
+ break;
+
+ if (!sbc_dif_prot_copy(&psg, &paddr, &poff, &dsg, &daddr,
+ &sdt, false)) {
+ cmd->sense_info = sector;
+ return TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED;
+ }
- avail = min(block_size, dsg->length - dsg_off);
- crc = crc_t10dif(daddr + dsg_off, avail);
- if (avail < block_size) {
- kunmap_atomic(daddr - dsg->offset);
- dsg = sg_next(dsg);
- if (!dsg) {
- kunmap_atomic(paddr - psg->offset);
- return 0;
- }
- daddr = kmap_atomic(sg_page(dsg)) + dsg->offset;
- dsg_off = block_size - avail;
- crc = crc_t10dif_update(crc, daddr, dsg_off);
- } else {
- dsg_off += block_size;
+ pr_debug("DIF READ sector: %llu guard_tag: 0x%04x app_tag: 0x%04x ref_tag: %u\n",
+ (unsigned long long)sector, sdt.guard_tag,
+ sdt.app_tag, be32_to_cpu(sdt.ref_tag));
+
+ if (sdt.app_tag == T10_PI_APP_ESCAPE) {
+ dsg_off += block_size;
+ goto next;
+ }
+
+ if (dsg_off >= dsg->length) {
+ dsg_off -= dsg->length;
+ kunmap_local(daddr - dsg->offset);
+ dsg = sg_next(dsg);
+ if (!dsg) {
+ kunmap_local(paddr - psg->offset);
+ return 0;
}
+ daddr = kmap_local_page(sg_page(dsg)) + dsg->offset;
+ }
- rc = sbc_dif_v1_verify(cmd, sdt, crc, sector, ei_lba);
- if (rc) {
- kunmap_atomic(daddr - dsg->offset);
- kunmap_atomic(paddr - psg->offset);
- cmd->sense_info = sector;
- return rc;
+ 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) {
+ kunmap_local(paddr - psg->offset);
+ return 0;
}
-next:
- sector++;
- ei_lba++;
+ 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;
}
- psg_off = 0;
- kunmap_atomic(daddr - dsg->offset);
- kunmap_atomic(paddr - psg->offset);
+ rc = sbc_dif_v1_verify(cmd, &sdt, crc, sector, ei_lba);
+ if (rc) {
+ kunmap_local(daddr - dsg->offset);
+ kunmap_local(paddr - psg->offset);
+ cmd->sense_info = sector;
+ return rc;
+ }
+next:
+ sector++;
+ ei_lba++;
}
+ kunmap_local(daddr - dsg->offset);
+ kunmap_local(paddr - psg->offset);
return 0;
}
EXPORT_SYMBOL(sbc_dif_verify);
--
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 ` Jia Jia [this message]
2026-10-06 9:33 ` [PATCH 6/8] scsi: target: limit DIF block CRC to each data sg Jia Jia
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-6-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.