# 2021q3 Homework1 (quiz1) contributed by < darnellyao > >[題目連結](https://hackmd.io/@sysprog/linux2021-summer-quiz1) > 解答: ``` AAA = list_for_each_entry_safe BBB = list_for_each_entry_safe CCC = list_add_tail(&proc->list_node, &hidden_proc) DDD = list_del(&proc->list_node) ``` >[作業連結](https://hackmd.io/@sysprog/linux2021-summer-homework1) ## 前置作業 * 目標: 可成功編譯程式,並正確執行 ### 開發環境 ``` OS: ubuntu 16.04 (VMware Workstation 16 Player) $ uname -r 4.15.0-142-generic ``` ### 編譯遇到的問題 1. error: implicit declaration of function ‘kmalloc’ [-Werror=implicit-function-declaration] 2. error: implicit declaration of function ‘kfree’ [-Werror=implicit-function-declaration] 3. error: implicit declaration of function ‘copy_to_user’ [-Werror=implicit-function-declaration] 4. error: implicit declaration of function ‘copy_from_user’ [-Werror=implicit-function-declaration] ``` make -C /lib/modules/`uname -r`/build M=/home/darnell/linux2021-summer/hw1 modules make[1]: Entering directory '/usr/src/linux-headers-4.15.0-142-generic' CC [M] /home/darnell/linux2021-summer/hw1/main.o /home/darnell/linux2021-summer/hw1/main.c: In function ‘hide_process’: /home/darnell/linux2021-summer/hw1/main.c:123:24: error: implicit declaration of function ‘kmalloc’ [-Werror=implicit-function-declaration] pid_node_t *proc = kmalloc(sizeof(pid_node_t), GFP_KERNEL); ^ /home/darnell/linux2021-summer/hw1/main.c:123:24: warning: initialization makes pointer from integer without a cast [-Wint-conversion] /home/darnell/linux2021-summer/hw1/main.c: In function ‘unhide_process’: /home/darnell/linux2021-summer/hw1/main.c:134:9: error: implicit declaration of function ‘kfree’ [-Werror=implicit-function-declaration] kfree(proc); ^ /home/darnell/linux2021-summer/hw1/main.c: In function ‘device_read’: /home/darnell/linux2021-summer/hw1/main.c:165:9: error: implicit declaration of function ‘copy_to_user’ [-Werror=implicit-function-declaration] copy_to_user(buffer + *offset, message, strlen(message)); ^ /home/darnell/linux2021-summer/hw1/main.c: In function ‘device_write’: /home/darnell/linux2021-summer/hw1/main.c:183:13: warning: assignment makes pointer from integer without a cast [-Wint-conversion] message = kmalloc(len + 1, GFP_KERNEL); ^ /home/darnell/linux2021-summer/hw1/main.c:185:5: error: implicit declaration of function ‘copy_from_user’ [-Werror=implicit-function-declaration] copy_from_user(message, buffer, len); ^ cc1: some warnings being treated as errors scripts/Makefile.build:330: recipe for target '/home/darnell/linux2021-summer/hw1/main.o' failed make[2]: *** [/home/darnell/linux2021-summer/hw1/main.o] Error 1 Makefile:1584: recipe for target '_module_/home/darnell/linux2021-summer/hw1' failed make[1]: *** [_module_/home/darnell/linux2021-summer/hw1] Error 2 make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-142-generic' Makefile:9: recipe for target 'all' failed make: *** [all] Error 2 ``` ### 問題解決方案 * 加入對應的標頭檔 * 問題 1 & 2 ```c #include <linux/slab.h> ``` * 問題 3 & 4 ```c #include <linux/uaccess.h> ``` * 重新編譯 ``` $ make make -C /lib/modules/`uname -r`/build M=/home/darnell/linux2021-summer/hw1 modules make[1]: Entering directory '/usr/src/linux-headers-4.15.0-142-generic' CC [M] /home/darnell/linux2021-summer/hw1/main.o LD [M] /home/darnell/linux2021-summer/hw1/hideproc.o Building modules, stage 2. MODPOST 1 modules CC /home/darnell/linux2021-summer/hw1/hideproc.mod.o LD [M] /home/darnell/linux2021-summer/hw1/hideproc.ko make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-142-generic' ``` * 載入 hideproc.ko 並執行 ``` $ sudo insmod hideproc.ko $ pidof systemd 1502 $ echo "add 1502" | sudo tee /dev/hideproc $ pidof systemd # 無法見到 systemd $ echo "del 1502" | sudo tee /dev/hideproc $ pidof systemd # 再次見到 systemd 1502 $ sudo rmmod hideproc ``` * kernel message ``` $ dmesg ... [ 81.314599] @ _hideproc_init [ 93.189709] @ _hideproc_exit ``` ### 原始程式碼存在的問題 * 執行完 rmmod 後系統當機,將在4.中改進並實作測試 ## 1.解釋上述程式碼運作原理,包含 ftrace 的使用 ## 2.本程式僅在 Linux v5.4 測試,若你用的核心較新,請試著找出替代方案 >2020 年的變更 Unexporting kallsyms_lookup_name() Access to kallsyms on Linux 5.7+ ## 3.本核心模組只能隱藏單一 PID,請擴充為允許其 PPID 也跟著隱藏,或允許給定一組 PID 列表,而非僅有單一 PID ## 4.指出程式碼可改進的地方,並動手實作 ### 1. 執行完 rmmod 後系統當機 * 主因: 移除模組時未釋放系統資源 * 程式碼修改 1. 打開 hook_remove 條件編譯 ```c #if 1 void hook_remove(struct ftrace_hook *hook) { int err = unregister_ftrace_function(&hook->ops); if (err) printk("unregister_ftrace_function() failed: %d\n", err); err = ftrace_set_filter_ip(&hook->ops, hook->address, 1, 0); if (err) printk("ftrace_set_filter_ip() failed: %d\n", err); } #endif ``` 2. 修補 _hideproc_exit 程式 ```c static int _hideproc_init(void) { int err, dev_major; dev_t dev; printk(KERN_INFO "@ %s\n", __func__); err = alloc_chrdev_region(&dev, 0, MINOR_VERSION, DEVICE_NAME); dev_major = MAJOR(dev); hideproc_class = class_create(THIS_MODULE, DEVICE_NAME); cdev_init(&cdev, &fops); cdev_add(&cdev, MKDEV(dev_major, MINOR_VERSION), 1); device_create(hideproc_class, NULL, MKDEV(dev_major, MINOR_VERSION), NULL, DEVICE_NAME); init_hook(); return 0; } ``` 將 _hideproc_init 索取的系統資源依序釋放 init_hook() -> hook_remove() device_create() -> device_destroy() cdev_add() -> cdev_del() class_create() -> class_destroy() alloc_chrdev_region() -> unregister_chrdev_region() ```c static void _hideproc_exit(void) { dev_t dev; printk(KERN_INFO "@ %s\n", __func__); hook_remove(&hook); device_destroy(hideproc_class , dev); cdev_del(&cdev); class_destroy(hideproc_class); unregister_chrdev_region(&dev, MINOR_VERSION); } ``` * 執行結果: 程式可正確執行且系統不會當機 ``` $ sudo insmod hideproc.ko $ pidof cron 897 $ echo "add 897" | sudo tee /dev/hideproc $ pidof cron # 無法見到 cron $ echo "del 897" | sudo tee /dev/hideproc $ pidof cron # 再次見到 cron 897 $ sudo rmmod hideproc $ dmesg ... [ 2686.958441] @ _hideproc_init [ 2796.544799] @ _hideproc_exit ```