#include #include #include #include #include #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); monitor_init(); 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"); // one more thing int monitor_init(void){ 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 }