Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28676d86 authored by Johannes Thumshirn's avatar Johannes Thumshirn Committed by Martin K. Petersen
Browse files

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: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Link: http://www.spinics.net/lists/linux-scsi/msg104400.html


Reported-by: default avatarDmitry Vyukov <dvyukov@google.com>
Signed-off-by: default avatarHannes Reinecke <hare@suse.com>
Tested-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 1bc0eb04
Loading
Loading
Loading
Loading
+34 −12
Original line number Diff line number Diff line
@@ -663,8 +663,6 @@ 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.
	 */
	if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
		static char cmd[TASK_COMM_LEN];
		if (strcmp(current->comm, cmd)) {
		printk_ratelimited(KERN_WARNING
				   "sg_write: data in/out %d/%d bytes "
				   "for SCSI command 0x%x-- guessing "
@@ -673,8 +671,6 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
				   old_hdr.reply_len - (int)SZ_SG_HEADER,
				   input_size, (unsigned int) cmnd[0],
				   current->comm);
			strcpy(cmd, current->comm);
		}
	}
	k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
	return (k < 0) ? k : count;
@@ -753,6 +749,29 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
	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
sg_common_write(Sg_fd * sfp, Sg_request * srp,
		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",
			(int) cmnd[0], (int) hp->cmd_len));

	if (!sg_is_valid_dxfer(hp))
		return -EINVAL;

	k = sg_start_req(srp, cmnd);
	if (k) {
		SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,