# 2021q3 Homework1 (quiz1) contribute by <Scott-Tsai0602> 環境: + win10 vmware + Ubuntu 18.04LTS + Kernel version: 5.4.0-80-generic # 問題 ## 1.解釋上述程式碼運作原理,包含 ftrace 的使用 + 使用 list (hidden_proc) 去記錄想要隱藏的 process ,在 init_hook() 中對 find_ge_pid() 進行 hook,並在 hook_ftrace_thunk() 將 find_ge_pid() 換成 hook_find_ge_pid(), hook_find_ge_pid() 會去檢查傳進來的 PID 是否在 hidden_proc 中,若存在則會將 PID 替換為 PID + 1 ,使pidof不會印出pid ## 2. 本程式僅在 Linux v5.4 測試,若你用的核心較新,請試著找出替代方案 kernel版本為v5.4 ## 3. 本核心模組只能隱藏單一 PID,請擴充為允許其 PPID 也跟著隱藏,或允許給定一組 PID 列表,而非僅有單一 PID + 原本打算使用strtok但發現kernel不支援,所以改用 strsep 實現 ```c= static ssize_t device_write(struct file *filep, const char *buffer, size_t len, loff_t *offset) { long pid; char *message; char * tmp; char * data; char add_message[] = "add", del_message[] = "del"; if (len < sizeof(add_message) - 1 && len < sizeof(del_message) - 1) return -EAGAIN; message = kmalloc(len + 1, GFP_KERNEL); memset(message, 0, len + 1); copy_from_user(message, buffer, len); if (!memcmp(message, add_message, sizeof(add_message) - 1)) { data = message + sizeof(add_message); tmp = strsep(&data, " ,"); while(tmp != NULL){ kstrtol(tmp, 10, &pid); hide_process(pid); tmp = strsep(&data, " ,"); } } else if (!memcmp(message, del_message, sizeof(del_message) - 1)) { data = message + sizeof(del_message); tmp = strsep(&data, " ,"); while(tmp != NULL){ kstrtol(message + sizeof(del_message), 10, &pid); unhide_process(pid); tmp = strsep(&data, " ,"); } } else { kfree(message); return -EAGAIN; } *offset = len; kfree(message); return len; } ``` ## 4. 指出程式碼可改進的地方,並動手實作 ### a.unhide_process() issue + Function 中並沒有確認pid就去刪除 hidden_proc 中的node,會導致要 unhide 的 process 不如預期 ```c= static int unhide_process(pid_t pid) { pid_node_t *proc, *tmp_proc; list_for_each_entry_safe (proc, tmp_proc, &hidden_proc, list_node) { //Check PID is in hidden_proc if(pid == proc->id) { list_del(&proc->list_node); kfree(proc); } } return SUCCESS; } ``` ### b._hideproc_exit()並沒有完成導致rmmod失敗 + 在device_destroy()中遇到access NULL pointerdereference的問題,發現原因為先調用cdev_del()在調用在device_destroy(),修正順序後即可正常執行 ```c= [ 398.915332] BUG: kernel NULL pointer dereference, address: 0000000000000070 [ 398.915365] Call Trace: [ 398.915370] device_remove_class_symlinks+0x63/0x70 [ 398.915371] device_del+0xbe/0x380 [ 398.915372] device_unregister+0x1a/0x60 [ 398.915372] device_destroy+0x4a/0x70 [ 398.915375] _hideproc_exit+0x85/0x9b0 [hideproc] [ 398.915377] __x64_sys_delete_module+0x146/0x290 ``` + _hideproc_exit() ```c= static void _hideproc_exit(void) { printk(KERN_INFO "@ %s\n", __func__); pid_node_t *proc, *tmp_proc; /* FIXME: ensure the release of all allocated resources */ //Destory device device_destroy(hideproc_class, MKDEV(dev_major, MINOR_VERSION)); //delete cdev cdev_del(&cdev); //Destory class class_destroy(hideproc_class); unregister_chrdev_region(dev, MINOR_VERSION); //Free hideproc list list_for_each_entry_safe(proc, tmp_proc, &hidden_proc, list_node) { list_del(&proc->list_node); kfree(proc); } //Remove hook hook_remove(&hook); } ``` ### c.hook_find_ge_pid() issue + Function當發現PID在hidden_proc中時會用 PID + 1 取代PID,但若是剛好 PID + 1 是存在的會導致隱藏失敗 + 將 PID + 1 改為 -1 避免發生此問題 ```c= static struct pid *hook_find_ge_pid(int nr, struct pid_namespace *ns) { struct pid *pid = real_find_ge_pid(nr, ns); while (pid && is_hidden_proc(pid->numbers->nr)) pid = real_find_ge_pid(-1, ns); return pid; } ``` ### d. _hideproc_init()中並沒有error handle + To do