# 2021q3 Homework1 (quiz1) contributed by < [`WayneLin1992`](https://github.com/WayneLin1992) > ###### tags: `linux2021` ## 延伸問題 - [ ] 解釋程式碼運作原理,包含 ftrace 的使用 - [ ] 本程式僅在 Linux v5.4 測試,若你用的核心較新,請試著找出替代方案 - [ ] 本核心模組只能隱藏單一 PID,請擴充為允許其 PPID 也跟著隱藏,或允許給定一組 PID 列表,而非僅有單一 PID - [ ] 指出程式碼可改進的地方,並動手實作 ## 開發環境 ```shell $ uname -r 5.8.0-63-generic ``` make 後的結果 ```shell make -C /lib/modules/`uname -r`/build M=/home/wayne/linux/2021q3-quiz1 modules make[1]: 進入目錄「/usr/src/linux-headers-5.8.0-63-generic」 CC [M] /home/wayne/linux/2021q3-quiz1/main.o LD [M] /home/wayne/linux/2021q3-quiz1/hideproc.o MODPOST /home/wayne/linux/2021q3-quiz1/Module.symvers ERROR: modpost: "kallsyms_lookup_name" [/home/wayne/linux/2021q3-quiz1/hideproc.ko] undefined! make[2]: *** [scripts/Makefile.modpost:124:/home/wayne/linux/2021q3-quiz1/Module.symvers] 錯誤 1 make[2]: *** 正在刪除檔案「/home/wayne/linux/2021q3-quiz1/Module.symvers」 make[1]: *** [Makefile:1698:modules] 錯誤 2 make[1]: 離開目錄「/usr/src/linux-headers-5.8.0-63-generic」 make: *** [Makefile:9:all] 錯誤 2 ``` 由 [Unexporting kallsyms_lookup_name()](https://lwn.net/Articles/813350/) 可以知道在v5.7 之後被遺除了,因為會有後門問題。 :::info The backdoor in question is kallsyms_lookup_name(), which will return the address associated with any symbol in the kernel's symbol table. ::: 可以透過 [Access to kallsyms on Linux 5.7+](https://github.com/h33p/kallsyms-mod) 加入 module 後可以運行。 ### 其他方案 因為 kallsyms 是相當常用 function ,他會 return address 可以從 github 搜尋 `kallsyms_lookup_name()` 可以找到大家的解決方式,看了一些,大部分向下由 kprobes 來取代。 ```cpp #define KPROBE_LOOKUP 1 #include <linux/kprobes.h> static struct kprobe kp = { .symbol_name = "kallsyms_lookup_name" }; typedef unsigned long (*kallsyms_lookup_name_t)(const char *name); kallsyms_lookup_name_t kallsyms_lookup_name; register_kprobe(&kp); kallsyms_lookup_name = (kallsyms_lookup_name_t) kp.addr; unregister_kprobe(&kp); ``` ## 程式碼運行說明 可以先從看起 `module_init(_hideproc_init);` `_hideproc_init` 主要為掛載 device 並註冊 `printk(KERN_INFO "@ %s\n", __func__);` dmesg 會顯示出信息 `__func__` 會讓 `printk` 出所在的 function。 `alloc_chrdev_region` 取得動態配置 device 範圍空間 `MAJOR` 將會得到 device 的 major ID `class_create` 將會創立 class , return pointer to struct class `cdev_init` 初始化 char device , fops 為 file operation `cdev_add` 新增 char device to system `device_create` 其中 ID 由 major + minor 組成 MKDEV 得到 :::info `alloc_chrdev_region` - register a range of char device numbers >Allocates a range of char device numbers. The major number will be chosen dynamically, and returned (along with the first minor number) in dev. Returns zero or a negative error code. `MAJOR` - manage a device number >A device ID consists of two parts: a major ID, identifying the class of the device, and a minor ID, identifying a specific instance of a device in that class. `class_create` - create a struct class structure >This is used to create a struct class pointer that can then be used in calls to device_create. >Returns struct class pointer on success, or ERR_PTR on error. `cdev_add` - add a char device to the system >adds the device represented by p to the system, making it live immediately. A negative error code is returned on failure. `device_create` - creates a device and registers it with sysfs >This function can be used by char device classes. A struct device will be created in sysfs, registered to the specified class. ::: `init_hook` 主要 `struct ftrace_hook` 的初始化 `kallsyms_lookup_name` lookup the address for a symbol。 :::info `ftrace_hook` ```cpp struct ftrace_hook { const char *name; void *func, *orig; unsigned long address; struct ftrace_ops ops; }; ``` ::: `hook_install` 主要設定 `hook->ops` 並 register ftrace `hook_resolve_addr` 透過 `kallsyms_lookup_name` 得到 `find_ge_pid` 的 address :::info `struct ftrace_ops` ```cpp struct ftrace_ops { ftrace_func_t func; struct ftrace_ops *next; unsigned long flags; void *private; ftrace_func_t saved_func; int __percpu *disabled; }; ``` ftrace - function trace >可以透過 events or break point(function) triggle > 參考資料: [ftrace](https://www.kernel.org/doc/Documentation/trace/ftrace.txt) [ftrace Wikipedia](https://en.wikipedia.org/wiki/Ftrace) [Tracing with Ftrace: Critical Tooling for Linux Development by Steven Rostedt](https://linuxfoundation.org/webinars/tracefs-the-building-blocks-of-linux-kernel-tracing-by-ftrace/) ::: `ftrace_set_filter_ip` 可以 filter 掉其他相同名子的相關 function 追蹤固定 address , 這裡為 `find_ge_pid` `register_ftrace_function` tell ftrace what function should be called as the callback as well as what protections the callback will perform and not require ftrace to handle. :::info `ftrace_set_filter_ip` - set a function to filter on in ftrace by address >Sometimes more than one function has the same name. To trace just a specific function in this case. `register_ftrace_function` - register a function for profiling >The registered callback will start being called some time after the `register_ftrace_function()` is called and before it returns. The exact time that callbacks start being called is dependent upon architecture and scheduling of services. The callback itself will have to handle any synchronization if it must begin at an exact moment. ::: ```cpp static void _hideproc_exit(void) { printk(KERN_INFO "@ %s\n", __func__); /* FIXME: ensure the release of all allocated resources */ cdev_del(&cdev); unregister_chrdev_region(&dev); class_destroy(hideproc_class); } ```