aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2012-09-05 11:09:15 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2012-09-05 20:20:28 -0400
commitd5829eac5f7cfff89c6d1cf11717eee97cf030d0 (patch)
tree9acff1b99c654235b5ad4534735fdaf03a9c5a45
parent27a2709912ac19c755d34c79fe11994b0bf8082b (diff)
target: fix use-after-free with PSCSI sense data
The pointer to the sense buffer is fetched by transport_get_sense_data, but this is called by target_complete_ok_work long after pscsi_req_done has freed the struct that contains it. Pass instead the fabric's sense buffer to transport_complete, and copy the data to it directly in transport_complete. Setting SCF_TRANSPORT_TASK_SENSE also becomes a duty of transport_complete. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/target_core_pscsi.c21
-rw-r--r--drivers/target/target_core_transport.c36
-rw-r--r--include/target/target_core_backend.h4
3 files changed, 24 insertions, 37 deletions
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 5552fa7426bc..5f7151d90344 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -667,7 +667,8 @@ static void pscsi_free_device(void *p)
667 kfree(pdv); 667 kfree(pdv);
668} 668}
669 669
670static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg) 670static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg,
671 unsigned char *sense_buffer)
671{ 672{
672 struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr; 673 struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr;
673 struct scsi_device *sd = pdv->pdv_sd; 674 struct scsi_device *sd = pdv->pdv_sd;
@@ -679,7 +680,7 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg)
679 * not been allocated because TCM is handling the emulation directly. 680 * not been allocated because TCM is handling the emulation directly.
680 */ 681 */
681 if (!pt) 682 if (!pt)
682 return 0; 683 return;
683 684
684 cdb = &pt->pscsi_cdb[0]; 685 cdb = &pt->pscsi_cdb[0];
685 result = pt->pscsi_result; 686 result = pt->pscsi_result;
@@ -750,10 +751,10 @@ after_mode_sense:
750 } 751 }
751after_mode_select: 752after_mode_select:
752 753
753 if (status_byte(result) & CHECK_CONDITION) 754 if (sense_buffer && (status_byte(result) & CHECK_CONDITION)) {
754 return 1; 755 memcpy(sense_buffer, pt->pscsi_sense, TRANSPORT_SENSE_BUFFER);
755 756 cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE;
756 return 0; 757 }
757} 758}
758 759
759enum { 760enum {
@@ -1184,13 +1185,6 @@ fail:
1184 return -ENOMEM; 1185 return -ENOMEM;
1185} 1186}
1186 1187
1187static unsigned char *pscsi_get_sense_buffer(struct se_cmd *cmd)
1188{
1189 struct pscsi_plugin_task *pt = cmd->priv;
1190
1191 return pt->pscsi_sense;
1192}
1193
1194/* pscsi_get_device_rev(): 1188/* pscsi_get_device_rev():
1195 * 1189 *
1196 * 1190 *
@@ -1273,7 +1267,6 @@ static struct se_subsystem_api pscsi_template = {
1273 .check_configfs_dev_params = pscsi_check_configfs_dev_params, 1267 .check_configfs_dev_params = pscsi_check_configfs_dev_params,
1274 .set_configfs_dev_params = pscsi_set_configfs_dev_params, 1268 .set_configfs_dev_params = pscsi_set_configfs_dev_params,
1275 .show_configfs_dev_params = pscsi_show_configfs_dev_params, 1269 .show_configfs_dev_params = pscsi_show_configfs_dev_params,
1276 .get_sense_buffer = pscsi_get_sense_buffer,
1277 .get_device_rev = pscsi_get_device_rev, 1270 .get_device_rev = pscsi_get_device_rev,
1278 .get_device_type = pscsi_get_device_type, 1271 .get_device_type = pscsi_get_device_type,
1279 .get_blocks = pscsi_get_blocks, 1272 .get_blocks = pscsi_get_blocks,
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 040f05fde4d6..8a29e3fd0195 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -568,38 +568,31 @@ static void target_complete_failure_work(struct work_struct *work)
568} 568}
569 569
570/* 570/*
571 * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd 571 * Used when asking transport to copy Sense Data from the underlying
572 * Linux/SCSI struct scsi_cmnd
572 */ 573 */
573static void transport_get_sense_data(struct se_cmd *cmd) 574static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd)
574{ 575{
575 unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL; 576 unsigned char *buffer = cmd->sense_buffer;
576 struct se_device *dev = cmd->se_dev; 577 struct se_device *dev = cmd->se_dev;
577 unsigned long flags;
578 u32 offset = 0; 578 u32 offset = 0;
579 579
580 WARN_ON(!cmd->se_lun); 580 WARN_ON(!cmd->se_lun);
581 581
582 if (!dev) 582 if (!dev)
583 return; 583 return NULL;
584
585 spin_lock_irqsave(&cmd->t_state_lock, flags);
586 if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
587 spin_unlock_irqrestore(&cmd->t_state_lock, flags);
588 return;
589 }
590 584
591 sense_buffer = dev->transport->get_sense_buffer(cmd); 585 if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION)
592 spin_unlock_irqrestore(&cmd->t_state_lock, flags); 586 return NULL;
593 587
594 offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER); 588 offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER);
595 589
596 memcpy(&buffer[offset], sense_buffer, TRANSPORT_SENSE_BUFFER);
597
598 /* Automatically padded */ 590 /* Automatically padded */
599 cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset; 591 cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
600 592
601 pr_debug("HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x and sense\n", 593 pr_debug("HBA_[%u]_PLUG[%s]: Requesting sense for SAM STATUS: 0x%02x\n",
602 dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status); 594 dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status);
595 return &buffer[offset];
603} 596}
604 597
605void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) 598void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
@@ -615,11 +608,11 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
615 cmd->transport_state &= ~CMD_T_BUSY; 608 cmd->transport_state &= ~CMD_T_BUSY;
616 609
617 if (dev && dev->transport->transport_complete) { 610 if (dev && dev->transport->transport_complete) {
618 if (dev->transport->transport_complete(cmd, 611 dev->transport->transport_complete(cmd,
619 cmd->t_data_sg) != 0) { 612 cmd->t_data_sg,
620 cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE; 613 transport_get_sense_buffer(cmd));
614 if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE)
621 success = 1; 615 success = 1;
622 }
623 } 616 }
624 617
625 /* 618 /*
@@ -1987,12 +1980,11 @@ static void target_complete_ok_work(struct work_struct *work)
1987 schedule_work(&cmd->se_dev->qf_work_queue); 1980 schedule_work(&cmd->se_dev->qf_work_queue);
1988 1981
1989 /* 1982 /*
1990 * Check if we need to retrieve a sense buffer from 1983 * Check if we need to send a sense buffer from
1991 * the struct se_cmd in question. 1984 * the struct se_cmd in question.
1992 */ 1985 */
1993 if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { 1986 if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {
1994 WARN_ON(!cmd->scsi_status); 1987 WARN_ON(!cmd->scsi_status);
1995 transport_get_sense_data(cmd);
1996 ret = transport_send_check_condition_and_sense( 1988 ret = transport_send_check_condition_and_sense(
1997 cmd, 0, 1); 1989 cmd, 0, 1);
1998 if (ret == -EAGAIN || ret == -ENOMEM) 1990 if (ret == -EAGAIN || ret == -ENOMEM)
diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h
index f1405d335a96..941c84bf1065 100644
--- a/include/target/target_core_backend.h
+++ b/include/target/target_core_backend.h
@@ -23,7 +23,9 @@ struct se_subsystem_api {
23 struct se_device *(*create_virtdevice)(struct se_hba *, 23 struct se_device *(*create_virtdevice)(struct se_hba *,
24 struct se_subsystem_dev *, void *); 24 struct se_subsystem_dev *, void *);
25 void (*free_device)(void *); 25 void (*free_device)(void *);
26 int (*transport_complete)(struct se_cmd *cmd, struct scatterlist *); 26 void (*transport_complete)(struct se_cmd *cmd,
27 struct scatterlist *,
28 unsigned char *);
27 29
28 int (*parse_cdb)(struct se_cmd *cmd); 30 int (*parse_cdb)(struct se_cmd *cmd);
29 ssize_t (*check_configfs_dev_params)(struct se_hba *, 31 ssize_t (*check_configfs_dev_params)(struct se_hba *,