+// Copyright (C) 2013 Jann Horn <jann@thejh.net>
+// This file is licensed under the GNU GPL v2 (see
+// the LICENSE file).
+
#undef __KERNEL__
#define __KERNEL__
#undef MODULE
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
+#include <linux/kallsyms.h>
+#include <linux/blkdev.h>
struct fetch_fops_args {
int fd;
return 0;
}
-static const struct file_operations dummy_fops = {};
-
-static long ioctl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
+static long ioctl_ioctl(struct file *filp_, unsigned int cmd, unsigned long arg) {
struct fetch_fops_args args;
- struct fd f;
- const struct file_operations *fops;
+ struct file *filp;
+ void *ioctl_method = NULL;
+ char ioctl_method_name[KSYM_NAME_LEN];
+ int (*lookup_symbol_name_)(unsigned long addr, char *symname);
+
+ lookup_symbol_name_ = (void*)kallsyms_lookup_name("lookup_symbol_name");
if (cmd != MOCTEL_FETCH_FOPS) return -EINVAL;
+ memset(ioctl_method_name, 0, sizeof(ioctl_method_name));
if (copy_from_user(&args, (struct fetch_fops_args __user *)arg, sizeof(args))) return -EINVAL;
- f = fdget(args.fd);
- if (!f.file) return -EBADF;
- fops = f.file->f_op;
- if (!fops) fops = dummy_fops;
- fdput(f);
- if (copy_to_user((struct file_operations __user *)args.retp, fops, sizeof(*fops))) return -EINVAL;
+ filp = fget(args.fd);
+ if (!filp) return -EBADF;
+ if (filp->f_op) ioctl_method = filp->f_op->unlocked_ioctl;
+ lookup_symbol_name_((unsigned long)ioctl_method, ioctl_method_name);
+ if (strcmp(ioctl_method_name, "block_ioctl") == 0) {
+ struct block_device *bdev = I_BDEV(filp->f_mapping->host);
+ ioctl_method = bdev->bd_disk->fops->ioctl;
+ lookup_symbol_name_((unsigned long)ioctl_method, ioctl_method_name);
+ }
+ fput(filp);
+ if (copy_to_user((struct file_operations __user *)args.retp, ioctl_method_name, KSYM_NAME_LEN)) return -EINVAL;
return 0;
}
static const struct file_operations ioctl_fops = {
.owner = THIS_MODULE,
- .ioctl = ioctl_ioctl, /* I have no idea about locking,
- so just take the Big Kernel Lock implicitly. */
+ .unlocked_ioctl = ioctl_ioctl,
.open = ioctl_open,
.release = ioctl_release
};
.fops = &ioctl_fops
};
-static int __init init_ioctl() {
+static int __init init_ioctl(void) {
int ret;
printk(KERN_INFO "loading ioctl helper\n");
return ret;
}
-static void __exit cleanup_ioctl() {
+static void __exit cleanup_ioctl(void) {
printk(KERN_INFO "unloading ioctl helper\n");
misc_deregister(&ioctl_miscdev);
}
module_init(init_ioctl);
module_exit(cleanup_ioctl);
+
+MODULE_LICENSE("GPL v2");