# 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
:::