scsi: Protect against buffer possible overflow in scsi_set_sense_information
authorSagi Grimberg <sagig@mellanox.com>
Wed, 15 Jul 2015 07:55:37 +0000 (10:55 +0300)
committerNicholas Bellinger <nab@linux-iscsi.org>
Fri, 24 Jul 2015 05:53:05 +0000 (22:53 -0700)
Make sure that the input sense buffer has sufficient length
to fit the information descriptor (12 additional bytes).
Modify scsi_set_sense_information to receive the sense buffer
length and adjust its callers scsi target and libata.

(Fix patch fuzz in scsi_set_sense_information - nab)

Reported-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Sagi Grimberg <sagig@mellanox.com>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Cc: Tejun Heo <tj@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/ata/libata-scsi.c
drivers/scsi/scsi_common.c
drivers/target/target_core_transport.c
include/scsi/scsi_common.h

index 3131adcc1f87e001f7f8bfe317e92527665e4dd4..2fb7c79e727f9bb62f791b97a102111c47a1833e 100644 (file)
@@ -289,7 +289,9 @@ void ata_scsi_set_sense_information(struct scsi_cmnd *cmd,
                return;
 
        information = ata_tf_read_block(tf, NULL);
-       scsi_set_sense_information(cmd->sense_buffer, information);
+       scsi_set_sense_information(cmd->sense_buffer,
+                                  SCSI_SENSE_BUFFERSIZE,
+                                  information);
 }
 
 static ssize_t
index ee6bdf43a8ea35114b6163e14910bde92c136caf..c126966130ab792b5dac44ab4a96f4c272debe66 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include <linux/errno.h>
 #include <asm/unaligned.h>
 #include <scsi/scsi_common.h>
 
@@ -249,10 +250,13 @@ EXPORT_SYMBOL(scsi_build_sense_buffer);
  * scsi_set_sense_information - set the information field in a
  *             formatted sense data buffer
  * @buf:       Where to build sense data
+ * @buf_len:    buffer length
  * @info:      64-bit information value to be set
  *
+ * Return value:
+ *     0 on success or EINVAL for invalid sense buffer length
  **/
-void scsi_set_sense_information(u8 *buf, u64 info)
+int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)
 {
        if ((buf[0] & 0x7f) == 0x72) {
                u8 *ucp, len;
@@ -263,6 +267,11 @@ void scsi_set_sense_information(u8 *buf, u64 info)
                        buf[7] = len + 0xc;
                        ucp = buf + 8 + len;
                }
+
+               if (buf_len < len + 0xc)
+                       /* Not enough room for info */
+                       return -EINVAL;
+
                ucp[0] = 0;
                ucp[1] = 0xa;
                ucp[2] = 0x80; /* Valid bit */
@@ -272,5 +281,7 @@ void scsi_set_sense_information(u8 *buf, u64 info)
                buf[0] |= 0x80;
                put_unaligned_be64(info, &buf[3]);
        }
+
+       return 0;
 }
 EXPORT_SYMBOL(scsi_set_sense_information);
index 2bece607ca0f93a4ded61bf449746d544a0fac64..7fb031bbcc8d142f6e489e912587cb1b83d83e6d 100644 (file)
@@ -2729,7 +2729,7 @@ static const struct sense_info sense_info_table[] = {
        },
 };
 
-static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason)
+static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason)
 {
        const struct sense_info *si;
        u8 *buffer = cmd->sense_buffer;
@@ -2756,7 +2756,11 @@ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason)
 
        scsi_build_sense_buffer(0, buffer, si->key, asc, ascq);
        if (si->add_sector_info)
-               scsi_set_sense_information(buffer, cmd->bad_sector);
+               return scsi_set_sense_information(buffer,
+                                                 cmd->scsi_sense_length,
+                                                 cmd->bad_sector);
+
+       return 0;
 }
 
 int
@@ -2774,10 +2778,14 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
        spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
        if (!from_transport) {
+               int rc;
+
                cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE;
-               translate_sense_reason(cmd, reason);
                cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
                cmd->scsi_sense_length  = TRANSPORT_SENSE_BUFFER;
+               rc = translate_sense_reason(cmd, reason);
+               if (rc)
+                       return rc;
        }
 
        trace_target_cmd_complete(cmd);
index 156d673db900c3c167fa4f836033c7f6ac98a54b..11571b2a831e3e7d223e7dcc17b36146d537e457 100644 (file)
@@ -62,7 +62,7 @@ extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
                                 struct scsi_sense_hdr *sshdr);
 
 extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
-extern void scsi_set_sense_information(u8 *buf, u64 info);
+int scsi_set_sense_information(u8 *buf, int buf_len, u64 info);
 extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
                                       int desc_type);