Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Browse files Browse the repository at this point in the history
Pull scsi target fixes from Nicholas Bellinger:
 "Here is the current set of target-pending fixes headed for v3.6-final

  The main parts of this series include bug-fixes from Paolo Bonzini to
  address an use-after-free bug in pSCSI sense exception handling, along
  with addressing some long-standing bugs wrt the handling of zero-
  length SCSI CDB payloads also specific to pSCSI pass-through device
  backends."

* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
  target: go through normal processing for zero-length REQUEST_SENSE
  target: support zero allocation length in REQUEST SENSE
  target: support zero-size allocation lengths in transport_kmap_data_sg
  target: fail REPORT LUNS with less than 16 bytes of payload
  target: report too-small parameter lists everywhere
  target: go through normal processing for zero-length PSCSI commands
  target: fix use-after-free with PSCSI sense data
  target: simplify code around transport_get_sense_data
  target: move transport_get_sense_data
  target: Check idr_get_new return value in iscsi_login_zero_tsih_s1
  target: Fix ->data_length re-assignment bug with SCSI overflow
  • Loading branch information
torvalds committed Sep 16, 2012
2 parents 9bc6759 + 6abbdf3 commit 76e77da
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 126 deletions.
11 changes: 10 additions & 1 deletion drivers/target/iscsi/iscsi_target_login.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ static int iscsi_login_zero_tsih_s1(
{
struct iscsi_session *sess = NULL;
struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
int ret;

sess = kzalloc(sizeof(struct iscsi_session), GFP_KERNEL);
if (!sess) {
Expand Down Expand Up @@ -257,9 +258,17 @@ static int iscsi_login_zero_tsih_s1(
return -ENOMEM;
}
spin_lock(&sess_idr_lock);
idr_get_new(&sess_idr, NULL, &sess->session_index);
ret = idr_get_new(&sess_idr, NULL, &sess->session_index);
spin_unlock(&sess_idr_lock);

if (ret < 0) {
pr_err("idr_get_new() for sess_idr failed\n");
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
ISCSI_LOGIN_STATUS_NO_RESOURCES);
kfree(sess);
return -ENOMEM;
}

sess->creation_time = get_jiffies_64();
spin_lock_init(&sess->session_stats_lock);
/*
Expand Down
7 changes: 7 additions & 0 deletions drivers/target/target_core_alua.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,13 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd)
cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
return -EINVAL;
}
if (cmd->data_length < 4) {
pr_warn("SET TARGET PORT GROUPS parameter list length %u too"
" small\n", cmd->data_length);
cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
return -EINVAL;
}

buf = transport_kmap_data_sg(cmd);

/*
Expand Down
7 changes: 7 additions & 0 deletions drivers/target/target_core_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,13 @@ int target_report_luns(struct se_cmd *se_cmd)
unsigned char *buf;
u32 lun_count = 0, offset = 8, i;

if (se_cmd->data_length < 16) {
pr_warn("REPORT LUNS allocation length %u too small\n",
se_cmd->data_length);
se_cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
return -EINVAL;
}

buf = transport_kmap_data_sg(se_cmd);
if (!buf)
return -ENOMEM;
Expand Down
17 changes: 15 additions & 2 deletions drivers/target/target_core_iblock.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,17 +325,30 @@ static int iblock_execute_unmap(struct se_cmd *cmd)
struct iblock_dev *ibd = dev->dev_ptr;
unsigned char *buf, *ptr = NULL;
sector_t lba;
int size = cmd->data_length;
int size;
u32 range;
int ret = 0;
int dl, bd_dl;

if (cmd->data_length < 8) {
pr_warn("UNMAP parameter list length %u too small\n",
cmd->data_length);
cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
return -EINVAL;
}

buf = transport_kmap_data_sg(cmd);

dl = get_unaligned_be16(&buf[0]);
bd_dl = get_unaligned_be16(&buf[2]);

size = min(size - 8, bd_dl);
size = cmd->data_length - 8;
if (bd_dl > size)
pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n",
cmd->data_length, bd_dl);
else
size = bd_dl;

if (size / 16 > dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) {
cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
ret = -EINVAL;
Expand Down
8 changes: 8 additions & 0 deletions drivers/target/target_core_pr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1540,6 +1540,14 @@ static int core_scsi3_decode_spec_i_port(
tidh_new->dest_local_nexus = 1;
list_add_tail(&tidh_new->dest_list, &tid_dest_list);

if (cmd->data_length < 28) {
pr_warn("SPC-PR: Received PR OUT parameter list"
" length too small: %u\n", cmd->data_length);
cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
ret = -EINVAL;
goto out;
}

buf = transport_kmap_data_sg(cmd);
/*
* For a PERSISTENT RESERVE OUT specify initiator ports payload,
Expand Down
29 changes: 11 additions & 18 deletions drivers/target/target_core_pscsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,8 @@ static void pscsi_free_device(void *p)
kfree(pdv);
}

static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg)
static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg,
unsigned char *sense_buffer)
{
struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr;
struct scsi_device *sd = pdv->pdv_sd;
Expand All @@ -679,19 +680,19 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg)
* not been allocated because TCM is handling the emulation directly.
*/
if (!pt)
return 0;
return;

cdb = &pt->pscsi_cdb[0];
result = pt->pscsi_result;
/*
* Hack to make sure that Write-Protect modepage is set if R/O mode is
* forced.
*/
if (!cmd->se_deve || !cmd->data_length)
goto after_mode_sense;

if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) &&
(status_byte(result) << 1) == SAM_STAT_GOOD) {
if (!cmd->se_deve)
goto after_mode_sense;

if (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) {
unsigned char *buf = transport_kmap_data_sg(cmd);

Expand All @@ -708,7 +709,7 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg)
}
after_mode_sense:

