mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-12-30 01:46:30 -05:00
165 lines
5.6 KiB
Plaintext
165 lines
5.6 KiB
Plaintext
From 47b3a105cc4cec0d912345d27d9743b97691b21c Mon Sep 17 00:00:00 2001
|
|
From: Robb Glasser <rglasser@google.com>
|
|
Date: Fri, 24 Mar 2017 16:23:37 -0700
|
|
Subject: [PATCH] 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>
|
|
---
|
|
drivers/scsi/sg.c | 34 ++++++++++++++++++++--------------
|
|
1 file changed, 20 insertions(+), 14 deletions(-)
|
|
|
|
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
|
|
index 721d839d6c543..9a600f05ab57a 100644
|
|
--- a/drivers/scsi/sg.c
|
|
+++ b/drivers/scsi/sg.c
|
|
@@ -486,7 +486,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:
|
|
@@ -832,8 +832,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,
|
|
@@ -873,8 +875,10 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
|
|
sfp->low_dma = 1;
|
|
if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
|
|
val = (int) sfp->reserve.bufflen;
|
|
+ mutex_lock(&sfp->parentdp->open_rel_lock);
|
|
sg_remove_scat(&sfp->reserve);
|
|
sg_build_reserve(sfp, val);
|
|
+ mutex_unlock(&sfp->parentdp->open_rel_lock);
|
|
}
|
|
} else {
|
|
if (sdp->detached)
|
|
@@ -942,15 +946,17 @@ 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,
|
|
queue_max_sectors(sdp->device->request_queue) * 512);
|
|
if (val != sfp->reserve.bufflen) {
|
|
if (sg_res_in_use(sfp) || sfp->mmap_called)
|
|
return -EBUSY;
|
|
+ mutex_lock(&sfp->parentdp->open_rel_lock);
|
|
sg_remove_scat(&sfp->reserve);
|
|
sg_build_reserve(sfp, val);
|
|
+ mutex_unlock(&sfp->parentdp->open_rel_lock);
|
|
}
|
|
return 0;
|
|
case SG_GET_RESERVED_SIZE:
|
|
@@ -1003,8 +1009,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
|
|
if (srp) {
|
|
rinfo[val].req_state = srp->done + 1;
|
|
rinfo[val].problem =
|
|
- srp->header.masked_status &
|
|
- srp->header.host_status &
|
|
+ srp->header.masked_status &
|
|
+ srp->header.host_status &
|
|
srp->header.driver_status;
|
|
if (srp->done)
|
|
rinfo[val].duration =
|
|
@@ -1025,7 +1031,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
|
|
}
|
|
}
|
|
read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
|
|
- result = __copy_to_user(p, rinfo,
|
|
+ result = __copy_to_user(p, rinfo,
|
|
SZ_SG_REQ_INFO * SG_MAX_QUEUE);
|
|
result = result ? -EFAULT : 0;
|
|
kfree(rinfo);
|
|
@@ -1127,14 +1133,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
|
|
@@ -1594,7 +1600,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;
|
|
@@ -2234,7 +2240,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,
|
|
@@ -2374,7 +2380,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)
|
|
{
|
|
@@ -2395,7 +2401,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)
|
|
{
|
|
@@ -2552,7 +2558,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
|
|
hp = &srp->header;
|
|
new_interface = (hp->interface_id == '\0') ? 0 : 1;
|
|
if (srp->res_used) {
|
|
- if (new_interface &&
|
|
+ if (new_interface &&
|
|
(SG_FLAG_MMAP_IO & hp->flags))
|
|
cp = " mmap>> ";
|
|
else
|
|
@@ -2566,7 +2572,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
|
|
seq_printf(s, cp);
|
|
blen = srp->data.bufflen;
|
|
usg = srp->data.k_use_sg;
|
|
- seq_printf(s, srp->done ?
|
|
+ seq_printf(s, srp->done ?
|
|
((1 == srp->done) ? "rcv:" : "fin:")
|
|
: "act:");
|
|
seq_printf(s, " id=%d blen=%d",
|