diff options
Diffstat (limited to 'kernel/monitor_kernel_lib.c')
| -rw-r--r-- | kernel/monitor_kernel_lib.c | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/kernel/monitor_kernel_lib.c b/kernel/monitor_kernel_lib.c new file mode 100644 index 0000000..3dea0cd --- /dev/null +++ b/kernel/monitor_kernel_lib.c @@ -0,0 +1,427 @@ +#include "monitor_kernel.h" + +unsigned char w_arg2k_w_arg(void *ptr, watch_arg warg, + kernel_watch_arg *k_watch_arg) { + // k_watch_arg init + k_watch_arg->task_id = warg.task_id; + strncpy(k_watch_arg->name, warg.name, MAX_NAME_LEN + 1); // name + k_watch_arg->name[MAX_NAME_LEN + 1] = '\0'; // just in case + k_watch_arg->kptr = ptr; + k_watch_arg->length_byte = warg.length_byte; + k_watch_arg->threshold = warg.threshold; + k_watch_arg->unsigned_flag = warg.unsigned_flag; + k_watch_arg->greater_flag = warg.greater_flag; + return 0; +} + +/// @brief get a valuable timer +/// @param time_ns +/// @return kernel_watch_timer *, NULL means fail +kernel_watch_timer *get_timer(unsigned long long time_ns) { + int i = 0; + kernel_watch_timer *timer = NULL; + // chose a timer + for (i = 0; i < kernel_wtimer_num; i++) { + timer = &kernel_wtimer_list[i]; + + if (TIMER_EMPTY(timer)) { + break; + } + if ((timer->time_ns == time_ns) && (!TIMER_FILLED(timer))) { + break; + } + } + // if all timer is full + if (i >= MAX_TIMER_NUM) { + printk(KERN_ERR "No timer available\n"); + return NULL; + } + // if a new timer, init it + if (i > kernel_wtimer_num - 1) { + printk(KERN_INFO "New timer\n"); + + kernel_wtimer_list[i].time_ns = time_ns; + kernel_wtimer_list[i].sentinel = 0; + + kernel_wtimer_list[i].kt = ktime_set(0, (unsigned long)time_ns); // ns + // CLOCK_MONOTONIC: time since boot | HRTIMER_MODE_REL : relative time + hrtimer_init(&(kernel_wtimer_list[i].hr_timer), CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + kernel_wtimer_list[i].hr_timer.function = + check_variable_cb; // callback function + + kernel_wtimer_num = i + 1; + } + printk(KERN_INFO "now, we have %d timers\n", kernel_wtimer_num); + return &kernel_wtimer_list[i]; +} + +/// @brief hrTimer add watch +/// @param timer +/// @param k_watch_arg +/// @return 0 is success +unsigned char timer_add_watch(kernel_watch_timer *timer, + kernel_watch_arg k_watch_arg) { + if (TIMER_FILLED(timer)) { + printk(KERN_ERR "Timer is full\n"); + return -1; + } + memcpy(&timer->k_watch_args[timer->sentinel], &k_watch_arg, + sizeof(k_watch_arg)); + // timer->k_watch_args[timer->sentinel] = k_watch_arg; + timer->sentinel++; + return 0; +} + +unsigned char timer_del_watch_by_pid(kernel_watch_timer *timer, pid_t pid) { + int i = 0; + for (i = 0; i < timer->sentinel; i++) { + // if pid match, delete it and move the last one to this position, check + // again + if (timer->k_watch_args[i].task_id == pid) { + if (i != timer->sentinel - 1) { + memcpy(&timer->k_watch_args[i], + &timer->k_watch_args[timer->sentinel - 1], + sizeof(kernel_watch_arg)); + } + timer->sentinel--; + i--; + } + } + return 0; +} + +/// @brief transfer user space address to kernel space address +/// change static global "kaddr" and "page" value +/// @param pid: process id +/// @param kaddr: user space address +/// @return kernel space address + offset +void *convert_user_space_ptr(pid_t pid, unsigned long addr) { + struct task_struct *task; + struct mm_struct *mm; + int ret; + + // unsigned long aligned_addr = 0; + // unsigned long offset = 0; + + watch_local_memory *node; + + // if (addr < TASK_SIZE || addr > -PAGE_SIZE) + // { + // printk(KERN_ERR "Invalid address\n"); + // return NULL; + // } + + // for get_user_pages_remote + unsigned long aligned_addr = addr & PAGE_MASK; + unsigned long offset = addr & ~PAGE_MASK; + + printk(KERN_INFO "%s\n", __FUNCTION__); + + node = kmalloc(sizeof(watch_local_memory), GFP_KERNEL); + node->task_id = pid; + + // Find the task with pid + rcu_read_lock(); + task = pid_task(find_vpid(pid), PIDTYPE_PID); + rcu_read_unlock(); + + if (!task) { + printk(KERN_ERR "Cannot find task for PID %d\n", pid); + kfree(node); // careful there is kfree + return NULL; + } + // Get memory descriptor + mm = get_task_mm(task); + if (!mm) { + printk(KERN_ERR "Cannot get memory descriptor\n"); + kfree(node); // careful there is kfree + return NULL; + } + down_read(&task->mm->mmap_lock); + ret = get_user_pages_remote(task->mm, aligned_addr, 1, FOLL_FORCE, + &(node->page), NULL, NULL); + up_read(&task->mm->mmap_lock); + + if (ret != 1) { + printk(KERN_ERR "Cannot get user page\n"); + kfree(node); // careful there is kfree + return NULL; + } + // Map the page to kernel space + node->kaddr = kmap(node->page); + list_add_tail(&node->entry, &watch_local_memory_list); // add to list + // printk(KERN_INFO "node->kaddr: %p, aligned_addr: %ld, offset: %ld\n", + // node->kaddr, aligned_addr, offset); + return (void *)((unsigned long)(node->kaddr) + offset); +} + +/// @brief free page in watch_local_memory_list with task_id +/// @param task_id +void free_page_list(pid_t task_id) { + watch_local_memory *node, *next; + list_for_each_entry_safe(node, next, &watch_local_memory_list, entry) { + if (node == NULL) + break; + if (node->task_id == task_id) { + // unmap and release the page + if (node->kaddr) + kunmap(node->kaddr); + if (node->page) + put_page(node->page); + list_del(&node->entry); + kfree(node); // careful there is kfree + } + } +} + +/// @brief free all page in watch_local_memory_list +/// @param +void free_all_page_list(void) { + watch_local_memory *node, *next; + list_for_each_entry_safe(node, next, &watch_local_memory_list, entry) { + if (node == NULL) + break; + // unmap and release the page + if (node->kaddr) + kunmap(node->kaddr); + if (node->page) + put_page(node->page); + list_del(&node->entry); + kfree(node); // careful there is kfree + } +} + +/// @brief hrTimer handler +enum hrtimer_restart check_variable_cb(struct hrtimer *timer) { + kernel_watch_timer *k_watch_timer = + container_of(timer, kernel_watch_timer, hr_timer); + int i = 0, j = 0; + int buffer[TIMER_MAX_WATCH_NUM]; // Buffer to store the messages + + // check all watched kernel_watch_arg + for (i = 0; i < k_watch_timer->sentinel; i++) { + if (read_and_compare(&k_watch_timer->k_watch_args[i])) { + // snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), " + // name: %s, threshold: %lld, pid: %d\n", + // k_watch_timer->k_watch_args[i].name, + // k_watch_timer->k_watch_args[i].threshold, + // k_watch_timer->k_watch_args[i].task_id); + buffer[j] = i; + j++; + + // printk(KERN_INFO "j: name %s, threshold: %lld\n", + // k_watch_timer->k_watch_args[i].name, + // k_watch_timer->k_watch_args[i].threshold); + // printk(KERN_INFO "j: %d\n", j); + } + } + if (j > 0) // if any threshold reached + { + printk("-------------------------------------\n"); + printk("-------------watch monitor-----------\n"); + printk("Threshold reached:\n"); + + for (i = 0; i < j; i++) { + printk(" name: %s, threshold: %lld, pid: %d\n", + k_watch_timer->k_watch_args[buffer[i]].name, //! todo + k_watch_timer->k_watch_args[buffer[i]].threshold, + k_watch_timer->k_watch_args[buffer[i]].task_id); + } + print_task_stack(); + // restart timer after 1s + hrtimer_forward(timer, timer->base->get_time(), ktime_set(1, 0)); //! todo + printk("-------------------------------------\n"); + } else { + // keep frequency + hrtimer_forward(timer, timer->base->get_time(), k_watch_timer->kt); + } + return HRTIMER_RESTART; // restart timer +} + +/// @brief start hrTimer +/// @param timeout: timeout in us +/// @return 0 is success +// int start_hrTimer(unsigned long timeout) +// { +// printk("HrTimer Start\n"); + +// kt = ktime_set(0, (unsigned long)timeout); // us -> ns +// // CLOCK_MONOTONIC: time since boot | HRTIMER_MODE_REL : relative time +// hrtimer_init(&hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +// hr_timer.function = check_variable_cb; +// // mode the same as hrtimer_init +// hrtimer_start(&hr_timer, kt, HRTIMER_MODE_REL); +// return 0; +// } + +/// @brief start all hrTimer +/// @param +void start_all_hrTimer(void) { + int i = 0; + kernel_watch_timer *timer = NULL; + for (i = 0; i < kernel_wtimer_num; i++) { + timer = &(kernel_wtimer_list[i]); + TIMER_START(timer); + } + printk("HrTimer start,module keep %d hrtimer for now\n", kernel_wtimer_num); +} + +/// @brief cancel hrTimer +/// @param +void cancel_all_hrTimer(void) { + int i = 0; + kernel_watch_timer *timer = NULL; + for (i = 0; i < kernel_wtimer_num; i++) { + timer = &(kernel_wtimer_list[i]); + TIMER_CANCEL(timer); + } + + printk("HrTimer cancel,module keep %d hrtimer for now\n", kernel_wtimer_num); +} + +// for read_and_compare +typedef unsigned char (*compare_func)(void *, long long); + +unsigned char compare_1_byte_signed(void *ptr, long long threshold) { + // printk("compare_1_byte_signed: value %d, biss: %lld\n", *(char *)ptr, + // threshold); + return *(char *)ptr > threshold; +} +unsigned char compare_1_byte_unsigned(void *ptr, long long threshold) { + // printk("compare_1_byte_unsigned: value %d, biss: %lld\n", *(unsigned char + // *)ptr, threshold); + return *(unsigned char *)ptr > threshold; +} +unsigned char compare_2_byte_signed(void *ptr, long long threshold) { + // printk("compare_2_byte_signed: value %d, biss: %lld\n", *(short int *)ptr, + // threshold); + return *(short int *)ptr > threshold; +} +unsigned char compare_2_byte_unsigned(void *ptr, long long threshold) { + // printk("compare_2_byte_unsigned: value %d, biss: %lld\n", *(unsigned short + // int *)ptr, threshold); + return *(unsigned short int *)ptr > threshold; +} +unsigned char compare_4_byte_signed(void *ptr, long long threshold) { + // printk("compare_4_byte_signed: value %d, biss: %lld\n", *(int *)ptr, + // threshold); + return *(int *)ptr > threshold; +} +unsigned char compare_4_byte_unsigned(void *ptr, long long threshold) { + // printk("compare_4_byte_unsigned: value %d, biss: %lld\n", *(unsigned int + // *)ptr, threshold); + return *(unsigned int *)ptr > threshold; +} +unsigned char compare_8_byte_signed(void *ptr, long long threshold) { + // printk("compare_8_byte_signed: value %lld, biss: %lld\n", *(long long + // *)ptr, threshold); + return *(long long *)ptr > threshold; +} +unsigned char compare_8_byte_unsigned(void *ptr, long long threshold) { + // printk("compare_8_byte_unsigned: value %lld, biss: %lld\n", *(unsigned long + // long *)ptr, threshold); + return *(unsigned long long *)ptr > threshold; +} +// list of compare functions +static compare_func compare_funcs[8] = { + compare_1_byte_signed, compare_2_byte_signed, compare_4_byte_signed, + compare_8_byte_signed, compare_1_byte_unsigned, compare_2_byte_unsigned, + compare_4_byte_unsigned, compare_8_byte_unsigned}; + +static int func_indices[2][9] = {{0, 0, 1, 0, 2, 0, 0, 0, 3}, + {0, 4, 5, 0, 6, 0, 0, 0, 7}}; + +/// @brief read k_arg->kptr and compare with threshold +/// @param k_arg +/// @return result of compare +unsigned char read_and_compare(kernel_watch_arg *k_arg) { + void *ptr = k_arg->kptr; + int len = k_arg->length_byte; + unsigned char is_unsigned = k_arg->unsigned_flag; + long long threshold = k_arg->threshold; + + unsigned char result = 0; + + // if (len != 1 && len != 2 && len != 4 && len != 8) + // { + // printk(KERN_ERR "Invalid length\n"); + // return 0; + // } + + result = compare_funcs[func_indices[is_unsigned][len]](ptr, threshold); + + // printk(KERN_INFO "read_and_compare: name %s, value %d, biss: %lld, result: + // %d \n", k_arg->name, *(int *)ptr, + // threshold, result); + + if (k_arg->greater_flag) + return result; + else + return !result; +} + +/// @brief init kallsyms_lookup_name +/// @param +/// @return 0 is success +int fn_kallsyms_lookup_name_init(void) { + register_kprobe(&kprobe_kallsyms_lookup_name); + diag_kallsyms_lookup_name = (void *)kprobe_kallsyms_lookup_name.addr; + unregister_kprobe(&kprobe_kallsyms_lookup_name); + + printk("xby-debug, diag_kallsyms_lookup_name is %p\n", + diag_kallsyms_lookup_name); + + if (!diag_kallsyms_lookup_name) { + return -EINVAL; + } + return 0; +} + +unsigned char del_all_kwarg_by_pid(pid_t pid) { + int i = 0; + kernel_watch_timer *timer = NULL; + + printk(KERN_INFO "del kwarg..."); + + for (i = 0; i < kernel_wtimer_num; i++) { + timer = &(kernel_wtimer_list[i]); + timer_del_watch_by_pid(timer, pid); + } + for (i = 0; i < kernel_wtimer_num; i++) { + timer = &(kernel_wtimer_list[i]); + if (TIMER_NO_KWARG(timer)) // no available kwarg + { + if (i != kernel_wtimer_num - 1) { + memcpy(timer, &kernel_wtimer_list[kernel_wtimer_num - 1], + sizeof(kernel_watch_timer)); + } + kernel_wtimer_num--; + i--; + } + } + return 0; +} + +/// @brief clear watch with pid +/// @param pid +void clear_watch(pid_t pid) { + printk(KERN_INFO "clear pid %d 's watch variable\n", pid); + cancel_all_hrTimer(); // just in case + del_all_kwarg_by_pid(pid); // delete all kwarg with pid + free_page_list(pid); // free page with pid + start_all_hrTimer(); // restart timer +} + +/// @brief clear all watch and reset kernel_wtimer_list/kernel_wtimer_num +/// @param +void clear_all_watch(void) { + printk(KERN_INFO "clear all watch variable\n"); + // unmap and release the page + free_all_page_list(); + // cancel timer + cancel_all_hrTimer(); + // clear timer + kernel_wtimer_num = 0; + memset(kernel_wtimer_list, 0, sizeof(kernel_wtimer_list)); +}
\ No newline at end of file |
