# 2021q3 Homework1 (quiz1) contribute by <`howard-hsien`> 開發環境: - Win 10 VMware - Ubuntu 16.04 ## 編譯紀錄 need to add the following include ``` c #include <linux/proc_fs.h> #include <linux/slab.h> #include <linux/uaccess.h> ``` Linux 版本 `uname -r` 的結果為 4.15.0-142-generic ## 延伸問題: ### 1. 解釋上述程式碼運作原理,包含 ftrace 的使用 The module finds the pid and adds the pid into the list. Whenever the system calls find_ge_pid, the module redirects the program to use `hook_find_ge_pid`, and in `hook_find_ge_pid` it replaces the pid number with pid number + 1. It creates an illusion that the certain pid is hidden. However there is some problem of this implementation, which will be explained in the answer 4. ``` 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(pid->numbers->nr + 1, ns); return pid; } ``` ftrace reference: [net blog introduce strace/ftrace](https://www.cntofu.com/book/46/linux_kernel/diao_shi_gong_ju_ltrace_strace_ftrace_de_shi_yong.md) [official doc](https://www.kernel.org/doc/Documentation/trace/ftrace.txt) [using ftrace for loadable module](https://stackoverflow.com/questions/29398042/using-ftrace-for-loadable-linux-driver-module) ftrace experiment: ``` root@ubuntu:/sys/kernel/debug/tracing# echo > trace root@ubuntu:/sys/kernel/debug/tracing# cat trace # tracer: function_graph # # CPU DURATION FUNCTION CALLS # | | | | | | | root@ubuntu:/sys/kernel/debug/tracing# echo hook_find_ge_pid >> set_ftrace_filter root@ubuntu:/sys/kernel/debug/tracing# echo 1 >tracing_on //use another terminal to send cmd to module howard@ubuntu:/mnt/hgfs/host-projects-dir/JSERV-LINUX-2021/week-1$ echo "add 880" | sudo tee /dev/hideproc add 880 root@ubuntu:/sys/kernel/debug/tracing# cat trace # tracer: function_graph # # CPU DURATION FUNCTION CALLS # | | | | | | | ... 0) 0.468 us | hook_find_ge_pid [hideproc](); 0) 0.363 us | hook_find_ge_pid [hideproc](); 0) 0.243 us | hook_find_ge_pid [hideproc](); 0) 0.241 us | hook_find_ge_pid [hideproc](); 0) 0.414 us | hook_find_ge_pid [hideproc](); 0) 0.304 us | hook_find_ge_pid [hideproc](); 0) 0.276 us | hook_find_ge_pid [hideproc](); ... ``` *Not very sure how to use this to trace.* ### 2. 本程式僅在 Linux v5.4 測試,若你用的核心較新,請試著找出替代方案 I am having older version of linux. Luckily I did not face this problem. ### 3. 本核心模組只能隱藏單一 PID,請擴充為允許其 PPID 也跟著隱藏,或允許給定一組 PID 列表,而非僅有單一 PID Not implemented yet. ### 4. 指出程式碼可改進的地方,並動手實作 **1. find_ge_pid issue** As question 1 mentions, the original `hook_find_ge_pid` returns `real_find_ge_pid(pid->numbers->nr + 1, ns)`, and if the pid happens to have another pid which is pid+1 in the list will result in failing to hide the process. Example: ``` root 841 0.0 0.4 450088 17880 ? Ssl Jul19 0:08 /usr/sbin/NetworkManager --no-daemon root 842 0.0 0.0 29008 2756 ? Ss Jul19 0:01 /usr/sbin/cron -f ``` ``` howard@ubuntu:$ pidof NetworkManager 841 howard@ubuntu:$ echo "add 841" |sudo tee /dev/hidproc add 841 howard@ubuntu:$ pidof NetworkManager 841 ``` It shows the hidproc mod has no function for the pid 841. To fix the problem: ``` 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); //make sure it finds nothing return pid; } ``` Change the nr + 1 to -1, which makes sure the pid cannot be found. **2. unhide process pid not matching issue** In the `unhide_process`, even the pid doesn't match the right pid, it clears the list. ``` c static int unhide_process(pid_t pid) { pid_node_t *proc, *tmp_proc; //from linux document => in list_for_each_entry_safe, n(tmp_proc) is the next node list_for_each_entry_safe (proc, tmp_proc, &hidden_proc, list_node) { //BBB if(pid == proc->id){ // the id needs to be matched list_del(&proc->list_node);//DDD kfree(proc); } } return SUCCESS; } ``` **3. rmmod has problem if the list has hidden proc** Should clean the list and all the used memories. It crashes my vm when reinstalled the module. ``` C static void _hideproc_exit(void) { pid_node_t *proc, *tmp_proc; printk(KERN_INFO "@ %s\n", __func__); hook_remove(&hook); // by JSERV's commented method // free the hidden list list_for_each_entry_safe(proc, tmp_proc, &hidden_proc, list_node) { list_del(&proc->list_node); kfree(proc); } //LIST_HEAD should be release??? /* FIXME: ensure the release of all allocated resources */ } ``` *However, I am having the question that should the LISTHEAD be released?*