[PATCH] Implement uhook(call kernel func from userspace) driver
From: bigfeng12
Date: Fri Jun 22 2012 - 22:31:20 EST
Signed-off-by: bigfeng12 <peiyong.feng.kernel@xxxxxxxxx>
---
drivers/staging/uhook/Kconfig | 3 +
drivers/staging/uhook/Makefile | 1 +
drivers/staging/uhook/uhook.c | 307 ++++++++++++++++++++++++++++++++++++++++
tools/uhook/Makefile | 2 +
tools/uhook/uuhook.c | 89 ++++++++++++
5 files changed, 402 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/uhook/Kconfig
create mode 100644 drivers/staging/uhook/Makefile
create mode 100644 drivers/staging/uhook/uhook.c
create mode 100644 tools/uhook/Makefile
create mode 100644 tools/uhook/uuhook.c
diff --git a/drivers/staging/uhook/Kconfig b/drivers/staging/uhook/Kconfig
new file mode 100644
index 0000000..074aeb8
--- /dev/null
+++ b/drivers/staging/uhook/Kconfig
@@ -0,0 +1,3 @@
+config UHOOK
+ tristate "Call kernel func from user space(uhook) driver"
+ default n
diff --git a/drivers/staging/uhook/Makefile b/drivers/staging/uhook/Makefile
new file mode 100644
index 0000000..d0d7d74
--- /dev/null
+++ b/drivers/staging/uhook/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_UHOOK) += uhook.o
diff --git a/drivers/staging/uhook/uhook.c b/drivers/staging/uhook/uhook.c
new file mode 100644
index 0000000..3f77443
--- /dev/null
+++ b/drivers/staging/uhook/uhook.c
@@ -0,0 +1,307 @@
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/vmalloc.h>
+#include <linux/kallsyms.h>
+
+#include <asm/ioctls.h>
+
+/*struct uhook*/
+#define MAX_ARGV_LEN 512 /*The length of the
buffer used to staorge argv*/
+#define UHOOK_STA_LEN 32 /*The length
of the buffer used to staorge argv*/
+
+
+#define UHOOKCMD_QUERY_FUNC 1 /*CMD used to query if
there is a
symbal in kernel*/
+#define UHOOKCMD_QUERY_VAL 2 /*CMD used to query
the value of a
argument in kernel*/
+#define UHOOKCMD_RUN 3 /*CMD used to run the
func in kernel*/
+
+
+
+struct uhook{
+ char fun_name[KSYM_NAME_LEN];/*function name called
from userspace*/
+ char argv[MAX_ARGV_LEN]; /*argv of function*/
+ int argc; /*number of arg*/
+ int ret; /*return value*/
+ char status[UHOOK_STA_LEN]; /*status of kernel func run*/
+ unsigned long addr; /*Address of the kernel symbal*/
+};
+
+struct uhook_desc{
+ struct miscdevice misc; /*The misc device*/
+ struct mutex mutex; /*mutex used to protect*/
+};
+
+static struct uhook_desc *uhook_global;
+
+int uhook_unlock(void)
+{
+ printk(KERN_INFO"Unlock mutex\n");
+ mutex_unlock(&uhook_global->mutex);
+ return -1;
+}
+
+int uhook_test(void)
+{
+ printk(">>>>>>>>>>uhook test sucessfully<<<<<<<<<<<<<<<<<<<\n");
+ return -1;
+}
+EXPORT_SYMBOL_GPL(uhook_test);
+EXPORT_SYMBOL_GPL(uhook_unlock);
+
+
+static ssize_t uhook_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ return 0;
+}
+
+
+
+static ssize_t uhook_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t ppos)
+{
+ return 0;
+}
+
+
+
+static int uhook_open(struct inode *inode, struct file *file)
+{
+
+ file->private_data = uhook_global;
+ printk(KERN_INFO"Open uhook device success\n");
+ return 0;
+}
+
+static int uhook_release(struct inode *ignored, struct file *file)
+{
+ return 0;
+}
+
+
+static long uhook_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct uhook_desc *desc = file->private_data;
+ struct uhook *tmp = (struct uhook *)arg;
+
+ /*Status of kernel function run*/
+ char *exsit = "exsit";
+ char *noexsit = "no-exsit";
+ char *success = "success";
+ char *fail = "fail";
+
+ struct uhook uhook;
+ unsigned long addr;
+ int ret = 0;
+ int val = 0;
+
+ memset(&uhook, 0, sizeof(struct uhook));
+ mutex_lock(&desc->mutex);
+
+ switch (cmd) {
+ case UHOOKCMD_QUERY_FUNC:
+ if (copy_from_user(&uhook, (struct uhook __user *)arg,
sizeof(struct uhook))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ addr = kallsyms_lookup_name(uhook.fun_name);
+ if (addr) {
+ if (copy_to_user(&tmp->addr, &addr,
sizeof(unsigned long))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ ret = 0;
+ if (copy_to_user(&tmp->ret, &ret,
sizeof(unsigned long))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ if (copy_to_user(tmp->status, exsit, strlen(exsit))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ mutex_unlock(&desc->mutex);
+
+ } else {
+ ret = -1;
+ if (copy_to_user(&tmp->addr, &ret,
sizeof(unsigned long))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ if (copy_to_user(&tmp->ret, &ret, sizeof(int))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ if (copy_to_user(tmp->status, noexsit,
strlen(noexsit))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ mutex_unlock(&desc->mutex);
+ }
+ break;
+ case UHOOKCMD_QUERY_VAL:
+ /*TODO:
+ * this version of uhook can just return the int value(4 byte for 32
bit system)
+ * from kernel space to user space. And if the value is -1,
how to deal it?*/
+ if (copy_from_user(&uhook, (struct uhook __user *)arg,
sizeof(struct uhook))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ addr = kallsyms_lookup_name(uhook.fun_name);
+ if (addr) {
+ val = *(int *)addr;
+ if (copy_to_user(&tmp->addr, &addr,
sizeof(unsigned long))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ if (copy_to_user(&tmp->ret, &val, sizeof(int))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ if (copy_to_user(tmp->status, success,
strlen(success))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ mutex_unlock(&desc->mutex);
+ } else {
+ ret = -1;
+ if (copy_to_user(&tmp->addr, &ret,
sizeof(unsigned long))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ if (copy_to_user(&tmp->ret, &ret, sizeof(int))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ if (copy_to_user(tmp->status, fail, strlen(fail))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ mutex_unlock(&desc->mutex);
+ }
+ break;
+ case UHOOKCMD_RUN:
+ /*This is the point. Call kernel space function from user space
+ * TODO:
+ * This version of uhook can just support function type like:
+ * int func(void)*/
+ if (copy_from_user(&uhook, (struct uhook __user *)arg,
sizeof(struct uhook))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ addr = kallsyms_lookup_name(uhook.fun_name);
+ if (addr) {
+ int (*func)(void);
+ func = (int (*)(void))addr;
+ ret = func();
+
+ if (copy_to_user(&tmp->addr, &addr,
sizeof(unsigned long))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ if (copy_to_user(&tmp->ret, &ret, sizeof(int))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ if (copy_to_user(tmp->status, success,
strlen(success))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ mutex_unlock(&desc->mutex);
+ } else {
+ ret = -1;
+
+ if (copy_to_user(&tmp->addr, &ret,
sizeof(unsigned long))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ if (copy_to_user(&tmp->ret, &ret, sizeof(int))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ if (copy_to_user(tmp->status, noexsit,
strlen(noexsit))) {
+ mutex_unlock(&desc->mutex);
+ return -EFAULT;
+ }
+ mutex_unlock(&desc->mutex);
+ }
+ break;
+ default:
+ printk(KERN_ERR"Unknown cmd\n");
+ }
+
+ mutex_unlock(&desc->mutex);
+
+ return ret;
+}
+
+static const struct file_operations uhook_fops = {
+ .owner = THIS_MODULE,
+ .read = uhook_read,
+ .aio_write = uhook_aio_write,
+ .unlocked_ioctl = uhook_ioctl,
+ .compat_ioctl = uhook_ioctl,
+ .open = uhook_open,
+ .release = uhook_release,
+};
+
+static int __init uhook_init(char *uhook_name)
+{
+ uhook_global = kzalloc(sizeof(struct uhook_desc), GFP_KERNEL);
+ int ret = 0;
+ if (!uhook_global)
+ return -ENOMEM;
+
+ /*Do some initilization*/
+ mutex_init(&uhook_global->mutex);
+
+ uhook_global->misc.minor = MISC_DYNAMIC_MINOR;
+ uhook_global->misc.name = kstrdup(uhook_name, GFP_KERNEL);
+ if (uhook_global->misc.name == NULL) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ uhook_global->misc.fops = &uhook_fops;
+ uhook_global->misc.parent = NULL;
+
+ /*Register the misc device for uhook */
+ ret = misc_register(&uhook_global->misc);
+ if (unlikely(ret)) {
+ printk(KERN_ERR "uhook: failed to register misc "
+ "device for log '%s'!\n", uhook_global->misc.name);
+ goto out_free;
+ }
+
+ printk(KERN_INFO "uhook: created:'%s'\n",
+ uhook_global->misc.name);
+
+ return 0;
+
+out_free:
+ kfree(uhook_global);
+
+ return ret;
+}
+static int __init uhook_dev_init(void)
+{
+ if (uhook_init("uhook")) {
+ printk(KERN_ERR"uhook init failed\n");
+ return -1;
+ }
+ printk(KERN_INFO"uhook init success\n");
+ return 0;
+}
+
+static void __exit uhook_dev_deinit(void)
+{
+ misc_deregister(&uhook_global->misc);
+ kfree(uhook_global);
+}
+MODULE_LICENSE("GPL");
+module_init(uhook_dev_init);
+module_exit(uhook_dev_deinit);
diff --git a/tools/uhook/Makefile b/tools/uhook/Makefile
new file mode 100644
index 0000000..4862fc0
--- /dev/null
+++ b/tools/uhook/Makefile
@@ -0,0 +1,2 @@
+all:
+ gcc uuhook.c -o uhook
diff --git a/tools/uhook/uuhook.c b/tools/uhook/uuhook.c
new file mode 100644
index 0000000..87d088d
--- /dev/null
+++ b/tools/uhook/uuhook.c
@@ -0,0 +1,89 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/*struct uhook*/
+#define MAX_ARGV_LEN 512 /*The length of the
buffer used to staorge argv*/
+#define UHOOK_STA_LEN 32 /*The length
of the buffer used to staorge argv*/
+#define KSYM_NAME_LEN 128
+struct uhook{
+ char fun_name[KSYM_NAME_LEN];/*function name called
from userspace*/
+ char argv[MAX_ARGV_LEN]; /*argv of function*/
+ int argc; /*number of arg*/
+ int ret; /*return value*/
+ char status[UHOOK_STA_LEN]; /*status of kernel func run*/
+ unsigned long addr; /*Address of kernel symbal*/
+};
+
+
+#define UHOOKCMD_QUERY_FUNC 1 /*CMD used to query if
there is a
symbal in kernel*/
+#define UHOOKCMD_QUERY_VAL 2 /*CMD used to query
the value of a
argument in kernel*/
+#define UHOOKCMD_RUN 3 /*CMD used to run the
func in kernel*/
+
+#define DEV_NAME "/dev/uhook"
+
+static int parse_cmd(char *cmd)
+{
+ if (strcmp(cmd, "query") == 0) {
+ return UHOOKCMD_QUERY_FUNC;
+ }
+ if (strcmp(cmd, "run") == 0) {
+ return UHOOKCMD_RUN;
+ }
+ if (strcmp(cmd, "query_val") == 0) {
+ return UHOOKCMD_QUERY_VAL;
+ }
+}
+
+static int parse_result(struct uhook *uhook, char *cmd)
+{
+ printf("The ret of cmd(%s) is %d\n", cmd, uhook->ret);
+ printf("The address of ksymbal(%s) is 0x%x\n",
uhook->fun_name, uhook->addr);
+ printf("The status of ksymbal(%s) run is %s\n", uhook->fun_name,
uhook->status);
+}
+
+static void build_uhook(struct uhook *uhook, char *name)
+{
+ strcpy(uhook->fun_name, name);
+}
+/*
+ * call type:
+ * uhook --type run func
+ * argv[0] argv[1] argv[2] argv[3]
+ * */
+int main(int argc, char **argv)
+{
+
+ int uhook_fd = open(DEV_NAME, O_RDWR);
+ struct uhook uhook;
+ memset(&uhook, 0, sizeof(struct uhook));
+
+ switch(parse_cmd(argv[2])) {
+
+ case UHOOKCMD_QUERY_FUNC:
+ build_uhook(&uhook, argv[3]);
+ ioctl(uhook_fd, UHOOKCMD_QUERY_FUNC, &uhook);
+ parse_result(&uhook, "query");
+ break;
+ case UHOOKCMD_RUN:
+ build_uhook(&uhook, argv[3]);
+ ioctl(uhook_fd, UHOOKCMD_RUN, &uhook);
+ parse_result(&uhook, "run");
+ break;
+ case UHOOKCMD_QUERY_VAL:
+ build_uhook(&uhook, argv[3]);
+ ioctl(uhook_fd, UHOOKCMD_QUERY_VAL, &uhook);
+ parse_result(&uhook, "query val");
+ break;
+ default:
+ printf("Unkown cmd\n");
+ }
+ close(uhook_fd);
+ return 0;
+}
+
--
1.7.7.6
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/