diff options
Diffstat (limited to 'kernel/monitor_kernel.c')
| -rw-r--r-- | kernel/monitor_kernel.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/kernel/monitor_kernel.c b/kernel/monitor_kernel.c new file mode 100644 index 0000000..1d17d64 --- /dev/null +++ b/kernel/monitor_kernel.c @@ -0,0 +1,157 @@ +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> + +#include "monitor_kernel_lib.c" +#include "monitor_kernel_task.c" + +#define DEVICE_NAME "variable_monitor" + +// for character device +static dev_t dev_num; +static struct cdev *watch_cdev; +static struct class *watch_class; + +struct my_device_data { + pid_t pid; +}; + +static int device_open(struct inode *inode, struct file *file) { + struct my_device_data *data; + printk(KERN_INFO "%s: with pid %d\n", __FUNCTION__, current->pid); + // save pid + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + data->pid = current->pid; + file->private_data = data; + return 0; +} + +static int device_release(struct inode *inode, struct file *file) { + // printk(KERN_INFO "%s\n", __FUNCTION__); + // load pid + struct my_device_data *data = file->private_data; + // clear watch with pid + clear_watch(data->pid); + kfree(data); // free data memory + return 0; +} + +static long device_ioctl(struct file *file, unsigned int ioctl_num, + unsigned long ioctl_param) { + watch_arg warg; + void *kptr; + kernel_watch_timer *timer = NULL; + kernel_watch_arg k_watch_arg; + // copy watch_arg + if (copy_from_user(&warg, (watch_arg *)ioctl_param, sizeof(warg))) { + return -EACCES; + } + + printk(KERN_INFO "Watch_arg: task_id=%d, name=%s, ptr=%p, length_byte=%d, " + "time_ns=%ld, threshold=%lld\n", + warg.task_id, warg.name, warg.ptr, warg.length_byte, warg.time_ns, + warg.threshold); + // user space address to kernel space address + kptr = convert_user_space_ptr(warg.task_id, (unsigned long)warg.ptr); + if (kptr == NULL) { + printk(KERN_ERR "Cannot access user space\n"); + return -EACCES; + } + // check length + if (warg.length_byte != 1 && warg.length_byte != 2 && warg.length_byte != 4 && + warg.length_byte != 8) { + printk(KERN_ERR "Invalid length %d\n", warg.length_byte); + return -EINVAL; + } + // k_watch_arg init + w_arg2k_w_arg(kptr, warg, &k_watch_arg); + timer = get_timer(warg.time_ns); // get a valuable timer + + printk(KERN_INFO "ptr transform kptr: %p\n", kptr); + printk(KERN_INFO "timer: %p\n", timer); + printk(KERN_INFO "timer->sentinel: %d, timer->time_ns: %lld\n", + timer->sentinel, timer->time_ns); + printk(KERN_INFO "timer->hr_timer: %p\n", &timer->hr_timer); + + TIMER_CANCEL(timer); // just in case + timer_add_watch(timer, k_watch_arg); + TIMER_START(timer); + + printk(KERN_INFO "Start watching var: %s\n", warg.name); + return 0; +} + +static struct file_operations fops = { + .open = device_open, + .release = device_release, + .unlocked_ioctl = device_ioctl, +}; + +int init_module(void) { + printk(KERN_INFO "%s\n", __FUNCTION__); + if (alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME) < 0) { + printk(KERN_ALERT "Failed to register device number\n"); + return -1; + } + + if ((watch_cdev = cdev_alloc()) == NULL) { + printk(KERN_ALERT "Failed to allocate cdev structure\n"); + unregister_chrdev_region(dev_num, 1); + return -1; + } + + cdev_init(watch_cdev, &fops); + if (cdev_add(watch_cdev, dev_num, 1) == -1) { + printk(KERN_ALERT "Failed to add cdev structure\n"); + device_destroy(watch_class, dev_num); + class_destroy(watch_class); + unregister_chrdev_region(dev_num, 1); + return -1; + } + + if ((watch_class = class_create(THIS_MODULE, DEVICE_NAME)) == NULL) { + printk(KERN_ALERT "Failed to create class\n"); + cdev_del(watch_cdev); + unregister_chrdev_region(dev_num, 1); + return -1; + } + + if (device_create(watch_class, NULL, dev_num, NULL, DEVICE_NAME) == NULL) { + printk(KERN_ALERT "Failed to create device\n"); + class_destroy(watch_class); + cdev_del(watch_cdev); + unregister_chrdev_region(dev_num, 1); + return -1; + } + + printk(KERN_INFO "dev number: %d\n", dev_num); + printk(KERN_INFO "path: /dev/%s %d\n", DEVICE_NAME, dev_num); + + fn_kallsyms_lookup_name_init(); // init kallsyms_lookup_name + LOOKUP_SYMS(stack_trace_save_tsk); // stack_trace_save_tsk + LOOKUP_SYMS(show_stack); // show_stack + LOOKUP_SYMS(idle_sched_class); // idle_sched_class + LOOKUP_SYMS(access_remote_vm); // access_remote_vm + + LOOKUP_SYMS_NORET(get_task_type); // get_task_type + LOOKUP_SYMS_NORET(kernfs_name); // kernfs_name + + return 0; +} + +void cleanup_module(void) { + printk(KERN_INFO "%s\n", __FUNCTION__); + // clear all timer and page list + clear_all_watch(); + // unmount + device_destroy(watch_class, dev_num); + class_destroy(watch_class); + cdev_del(watch_cdev); + unregister_chrdev_region(dev_num, 1); +} + +MODULE_LICENSE("GPL");
\ No newline at end of file |
