Skip to content

Commit

Permalink
scsi: Protect against buffer possible overflow in scsi_set_sense_info…
Browse files Browse the repository at this point in the history
…rmation

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 <[email protected]>
Signed-off-by: Sagi Grimberg <[email protected]>
Reviewed-by: Martin K. Petersen <[email protected]>
Cc: Tejun Heo <[email protected]>
Reviewed-by: Christoph Hellwig <[email protected]>
Signed-off-by: Nicholas Bellinger <[email protected]>
  • Loading branch information
Sagi Grimberg authored and Nicholas Bellinger committed Jul 24, 2015
1 parent 12306b4 commit f5a8b3a
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 6 deletions.
4 changes: 3 additions & 1 deletion drivers/ata/libata-scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 12 additions & 1 deletion drivers/scsi/scsi_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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;
Expand All @@ -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 */
Expand All @@ -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);
14 changes: 11 additions & 3 deletions drivers/target/target_core_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion include/scsi/scsi_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit f5a8b3a

Please sign in to comment.