summaryrefslogtreecommitdiff
path: root/kernel/monitor_kernel.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/monitor_kernel.c')
-rw-r--r--kernel/monitor_kernel.c157
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