# 2021q3 Homework1 (quiz1)
contributed by < `lekoOwO` >
## 1. 解釋上述程式碼運作原理,包含 ftrace 的使用
這個程式藉由 Hook ftrace 的方式換掉了原本的 `find_ge_pid` (本次用以代換的函式是 `hook->ops.func`,也就是 `hook_ftrace_thunk`)。
在被觸發時,`hook_ftrace_thunk` 內部的操作 (`regs->ip = (unsigned long) hook->func;`) 會把 ip 指到 `hook_find_ge_pid` 上去,藉此綁架原先的 `find_ge_pid`。
```cpp
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;
}
```
可以看到,如果發現是 hidden proc 的話,pid 就會故意 + 1,讓原本的 `find_ge_pid` 找不到。
## 2. 本程式僅在 Linux v5.4 測試,若你用的核心較新,請試著找出替代方案
```shell
$ uname -r
5.4.0-80-generic
```
所以我就沒找了(
## 3. 本核心模組只能隱藏單一 PID,請擴充為允許其 PPID 也跟著隱藏,或允許給定一組 PID 列表,而非僅有單一 PID
修改部分 `device_write` 的 Code:
```c=
static ssize_t device_write(struct file *filep,
const char *buffer,
size_t len,
loff_t *offset)
{
long pid;
char *message;
char add_message[] = "add", del_message[] = "del";
char delim[] = " ";
if (len < sizeof(add_message) - 1 && len < sizeof(del_message) - 1)
return -EAGAIN;
message = kmalloc(len + 1, GFP_KERNEL);
memset(message, 0, len + 1);
copy_from_user(message, buffer, len);
if (!memcmp(message, add_message, sizeof(add_message) - 1)) {
char token = strsep(&message, delim);
for(token = strsep(&message, delim); token != NULL; token = strsep(&message, delim)) {
kstrtol(token, 10, &pid);
hideprocess(pid);
}
} else if (!memcmp(message, del_message, sizeof(del_message) - 1)) {
char* token = strsep(&message, delim);
for(token = strsep(&message, delim); token != NULL; token = strsep(&message, delim)) {
kstrtol(token, 10, &pid);
unhide_process(pid);
}
} else {
kfree(message);
return -EAGAIN;
}
*offset = len;
kfree(message);
return len;
}
```
注意到 L18 ~ L22, L24 ~ L28
使用了 `strsep` 來對 `message` 以 `delim` 切割
藉此讀入多組 pid
而預設的 `delim` 是 `" "` (L10)。
## 4.指出程式碼可改進的地方,並動手實作
1. `unhide_process` 沒有驗證 `pid`,直接刪光光
修正:
```c=
static int unhide_process(pid_t pid)
{
pid_node_t *proc, *tmp_proc;
list_for_each_entry_safe(proc, tmp_proc, &hidden_proc, list_node) {
if (proc->id == pid) {
list_del(&proc->list_node);
kfree(proc);
}
}
return SUCCESS;
}
```
2. 資源釋放
```c=
static void _hideproc_exit(void)
{
printk(KERN_INFO "@ %s\n", __func__);
hook_remove(&hook);
device_destroy(hideproc_class, minor_dev);
class_destroy(hideproc_class);
cdev_del(&cdev);
unregister_chrdev_region(dev, MINOR_VERSION);
}
```
L6 的 minor_dev 是 `_hideproc_init` 裡 `MKDEV(dev_major, MINOR_VERSION)` 的 `dev_t`
我覺得一直 call 他很醜,所以就拿出來存比較好看。