aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSagi Grimberg <sagig@mellanox.com>2015-07-15 03:55:37 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2015-07-24 01:53:05 -0400
commitf5a8b3a796db01b639435515b3adc003b9f27387 (patch)
tree3ff4e026ec2af94cbef2cef9d365a5faf141059c
parent12306b425d0dbab7b60f54e02d67cf3dfae494d1 (diff)
scsi: Protect against buffer possible overflow in scsi_set_sense_information
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>
-rw-r--r--drivers/ata/libata-scsi.c4
-rw-r--r--drivers/scsi/scsi_common.c13
-rw-r--r--drivers/target/target_core_transport.c14
-rw-r--r--include/scsi/scsi_common.h2
4 files changed, 27 insertions, 6 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 3131adcc1f87..2fb7c79e727f 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -289,7 +289,9 @@ void ata_scsi_set_sense_information(struct scsi_cmnd *cmd,
289 return; 289 return;
290 290
291 information = ata_tf_read_block(tf, NULL); 291 information = ata_tf_read_block(tf, NULL);
292 scsi_set_sense_information(cmd->sense_buffer, information); 292 scsi_set_sense_information(cmd->sense_buffer,
293 SCSI_SENSE_BUFFERSIZE,
294 information);
293} 295}
294 296
295static ssize_t 297static ssize_t
diff --git a/drivers/scsi/scsi_common.c b/drivers/scsi/scsi_common.c
index ee6bdf43a8ea..c126966130ab 100644
--- a/drivers/scsi/scsi_common.c
+++ b/drivers/scsi/scsi_common.c
@@ -5,6 +5,7 @@
5#include <linux/bug.h> 5#include <linux/bug.h>
6#include <linux/kernel.h> 6#include <linux/kernel.h>
7#include <linux/string.h> 7#include <linux/string.h>
8#include <linux/errno.h>
8#include <asm/unaligned.h> 9#include <asm/unaligned.h>
9#include <scsi/scsi_common.h> 10#include <scsi/scsi_common.h>
10 11
@@ -249,10 +250,13 @@ EXPORT_SYMBOL(scsi_build_sense_buffer);
249 * scsi_set_sense_information - set the information field in a 250 * scsi_set_sense_information - set the information field in a
250 * formatted sense data buffer 251 * formatted sense data buffer
251 * @buf: Where to build sense data 252 * @buf: Where to build sense data
253 * @buf_len: buffer length
252 * @info: 64-bit information value to be set 254 * @info: 64-bit information value to be set
253 * 255 *
256 * Return value:
257 * 0 on success or EINVAL for invalid sense buffer length
254 **/ 258 **/
255void scsi_set_sense_information(u8 *buf, u64 info) 259int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)
256{ 260{
257 if ((buf[0] & 0x7f) == 0x72) { 261 if ((buf[0] & 0x7f) == 0x72) {
258 u8 *ucp, len; 262 u8 *ucp, len;
@@ -263,6 +267,11 @@ void scsi_set_sense_information(u8 *buf, u64 info)
263 buf[7] = len + 0xc; 267 buf[7] = len + 0xc;
264 ucp = buf + 8 + len; 268 ucp = buf + 8 + len;
265 } 269 }
270
271 if (buf_len < len + 0xc)
272 /* Not enough room for info */
273 return -EINVAL;
274
266 ucp[0] = 0; 275 ucp[0] = 0;
267 ucp[1] = 0xa; 276 ucp[1] = 0xa;
268 ucp[2] = 0x80; /* Valid bit */ 277 ucp[2] = 0x80; /* Valid bit */
@@ -272,5 +281,7 @@ void scsi_set_sense_information(u8 *buf, u64 info)
272 buf[0] |= 0x80; 281 buf[0] |= 0x80;
273 put_unaligned_be64(info, &buf[3]); 282 put_unaligned_be64(info, &buf[3]);
274 } 283 }
284
285 return 0;
275} 286}
276EXPORT_SYMBOL(scsi_set_sense_information); 287EXPORT_SYMBOL(scsi_set_sense_information);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 2bece607ca0f..7fb031bbcc8d 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -2729,7 +2729,7 @@ static const struct sense_info sense_info_table[] = {
2729 }, 2729 },
2730}; 2730};
2731 2731
2732static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) 2732static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason)
2733{ 2733{
2734 const struct sense_info *si; 2734 const struct sense_info *si;
2735 u8 *buffer = cmd->sense_buffer; 2735 u8 *buffer = cmd->sense_buffer;
@@ -2756,7 +2756,11 @@ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason)
2756 2756
2757 scsi_build_sense_buffer(0, buffer, si->key, asc, ascq); 2757 scsi_build_sense_buffer(0, buffer, si->key, asc, ascq);
2758 if (si->add_sector_info) 2758 if (si->add_sector_info)
2759 scsi_set_sense_information(buffer, cmd->bad_sector); 2759 return scsi_set_sense_information(buffer,
2760 cmd->scsi_sense_length,
2761 cmd->bad_sector);
2762
2763 return 0;
2760} 2764}
2761 2765
2762int 2766int
@@ -2774,10 +2778,14 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
2774 spin_unlock_irqrestore(&cmd->t_state_lock, flags); 2778 spin_unlock_irqrestore(&cmd->t_state_lock, flags);
2775 2779
2776 if (!from_transport) { 2780 if (!from_transport) {
2781 int rc;
2782
2777 cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; 2783 cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE;
2778 translate_sense_reason(cmd, reason);
2779 cmd->scsi_status = SAM_STAT_CHECK_CONDITION; 2784 cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
2780 cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; 2785 cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER;
2786 rc = translate_sense_reason(cmd, reason);
2787 if (rc)
2788 return rc;
2781 } 2789 }
2782 2790
2783 trace_target_cmd_complete(cmd); 2791 trace_target_cmd_complete(cmd);
diff --git a/include/scsi/scsi_common.h b/include/scsi/scsi_common.h
index 156d673db900..11571b2a831e 100644
--- a/include/scsi/scsi_common.h
+++ b/include/scsi/scsi_common.h
@@ -62,7 +62,7 @@ extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
62 struct scsi_sense_hdr *sshdr); 62 struct scsi_sense_hdr *sshdr);
63 63
64extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); 64extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
65extern void scsi_set_sense_information(u8 *buf, u64 info); 65int scsi_set_sense_information(u8 *buf, int buf_len, u64 info);
66extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, 66extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
67 int desc_type); 67 int desc_type);
68 68