Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Viro <viro@parcelfarce.linux.theplanet.co.uk>2005-02-10 16:19:45 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-02-10 16:19:45 -0800
commit8b1ef6f51b16ed94db86979fadc87a13647b051b (patch)
treecad899a9c0041e508d52e6897cdb5b24e1510e2a
parent4e979b187f7528fcc924f21a5a7b805d9e5d413f (diff)
[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: Al Viro <viro@parcelfarce.linux.theplanet.co.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/compat_ioctl.c46
1 files changed, 20 insertions, 26 deletions
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 6f47864f9e9a..3f5c7264cff6 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -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);