# 2021q3 Homework1 (quiz1) contributed by < `BurkeyLai` > Linux 核心版本: 4.15.0-142-generic :::warning 版本過舊,該升級! :notes: jserv ::: ## 環境設置 在 `make` 的過程中出現: ``` error: implicit declaration of function 'kmalloc' error: implicit declaration of function 'kfree' error: implicit declaration of function 'copy_from_user' ``` 因此新增兩個 header file: ```c= #include <linux/slab.h> #include <linux/uaccess.h> ``` ## 解釋程式碼運作原理 首先,在 `_hideproc_init` 過程中,透過 [`alloc_chrdev_region`](https://elixir.bootlin.com/linux/v4.15/source/fs/char_dev.c#L239) 來註冊一個 major number 並存在 `dev` ,這個 major number 可建立 character 裝置驅動程式。 ```c= err = alloc_chrdev_region(&dev, 0, MINOR_VERSION, DEVICE_NAME); ``` 再利用 [`class_create`](https://elixir.bootlin.com/linux/v4.15/source/include/linux/device.h#L523) 巨集建構指標,以便我們後續使用 `device_create()` ```c= hideproc_class = class_create(THIS_MODULE, DEVICE_NAME); ``` [cdev_init](https://elixir.bootlin.com/linux/v4.15/source/fs/char_dev.c#L651) 和 [cdev_add](https://elixir.bootlin.com/linux/v4.15/source/fs/char_dev.c#L482) 可以利用 [MKDEV](https://elixir.bootlin.com/linux/v4.15/source/include/linux/kdev_t.h#L12) 和前面產生的 major number 以及 file_operations 來為系統新建一個 character 裝置 ```cpp cdev_init(&cdev, &fops); cdev_add(&cdev, MKDEV(dev_major, MINOR_VERSION), 1); ``` 最後利用 [device_create](https://elixir.bootlin.com/linux/v4.15/source/drivers/base/core.c#L2499) 為我們的 character 裝置在 `/dev/` 中建立一個 `DEVICE_NAME` 的檔案 ```cpp device_create(hideproc_class, NULL, MKDEV(dev_major, MINOR_VERSION), NULL, DEVICE_NAME); ``` --- 接著看 `init_hook` 函式,這裡有一個很重要的步驟是利用 [`kallsyms_lookup_name`](https://elixir.bootlin.com/linux/v4.15/source/kernel/kallsyms.c#L197) 來找到給定符號的地址,並存放在 `real_find_ge_pid` ,它的變數型態 `find_ge_pid_func` 是一個被定義成 `struct pid *` 的函式指標。 ```c= typedef struct pid *(*find_ge_pid_func)(int nr, struct pid_namespace *ns); static find_ge_pid_func real_find_ge_pid; ``` ```c= real_find_ge_pid = (find_ge_pid_func) kallsyms_lookup_name("find_ge_pid"); ``` 若觀察給定符號 [`find_ge_pid`](https://elixir.bootlin.com/linux/v4.15/source/kernel/pid.c#L424) 可以發現它的參數型態和 `find_ge_pid_func` 一樣,代表該指標指向的位址就是傳入的符號所在的位址。並且這個查找 PID 的函數實現在 `hook_find_ge_pid` 裡頭,這個函數是這個 kernel function 的核心,透過查找隱藏的 PID 是否存放在 list 內,進而規避掉真正要找的 PID。 ```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; } ``` :::warning 注意用語,儘量用 1970 年代台灣資訊科技前輩採用的詞彙,避免「共製漢語」 :notes: jserv ::: --- 再來是 `hook_install` ,這個函式裡頭運用 [`ftrace_set_filter_ip`](https://elixir.bootlin.com/linux/v4.9/source/kernel/trace/ftrace.c#L4253) 和 [`register_ftrace_function`](https://elixir.bootlin.com/linux/v4.9/source/kernel/trace/ftrace.c#L5617) 來將函數 `hook_ftrace_thunk` 設置在符號 `find_ge_pid` 所在的位置。 ```c= hook->address = kallsyms_lookup_name(hook->name); ``` ```c= hook->ops.func = hook_ftrace_thunk; hook->ops.flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_IPMODIFY; err = ftrace_set_filter_ip(&hook->ops, hook->address, 0, 0); ``` ```c= err = register_ftrace_function(&hook->ops); ``` 這樣當執行到 `find_ge_pid` 時,可以變更為執行 `hook_ftrace_thunk`,進而執行 `hook.func`、也就是上面提到的函數 `hook_find_ge_pid` ,實現隱藏 PID 的效果。 ```c= static void notrace hook_ftrace_thunk(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct pt_regs *regs) { struct ftrace_hook *hook = container_of(ops, struct ftrace_hook, ops); if (!within_module(parent_ip, THIS_MODULE)) regs->ip = (unsigned long) hook->func; } ``` * 參考同學 [`leon123858`的開發紀錄](https://hackmd.io/@leon123858/hideproc) 可以理解 callback function 的實現。 --- ## Reference * [alloc_chrdev_region](https://www.kernel.org/doc/html/latest/core-api/kernel-api.html?highlight=alloc_chrdev_region#c.alloc_chrdev_region): register a range of char device numbers * [class_create](https://www.kernel.org/doc/html/latest/driver-api/infrastructure.html?highlight=class_create#c.__class_create): create a struct class structure * [device_create](https://www.kernel.org/doc/html/latest/driver-api/infrastructure.html?highlight=device_create#c.device_create): creates a device and registers it with sysfs * [list_for_each_entry_safe](https://www.kernel.org/doc/html/latest/core-api/kernel-api.html?highlight=list_for_each_entry_safe#c.list_for_each_entry_safe): iterate over list of given type safe against removal of list entry <s> </s> :::warning 參考資料應以第一手資料為主,即 Linux 核心附帶的文件或者 Linux 核心開發者撰寫的素材。 :notes: jserv :::