Commit 8b1ef6f5 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] i2c compat ioctl breakage

do_i2c_rdwr_ioctl() does two compat_alloc_user_space().  That doesn't
work; no state is kept and second allocation will ignore the first one
(i.e.  give overlapping chunk of user stack).

Fixed by doing allocation at once, slightly cleaned up.
Signed-off-by: default avatarAl Viro <viro@parcelfarce.linux.theplanet.co.uk>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 4e979b18
......@@ -2848,48 +2848,42 @@ struct i2c_smbus_ioctl_data32 {
compat_caddr_t data; /* union i2c_smbus_data *data */
};
struct i2c_rdwr_aligned {
struct i2c_rdwr_ioctl_data cmd;
struct i2c_msg msgs[0];
};
static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct i2c_rdwr_ioctl_data __user *tdata;
struct i2c_rdwr_ioctl_data32 __user *udata;
struct i2c_rdwr_ioctl_data32 __user *udata = compat_ptr(arg);
struct i2c_rdwr_aligned __user *tdata;
struct i2c_msg __user *tmsgs;
struct i2c_msg32 __user *umsgs;
compat_caddr_t datap;
int nmsgs, i;
tdata = compat_alloc_user_space(sizeof(*tdata));
if (tdata == NULL)
return -ENOMEM;
if (verify_area(VERIFY_WRITE, tdata, sizeof(*tdata)))
return -EFAULT;
udata = compat_ptr(arg);
if (verify_area(VERIFY_READ, udata, sizeof(*udata)))
return -EFAULT;
if (__get_user(nmsgs, &udata->nmsgs) || __put_user(nmsgs, &tdata->nmsgs))
if (get_user(nmsgs, &udata->nmsgs))
return -EFAULT;
if (nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
return -EINVAL;
if (__get_user(datap, &udata->msgs))
if (get_user(datap, &udata->msgs))
return -EFAULT;
umsgs = compat_ptr(datap);
if (verify_area(VERIFY_READ, umsgs, sizeof(struct i2c_msg) * nmsgs))
return -EFAULT;
tmsgs = compat_alloc_user_space(sizeof(struct i2c_msg) * nmsgs);
if (tmsgs == NULL)
return -ENOMEM;
if (verify_area(VERIFY_WRITE, tmsgs, sizeof(struct i2c_msg) * nmsgs))
tdata = compat_alloc_user_space(sizeof(*tdata) +
nmsgs * sizeof(struct i2c_msg));
tmsgs = &tdata->msgs[0];
if (put_user(nmsgs, &tdata->cmd.nmsgs) ||
put_user(tmsgs, &tdata->cmd.msgs))
return -EFAULT;
if (__put_user(tmsgs, &tdata->msgs))
return -ENOMEM;
for (i = 0; i < nmsgs; i++) {
if (__copy_in_user(&tmsgs[i].addr,
&umsgs[i].addr,
3 * sizeof(u16)))
if (copy_in_user(&tmsgs[i].addr, &umsgs[i].addr, 3*sizeof(u16)))
return -EFAULT;
if (__get_user(datap, &umsgs[i].buf) ||
__put_user(compat_ptr(datap), &tmsgs[i].buf))
if (get_user(datap, &umsgs[i].buf) ||
put_user(compat_ptr(datap), &tmsgs[i].buf))
return -EFAULT;
}
return sys_ioctl(fd, cmd, (unsigned long)tdata);
......
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