[PATCH 2/4] scsi: target: Fix WRITE_SAME NDOB handling in file

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If NDOB is set we don't have a buffer. We will then crash when trying to
access the t_data_sg. This has us allocate a page to use for the data
buffer that gets passed to vfs_iter_write.

Signed-off-by: Mike Christie <michael.christie@xxxxxxxxxx>
---
 drivers/target/target_core_file.c | 32 +++++++++++++++++++++++++------
 1 file changed, 26 insertions(+), 6 deletions(-)

diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index e68f1cc8ef98..2011836ab7f4 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -433,6 +433,9 @@ fd_execute_write_same(struct se_cmd *cmd)
 	struct fd_dev *fd_dev = FD_DEV(se_dev);
 	loff_t pos = cmd->t_task_lba * se_dev->dev_attrib.block_size;
 	sector_t nolb = sbc_get_write_same_sectors(cmd);
+	bool ndob = cmd->t_task_cdb[1] & 0x01;
+	struct scatterlist *sg, ndob_sg;
+	struct page *pg = NULL;
 	struct iov_iter iter;
 	struct bio_vec *bvec;
 	unsigned int len = 0, i;
@@ -447,13 +450,13 @@ fd_execute_write_same(struct se_cmd *cmd)
 		       " backends not supported\n");
 		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 	}
+	sg = &cmd->t_data_sg[0];
 
 	if (cmd->t_data_nents > 1 ||
-	    cmd->t_data_sg[0].length != cmd->se_dev->dev_attrib.block_size) {
+	    (sg && sg->length != cmd->se_dev->dev_attrib.block_size)) {
 		pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u"
 			" block_size: %u\n",
-			cmd->t_data_nents,
-			cmd->t_data_sg[0].length,
+			cmd->t_data_nents, sg->length,
 			cmd->se_dev->dev_attrib.block_size);
 		return TCM_INVALID_CDB_FIELD;
 	}
@@ -462,10 +465,23 @@ fd_execute_write_same(struct se_cmd *cmd)
 	if (!bvec)
 		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
+	if (ndob) {
+		pg = alloc_page(GFP_KERNEL | __GFP_ZERO);
+		if (!pg) {
+			kfree(bvec);
+			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+		}
+
+		sg_init_table(&ndob_sg, 1);
+		sg_set_page(&ndob_sg, pg, cmd->se_dev->dev_attrib.block_size,
+			    0);
+		sg = &ndob_sg;
+	}
+
 	for (i = 0; i < nolb; i++) {
-		bvec[i].bv_page = sg_page(&cmd->t_data_sg[0]);
-		bvec[i].bv_len = cmd->t_data_sg[0].length;
-		bvec[i].bv_offset = cmd->t_data_sg[0].offset;
+		bvec[i].bv_page = sg_page(sg);
+		bvec[i].bv_len = sg->length;
+		bvec[i].bv_offset = sg->offset;
 
 		len += se_dev->dev_attrib.block_size;
 	}
@@ -474,6 +490,10 @@ fd_execute_write_same(struct se_cmd *cmd)
 	ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos, 0);
 
 	kfree(bvec);
+
+	if (pg)
+		__free_page(pg);
+
 	if (ret < 0 || ret != len) {
 		pr_err("vfs_iter_write() returned %zd for write same\n", ret);
 		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-- 
2.25.1




[Index of Archives]     [Linux SCSI]     [Kernel Newbies]     [Linux SCSI Target Infrastructure]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Device Mapper]

  Powered by Linux