--- /dev/null
+show_ioctl
+moctel_mod.ko
+moctel_mod.mod.*
+.tmp_versions
+*.cmd
+modules.order
+*.o
+Module.symvers
obj-m := moctel_mod.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
-
-all:
+
+all: show_ioctl
$(MAKE) -C $(KDIR) M=$(PWD) modules
+
+show_ioctl:
+ gcc -o show_ioctl show_ioctl.c -std=gnu99
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
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;
+ struct file *filp;
const struct file_operations *fops;
if (cmd != MOCTEL_FETCH_FOPS) 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);
+ filp = fget(args.fd);
+ if (!filp) return -EBADF;
+ fops = filp->f_op;
+ if (!fops) fops = &dummy_fops;
+ fput(filp);
if (copy_to_user((struct file_operations __user *)args.retp, fops, sizeof(*fops))) 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);
}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/ioctl.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+struct fetch_fops_args {
+ int fd;
+ uint64_t retp;
+};
+
+#define MOCTEL_FETCH_FOPS _IOR('m', 1, struct fetch_fops_args)
+
+struct file_operations {
+ void *owner;
+ void *llseek;
+ void *read;
+ void *write;
+ void *aio_read;
+ void *aio_write;
+ void *readdir;
+ void *poll;
+ void *unlocked_ioctl;
+ void *compat_ioctl;
+ void *mmap;
+ void *open;
+ void *flush;
+ void *release;
+ void *fsync;
+ void *aio_fsync;
+ void *fasync;
+ void *lock;
+ void *sendpage;
+ void *get_unmapped_area;
+ void *check_flags;
+ void *flock;
+ void *splice_write;
+ void *splice_read;
+ void *setlease;
+ void *fallocate;
+};
+
+
+
+int main(int argc, char **argv) {
+ if (argc != 2) fputs("Usage: show_ioctl <device>\n", stderr), exit(1);
+
+ char *devname = argv[1];
+ int devfd = open(devname, O_RDONLY);
+ if (devfd == -1) fprintf(stderr, "Can't open %s: %m\n", devname), exit(1);
+
+ int ioctlfd = open("/dev/ioctl_info", O_RDONLY);
+ if (ioctlfd == -1) fprintf(stderr, "Can't open /dev/ioctl_info: %m\n"), exit(1);
+
+ struct file_operations fops;
+ struct fetch_fops_args ioctl_args = {
+ .fd = devfd,
+ .retp = (uint64_t)&fops
+ };
+ int ret = ioctl(ioctlfd, MOCTEL_FETCH_FOPS, &ioctl_args);
+ if (ret) fprintf(stderr, "can't perform MOCTEL_FETCH_FOPS: %m\n"), exit(1);
+
+ close(ioctlfd);
+ close(devfd);
+
+ printf("unlocked_ioctl: %llx\n", (unsigned long long)fops.unlocked_ioctl);
+
+ return 0;
+}