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