diff options
author | Robb Glasser <rglasser@google.com> | 2017-03-24 16:23:37 -0700 |
---|---|---|
committer | Sayali Lokhande <sayalil@codeaurora.org> | 2017-11-14 18:46:51 +0530 |
commit | 36f332c5664ec2119211f7d9eb39d0b0f230b7a2 (patch) | |
tree | ca104e1310935ad77fe6c33a42c2907be3d69e29 /drivers/scsi/sg.c | |
parent | f2170a291768f24d6220c95386ef0b2f821a5495 (diff) |
Prevent potential double frees in sg driver
sg_ioctl could be spammed by requests, leading to a double free in
__free_pages. This protects the entry points of sg_ioctl where the
memory could be corrupted by a double call to __free_pages if multiple
requests are happening concurrently.
Bug:35644812
Change-Id: Ie13f65beb6974430f90292e2742841b26aecb8b1
Signed-off-by: Robb Glasser <rglasser@google.com>
Git-commit: 22d8e80738b5ce8784d59b48b0b051a520da4bec
Git-repo: https://android.googlesource.com/kernel/msm
[srkupp@codeaurora.org: Resolved trivial conflicts]
Signed-off-by: Srinivasa Rao Kuppala <srkupp@codeaurora.org>
Signed-off-by: Sayali Lokhande <sayalil@codeaurora.org>
Diffstat (limited to 'drivers/scsi/sg.c')
-rw-r--r-- | drivers/scsi/sg.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index b0e2e292e3cb..bb6518159d12 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -510,7 +510,7 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) old_hdr->result = EIO; break; case DID_ERROR: - old_hdr->result = (srp->sense_b[0] == 0 && + old_hdr->result = (srp->sense_b[0] == 0 && hp->masked_status == GOOD) ? 0 : EIO; break; default: @@ -898,8 +898,10 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) return -ENXIO; if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR)) return -EFAULT; + mutex_lock(&sfp->parentdp->open_rel_lock); result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR, 1, read_only, 1, &srp); + mutex_unlock(&sfp->parentdp->open_rel_lock); if (result < 0) return result; result = wait_event_interruptible(sfp->read_wait, @@ -939,8 +941,10 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) sfp->low_dma = 1; if ((0 == sfp->low_dma) && !sfp->res_in_use) { val = (int) sfp->reserve.bufflen; + mutex_lock(&sfp->parentdp->open_rel_lock); sg_remove_scat(sfp, &sfp->reserve); sg_build_reserve(sfp, val); + mutex_unlock(&sfp->parentdp->open_rel_lock); } } else { if (atomic_read(&sdp->detaching)) @@ -1009,8 +1013,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) result = get_user(val, ip); if (result) return result; - if (val < 0) - return -EINVAL; + if (val < 0) + return -EINVAL; val = min_t(int, val, max_sectors_bytes(sdp->device->request_queue)); mutex_lock(&sfp->f_mutex); @@ -1020,9 +1024,10 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) mutex_unlock(&sfp->f_mutex); return -EBUSY; } - + mutex_lock(&sfp->parentdp->open_rel_lock); sg_remove_scat(sfp, &sfp->reserve); sg_build_reserve(sfp, val); + mutex_unlock(&sfp->parentdp->open_rel_lock); } mutex_unlock(&sfp->f_mutex); return 0; @@ -1149,14 +1154,14 @@ static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned lon return -ENXIO; sdev = sdp->device; - if (sdev->host->hostt->compat_ioctl) { + if (sdev->host->hostt->compat_ioctl) { int ret; ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg); return ret; } - + return -ENOIOCTLCMD; } #endif @@ -1646,7 +1651,7 @@ init_sg(void) else def_reserved_size = sg_big_buff; - rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), + rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS, "sg"); if (rc) return rc; @@ -2304,7 +2309,7 @@ static const struct file_operations adio_fops = { }; static int sg_proc_single_open_dressz(struct inode *inode, struct file *file); -static ssize_t sg_proc_write_dressz(struct file *filp, +static ssize_t sg_proc_write_dressz(struct file *filp, const char __user *buffer, size_t count, loff_t *off); static const struct file_operations dressz_fops = { .owner = THIS_MODULE, @@ -2444,7 +2449,7 @@ static int sg_proc_single_open_adio(struct inode *inode, struct file *file) return single_open(file, sg_proc_seq_show_int, &sg_allow_dio); } -static ssize_t +static ssize_t sg_proc_write_adio(struct file *filp, const char __user *buffer, size_t count, loff_t *off) { @@ -2465,7 +2470,7 @@ static int sg_proc_single_open_dressz(struct inode *inode, struct file *file) return single_open(file, sg_proc_seq_show_int, &sg_big_buff); } -static ssize_t +static ssize_t sg_proc_write_dressz(struct file *filp, const char __user *buffer, size_t count, loff_t *off) { @@ -2640,6 +2645,9 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) seq_puts(s, srp->done ? ((1 == srp->done) ? "rcv:" : "fin:") : "act:"); + seq_printf(s, srp->done ? + ((1 == srp->done) ? "rcv:" : "fin:") + : "act:"); seq_printf(s, " id=%d blen=%d", srp->header.pack_id, blen); if (srp->done) |