if (sd->type != TYPE_TAPE)
if (sd->type != TYPE_TAPE || !cmd->data_length)
goto after_mode_select;

/*
Expand Down Expand Up @@ -750,10 +751,10 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg)
}
after_mode_select:

if (status_byte(result) & CHECK_CONDITION)
return 1;

return 0;
if (sense_buffer && (status_byte(result) & CHECK_CONDITION)) {
memcpy(sense_buffer, pt->pscsi_sense, TRANSPORT_SENSE_BUFFER);
cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE;
}
}

enum {
Expand Down Expand Up @@ -1184,13 +1185,6 @@ static int pscsi_execute_cmd(struct se_cmd *cmd)
return -ENOMEM;
}

static unsigned char *pscsi_get_sense_buffer(struct se_cmd *cmd)
{
struct pscsi_plugin_task *pt = cmd->priv;

return pt->pscsi_sense;
}

/* pscsi_get_device_rev():
*
*
Expand Down Expand Up @@ -1273,7 +1267,6 @@ static struct se_subsystem_api pscsi_template = {
.check_configfs_dev_params = pscsi_check_configfs_dev_params,
.set_configfs_dev_params = pscsi_set_configfs_dev_params,
.show_configfs_dev_params = pscsi_show_configfs_dev_params,
.get_sense_buffer = pscsi_get_sense_buffer,
.get_device_rev = pscsi_get_device_rev,
.get_device_type = pscsi_get_device_type,
.get_blocks = pscsi_get_blocks,
Expand Down
35 changes: 18 additions & 17 deletions drivers/target/target_core_spc.c
Original file line number Diff line number Diff line change
Expand Up @@ -877,9 +877,11 @@ static int spc_emulate_modesense(struct se_cmd *cmd)
static int spc_emulate_request_sense(struct se_cmd *cmd)
{
unsigned char *cdb = cmd->t_task_cdb;
unsigned char *buf;
unsigned char *rbuf;
u8 ua_asc = 0, ua_ascq = 0;
int err = 0;
unsigned char buf[SE_SENSE_BUF];

memset(buf, 0, SE_SENSE_BUF);

if (cdb[1] & 0x01) {
pr_err("REQUEST_SENSE description emulation not"
Expand All @@ -888,20 +890,21 @@ static int spc_emulate_request_sense(struct se_cmd *cmd)
return -ENOSYS;
}

buf = transport_kmap_data_sg(cmd);

if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) {
rbuf = transport_kmap_data_sg(cmd);
if (cmd->scsi_sense_reason != 0) {
/*
* Out of memory. We will fail with CHECK CONDITION, so
* we must not clear the unit attention condition.
*/
target_complete_cmd(cmd, CHECK_CONDITION);
return 0;
} else if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) {
/*
* CURRENT ERROR, UNIT ATTENTION
*/
buf[0] = 0x70;
buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;

if (cmd->data_length < 18) {
buf[7] = 0x00;
err = -EINVAL;
goto end;
}
/*
* The Additional Sense Code (ASC) from the UNIT ATTENTION
*/
Expand All @@ -915,20 +918,18 @@ static int spc_emulate_request_sense(struct se_cmd *cmd)
buf[0] = 0x70;
buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE;

if (cmd->data_length < 18) {
buf[7] = 0x00;
err = -EINVAL;
goto end;
}
/*
* NO ADDITIONAL SENSE INFORMATION
*/
buf[SPC_ASC_KEY_OFFSET] = 0x00;
buf[7] = 0x0A;
}

end:
transport_kunmap_data_sg(cmd);
if (rbuf) {
memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
transport_kunmap_data_sg(cmd);
}

target_complete_cmd(cmd, GOOD);
return 0;
}
Expand Down
Loading

0 comments on commit 76e77da

Please sign in to comment.