aboutsummaryrefslogtreecommitdiff
path: root/drivers/message/i2o/i2o_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/message/i2o/i2o_config.c')
-rw-r--r--drivers/message/i2o/i2o_config.c96
1 files changed, 53 insertions, 43 deletions
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index efba7021948..04bd3b6de40 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -31,8 +31,9 @@
*/
#include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/compat.h>
+#include <linux/slab.h>
#include <asm/uaccess.h>
@@ -40,8 +41,8 @@
#define SG_TABLESIZE 30
-static int i2o_cfg_ioctl(struct inode *, struct file *, unsigned int,
- unsigned long);
+static DEFINE_MUTEX(i2o_cfg_mutex);
+static long i2o_cfg_ioctl(struct file *, unsigned int, unsigned long);
static spinlock_t i2o_config_lock;
@@ -111,11 +112,11 @@ static int i2o_cfg_gethrt(unsigned long arg)
len = 8 + ((hrt->entry_len * hrt->num_entries) << 2);
- /* We did a get user...so assuming mem is ok...is this bad? */
- put_user(len, kcmd.reslen);
- if (len > reslen)
+ if (put_user(len, kcmd.reslen))
+ ret = -EFAULT;
+ else if (len > reslen)
ret = -ENOBUFS;
- if (copy_to_user(kcmd.resbuf, (void *)hrt, len))
+ else if (copy_to_user(kcmd.resbuf, (void *)hrt, len))
ret = -EFAULT;
return ret;
@@ -147,8 +148,9 @@ static int i2o_cfg_getlct(unsigned long arg)
lct = (i2o_lct *) c->lct;
len = (unsigned int)lct->table_size << 2;
- put_user(len, kcmd.reslen);
- if (len > reslen)
+ if (put_user(len, kcmd.reslen))
+ ret = -EFAULT;
+ else if (len > reslen)
ret = -ENOBUFS;
else if (copy_to_user(kcmd.resbuf, lct, len))
ret = -EFAULT;
@@ -186,14 +188,16 @@ static int i2o_cfg_parms(unsigned long arg, unsigned int type)
if (!dev)
return -ENXIO;
- ops = kmalloc(kcmd.oplen, GFP_KERNEL);
- if (!ops)
- return -ENOMEM;
+ /*
+ * Stop users being able to try and allocate arbitrary amounts
+ * of DMA space. 64K is way more than sufficient for this.
+ */
+ if (kcmd.oplen > 65536)
+ return -EMSGSIZE;
- if (copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) {
- kfree(ops);
- return -EFAULT;
- }
+ ops = memdup_user(kcmd.opbuf, kcmd.oplen);
+ if (IS_ERR(ops))
+ return PTR_ERR(ops);
/*
* It's possible to have a _very_ large table
@@ -213,8 +217,9 @@ static int i2o_cfg_parms(unsigned long arg, unsigned int type)
return -EAGAIN;
}
- put_user(len, kcmd.reslen);
- if (len > reslen)
+ if (put_user(len, kcmd.reslen))
+ ret = -EFAULT;
+ else if (len > reslen)
ret = -ENOBUFS;
else if (copy_to_user(kcmd.resbuf, res, len))
ret = -EFAULT;
@@ -314,22 +319,22 @@ static int i2o_cfg_swul(unsigned long arg)
int ret = 0;
if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
- goto return_fault;
+ return -EFAULT;
if (get_user(swlen, kxfer.swlen) < 0)
- goto return_fault;
+ return -EFAULT;
if (get_user(maxfrag, kxfer.maxfrag) < 0)
- goto return_fault;
+ return -EFAULT;
if (get_user(curfrag, kxfer.curfrag) < 0)
- goto return_fault;
+ return -EFAULT;
if (curfrag == maxfrag)
fragsize = swlen - (maxfrag - 1) * 8192;
if (!kxfer.buf)
- goto return_fault;
+ return -EFAULT;
c = i2o_find_iop(kxfer.iop);
if (!c)
@@ -373,12 +378,8 @@ static int i2o_cfg_swul(unsigned long arg)
i2o_dma_free(&c->pdev->dev, &buffer);
- return_ret:
return ret;
- return_fault:
- ret = -EFAULT;
- goto return_ret;
-};
+}
static int i2o_cfg_swdel(unsigned long arg)
{
@@ -686,6 +687,11 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
}
size = size >> 16;
size *= 4;
+ if (size > sizeof(rmsg)) {
+ rcode = -EINVAL;
+ goto sg_list_cleanup;
+ }
+
/* Copy in the user's I2O command */
if (copy_from_user(rmsg, user_msg, size)) {
rcode = -EFAULT;
@@ -748,19 +754,19 @@ static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd,
unsigned long arg)
{
int ret;
- lock_kernel();
switch (cmd) {
case I2OGETIOPS:
- ret = i2o_cfg_ioctl(NULL, file, cmd, arg);
+ ret = i2o_cfg_ioctl(file, cmd, arg);
break;
case I2OPASSTHRU32:
+ mutex_lock(&i2o_cfg_mutex);
ret = i2o_cfg_passthru32(file, cmd, arg);
+ mutex_unlock(&i2o_cfg_mutex);
break;
default:
ret = -ENOIOCTLCMD;
break;
}
- unlock_kernel();
return ret;
}
@@ -921,6 +927,11 @@ static int i2o_cfg_passthru(unsigned long arg)
}
size = size >> 16;
size *= 4;
+ if (size > sizeof(rmsg)) {
+ rcode = -EFAULT;
+ goto sg_list_cleanup;
+ }
+
/* Copy in the user's I2O command */
if (copy_from_user(rmsg, user_msg, size)) {
rcode = -EFAULT;
@@ -984,11 +995,11 @@ out:
/*
* IOCTL Handler
*/
-static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
- unsigned long arg)
+static long i2o_cfg_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
int ret;
+ mutex_lock(&i2o_cfg_mutex);
switch (cmd) {
case I2OGETIOPS:
ret = i2o_cfg_getiops(arg);
@@ -1044,21 +1055,20 @@ static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
osm_debug("unknown ioctl called!\n");
ret = -EINVAL;
}
-
+ mutex_unlock(&i2o_cfg_mutex);
return ret;
}
static int cfg_open(struct inode *inode, struct file *file)
{
- struct i2o_cfg_info *tmp =
- (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info),
+ struct i2o_cfg_info *tmp = kmalloc(sizeof(struct i2o_cfg_info),
GFP_KERNEL);
unsigned long flags;
if (!tmp)
return -ENOMEM;
- lock_kernel();
+ mutex_lock(&i2o_cfg_mutex);
file->private_data = (void *)(i2o_cfg_info_id++);
tmp->fp = file;
tmp->fasync = NULL;
@@ -1072,7 +1082,7 @@ static int cfg_open(struct inode *inode, struct file *file)
spin_lock_irqsave(&i2o_config_lock, flags);
open_files = tmp;
spin_unlock_irqrestore(&i2o_config_lock, flags);
- unlock_kernel();
+ mutex_unlock(&i2o_cfg_mutex);
return 0;
}
@@ -1083,14 +1093,14 @@ static int cfg_fasync(int fd, struct file *fp, int on)
struct i2o_cfg_info *p;
int ret = -EBADF;
- lock_kernel();
+ mutex_lock(&i2o_cfg_mutex);
for (p = open_files; p; p = p->next)
if (p->q_id == id)
break;
if (p)
ret = fasync_helper(fd, fp, on, &p->fasync);
- unlock_kernel();
+ mutex_unlock(&i2o_cfg_mutex);
return ret;
}
@@ -1100,7 +1110,7 @@ static int cfg_release(struct inode *inode, struct file *file)
struct i2o_cfg_info *p, **q;
unsigned long flags;
- lock_kernel();
+ mutex_lock(&i2o_cfg_mutex);
spin_lock_irqsave(&i2o_config_lock, flags);
for (q = &open_files; (p = *q) != NULL; q = &p->next) {
if (p->q_id == id) {
@@ -1110,7 +1120,7 @@ static int cfg_release(struct inode *inode, struct file *file)
}
}
spin_unlock_irqrestore(&i2o_config_lock, flags);
- unlock_kernel();
+ mutex_unlock(&i2o_cfg_mutex);
return 0;
}
@@ -1118,7 +1128,7 @@ static int cfg_release(struct inode *inode, struct file *file)
static const struct file_operations config_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
- .ioctl = i2o_cfg_ioctl,
+ .unlocked_ioctl = i2o_cfg_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = i2o_cfg_compat_ioctl,
#endif