Commit f5a8b3a7 authored by Sagi Grimberg's avatar Sagi Grimberg Committed by Nicholas Bellinger

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: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarSagi Grimberg <sagig@mellanox.com>
Reviewed-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Cc: Tejun Heo <tj@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 12306b42
...@@ -289,7 +289,9 @@ void ata_scsi_set_sense_information(struct scsi_cmnd *cmd, ...@@ -289,7 +289,9 @@ void ata_scsi_set_sense_information(struct scsi_cmnd *cmd,
return; return;
information = ata_tf_read_block(tf, NULL); 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 static ssize_t
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/errno.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <scsi/scsi_common.h> #include <scsi/scsi_common.h>
...@@ -249,10 +250,13 @@ EXPORT_SYMBOL(scsi_build_sense_buffer); ...@@ -249,10 +250,13 @@ EXPORT_SYMBOL(scsi_build_sense_buffer);
* scsi_set_sense_information - set the information field in a * scsi_set_sense_information - set the information field in a
* formatted sense data buffer * formatted sense data buffer
* @buf: Where to build sense data * @buf: Where to build sense data
* @buf_len: buffer length
* @info: 64-bit information value to be set * @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) { if ((buf[0] & 0x7f) == 0x72) {
u8 *ucp, len; u8 *ucp, len;
...@@ -263,6 +267,11 @@ void scsi_set_sense_information(u8 *buf, u64 info) ...@@ -263,6 +267,11 @@ void scsi_set_sense_information(u8 *buf, u64 info)
buf[7] = len + 0xc; buf[7] = len + 0xc;
ucp = buf + 8 + len; ucp = buf + 8 + len;
} }
if (buf_len < len + 0xc)
/* Not enough room for info */
return -EINVAL;
ucp[0] = 0; ucp[0] = 0;
ucp[1] = 0xa; ucp[1] = 0xa;
ucp[2] = 0x80; /* Valid bit */ ucp[2] = 0x80; /* Valid bit */
...@@ -272,5 +281,7 @@ void scsi_set_sense_information(u8 *buf, u64 info) ...@@ -272,5 +281,7 @@ void scsi_set_sense_information(u8 *buf, u64 info)
buf[0] |= 0x80; buf[0] |= 0x80;
put_unaligned_be64(info, &buf[3]); put_unaligned_be64(info, &buf[3]);
} }
return 0;
} }
EXPORT_SYMBOL(scsi_set_sense_information); EXPORT_SYMBOL(scsi_set_sense_information);
...@@ -2729,7 +2729,7 @@ static const struct sense_info sense_info_table[] = { ...@@ -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; const struct sense_info *si;
u8 *buffer = cmd->sense_buffer; u8 *buffer = cmd->sense_buffer;
...@@ -2756,7 +2756,11 @@ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) ...@@ -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); scsi_build_sense_buffer(0, buffer, si->key, asc, ascq);
if (si->add_sector_info) 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 int
...@@ -2774,10 +2778,14 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, ...@@ -2774,10 +2778,14 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
spin_unlock_irqrestore(&cmd->t_state_lock, flags); spin_unlock_irqrestore(&cmd->t_state_lock, flags);
if (!from_transport) { if (!from_transport) {
int rc;
cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE;
translate_sense_reason(cmd, reason);
cmd->scsi_status = SAM_STAT_CHECK_CONDITION; cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER;
rc = translate_sense_reason(cmd, reason);
if (rc)
return rc;
} }
trace_target_cmd_complete(cmd); trace_target_cmd_complete(cmd);
......
...@@ -62,7 +62,7 @@ extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len, ...@@ -62,7 +62,7 @@ extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
struct scsi_sense_hdr *sshdr); struct scsi_sense_hdr *sshdr);
extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); 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, extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
int desc_type); int desc_type);
......
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