# 2021q3 Homework1 (quiz1)
contribute by <`howard-hsien`>
開發環境:
- Win 10 VMware
- Ubuntu 16.04
## 編譯紀錄
need to add the following include
``` c
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
```
Linux 版本 `uname -r` 的結果為 4.15.0-142-generic
## 延伸問題:
### 1. 解釋上述程式碼運作原理,包含 ftrace 的使用
The module finds the pid and adds the pid into the list. Whenever the system calls find_ge_pid, the module redirects the program to use `hook_find_ge_pid`, and in `hook_find_ge_pid` it replaces the pid number with pid number + 1. It creates an illusion that the certain pid is hidden. However there is some problem of this implementation, which will be explained in the answer 4.
``` 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;
}
```
ftrace reference:
[net blog introduce strace/ftrace](https://www.cntofu.com/book/46/linux_kernel/diao_shi_gong_ju_ltrace_strace_ftrace_de_shi_yong.md)
[official doc](https://www.kernel.org/doc/Documentation/trace/ftrace.txt)
[using ftrace for loadable module](https://stackoverflow.com/questions/29398042/using-ftrace-for-loadable-linux-driver-module)
ftrace experiment:
```
root@ubuntu:/sys/kernel/debug/tracing# echo > trace
root@ubuntu:/sys/kernel/debug/tracing# cat trace
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
root@ubuntu:/sys/kernel/debug/tracing# echo hook_find_ge_pid >> set_ftrace_filter
root@ubuntu:/sys/kernel/debug/tracing# echo 1 >tracing_on
//use another terminal to send cmd to module
howard@ubuntu:/mnt/hgfs/host-projects-dir/JSERV-LINUX-2021/week-1$ echo "add 880" | sudo tee /dev/hideproc
add 880
root@ubuntu:/sys/kernel/debug/tracing# cat trace
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
...
0) 0.468 us | hook_find_ge_pid [hideproc]();
0) 0.363 us | hook_find_ge_pid [hideproc]();
0) 0.243 us | hook_find_ge_pid [hideproc]();
0) 0.241 us | hook_find_ge_pid [hideproc]();
0) 0.414 us | hook_find_ge_pid [hideproc]();
0) 0.304 us | hook_find_ge_pid [hideproc]();
0) 0.276 us | hook_find_ge_pid [hideproc]();
...
```
*Not very sure how to use this to trace.*
### 2. 本程式僅在 Linux v5.4 測試,若你用的核心較新,請試著找出替代方案
I am having older version of linux. Luckily I did not face this problem.
### 3. 本核心模組只能隱藏單一 PID,請擴充為允許其 PPID 也跟著隱藏,或允許給定一組 PID 列表,而非僅有單一 PID
Not implemented yet.
### 4. 指出程式碼可改進的地方,並動手實作
**1. find_ge_pid issue**
As question 1 mentions, the original `hook_find_ge_pid` returns `real_find_ge_pid(pid->numbers->nr + 1, ns)`, and if the pid happens to have another pid which is pid+1 in the list will result in failing to hide the process.
Example:
```
root 841 0.0 0.4 450088 17880 ? Ssl Jul19 0:08 /usr/sbin/NetworkManager --no-daemon
root 842 0.0 0.0 29008 2756 ? Ss Jul19 0:01 /usr/sbin/cron -f
```
```
howard@ubuntu:$ pidof NetworkManager
841
howard@ubuntu:$ echo "add 841" |sudo tee /dev/hidproc
add 841
howard@ubuntu:$ pidof NetworkManager
841
```
It shows the hidproc mod has no function for the pid 841.
To fix the problem:
``` 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); //make sure it finds nothing
return pid;
}
```
Change the nr + 1 to -1, which makes sure the pid cannot be found.
**2. unhide process pid not matching issue**
In the `unhide_process`, even the pid doesn't match the right pid, it clears the list.
``` c
static int unhide_process(pid_t pid)
{
pid_node_t *proc, *tmp_proc; //from linux document => in list_for_each_entry_safe, n(tmp_proc) is the next node
list_for_each_entry_safe (proc, tmp_proc, &hidden_proc, list_node) { //BBB
if(pid == proc->id){ // the id needs to be matched
list_del(&proc->list_node);//DDD
kfree(proc);
}
}
return SUCCESS;
}
```
**3. rmmod has problem if the list has hidden proc**
Should clean the list and all the used memories.
It crashes my vm when reinstalled the module.
``` C
static void _hideproc_exit(void)
{
pid_node_t *proc, *tmp_proc;
printk(KERN_INFO "@ %s\n", __func__);
hook_remove(&hook); // by JSERV's commented method
// free the hidden list
list_for_each_entry_safe(proc, tmp_proc, &hidden_proc, list_node) {
list_del(&proc->list_node);
kfree(proc);
}
//LIST_HEAD should be release???
/* FIXME: ensure the release of all allocated resources */
}
```
*However, I am having the question that should the LISTHEAD be released?*