|
@@ -57,7 +57,6 @@
|
|
|
#include <linux/serial.h>
|
|
|
#include <linux/if_tun.h>
|
|
|
#include <linux/ctype.h>
|
|
|
-#include <linux/ioctl32.h>
|
|
|
#include <linux/syscalls.h>
|
|
|
#include <linux/i2c.h>
|
|
|
#include <linux/i2c-dev.h>
|
|
@@ -65,7 +64,6 @@
|
|
|
#include <linux/atalk.h>
|
|
|
#include <linux/blktrace_api.h>
|
|
|
|
|
|
-#include <net/sock.h> /* siocdevprivate_ioctl */
|
|
|
#include <net/bluetooth/bluetooth.h>
|
|
|
#include <net/bluetooth/hci.h>
|
|
|
#include <net/bluetooth/rfcomm.h>
|
|
@@ -474,7 +472,7 @@ static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
|
|
|
};
|
|
|
}
|
|
|
|
|
|
-int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
|
|
|
+static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
|
|
|
{
|
|
|
struct ifreq __user *u_ifreq64;
|
|
|
struct ifreq32 __user *u_ifreq32 = compat_ptr(arg);
|
|
@@ -2384,6 +2382,16 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
|
|
|
return sys_ioctl(fd, cmd, (unsigned long)tn);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+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) },
|
|
|
|
|
@@ -2404,7 +2412,7 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
|
|
|
Most other reasons are not valid. */
|
|
|
#define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd)
|
|
|
|
|
|
-struct ioctl_trans ioctl_start[] = {
|
|
|
+static struct ioctl_trans ioctl_start[] = {
|
|
|
/* 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 */
|
|
@@ -3464,4 +3472,156 @@ IGNORE_IOCTL(VFAT_IOCTL_READDIR_BOTH32)
|
|
|
IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32)
|
|
|
};
|
|
|
|
|
|
-int ioctl_table_size = ARRAY_SIZE(ioctl_start);
|
|
|
+#define IOCTL_HASHSIZE 256
|
|
|
+static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
|
|
|
+
|
|
|
+static inline unsigned long ioctl32_hash(unsigned long cmd)
|
|
|
+{
|
|
|
+ return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
|
|
|
+}
|
|
|
+
|
|
|
+static void compat_ioctl_error(struct file *filp, unsigned int fd,
|
|
|
+ unsigned int cmd, unsigned long arg)
|
|
|
+{
|
|
|
+ char buf[10];
|
|
|
+ char *fn = "?";
|
|
|
+ char *path;
|
|
|
+
|
|
|
+ /* find the name of the device. */
|
|
|
+ path = (char *)__get_free_page(GFP_KERNEL);
|
|
|
+ if (path) {
|
|
|
+ fn = d_path(filp->f_path.dentry, filp->f_path.mnt, path, PAGE_SIZE);
|
|
|
+ if (IS_ERR(fn))
|
|
|
+ fn = "?";
|
|
|
+ }
|
|
|
+
|
|
|
+ sprintf(buf,"'%c'", (cmd>>_IOC_TYPESHIFT) & _IOC_TYPEMASK);
|
|
|
+ if (!isprint(buf[1]))
|
|
|
+ sprintf(buf, "%02x", buf[1]);
|
|
|
+ compat_printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
|
|
|
+ "cmd(%08x){t:%s;sz:%u} arg(%08x) on %s\n",
|
|
|
+ current->comm, current->pid,
|
|
|
+ (int)fd, (unsigned int)cmd, buf,
|
|
|
+ (cmd >> _IOC_SIZESHIFT) & _IOC_SIZEMASK,
|
|
|
+ (unsigned int)arg, fn);
|
|
|
+
|
|
|
+ if (path)
|
|
|
+ free_page((unsigned long)path);
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
|
|
|
+ unsigned long arg)
|
|
|
+{
|
|
|
+ struct file *filp;
|
|
|
+ int error = -EBADF;
|
|
|
+ struct ioctl_trans *t;
|
|
|
+ int fput_needed;
|
|
|
+
|
|
|
+ filp = fget_light(fd, &fput_needed);
|
|
|
+ if (!filp)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /* RED-PEN how should LSM module know it's handling 32bit? */
|
|
|
+ error = security_file_ioctl(filp, cmd, arg);
|
|
|
+ if (error)
|
|
|
+ goto out_fput;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * To allow the compat_ioctl handlers to be self contained
|
|
|
+ * we need to check the common ioctls here first.
|
|
|
+ * Just handle them with the standard handlers below.
|
|
|
+ */
|
|
|
+ switch (cmd) {
|
|
|
+ case FIOCLEX:
|
|
|
+ case FIONCLEX:
|
|
|
+ case FIONBIO:
|
|
|
+ case FIOASYNC:
|
|
|
+ case FIOQSIZE:
|
|
|
+ break;
|
|
|
+
|
|
|
+ case FIBMAP:
|
|
|
+ case FIGETBSZ:
|
|
|
+ case FIONREAD:
|
|
|
+ if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
|
|
|
+ break;
|
|
|
+ /*FALL THROUGH*/
|
|
|
+
|
|
|
+ default:
|
|
|
+ if (filp->f_op && filp->f_op->compat_ioctl) {
|
|
|
+ error = filp->f_op->compat_ioctl(filp, cmd, arg);
|
|
|
+ if (error != -ENOIOCTLCMD)
|
|
|
+ goto out_fput;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!filp->f_op ||
|
|
|
+ (!filp->f_op->ioctl && !filp->f_op->unlocked_ioctl))
|
|
|
+ goto do_ioctl;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) {
|
|
|
+ if (t->cmd == cmd)
|
|
|
+ goto found_handler;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) &&
|
|
|
+ cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
|
|
|
+ error = siocdevprivate_ioctl(fd, cmd, arg);
|
|
|
+ } else {
|
|
|
+ static int count;
|
|
|
+
|
|
|
+ if (++count <= 50)
|
|
|
+ compat_ioctl_error(filp, fd, cmd, arg);
|
|
|
+ error = -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ goto out_fput;
|
|
|
+
|
|
|
+ found_handler:
|
|
|
+ if (t->handler) {
|
|
|
+ lock_kernel();
|
|
|
+ error = t->handler(fd, cmd, arg, filp);
|
|
|
+ unlock_kernel();
|
|
|
+ goto out_fput;
|
|
|
+ }
|
|
|
+
|
|
|
+ do_ioctl:
|
|
|
+ error = vfs_ioctl(filp, fd, cmd, arg);
|
|
|
+ out_fput:
|
|
|
+ fput_light(filp, fput_needed);
|
|
|
+ out:
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
+static void ioctl32_insert_translation(struct ioctl_trans *trans)
|
|
|
+{
|
|
|
+ unsigned long hash;
|
|
|
+ struct ioctl_trans *t;
|
|
|
+
|
|
|
+ hash = ioctl32_hash (trans->cmd);
|
|
|
+ if (!ioctl32_hash_table[hash])
|
|
|
+ ioctl32_hash_table[hash] = trans;
|
|
|
+ else {
|
|
|
+ t = ioctl32_hash_table[hash];
|
|
|
+ while (t->next)
|
|
|
+ t = t->next;
|
|
|
+ trans->next = NULL;
|
|
|
+ t->next = trans;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int __init init_sys32_ioctl(void)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(ioctl_start); i++) {
|
|
|
+ if (ioctl_start[i].next != 0) {
|
|
|
+ printk("ioctl translation %d bad\n",i);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ioctl32_insert_translation(&ioctl_start[i]);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+__initcall(init_sys32_ioctl);
|