summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2016-03-03 00:31:29 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2016-03-09 20:41:04 -0500
commit5ecee0a3ee8d74b6950cb41e8989b0c2174568d4 (patch)
tree77fcc7b053e805dbb4e726fefb031ee21175fdee
parentff06c5ffbcb4ffa542fb80c897be977956fafecc (diff)
downloadlinux-5ecee0a3ee8d74b6950cb41e8989b0c2174568d4.tar.bz2
sg: fix dxferp in from_to case
One of the strange things that the original sg driver did was let the user provide both a data-out buffer (it followed the sg_header+cdb) _and_ specify a reply length greater than zero. What happened was that the user data-out buffer was copied into some kernel buffers and then the mid level was told a read type operation would take place with the data from the device overwriting the same kernel buffers. The user would then read those kernel buffers back into the user space. From what I can tell, the above action was broken by commit fad7f01e61bf ("sg: set dxferp to NULL for READ with the older SG interface") in 2008 and syzkaller found that out recently. Make sure that a user space pointer is passed through when data follows the sg_header structure and command. Fix the abnormal case when a non-zero reply_len is also given. Fixes: fad7f01e61bf737fe8a3740d803f000db57ecac6 Cc: <stable@vger.kernel.org> #v2.6.28+ Signed-off-by: Douglas Gilbert <dgilbert@interlog.com> Reviewed-by: Ewan Milne <emilne@redhat.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/sg.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 5e820674432c..ae7d9bdf409c 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -652,7 +652,8 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
else
hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
hp->dxfer_len = mxsize;
- if (hp->dxfer_direction == SG_DXFER_TO_DEV)
+ if ((hp->dxfer_direction == SG_DXFER_TO_DEV) ||
+ (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV))
hp->dxferp = (char __user *)buf + cmd_size;
else
hp->dxferp = NULL;