Commit 4b3766ec authored by Bart Van Assche's avatar Bart Van Assche Committed by Martin K. Petersen

scsi: target/iscsi: Make sure PDU processing continues if parsing a command fails

Currently the iSCSI target driver sends a CHECK CONDITION code back to the
initiator if the immediate data buffer is too large but it does not discard
that immediate data buffer. The result is that the iSCSI target driver
attempts to parse the immediate data itself as iSCSI PDUs and that all
further iSCSI communication fails. Fix this by receiving and discarding too
large immediate data buffers.

Cc: Mike Christie <mchristi@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Nicholas Bellinger <nab@linux-iscsi.org>
Signed-off-by: default avatarBart Van Assche <bvanassche@acm.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 2e39f1c9
...@@ -1285,27 +1285,27 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, ...@@ -1285,27 +1285,27 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
bool dump_payload) bool dump_payload)
{ {
int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
int rc;
/* /*
* Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
*/ */
if (dump_payload) if (dump_payload) {
goto after_immediate_data; u32 length = min(cmd->se_cmd.data_length - cmd->write_data_done,
/* cmd->first_burst_len);
* Check for underflow case where both EDTL and immediate data payload
* exceeds what is presented by CDB's TRANSFER LENGTH, and what has
* already been set in target_cmd_size_check() as se_cmd->data_length.
*
* For this special case, fail the command and dump the immediate data
* payload.
*/
if (cmd->first_burst_len > cmd->se_cmd.data_length) {
cmd->sense_reason = TCM_INVALID_CDB_FIELD;
goto after_immediate_data;
}
pr_debug("Dumping min(%d - %d, %d) = %d bytes of immediate data\n",
cmd->se_cmd.data_length, cmd->write_data_done,
cmd->first_burst_len, length);
rc = iscsit_dump_data_payload(cmd->conn, length, 1);
pr_debug("Finished dumping immediate data\n");
if (rc < 0)
immed_ret = IMMEDIATE_DATA_CANNOT_RECOVER;
} else {
immed_ret = iscsit_handle_immediate_data(cmd, hdr, immed_ret = iscsit_handle_immediate_data(cmd, hdr,
cmd->first_burst_len); cmd->first_burst_len);
after_immediate_data: }
if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) { if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) {
/* /*
* A PDU/CmdSN carrying Immediate Data passed * A PDU/CmdSN carrying Immediate Data passed
...@@ -1318,12 +1318,9 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, ...@@ -1318,12 +1318,9 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
return -1; return -1;
if (cmd->sense_reason || cmdsn_ret == CMDSN_LOWER_THAN_EXP) { if (cmd->sense_reason || cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
int rc;
rc = iscsit_dump_data_payload(cmd->conn,
cmd->first_burst_len, 1);
target_put_sess_cmd(&cmd->se_cmd); target_put_sess_cmd(&cmd->se_cmd);
return rc;
return 0;
} else if (cmd->unsolicited_data) } else if (cmd->unsolicited_data)
iscsit_set_unsolicited_dataout(cmd); iscsit_set_unsolicited_dataout(cmd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment