i2c: dev: Fix memory leak when underlying adapter does not support I2C

Early return in i2cdev_ioctl_rdwr() failed to free the memory allocated
by the caller. Move freeing the memory to the function where it has been
allocated to prevent similar leaks in the future.

Fixes: 97ca843f6a ("i2c: dev: Check for I2C_FUNC_I2C before calling i2c_transfer")
Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
[wsa: replaced '== NULL' with '!']
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
This commit is contained in:
Igor Pylypiv 2024-11-08 00:15:42 +00:00 committed by Wolfram Sang
parent 433c691662
commit 48730a9d04
1 changed files with 9 additions and 8 deletions

View File

@ -251,10 +251,8 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
return -EOPNOTSUPP; return -EOPNOTSUPP;
data_ptrs = kmalloc_array(nmsgs, sizeof(u8 __user *), GFP_KERNEL); data_ptrs = kmalloc_array(nmsgs, sizeof(u8 __user *), GFP_KERNEL);
if (data_ptrs == NULL) { if (!data_ptrs)
kfree(msgs);
return -ENOMEM; return -ENOMEM;
}
res = 0; res = 0;
for (i = 0; i < nmsgs; i++) { for (i = 0; i < nmsgs; i++) {
@ -302,7 +300,6 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
for (j = 0; j < i; ++j) for (j = 0; j < i; ++j)
kfree(msgs[j].buf); kfree(msgs[j].buf);
kfree(data_ptrs); kfree(data_ptrs);
kfree(msgs);
return res; return res;
} }
@ -316,7 +313,6 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
kfree(msgs[i].buf); kfree(msgs[i].buf);
} }
kfree(data_ptrs); kfree(data_ptrs);
kfree(msgs);
return res; return res;
} }
@ -446,6 +442,7 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case I2C_RDWR: { case I2C_RDWR: {
struct i2c_rdwr_ioctl_data rdwr_arg; struct i2c_rdwr_ioctl_data rdwr_arg;
struct i2c_msg *rdwr_pa; struct i2c_msg *rdwr_pa;
int res;
if (copy_from_user(&rdwr_arg, if (copy_from_user(&rdwr_arg,
(struct i2c_rdwr_ioctl_data __user *)arg, (struct i2c_rdwr_ioctl_data __user *)arg,
@ -467,7 +464,9 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (IS_ERR(rdwr_pa)) if (IS_ERR(rdwr_pa))
return PTR_ERR(rdwr_pa); return PTR_ERR(rdwr_pa);
return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); res = i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa);
kfree(rdwr_pa);
return res;
} }
case I2C_SMBUS: { case I2C_SMBUS: {
@ -540,7 +539,7 @@ static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lo
struct i2c_rdwr_ioctl_data32 rdwr_arg; struct i2c_rdwr_ioctl_data32 rdwr_arg;
struct i2c_msg32 __user *p; struct i2c_msg32 __user *p;
struct i2c_msg *rdwr_pa; struct i2c_msg *rdwr_pa;
int i; int i, res;
if (copy_from_user(&rdwr_arg, if (copy_from_user(&rdwr_arg,
(struct i2c_rdwr_ioctl_data32 __user *)arg, (struct i2c_rdwr_ioctl_data32 __user *)arg,
@ -573,7 +572,9 @@ static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lo
}; };
} }
return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); res = i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa);
kfree(rdwr_pa);
return res;
} }
case I2C_SMBUS: { case I2C_SMBUS: {
struct i2c_smbus_ioctl_data32 data32; struct i2c_smbus_ioctl_data32 data32;