aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-11 20:57:46 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-11 20:57:46 -0800
commit92340ee3198a2afd7664ed2f5472fa072b15fa32 (patch)
treeb77411ace423d8702da51938c953914d341fba80
parenta1c36e52068a59374e127d60e4d8f4377072fc98 (diff)
parent637e8a60a7aaf4ef7d46cfdf83bcfac9cf6f0fbd (diff)
Merge branch 'compat-ioctl-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground
* 'compat-ioctl-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground: usbdevfs: move compat_ioctl handling to devio.c lp: move compat_ioctl handling into lp.c compat_ioctl: pass compat pointer directly to handlers compat_ioctl: simplify lookup table compat_ioctl: simplify calling of handlers compat_ioctl: inline all conversion handlers compat_ioctl: Remove BKL compat_ioctl: remove all VT ioctl handling
-rw-r--r--drivers/char/lp.c115
-rw-r--r--drivers/usb/core/devio.c110
-rw-r--r--fs/compat_ioctl.c767
-rw-r--r--include/linux/usbdevice_fs.h26
4 files changed, 417 insertions, 601 deletions
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index e444c2dba16..938a3a27388 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -127,6 +127,7 @@
#include <linux/wait.h>
#include <linux/jiffies.h>
#include <linux/smp_lock.h>
+#include <linux/compat.h>
#include <linux/parport.h>
#undef LP_STATS
@@ -571,13 +572,11 @@ static int lp_release(struct inode * inode, struct file * file)
return 0;
}
-static int lp_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int lp_do_ioctl(unsigned int minor, unsigned int cmd,
+ unsigned long arg, void __user *argp)
{
- unsigned int minor = iminor(inode);
int status;
int retval = 0;
- void __user *argp = (void __user *)arg;
#ifdef LP_DEBUG
printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg);
@@ -587,9 +586,6 @@ static int lp_ioctl(struct inode *inode, struct file *file,
if ((LP_F(minor) & LP_EXIST) == 0)
return -ENODEV;
switch ( cmd ) {
- struct timeval par_timeout;
- long to_jiffies;
-
case LPTIME:
LP_TIME(minor) = arg * HZ/100;
break;
@@ -652,34 +648,101 @@ static int lp_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
break;
- case LPSETTIMEOUT:
- if (copy_from_user (&par_timeout, argp,
- sizeof (struct timeval))) {
- return -EFAULT;
- }
- /* Convert to jiffies, place in lp_table */
- if ((par_timeout.tv_sec < 0) ||
- (par_timeout.tv_usec < 0)) {
- return -EINVAL;
- }
- to_jiffies = DIV_ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
- to_jiffies += par_timeout.tv_sec * (long) HZ;
- if (to_jiffies <= 0) {
- return -EINVAL;
- }
- lp_table[minor].timeout = to_jiffies;
- break;
-
default:
retval = -EINVAL;
}
return retval;
}
+static int lp_set_timeout(unsigned int minor, struct timeval *par_timeout)
+{
+ long to_jiffies;
+
+ /* Convert to jiffies, place in lp_table */
+ if ((par_timeout->tv_sec < 0) ||
+ (par_timeout->tv_usec < 0)) {
+ return -EINVAL;
+ }
+ to_jiffies = DIV_ROUND_UP(par_timeout->tv_usec, 1000000/HZ);
+ to_jiffies += par_timeout->tv_sec * (long) HZ;
+ if (to_jiffies <= 0) {
+ return -EINVAL;
+ }
+ lp_table[minor].timeout = to_jiffies;
+ return 0;
+}
+
+static long lp_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ unsigned int minor;
+ struct timeval par_timeout;
+ int ret;
+
+ minor = iminor(file->f_path.dentry->d_inode);
+ lock_kernel();
+ switch (cmd) {
+ case LPSETTIMEOUT:
+ if (copy_from_user(&par_timeout, (void __user *)arg,
+ sizeof (struct timeval))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = lp_set_timeout(minor, &par_timeout);
+ break;
+ default:
+ ret = lp_do_ioctl(minor, cmd, arg, (void __user *)arg);
+ break;
+ }
+ unlock_kernel();
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long lp_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ unsigned int minor;
+ struct timeval par_timeout;
+ struct compat_timeval __user *tc;
+ int ret;
+
+ minor = iminor(file->f_path.dentry->d_inode);
+ lock_kernel();
+ switch (cmd) {
+ case LPSETTIMEOUT:
+ tc = compat_ptr(arg);
+ if (get_user(par_timeout.tv_sec, &tc->tv_sec) ||
+ get_user(par_timeout.tv_usec, &tc->tv_usec)) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = lp_set_timeout(minor, &par_timeout);
+ break;
+#ifdef LP_STATS
+ case LPGETSTATS:
+ /* FIXME: add an implementation if you set LP_STATS */
+ ret = -EINVAL;
+ break;
+#endif
+ default:
+ ret = lp_do_ioctl(minor, cmd, arg, compat_ptr(arg));
+ break;
+ }
+ unlock_kernel();
+
+ return ret;
+}
+#endif
+
static const struct file_operations lp_fops = {
.owner = THIS_MODULE,
.write = lp_write,
- .ioctl = lp_ioctl,
+ .unlocked_ioctl = lp_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lp_compat_ioctl,
+#endif
.open = lp_open,
.release = lp_release,
#ifdef CONFIG_PARPORT_1284
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 181f78c8410..6e8bcdfd23b 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1388,6 +1388,46 @@ static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
}
#ifdef CONFIG_COMPAT
+static int proc_control_compat(struct dev_state *ps,
+ struct usbdevfs_ctrltransfer32 __user *p32)
+{
+ struct usbdevfs_ctrltransfer __user *p;
+ __u32 udata;
+ p = compat_alloc_user_space(sizeof(*p));
+ if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) ||
+ get_user(udata, &p32->data) ||
+ put_user(compat_ptr(udata), &p->data))
+ return -EFAULT;
+ return proc_control(ps, p);
+}
+
+static int proc_bulk_compat(struct dev_state *ps,
+ struct usbdevfs_bulktransfer32 __user *p32)
+{
+ struct usbdevfs_bulktransfer __user *p;
+ compat_uint_t n;
+ compat_caddr_t addr;
+
+ p = compat_alloc_user_space(sizeof(*p));
+
+ if (get_user(n, &p32->ep) || put_user(n, &p->ep) ||
+ get_user(n, &p32->len) || put_user(n, &p->len) ||
+ get_user(n, &p32->timeout) || put_user(n, &p->timeout) ||
+ get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data))
+ return -EFAULT;
+
+ return proc_bulk(ps, p);
+}
+static int proc_disconnectsignal_compat(struct dev_state *ps, void __user *arg)
+{
+ struct usbdevfs_disconnectsignal32 ds;
+
+ if (copy_from_user(&ds, arg, sizeof(ds)))
+ return -EFAULT;
+ ps->discsignr = ds.signr;
+ ps->disccontext = compat_ptr(ds.context);
+ return 0;
+}
static int get_urb32(struct usbdevfs_urb *kurb,
struct usbdevfs_urb32 __user *uurb)
@@ -1482,6 +1522,7 @@ static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)
return processcompl_compat(as, (void __user * __user *)arg);
}
+
#endif
static int proc_disconnectsignal(struct dev_state *ps, void __user *arg)
@@ -1648,12 +1689,12 @@ static int proc_release_port(struct dev_state *ps, void __user *arg)
* are assuming that somehow the configuration has been prevented from
* changing. But there's no mechanism to ensure that...
*/
-static int usbdev_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
+ void __user *p)
{
struct dev_state *ps = file->private_data;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct usb_device *dev = ps->dev;
- void __user *p = (void __user *)arg;
int ret = -ENOTTY;
if (!(file->f_mode & FMODE_WRITE))
@@ -1726,6 +1767,24 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
break;
#ifdef CONFIG_COMPAT
+ case USBDEVFS_CONTROL32:
+ snoop(&dev->dev, "%s: CONTROL32\n", __func__);
+ ret = proc_control_compat(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_BULK32:
+ snoop(&dev->dev, "%s: BULK32\n", __func__);
+ ret = proc_bulk_compat(ps, p);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_DISCSIGNAL32:
+ snoop(&dev->dev, "%s: DISCSIGNAL32\n", __func__);
+ ret = proc_disconnectsignal_compat(ps, p);
+ break;
case USBDEVFS_SUBMITURB32:
snoop(&dev->dev, "%s: SUBMITURB32\n", __func__);
@@ -1745,7 +1804,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
break;
case USBDEVFS_IOCTL32:
- snoop(&dev->dev, "%s: IOCTL\n", __func__);
+ snoop(&dev->dev, "%s: IOCTL32\n", __func__);
ret = proc_ioctl_compat(ps, ptr_to_compat(p));
break;
#endif
@@ -1801,6 +1860,32 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
return ret;
}
+static long usbdev_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+
+ lock_kernel();
+ ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
+ unlock_kernel();
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long usbdev_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+
+ lock_kernel();
+ ret = usbdev_do_ioctl(file, cmd, compat_ptr(arg));
+ unlock_kernel();
+
+ return ret;
+}
+#endif
+
/* No kernel lock - fine */
static unsigned int usbdev_poll(struct file *file,
struct poll_table_struct *wait)
@@ -1817,13 +1902,16 @@ static unsigned int usbdev_poll(struct file *file,
}
const struct file_operations usbdev_file_operations = {
- .owner = THIS_MODULE,
- .llseek = usbdev_lseek,
- .read = usbdev_read,
- .poll = usbdev_poll,
- .ioctl = usbdev_ioctl,
- .open = usbdev_open,
- .release = usbdev_release,
+ .owner = THIS_MODULE,
+ .llseek = usbdev_lseek,
+ .read = usbdev_read,
+ .poll = usbdev_poll,
+ .unlocked_ioctl = usbdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = usbdev_compat_ioctl,
+#endif
+ .open = usbdev_open,
+ .release = usbdev_release,
};
static void usbdev_remove(struct usb_device *udev)
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 2346895b3a7..278020d2449 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -111,43 +111,40 @@
#include <linux/dvb/frontend.h>
#include <linux/dvb/video.h>
+#include <linux/sort.h>
+
#ifdef CONFIG_SPARC
#include <asm/fbio.h>
#endif
-static int do_ioctl32_pointer(unsigned int fd, unsigned int cmd,
- unsigned long arg, struct file *f)
-{
- return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
-}
-
-static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int w_long(unsigned int fd, unsigned int cmd,
+ compat_ulong_t __user *argp)
{
mm_segment_t old_fs = get_fs();
int err;
unsigned long val;
-
+
set_fs (KERNEL_DS);
err = sys_ioctl(fd, cmd, (unsigned long)&val);
set_fs (old_fs);
- if (!err && put_user(val, (u32 __user *)compat_ptr(arg)))
+ if (!err && put_user(val, argp))
return -EFAULT;
return err;
}
-
-static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg)
+
+static int rw_long(unsigned int fd, unsigned int cmd,
+ compat_ulong_t __user *argp)
{
mm_segment_t old_fs = get_fs();
- u32 __user *argptr = compat_ptr(arg);
int err;
unsigned long val;
-
- if(get_user(val, argptr))
+
+ if(get_user(val, argp))
return -EFAULT;
set_fs (KERNEL_DS);
err = sys_ioctl(fd, cmd, (unsigned long)&val);
set_fs (old_fs);
- if (!err && put_user(val, argptr))
+ if (!err && put_user(val, argp))
return -EFAULT;
return err;
}
@@ -161,7 +158,8 @@ struct compat_video_event {
} u;
};
-static int do_video_get_event(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int do_video_get_event(unsigned int fd, unsigned int cmd,
+ struct compat_video_event __user *up)
{
struct video_event kevent;
mm_segment_t old_fs = get_fs();
@@ -172,8 +170,6 @@ static int do_video_get_event(unsigned int fd, unsigned int cmd, unsigned long a
set_fs(old_fs);
if (!err) {
- struct compat_video_event __user *up = compat_ptr(arg);
-
err = put_user(kevent.type, &up->type);
err |= put_user(kevent.timestamp, &up->timestamp);
err |= put_user(kevent.u.size.w, &up->u.size.w);
@@ -192,15 +188,14 @@ struct compat_video_still_picture {
int32_t size;
};
-static int do_video_stillpicture(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int do_video_stillpicture(unsigned int fd, unsigned int cmd,
+ struct compat_video_still_picture __user *up)
{
- struct compat_video_still_picture __user *up;
struct video_still_picture __user *up_native;
compat_uptr_t fp;
int32_t size;
int err;
- up = (struct compat_video_still_picture __user *) arg;
err = get_user(fp, &up->iFrame);
err |= get_user(size, &up->size);
if (err)
@@ -224,14 +219,13 @@ struct compat_video_spu_palette {
compat_uptr_t palette;
};
-static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd,
+ struct compat_video_spu_palette __user *up)
{
- struct compat_video_spu_palette __user *up;
struct video_spu_palette __user *up_native;
compat_uptr_t palp;
int length, err;
- up = (struct compat_video_spu_palette __user *) arg;
err = get_user(palp, &up->palette);
err |= get_user(length, &up->length);
@@ -299,16 +293,15 @@ static int sg_build_iovec(sg_io_hdr_t __user *sgio, void __user *dxferp, u16 iov
return 0;
}
-static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int sg_ioctl_trans(unsigned int fd, unsigned int cmd,
+ sg_io_hdr32_t __user *sgio32)
{
sg_io_hdr_t __user *sgio;
- sg_io_hdr32_t __user *sgio32;
u16 iovec_count;
u32 data;
void __user *dxferp;
int err;
- sgio32 = compat_ptr(arg);
if (get_user(iovec_count, &sgio32->iovec_count))
return -EFAULT;
@@ -398,11 +391,11 @@ struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
int unused;
};
-static int sg_grt_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int sg_grt_trans(unsigned int fd, unsigned int cmd, struct
+ compat_sg_req_info __user *o)
{
int err, i;
sg_req_info_t __user *r;
- struct compat_sg_req_info __user *o = (void __user *)arg;
r = compat_alloc_user_space(sizeof(sg_req_info_t)*SG_MAX_QUEUE);
err = sys_ioctl(fd,cmd,(unsigned long)r);
if (err < 0)
@@ -430,9 +423,9 @@ struct sock_fprog32 {
#define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32)
#define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32)
-static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd,
+ struct sock_fprog32 __user *u_fprog32)
{
- struct sock_fprog32 __user *u_fprog32 = compat_ptr(arg);
struct sock_fprog __user *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog));
void __user *fptr64;
u32 fptr32;
@@ -469,15 +462,14 @@ struct ppp_idle32 {
};
#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32)
-static int ppp_gidle(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int ppp_gidle(unsigned int fd, unsigned int cmd,
+ struct ppp_idle32 __user *idle32)
{
struct ppp_idle __user *idle;
- struct ppp_idle32 __user *idle32;
__kernel_time_t xmit, recv;
int err;
idle = compat_alloc_user_space(sizeof(*idle));
- idle32 = compat_ptr(arg);
err = sys_ioctl(fd, PPPIOCGIDLE, (unsigned long) idle);
@@ -491,15 +483,14 @@ static int ppp_gidle(unsigned int fd, unsigned int cmd, unsigned long arg)
return err;
}
-static int ppp_scompress(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int ppp_scompress(unsigned int fd, unsigned int cmd,
+ struct ppp_option_data32 __user *odata32)
{
struct ppp_option_data __user *odata;
- struct ppp_option_data32 __user *odata32;
__u32 data;
void __user *datap;
odata = compat_alloc_user_space(sizeof(*odata));
- odata32 = compat_ptr(arg);
if (get_user(data, &odata32->ptr))
return -EFAULT;
@@ -515,35 +506,6 @@ static int ppp_scompress(unsigned int fd, unsigned int cmd, unsigned long arg)
return sys_ioctl(fd, PPPIOCSCOMPRESS, (unsigned long) odata);
}
-static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- int err;
-
- switch (cmd) {
- case PPPIOCGIDLE32:
- err = ppp_gidle(fd, cmd, arg);
- break;
-
- case PPPIOCSCOMPRESS32:
- err = ppp_scompress(fd, cmd, arg);
- break;
-
- default:
- do {
- static int count;
- if (++count <= 20)
- printk("ppp_ioctl: Unknown cmd fd(%d) "
- "cmd(%08x) arg(%08x)\n",
- (int)fd, (unsigned int)cmd, (unsigned int)arg);
- } while(0);
- err = -EINVAL;
- break;
- };
-
- return err;
-}
-
-
#ifdef CONFIG_BLOCK
struct mtget32 {
compat_long_t mt_type;
@@ -561,7 +523,7 @@ struct mtpos32 {
};
#define MTIOCPOS32 _IOR('m', 3, struct mtpos32)
-static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, void __user *argp)
{
mm_segment_t old_fs = get_fs();
struct mtget get;
@@ -581,15 +543,6 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
kcmd = MTIOCGET;
karg = &get;
break;
- default:
- do {
- static int count;
- if (++count <= 20)
- printk("mt_ioctl: Unknown cmd fd(%d) "
- "cmd(%08x) arg(%08x)\n",
- (int)fd, (unsigned int)cmd, (unsigned int)arg);
- } while(0);
- return -EINVAL;
}
set_fs (KERNEL_DS);
err = sys_ioctl (fd, kcmd, (unsigned long)karg);
@@ -598,11 +551,11 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
return err;
switch (cmd) {
case MTIOCPOS32:
- upos32 = compat_ptr(arg);
+ upos32 = argp;
err = __put_user(pos.mt_blkno, &upos32->mt_blkno);
break;
case MTIOCGET32:
- umget32 = compat_ptr(arg);
+ umget32 = argp;
err = __put_user(get.mt_type, &umget32->mt_type);
err |= __put_user(get.mt_resid, &umget32->mt_resid);
err |= __put_user(get.mt_dsreg, &umget32->mt_dsreg);
@@ -617,162 +570,8 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
#endif /* CONFIG_BLOCK */
-#ifdef CONFIG_VT
-
-static int vt_check(struct file *file)
-{
- struct tty_struct *tty;
- struct inode *inode = file->f_path.dentry->d_inode;
- struct vc_data *vc;
-
- if (file->f_op->unlocked_ioctl != tty_ioctl)
- return -EINVAL;
-
- tty = (struct tty_struct *)file->private_data;
- if (tty_paranoia_check(tty, inode, "tty_ioctl"))
- return -EINVAL;
-
- if (tty->ops->ioctl != vt_ioctl)
- return -EINVAL;
-
- vc = (struct vc_data *)tty->driver_data;
- if (!vc_cons_allocated(vc->vc_num)) /* impossible? */
- return -ENOIOCTLCMD;
-
- /*
- * To have permissions to do most of the vt ioctls, we either have
- * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
- */
- if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
- return 1;
- return 0;
-}
-
-struct consolefontdesc32 {
- unsigned short charcount; /* characters in font (256 or 512) */
- unsigned short charheight; /* scan lines per character (1-32) */
- compat_caddr_t chardata; /* font data in expanded form */
-};
-
-static int do_fontx_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
-{
- struct consolefontdesc32 __user *user_cfd = compat_ptr(arg);
- struct console_font_op op;
- compat_caddr_t data;
- int i, perm;
-
- perm = vt_check(file);
- if (perm < 0) return perm;
-
- switch (cmd) {
- case PIO_FONTX:
- if (!perm)
- return -EPERM;
- op.op = KD_FONT_OP_SET;
- op.flags = 0;
- op.width = 8;
- if (get_user(op.height, &user_cfd->charheight) ||
- get_user(op.charcount, &user_cfd->charcount) ||
- get_user(data, &user_cfd->chardata))
- return -EFAULT;
- op.data = compat_ptr(data);
- return con_font_op(vc_cons[fg_console].d, &op);
- case GIO_FONTX:
- op.op = KD_FONT_OP_GET;
- op.flags = 0;
- op.width = 8;
- if (get_user(op.height, &user_cfd->charheight) ||
- get_user(op.charcount, &user_cfd->charcount) ||
- get_user(data, &user_cfd->chardata))
- return -EFAULT;
- if (!data)
- return 0;
- op.data = compat_ptr(data);
- i = con_font_op(vc_cons[fg_console].d, &op);
- if (i)
- return i;
- if (put_user(op.height, &user_cfd->charheight) ||
- put_user(op.charcount, &user_cfd->charcount) ||
- put_user((compat_caddr_t)(unsigned long)op.data,
- &user_cfd->chardata))
- return -EFAULT;
- return 0;
- }
- return -EINVAL;
-}
-
-struct console_font_op32 {
- compat_uint_t op; /* operation code KD_FONT_OP_* */
- compat_uint_t flags; /* KD_FONT_FLAG_* */
- compat_uint_t width, height; /* font size */
- compat_uint_t charcount;
- compat_caddr_t data; /* font data with height fixed to 32 */
-};
-
-static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
-{
- struct console_font_op op;
- struct console_font_op32 __user *fontop = compat_ptr(arg);
- int perm = vt_check(file), i;
- struct vc_data *vc;
-
- if (perm < 0) return perm;
-
- if (copy_from_user(&op, fontop, sizeof(struct console_font_op32)))
- return -EFAULT;
- if (!perm && op.op != KD_FONT_OP_GET)
- return -EPERM;
- op.data = compat_ptr(((struct console_font_op32 *)&op)->data);
- op.flags |= KD_FONT_FLAG_OLD;
- vc = ((struct tty_struct *)file->private_data)->driver_data;
- i = con_font_op(vc, &op);
- if (i)
- return i;
- ((struct console_font_op32 *)&op)->data = (unsigned long)op.data;
- if (copy_to_user(fontop, &op, sizeof(struct console_font_op32)))
- return -EFAULT;
- return 0;
-}
-
-struct unimapdesc32 {
- unsigned short entry_ct;
- compat_caddr_t entries;
-};
-
-static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
-{
- struct unimapdesc32 tmp;
- struct unimapdesc32 __user *user_ud = compat_ptr(arg);
- int perm = vt_check(file);
- struct vc_data *vc;
-
- if (perm < 0)
- return perm;
- if (copy_from_user(&tmp, user_ud, sizeof tmp))
- return -EFAULT;
- if (tmp.entries)
- if (!access_ok(VERIFY_WRITE, compat_ptr(tmp.entries),
- tmp.entry_ct*sizeof(struct unipair)))
- return -EFAULT;
- vc = ((struct tty_struct *)file->private_data)->driver_data;
- switch (cmd) {
- case PIO_UNIMAP:
- if (!perm)
- return -EPERM;
- return con_set_unimap(vc, tmp.entry_ct,
- compat_ptr(tmp.entries));
- case GIO_UNIMAP:
- if (!perm && fg_console != vc->vc_num)
- return -EPERM;
- return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct),
- compat_ptr(tmp.entries));
- }
- return 0;
-}
-
-#endif /* CONFIG_VT */
-
-static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int do_smb_getmountuid(unsigned int fd, unsigned int cmd,
+ compat_uid_t __user *argp)
{
mm_segment_t old_fs = get_fs();
__kernel_uid_t kuid;
@@ -785,20 +584,15 @@ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long a
set_fs(old_fs);
if (err >= 0)
- err = put_user(kuid, (compat_uid_t __user *)compat_ptr(arg));
+ err = put_user(kuid, argp);
return err;
}
-static __used int
-ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- return -EINVAL;
-}
-
-static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int ioc_settimeout(unsigned int fd, unsigned int cmd,
+ compat_ulong_t __user *argp)
{
- return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
+ return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, argp);
}
/* Bluetooth ioctls */
@@ -856,7 +650,8 @@ static int set_raw32_request(struct raw_config_request *req, struct raw32_config
return ret ? -EFAULT : 0;
}
-static int raw_ioctl(unsigned fd, unsigned cmd, unsigned long arg)
+static int raw_ioctl(unsigned fd, unsigned cmd,
+ struct raw32_config_request __user *user_req)
{
int ret;
@@ -864,7 +659,6 @@ static int raw_ioctl(unsigned fd, unsigned cmd, unsigned long arg)
case RAW_SETBIND:
case RAW_GETBIND: {
struct raw_config_request req;
- struct raw32_config_request __user *user_req = compat_ptr(arg);
mm_segment_t oldfs = get_fs();
if ((ret = get_raw32_request(&req, user_req)))
@@ -879,9 +673,6 @@ static int raw_ioctl(unsigned fd, unsigned cmd, unsigned long arg)
}
break;
}
- default:
- ret = sys_ioctl(fd, cmd, arg);
- break;
}
return ret;
}
@@ -909,11 +700,11 @@ struct serial_struct32 {
compat_int_t reserved[1];
};
-static int serial_struct_ioctl(unsigned fd, unsigned cmd, unsigned long arg)
+static int serial_struct_ioctl(unsigned fd, unsigned cmd,
+ struct serial_struct32 __user *ss32)
{
typedef struct serial_struct SS;
typedef struct serial_struct32 SS32;
- struct serial_struct32 __user *ss32 = compat_ptr(arg);
int err;
struct serial_struct ss;
mm_segment_t oldseg = get_fs();
@@ -951,96 +742,6 @@ static int serial_struct_ioctl(unsigned fd, unsigned cmd, unsigned long arg)
return err;
}
-struct usbdevfs_ctrltransfer32 {
- u8 bRequestType;
- u8 bRequest;
- u16 wValue;
- u16 wIndex;
- u16 wLength;
- u32 timeout; /* in milliseconds */
- compat_caddr_t data;
-};
-
-#define USBDEVFS_CONTROL32 _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
-
-static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct usbdevfs_ctrltransfer32 __user *p32 = compat_ptr(arg);
- struct usbdevfs_ctrltransfer __user *p;
- __u32 udata;
- p = compat_alloc_user_space(sizeof(*p));
- if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) ||
- get_user(udata, &p32->data) ||
- put_user(compat_ptr(udata), &p->data))
- return -EFAULT;
- return sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)p);
-}
-
-
-struct usbdevfs_bulktransfer32 {
- compat_uint_t ep;
- compat_uint_t len;
- compat_uint_t timeout; /* in milliseconds */
- compat_caddr_t data;
-};
-
-#define USBDEVFS_BULK32 _IOWR('U', 2, struct usbdevfs_bulktransfer32)
-
-static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct usbdevfs_bulktransfer32 __user *p32 = compat_ptr(arg);
- struct usbdevfs_bulktransfer __user *p;
- compat_uint_t n;
- compat_caddr_t addr;
-
- p = compat_alloc_user_space(sizeof(*p));
-
- if (get_user(n, &p32->ep) || put_user(n, &p->ep) ||
- get_user(n, &p32->len) || put_user(n, &p->len) ||
- get_user(n, &p32->timeout) || put_user(n, &p->timeout) ||
- get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data))
- return -EFAULT;
-
- return sys_ioctl(fd, USBDEVFS_BULK, (unsigned long)p);
-}
-
-
-/*
- * USBDEVFS_SUBMITURB, USBDEVFS_REAPURB and USBDEVFS_REAPURBNDELAY
- * are handled in usbdevfs core. -Christopher Li
- */
-
-struct usbdevfs_disconnectsignal32 {
- compat_int_t signr;
- compat_caddr_t context;
-};
-
-#define USBDEVFS_DISCSIGNAL32 _IOR('U', 14, struct usbdevfs_disconnectsignal32)
-
-static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct usbdevfs_disconnectsignal kdis;
- struct usbdevfs_disconnectsignal32 __user *udis;
- mm_segment_t old_fs;
- u32 uctx;
- int err;
-
- udis = compat_ptr(arg);
-
- if (get_user(kdis.signr, &udis->signr) ||
- __get_user(uctx, &udis->context))
- return -EFAULT;
-
- kdis.context = compat_ptr(uctx);
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd, USBDEVFS_DISCSIGNAL, (unsigned long) &kdis);
- set_fs(old_fs);
-
- return err;
-}
-
/*
* I2C layer ioctls
*/
@@ -1069,9 +770,9 @@ struct i2c_rdwr_aligned {
struct i2c_msg msgs[0];
};
-static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd,
+ 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;
@@ -1105,10 +806,10 @@ static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd, unsigned long ar
return sys_ioctl(fd, cmd, (unsigned long)tdata);
}
-static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd,
+ struct i2c_smbus_ioctl_data32 __user *udata)
{
struct i2c_smbus_ioctl_data __user *tdata;
- struct i2c_smbus_ioctl_data32 __user *udata;
compat_caddr_t datap;
tdata = compat_alloc_user_space(sizeof(*tdata));
@@ -1117,7 +818,6 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a
if (!access_ok(VERIFY_WRITE, tdata, sizeof(*tdata)))
return -EFAULT;
- udata = compat_ptr(arg);
if (!access_ok(VERIFY_READ, udata, sizeof(*udata)))
return -EFAULT;
@@ -1137,7 +837,7 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a
#define RTC_EPOCH_READ32 _IOR('p', 0x0d, compat_ulong_t)
#define RTC_EPOCH_SET32 _IOW('p', 0x0e, compat_ulong_t)
-static int rtc_ioctl(unsigned fd, unsigned cmd, unsigned long arg)
+static int rtc_ioctl(unsigned fd, unsigned cmd, void __user *argp)
{
mm_segment_t oldfs = get_fs();
compat_ulong_t val32;
@@ -1155,29 +855,14 @@ static int rtc_ioctl(unsigned fd, unsigned cmd, unsigned long arg)
if (ret)
return ret;
val32 = kval;
- return put_user(val32, (unsigned int __user *)arg);
+ return put_user(val32, (unsigned int __user *)argp);
case RTC_IRQP_SET32:
- return sys_ioctl(fd, RTC_IRQP_SET, arg);
+ return sys_ioctl(fd, RTC_IRQP_SET, (unsigned long)argp);
case RTC_EPOCH_SET32:
- return sys_ioctl(fd, RTC_EPOCH_SET, arg);
- default:
- /* unreached */
- return -ENOIOCTLCMD;
+ return sys_ioctl(fd, RTC_EPOCH_SET, (unsigned long)argp);
}
-}
-static int
-lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct compat_timeval __user *tc = (struct compat_timeval __user *)arg;
- struct timeval __user *tn = compat_alloc_user_space(sizeof(struct timeval));
- struct timeval ts;
- if (get_user(ts.tv_sec, &tc->tv_sec) ||
- get_user(ts.tv_usec, &tc->tv_usec) ||
- put_user(ts.tv_sec, &tn->tv_sec) ||
- put_user(ts.tv_usec, &tn->tv_usec))
- return -EFAULT;
- return sys_ioctl(fd, cmd, (unsigned long)tn);
+ return -ENOIOCTLCMD;
}
/* on ia32 l_start is on a 32-bit boundary */
@@ -1197,9 +882,9 @@ struct space_resv_32 {
#define FS_IOC_RESVSP64_32 _IOW ('X', 42, struct space_resv_32)
/* just account for different alignment */
-static int compat_ioctl_preallocate(struct file *file, unsigned long arg)
+static int compat_ioctl_preallocate(struct file *file,
+ struct space_resv_32 __user *p32)
{
- struct space_resv_32 __user *p32 = compat_ptr(arg);
struct space_resv __user *p = compat_alloc_user_space(sizeof(*p));
if (copy_in_user(&p->l_type, &p32->l_type, sizeof(s16)) ||
@@ -1215,27 +900,13 @@ static int compat_ioctl_preallocate(struct file *file, unsigned long arg)
}
#endif
+/*
+ * simple reversible transform to make our table more evenly
+ * distributed after sorting.
+ */
+#define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
-typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int,
- unsigned long, struct file *);
-
-struct ioctl_trans {
- unsigned long cmd;
- ioctl_trans_handler_t handler;
- struct ioctl_trans *next;
-};
-
-#define HANDLE_IOCTL(cmd,handler) \
- { (cmd), (ioctl_trans_handler_t)(handler) },
-
-/* pointer to compatible structure or no argument */
-#define COMPATIBLE_IOCTL(cmd) \
- { (cmd), do_ioctl32_pointer },
-
-/* argument is an unsigned long integer, not a pointer */
-#define ULONG_IOCTL(cmd) \
- { (cmd), (ioctl_trans_handler_t)sys_ioctl },
-
+#define COMPATIBLE_IOCTL(cmd) XFORM(cmd),
/* ioctl should not be warned about even if it's not implemented.
Valid reasons to use this:
- It is implemented with ->compat_ioctl on some device, but programs
@@ -1245,7 +916,7 @@ struct ioctl_trans {
Most other reasons are not valid. */
#define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd)
-static struct ioctl_trans ioctl_start[] = {
+static unsigned int ioctl_pointer[] = {
/* compatible ioctls first */
COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */
COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */
@@ -1256,7 +927,6 @@ COMPATIBLE_IOCTL(TCSETA)
COMPATIBLE_IOCTL(TCSETAW)
COMPATIBLE_IOCTL(TCSETAF)
COMPATIBLE_IOCTL(TCSBRK)
-ULONG_IOCTL(TCSBRKP)
COMPATIBLE_IOCTL(TCXONC)
COMPATIBLE_IOCTL(TCFLSH)
COMPATIBLE_IOCTL(TCGETS)
@@ -1266,7 +936,6 @@ COMPATIBLE_IOCTL(TCSETSF)
COMPATIBLE_IOCTL(TIOCLINUX)
COMPATIBLE_IOCTL(TIOCSBRK)
COMPATIBLE_IOCTL(TIOCCBRK)
-ULONG_IOCTL(TIOCMIWAIT)
COMPATIBLE_IOCTL(TIOCGICOUNT)
/* Little t */
COMPATIBLE_IOCTL(TIOCGETD)
@@ -1288,7 +957,6 @@ COMPATIBLE_IOCTL(TIOCSTI)
COMPATIBLE_IOCTL(TIOCOUTQ)
COMPATIBLE_IOCTL(TIOCSPGRP)
COMPATIBLE_IOCTL(TIOCGPGRP)
-ULONG_IOCTL(TIOCSCTTY)
COMPATIBLE_IOCTL(TIOCGPTN)
COMPATIBLE_IOCTL(TIOCSPTLCK)
COMPATIBLE_IOCTL(TIOCSERGETLSR)
@@ -1319,36 +987,21 @@ COMPATIBLE_IOCTL(PRINT_RAID_DEBUG)
COMPATIBLE_IOCTL(RAID_AUTORUN)
COMPATIBLE_IOCTL(CLEAR_ARRAY)
COMPATIBLE_IOCTL(