# 2021q3 Homework1 (quiz1)
contributed by <[`hochunlin`](https://github.com/hochunlin28)>
###### tags: `linux2021`
>[測驗題目描述](https://hackmd.io/@sysprog/linux2021-summer-quiz1#2021-%E5%B9%B4%E6%9A%91%E6%9C%9F-Linux-%E6%A0%B8%E5%BF%83-%E7%AC%AC-1-%E9%80%B1%E6%B8%AC%E9%A9%97%E9%A1%8C)
## 測驗解答
AAA = list_for_each_entry
BBB = list_for_each_entry_safe (因為有修改到 list)
CCC = list_add_tail(&proc->list_node, &hidden_proc)
> list_add_tail : Insert a new entry before the specified head,This is useful for implementing queues.
DDD = list_del(&proc->list_node)
[list介紹](https://myao0730.blogspot.com/2016/12/linux.html)
## 延伸問題
- [ ] 解釋程式碼運作原理,包含 ftrace 的使用 -> find_ge_pid 代表意義
- [ ] 本程式僅在 Linux v5.4 測試,若你用的核心較新,請試著找出替代方案 -> livepatch ,了解其運作原理
- [ ] 本核心模組只能隱藏單一 PID,請擴充為允許其 PPID 也跟著隱藏,或允許給定一組 PID 列表,而非僅有單一 PID
- [ ] 指出程式碼可改進的地方,並動手實作
## 開發環境
在 windows 中,利用 multipass 搭建 linux v5.4的環境, multipass 在 Windows 10 Pro/Enterprise/Education 的環境中才能使用。
```
PS C:\Users\Hochun> multipass version //查看multipass version
multipass 1.7.0+win
multipassd 1.7.0+win
```
搭建一個 linux v5.4的環境,`-n`可以命名此環境的名字
```
PS C:\Users\Hochun> multipass launch -n linux-hw1
```
利用 `multipass info (name)` 來查看目前所建立的環境
```
PS C:\Users\Hochun> multipass info linux-hw1
Name: linux-hw1
State: Running
IPv4: 172.21.171.149
Release: Ubuntu 20.04.2 LTS
Image hash: 1d3f69a8984a (Ubuntu 20.04 LTS)
Load: 0.00 0.01 0.00
Disk usage: 1.3G out of 4.7G
Memory usage: 528.2M out of 916.9M
Mounts: --
```
輸入`multipass shell (name)` 進入建立的環境
```
PS C:\Users\Hochun> multipass shell linux-hw1
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-80-generic x86_64)
System information as of Mon Jul 26 21:15:29 CST 2021
System load: 0.0 Processes: 112
Usage of /: 27.2% of 4.67GB Users logged in: 0
Memory usage: 62% IPv4 address for eth0: 172.21.171.149
Swap usage: 0%
ubuntu@linux-hw1:~$
```
## 解釋程式碼運作原理
### 由 module_init 開始看
在 hideproc.ko 被 insert 到 kernel 後,`_hideproc_init`就會執行,
```cpp
dev_t dev;
err = alloc_chrdev_region(&dev, 0, MINOR_VERSION, DEVICE_NAME);
```
`alloc_chrdev_region` 用來動態的取得一個未被其他 character device 的 number ,存放至 `dev` 中,而 `err` 用來判斷是否成功取得,若 `err` = 0 則為成功。在 [The Linux kernel API](https://www.kernel.org/doc/html/latest/core-api/kernel-api.html?highlight=alloc_chrdev_region#char-devices) 中定義了此 function:
```cpp
int alloc_chrdev_region(
dev_t *dev, //major number 與 first minor number 組成
unsigned baseminor, //第一個 minor number 的數值
unsigned count, //需要的 minor number 個數
const char *name //device 名字
)
```
在 `alloc_chrdev_region` 中,`dev` 以 `MKDEV` macro 產生,而在[linux/kdev.h](https://github.com/torvalds/linux/blob/5bfc75d92efd494db37f5c4c173d3639d4772966/include/linux/kdev_t.h) 中也定義了 `minor` number 為 20 bits,所以 `dev` 前 12 個 bits 為 major number ,後 20 bits 為 minor number,分別以 `MAJOR` 、 `MINOR` macro 取得數值
```cpp
#define MINORBITS 20
#define MINORMASK ((1U << MINORBITS) - 1)
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
```
接下來看 `class_create` ,在 [linux/class.h](https://github.com/torvalds/linux/blob/master/include/linux/device/class.h) 中定義的 macro ,會指定擁有 `struct class` 的 `owner` (通常是設定為 `THIS_MODULE` ),建立一個名為 `name` 的 class 目錄於 `sys/class` 中,回傳一個 `struct class` 指標,用於 `device_create()` 參數傳入 ,
```cpp
#define class_create(owner, name) \
({ \
static struct lock_class_key __key; \
__class_create(owner, name, &__key); \
})
```
而這裡牽扯到了 `sys` ,在[linux manual page](https://man7.org/linux/man-pages/man5/sysfs.5.html) 中可以找到 `sysfs` ,而 manual 為這樣描述:
> The sysfs filesystem is a pseudo-filesystem which provides an interface to kernel data structures (More precisely, the files and directories in sysfs **provide a view of the kobject structures** defined internally within the kernel.)
在這裡提到了 `pseudo-filesystem` 這個詞,解釋就是虛擬的 file system,在 Linux 2.6 時設計了一個 kobject structure ,利用 kobject 來建立裝置的資訊,由於 kobject 的階層化組織特性,建出一系列有組織的目錄,例如:
* /sys/module: module ( .ko 檔案)在載入後會出現對應的/sys/module/<module_name>/, 並且在這個目錄下會出現一些屬性檔案和屬性目錄來表示此 module 的一些資訊,如版本號、載入狀態、所提供的驅動程式等
* /sys/class: 利用 `class_create` 註冊在系統上,在 /sys/class 中就會出現對應的 class 目錄,在目錄中包含與 device 的 symbolic links,以題目來說,自己的了解為 `hideproc` 的 class 會建立,並與 sys/devices 做 symbolic link
> Inside each of these subdirectories are symbolic links for each of the devices in this class. These symbolic links refer to entries in the /sys/devices directory.
>> A symbolic link is a file-system object that points to another file system object
* sys/device: 這是核心對系統中所有裝置的分層次表達模型,利用 `ls -F /sys/device/` 查看
```
ubuntu@linux-hw1:~$ ls -F /sys/devices/
0006:045E:0621.0001/ breakpoint/ kprobe/ pci0000:00/ pnp0/ system/
uprobe/ LNXSYSTM:00/ isa/ msr/ platform/ software/
tracepoint/ virtual/
```
以此次作業為例, `device_create` 建立了名為 `hideproc` 的 device,其目錄會在 `sys/device/virtual` 中
```
ubuntu@linux-hw1:~$ ls -F /sys/devices/virtual
bdi/ dmi/ hideproc/ mem/ net/ ptp/ tty/ vtconsole/
block/ graphics/ input/ misc/ ppp/ thermal/ vc/ workqueue/
```
> [TODO] kobject 介紹
接下來, `cdev_init` 用來初始化 cdev structure, `fops` 為 device 的 file operation ,主要有 open 、 release 、 llseek 、read 、 write 的 file operation , 利用 `cdev_add` 來把利用 cdev structure 表示的 device 加入系統
`cdev` 的 structure 如下:
```cpp
struct cdev {
struct kobject kobj; //kobject!
struct module *owner; //used to be THIS_MODULE
const struct file_operations *ops; //file operation
struct list_head list; //??
dev_t dev; //device number
unsigned int count; //device count
} __randomize_layout;
```
最後利用 `device_create` 來創造 device 並利用 sysfs 註冊,在 /dev 中建立了名為 `hideproc` 的 device file,在 /dev 中的 device file,類似一個對於 device driver 的 interface,利用 `ls -F /dev` 也可以查詢到 `hideproc` 的 device file
> [TODO] fops function 簡介
:::info
1. 完整 device 創造流程:
* 利用 `alloc_chrdev_region` 要求 device number ,存至 `dev_t` type 之變數
* `class_create` 產生 device class
* 產生 cdev structure 來表示 device ( fops 在此設定)
* 利用 `class_create` 產生出的 class structure 以及 device number 當成參數傳至 `device_create` ,實際創造 device 出來
2. 由於自己在 `rmmod hidden_proc.ko` 之後,在/sys/class以及/dev中仍會看到`hideproc` 之 device ,所以在 `_hideproc_exit`需要把 class、device、cdev釋放
:::
## ftrace_hook 使用
參考 [Using ftrace to hook to functions](https://www.kernel.org/doc/html/v4.17/trace/ftrace-uses.html#the-callback-function) ,了解 ftrace 使用方法