scsi: sg: check for valid direction before starting the request
Check for a valid direction before starting the request, otherwise we risk running into an assertion in the scsi midlayer checking for valid requests. [mkp: fixed typo] Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de> Link: http://www.spinics.net/lists/linux-scsi/msg104400.html Reported-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Hannes Reinecke <hare@suse.com> Tested-by: Johannes Thumshirn <jthumshirn@suse.de> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
1bc0eb0446
commit
28676d869b
|
@ -663,18 +663,14 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
|
||||||
* is a non-zero input_size, so emit a warning.
|
* is a non-zero input_size, so emit a warning.
|
||||||
*/
|
*/
|
||||||
if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
|
if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
|
||||||
static char cmd[TASK_COMM_LEN];
|
printk_ratelimited(KERN_WARNING
|
||||||
if (strcmp(current->comm, cmd)) {
|
"sg_write: data in/out %d/%d bytes "
|
||||||
printk_ratelimited(KERN_WARNING
|
"for SCSI command 0x%x-- guessing "
|
||||||
"sg_write: data in/out %d/%d bytes "
|
"data in;\n program %s not setting "
|
||||||
"for SCSI command 0x%x-- guessing "
|
"count and/or reply_len properly\n",
|
||||||
"data in;\n program %s not setting "
|
old_hdr.reply_len - (int)SZ_SG_HEADER,
|
||||||
"count and/or reply_len properly\n",
|
input_size, (unsigned int) cmnd[0],
|
||||||
old_hdr.reply_len - (int)SZ_SG_HEADER,
|
current->comm);
|
||||||
input_size, (unsigned int) cmnd[0],
|
|
||||||
current->comm);
|
|
||||||
strcpy(cmd, current->comm);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
|
k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
|
||||||
return (k < 0) ? k : count;
|
return (k < 0) ? k : count;
|
||||||
|
@ -753,6 +749,29 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
|
||||||
|
{
|
||||||
|
switch (hp->dxfer_direction) {
|
||||||
|
case SG_DXFER_NONE:
|
||||||
|
if (hp->dxferp || hp->dxfer_len > 0)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
case SG_DXFER_TO_DEV:
|
||||||
|
case SG_DXFER_FROM_DEV:
|
||||||
|
case SG_DXFER_TO_FROM_DEV:
|
||||||
|
if (!hp->dxferp || hp->dxfer_len == 0)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
case SG_DXFER_UNKNOWN:
|
||||||
|
if ((!hp->dxferp && hp->dxfer_len) ||
|
||||||
|
(hp->dxferp && hp->dxfer_len == 0))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sg_common_write(Sg_fd * sfp, Sg_request * srp,
|
sg_common_write(Sg_fd * sfp, Sg_request * srp,
|
||||||
unsigned char *cmnd, int timeout, int blocking)
|
unsigned char *cmnd, int timeout, int blocking)
|
||||||
|
@ -773,6 +792,9 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
|
||||||
"sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n",
|
"sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n",
|
||||||
(int) cmnd[0], (int) hp->cmd_len));
|
(int) cmnd[0], (int) hp->cmd_len));
|
||||||
|
|
||||||
|
if (!sg_is_valid_dxfer(hp))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
k = sg_start_req(srp, cmnd);
|
k = sg_start_req(srp, cmnd);
|
||||||
if (k) {
|
if (k) {
|
||||||
SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
|
SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
|
||||||
|
|
Loading…
Reference in a new issue