fix get_ioctl_names.sh
[moctel.git] / moctel_mod.c
index bb0652e..1273ff3 100644 (file)
@@ -1,3 +1,7 @@
+// 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
 #undef __KERNEL__
 #define __KERNEL__
 #undef MODULE
@@ -11,6 +15,8 @@
 #include <linux/ioctl.h>
 #include <linux/uaccess.h>
 #include <linux/miscdevice.h>
 #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;
 
 struct fetch_fops_args {
   int fd;
@@ -23,21 +29,29 @@ static int ioctl_open(struct inode *nodp, struct file *filp) {
   return 0;
 }
 
   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 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;
 
   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;
   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;
 }
 
   return 0;
 }
 
@@ -47,8 +61,7 @@ static int ioctl_release(struct inode *nodp, struct file *filp) {
 
 static const struct file_operations ioctl_fops = {
   .owner = THIS_MODULE,
 
 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
 };
   .open = ioctl_open,
   .release = ioctl_release
 };
@@ -59,7 +72,7 @@ static struct miscdevice ioctl_miscdev = {
   .fops = &ioctl_fops
 };
 
   .fops = &ioctl_fops
 };
 
-static int __init init_ioctl() {
+static int __init init_ioctl(void) {
   int ret;
   printk(KERN_INFO "loading ioctl helper\n");
 
   int ret;
   printk(KERN_INFO "loading ioctl helper\n");
 
@@ -67,10 +80,12 @@ static int __init init_ioctl() {
   return ret;
 }
 
   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);
   printk(KERN_INFO "unloading ioctl helper\n");
   misc_deregister(&ioctl_miscdev);
 }
 
 module_init(init_ioctl);
 module_exit(cleanup_ioctl);
+
+MODULE_LICENSE("GPL v2");