# 2021q3 Homework1 (quiz1)
contribute by <Scott-Tsai0602>
環境:
+ win10 vmware
+ Ubuntu 18.04LTS
+ Kernel version: 5.4.0-80-generic
# 問題
## 1.解釋上述程式碼運作原理,包含 ftrace 的使用
+ 使用 list (hidden_proc) 去記錄想要隱藏的 process ,在 init_hook() 中對 find_ge_pid() 進行 hook,並在 hook_ftrace_thunk() 將 find_ge_pid() 換成 hook_find_ge_pid(), hook_find_ge_pid() 會去檢查傳進來的 PID 是否在 hidden_proc 中,若存在則會將 PID 替換為 PID + 1 ,使pidof不會印出pid
## 2. 本程式僅在 Linux v5.4 測試,若你用的核心較新,請試著找出替代方案
kernel版本為v5.4
## 3. 本核心模組只能隱藏單一 PID,請擴充為允許其 PPID 也跟著隱藏,或允許給定一組 PID 列表,而非僅有單一 PID
+ 原本打算使用strtok但發現kernel不支援,所以改用 strsep 實現
```c=
static ssize_t device_write(struct file *filep,
const char *buffer,
size_t len,
loff_t *offset)
{
long pid;
char *message;
char * tmp;
char * data;
char add_message[] = "add", del_message[] = "del";
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)) {
data = message + sizeof(add_message);
tmp = strsep(&data, " ,");
while(tmp != NULL){
kstrtol(tmp, 10, &pid);
hide_process(pid);
tmp = strsep(&data, " ,");
}
} else if (!memcmp(message, del_message, sizeof(del_message) - 1)) {
data = message + sizeof(del_message);
tmp = strsep(&data, " ,");
while(tmp != NULL){
kstrtol(message + sizeof(del_message), 10, &pid);
unhide_process(pid);
tmp = strsep(&data, " ,");
}
} else {
kfree(message);
return -EAGAIN;
}
*offset = len;
kfree(message);
return len;
}
```
## 4. 指出程式碼可改進的地方,並動手實作
### a.unhide_process() issue
+ Function 中並沒有確認pid就去刪除 hidden_proc 中的node,會導致要 unhide 的 process 不如預期
```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) {
//Check PID is in hidden_proc
if(pid == proc->id) {
list_del(&proc->list_node);
kfree(proc);
}
}
return SUCCESS;
}
```
### b._hideproc_exit()並沒有完成導致rmmod失敗
+ 在device_destroy()中遇到access NULL pointerdereference的問題,發現原因為先調用cdev_del()在調用在device_destroy(),修正順序後即可正常執行
```c=
[ 398.915332] BUG: kernel NULL pointer dereference, address: 0000000000000070
[ 398.915365] Call Trace:
[ 398.915370] device_remove_class_symlinks+0x63/0x70
[ 398.915371] device_del+0xbe/0x380
[ 398.915372] device_unregister+0x1a/0x60
[ 398.915372] device_destroy+0x4a/0x70
[ 398.915375] _hideproc_exit+0x85/0x9b0 [hideproc]
[ 398.915377] __x64_sys_delete_module+0x146/0x290
```
+ _hideproc_exit()
```c=
static void _hideproc_exit(void)
{
printk(KERN_INFO "@ %s\n", __func__);
pid_node_t *proc, *tmp_proc;
/* FIXME: ensure the release of all allocated resources */
//Destory device
device_destroy(hideproc_class, MKDEV(dev_major, MINOR_VERSION));
//delete cdev
cdev_del(&cdev);
//Destory class
class_destroy(hideproc_class);
unregister_chrdev_region(dev, MINOR_VERSION);
//Free hideproc list
list_for_each_entry_safe(proc, tmp_proc, &hidden_proc, list_node) {
list_del(&proc->list_node);
kfree(proc);
}
//Remove hook
hook_remove(&hook);
}
```
### c.hook_find_ge_pid() issue
+ Function當發現PID在hidden_proc中時會用 PID + 1 取代PID,但若是剛好 PID + 1 是存在的會導致隱藏失敗
+ 將 PID + 1 改為 -1 避免發生此問題
```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(-1, ns);
return pid;
}
```
### d. _hideproc_init()中並沒有error handle
+ To do