Commit a4745635 authored by Jean Delvare's avatar Jean Delvare Committed by Tom Rini

[PATCH] i2c: user/kernel bug and memory leak in i2c-dev

parent e7a4f368
......@@ -181,6 +181,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
struct i2c_smbus_ioctl_data data_arg;
union i2c_smbus_data temp;
struct i2c_msg *rdwr_pa;
u8 **data_ptrs;
int i,datasize,res;
unsigned long funcs;
......@@ -214,7 +215,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
return (copy_to_user((unsigned long __user *)arg, &funcs,
sizeof(unsigned long)))?-EFAULT:0;
case I2C_RDWR:
case I2C_RDWR:
if (copy_from_user(&rdwr_arg,
(struct i2c_rdwr_ioctl_data __user *)arg,
sizeof(rdwr_arg)))
......@@ -231,28 +232,37 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
if (rdwr_pa == NULL) return -ENOMEM;
if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
kfree(rdwr_pa);
return -EFAULT;
}
data_ptrs = (u8 **) kmalloc(rdwr_arg.nmsgs * sizeof(u8 *),
GFP_KERNEL);
if (data_ptrs == NULL) {
kfree(rdwr_pa);
return -ENOMEM;
}
res = 0;
for( i=0; i<rdwr_arg.nmsgs; i++ ) {
if(copy_from_user(&(rdwr_pa[i]),
&(rdwr_arg.msgs[i]),
sizeof(rdwr_pa[i]))) {
res = -EFAULT;
break;
}
/* Limit the size of the message to a sane amount */
if (rdwr_pa[i].len > 8192) {
res = -EINVAL;
break;
}
data_ptrs[i] = rdwr_pa[i].buf;
rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
if(rdwr_pa[i].buf == NULL) {
res = -ENOMEM;
break;
}
if(copy_from_user(rdwr_pa[i].buf,
rdwr_arg.msgs[i].buf,
data_ptrs[i],
rdwr_pa[i].len)) {
res = -EFAULT;
++i; /* Needs to be kfreed too */
res = -EFAULT;
break;
}
}
......@@ -260,18 +270,18 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
int j;
for (j = 0; j < i; ++j)
kfree(rdwr_pa[j].buf);
kfree(data_ptrs);
kfree(rdwr_pa);
return res;
}
if (!res) {
res = i2c_transfer(client->adapter,
rdwr_pa,
rdwr_arg.nmsgs);
}
res = i2c_transfer(client->adapter,
rdwr_pa,
rdwr_arg.nmsgs);
while(i-- > 0) {
if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) {
if(copy_to_user(
rdwr_arg.msgs[i].buf,
data_ptrs[i],
rdwr_pa[i].buf,
rdwr_pa[i].len)) {
res = -EFAULT;
......@@ -279,6 +289,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
}
kfree(rdwr_pa[i].buf);
}
kfree(data_ptrs);
kfree(rdwr_pa);
return res;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment