---
# System prepended metadata

title: 2021q3 Homework1 (quiz1)
tags: [linux2021]

---

# 2021q3 Homework1 (quiz1)
contributed by < `bochengC` >

###### tags: `linux2021`
參考資料： [ftrace的使用](https://richardweiyang-2.gitbook.io/kernel-exploring/00-index-3/05-kernel_live_patch) 、 [about macro](https://stackoverflow.com/questions/21361854/how-are-linux-kernel-macros-used-as-functions)、[macro2](https://www.programmersought.com/article/51941881025/)


 ### 1.解釋上述程式碼運作原理，包含 ftrace 的使用 
 
ftrace 的重點部分都是在 hook_install 裡
```c=
static int hook_install(struct ftrace_hook *hook) // after hook_init
{
    int err = hook_resolve_addr(hook);//line 20 給addr 
    if (err)
        return err;

    hook->ops.func = hook_ftrace_thunk; 
    hook->ops.flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_RECURSION_SAFE |
                      FTRACE_OPS_FL_IPMODIFY;

    err = ftrace_set_filter_ip(&hook->ops, hook->address, 0, 0);
    if (err) {
        printk("ftrace_set_filter_ip() failed: %d\n", err); 
        return err;
    }
    err = register_ftrace_function(&hook->ops); 
    if (err) {
        printk("register_ftrace_function() failed: %d\n", err);
        ftrace_set_filter_ip(&hook->ops, hook->address, 1, 0); // remove 
        return err;
    }
    return 0;
}
```
在 hook_install 中，利用 `ftrace_set_filter_ip` 函數由這個函數決定是否要啟動 hook 的功能，只知道跟 `ftrace_ops` 結構中的  `*notrace_hash`, `*filter_hash` 兩個雜湊表有關係，但是詳細在看程式碼時沒有完全明白，只知道換成 `filter_hash` 會觸發 hook 的函式。
再利用 `register_ftrace_function` 將這個 ops 加入到整個系統的 `ops list` 中。 當系統呼叫 `real_find_ge_pid` 時，會引發 hook 透過 `ftrace_ops_test()` 來比對 ops 。 



### 2. 本程式僅在 Linux v5.4 測試，若你用的核心較新，請試著找出替代方案
運氣不錯，剛好用 linux v5.4，沒有遇到這個問題

### 3.1 隱藏 PPID (未完成) 
hint: [kstrtol()](http://c.biancheng.net/cpp/html/129.html) return 0 原本設計是想使用 kstrtol() ，作為分割的函數即可，可惜後來發現， kstrtol()，要直到遇到結束符號才會進行回傳，因此會在加入多個 pid 時，只有讀取到最後一個，只好更換策略，使用strsep。
原始 kstrtol 程式碼如下。
```c=
                if(state == 1){                
                    ret=kstrtol(message + i, 10, &pid); //return 0 when success 
                    printk("i=%d, pid=%ld, ret=%d", i, pid, ret);
                    if(!ret)hide_process(pid); //-22 是parsing error -EINVAL
                    state = 0;
                }
```

使用 strsep() 的程式碼如下
```c=
    if (!memcmp(message, add_message, sizeof(add_message) - 1)) {
        cptr = message + sizeof(add_message);
        for (token = strsep(&cptr, delim); token != NULL;
             token = strsep(&cptr, delim)) {
            kstrtol(token, 10, &pid);
            if (pid)
                hide_process(pid);
        }
    } else if (!memcmp(message, del_message, sizeof(del_message) - 1)) {
        cptr = message + sizeof(del_message);
        for (token = strsep(&cptr, delim); token != NULL;
             token = strsep(&cptr, delim)) {
            kstrtol(token, 10, &pid);
            if (pid)
                unhide_process(pid);
        }
    } else {
        kfree(message);
        return -EAGAIN;
    }

```
但這樣會有讀取到負數的問題，


### 3.2 隱藏 PIDlist (未完成) 



 ?? 兩個混合？ 
### 4.指出程式碼可改進的地方，並動手實作
ref : [github](https://github.com/lvming/sample-modules/blob/master/sample-cdev.c)

離開 hideproc 的時候，沒有把資源歸還，即便 rmmod 了，仍然會造成系統crash， 因此在程式碼中加入移除 module 時，將使用的資源完全歸還。這部分的做法基本上就是，在 init 增加了什麼，就在 exit 還回去，有一一對應的關係。
根據 `The Linux Kernel Module Guide` 29頁的做法，將` character device` 註銷。 又在 `_hideproc_init` 中沒有看到 `register_chrdev_region ` ，因此把 `unregister` 的部分拿掉。 再把 _hideproc_init() 內的 dev_t dev 變成全域變數。
修改好的 _hideproc_exit() 如下
```c=
static void _hideproc_exit(void)
{
    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);

    /* FIXME: ensure the release of all allocated resources */
}
```

5. 加入會隱藏hideproc本身的 pid 方法，讓自己本身也不會被函數抓到。


