# 2021q3 Homework1 (quiz1) contributed by < F74021200 > 在執行 make 時,遇到以下錯誤: `could not insert module operation not permitted` [google 搜尋後](https://stackoverflow.com/a/60190180),得知需將 [secure boot 設為 disable](https://askubuntu.com/questions/762254/why-do-i-get-required-key-not-available-when-install-3rd-party-kernel-modules) 接著,遇到 **kallsyms_lookup_name** 沒被定義的問題: ``` make -C /lib/modules/`uname -r`/build M=/home/tienwu/summer-sysprog/hideproc modules make[1]: 進入目錄「/usr/src/linux-headers-5.8.0-63-generic」 CC [M] /home/tienwu/summer-sysprog/hideproc/main.o LD [M] /home/tienwu/summer-sysprog/hideproc/hideproc.o MODPOST /home/tienwu/summer-sysprog/hideproc/Module.symvers ERROR: modpost: "kallsyms_lookup_name" [/home/tienwu/summer-sysprog/hideproc/hideproc.ko] undefined! make[2]: *** [scripts/Makefile.modpost:124:/home/tienwu/summer-sysprog/hideproc/Module.symvers] 錯誤 1 make[2]: *** 正在刪除檔案「/home/tienwu/summer-sysprog/hideproc/Module.symvers」 make[1]: *** [Makefile:1698:modules] 錯誤 2 make[1]: 離開目錄「/usr/src/linux-headers-5.8.0-63-generic」 make: *** [Makefile:9:all] 錯誤 2 ``` 依據老師提供的[連結](https://github.com/h33p/kallsyms-mod),引入 kprobe 機制, 修改 main.c ```click= #include <linux/cdev.h> #include <linux/ftrace.h> #include <linux/kallsyms.h> #include <linux/list.h> #include <linux/module.h> #include <linux/proc_fs.h> #include "kallsyms.h" #include "ksyms.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("National Cheng Kung University, Taiwan"); enum RETURN_CODE { SUCCESS }; struct ftrace_hook { const char *name; void *func, *orig; unsigned long address; struct ftrace_ops ops; }; static int hook_resolve_addr(struct ftrace_hook *hook) { hook->address = kallsyms_lookup_name(hook->name); if (!hook->address) { printk("unresolved symbol: %s\n", hook->name); return -ENOENT; } *((unsigned long *) hook->orig) = hook->address; return 0; } static void notrace hook_ftrace_thunk(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct pt_regs *regs) { struct ftrace_hook *hook = container_of(ops, struct ftrace_hook, ops); if (!within_module(parent_ip, THIS_MODULE)) regs->ip = (unsigned long) hook->func; } static int hook_install(struct ftrace_hook *hook) { int err = hook_resolve_addr(hook); 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); return err; } return 0; } #if 0 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 typedef struct { pid_t id; struct list_head list_node; } pid_node_t; LIST_HEAD(hidden_proc); typedef struct pid *(*find_ge_pid_func)(int nr, struct pid_namespace *ns); static find_ge_pid_func real_find_ge_pid; static struct ftrace_hook hook; static bool is_hidden_proc(pid_t pid) { pid_node_t *proc, *tmp_proc; list_for_each_entry_safe (proc, tmp_proc, &hidden_proc, list_node) { if (proc->id == pid) return true; } return false; } 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; } static void init_hook(void) { real_find_ge_pid = (find_ge_pid_func) kallsyms_lookup_name("find_ge_pid"); hook.name = "find_ge_pid"; hook.func = hook_find_ge_pid; hook.orig = &real_find_ge_pid; hook_install(&hook); } static int hide_process(pid_t pid) { pid_node_t *proc = kmalloc(sizeof(pid_node_t), GFP_KERNEL); proc->id = pid; list_add_tail(&proc->list_node, &hidden_proc); return SUCCESS; } 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) { list_del(&hidden_proc); kfree(proc); } return SUCCESS; } #define OUTPUT_BUFFER_FORMAT "pid: %d\n" #define MAX_MESSAGE_SIZE (sizeof(OUTPUT_BUFFER_FORMAT) + 4) static int device_open(struct inode *inode, struct file *file) { return SUCCESS; } static int device_close(struct inode *inode, struct file *file) { return SUCCESS; } static ssize_t device_read(struct file *filep, char *buffer, size_t len, loff_t *offset) { pid_node_t *proc, *tmp_proc; char message[MAX_MESSAGE_SIZE]; if (*offset) return 0; list_for_each_entry_safe (proc, tmp_proc, &hidden_proc, list_node) { memset(message, 0, MAX_MESSAGE_SIZE); sprintf(message, OUTPUT_BUFFER_FORMAT, proc->id); copy_to_user(buffer + *offset, message, strlen(message)); *offset += strlen(message); } return *offset; } static ssize_t device_write(struct file *filep, const char *buffer, size_t len, loff_t *offset) { long pid; char *message; 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)) { kstrtol(message + sizeof(add_message), 10, &pid); hide_process(pid); } else if (!memcmp(message, del_message, sizeof(del_message) - 1)) { kstrtol(message + sizeof(del_message), 10, &pid); unhide_process(pid); } else { kfree(message); return -EAGAIN; } *offset = len; kfree(message); return len; } static struct cdev cdev; static struct class *hideproc_class = NULL; static const struct file_operations fops = { .owner = THIS_MODULE, .open = device_open, .release = device_close, .read = device_read, .write = device_write, }; #define MINOR_VERSION 1 #define DEVICE_NAME "hideproc" KSYMDEF(kvm_lock); KSYMDEF(vm_list); static int _hideproc_init(void) { int err, dev_major; dev_t dev; int r; printk(KERN_INFO "@ %s\n", __func__); err = alloc_chrdev_region(&dev, 0, MINOR_VERSION, DEVICE_NAME); dev_major = MAJOR(dev); if ((r = init_kallsyms())) return r; KSYMINIT_FAULT(kvm_lock); KSYMINIT_FAULT(vm_list); if (r) return r; 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; } static void _hideproc_exit(void) { printk(KERN_INFO "@ %s\n", __func__); /* FIXME: ensure the release of all allocated resources */ } module_init(_hideproc_init); module_exit(_hideproc_exit); ``` 修改 Makefile: ```click= MODULENAME := hideproc obj-m += $(MODULENAME).o $(MODULENAME)-y += main.o kallsyms.o KERNELDIR ?= /lib/modules/`uname -r`/build PWD := $(shell pwd) all: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: $(MAKE) -C $(KERNELDIR) M=$(PWD) clean ``` make 後: ``` make -C /lib/modules/`uname -r`/build M=/home/tienwu/summer-sysprog/hideproc modules make[1]: 進入目錄「/usr/src/linux-headers-5.8.0-63-generic」 CC [M] /home/tienwu/summer-sysprog/hideproc/main.o CC [M] /home/tienwu/summer-sysprog/hideproc/kallsyms.o LD [M] /home/tienwu/summer-sysprog/hideproc/hideproc.o MODPOST /home/tienwu/summer-sysprog/hideproc/Module.symvers CC [M] /home/tienwu/summer-sysprog/hideproc/hideproc.mod.o LD [M] /home/tienwu/summer-sysprog/hideproc/hideproc.ko make[1]: 離開目錄「/usr/src/linux-headers-5.8.0-63-generic」 ``` ``` $ sudo insmod hideproc.ko $ pidof cron 719 $ echo "add 719" | sudo tee /dev/hideproc add 719 $ pidof cron $ echo "del 719" | sudo tee /dev/hideproc del 719 $ pidof cron Segmentation fault $ sudo rmmod hideproc ``` 由於在 main.c 中,使用 `list_del(&hidden_proc)` ,導致出現 `Segmentation fault`,並在 `rmmod` 時,電腦畫面突然變得非常不穩,畫面甚至直接消失,在無法操作的情況下,只能長按電源鍵強制重開機,然而,第一次重開機時,在登入後,畫面又再次消失,直到第二次重開機,電腦畫面才不再消失。在此經歷後,決定使用課堂上老師提到的 ==**multipass**== ## multipass ``` $ sudo snap install multipass ``` 開啟一個虛擬機,4 核,512M Ram,4G disk,名稱為 foo1 ``` $ multipass launch -c 4 -m 512M -d 4G -n foo1 Launched: foo1 ``` 列出目前存在的虛擬機 ``` $ multipass list Name State IPv4 Image foo1 Running 10.212.153.251 Ubuntu 20.04 LTS ``` 查看虛擬機 foo1 的資訊 ``` $multipass info foo1 Name: foo1 State: Running IPv4: 10.212.153.251 Release: Ubuntu 20.04.2 LTS Image hash: 1d3f69a8984a (Ubuntu 20.04 LTS) Load: 0.01 0.11 0.07 Disk usage: 1.3G out of 3.7G Memory usage: 153.3M out of 477.3M Mounts: -- ``` 進入虛擬機 foo1 的 shell ``` $multipass shell foo1 Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-80-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Wed Jul 28 15:55:54 CST 2021 System load: 0.0 Processes: 123 Usage of /: 34.3% of 3.71GB Users logged in: 0 Memory usage: 43% IPv4 address for ens4: 10.212.153.251 Swap usage: 0% 1 update can be applied immediately. To see these additional updates run: apt list --upgradable The list of available updates is more than a week old. To check for new updates run: sudo apt update To run a command as administrator (user "root"), use "sudo <command>". See "man sudo_root" for details. ubuntu@foo1:~$ ``` ### multipass - 與本地端共享目錄 [How to share data between host and VM with Multipass](https://www.techrepublic.com/article/how-to-share-data-between-host-and-vm-with-multipass/) ``` $ mkdir multipass_share $ multipass mount ~/multipass_share foo1 $ multipass info foo1 Name: foo1 State: Running IPv4: 10.212.153.74 Release: Ubuntu 20.04.2 LTS Image hash: 1d3f69a8984a (Ubuntu 20.04 LTS) Load: 0.01 0.11 0.09 Disk usage: 1.3G out of 3.7G Memory usage: 181.9M out of 477.3M Mounts: /home/"your username"/multipass_share => /home/tienwu/multipass_share UID map: 1000:default GID map: 1000:default ``` 共用目錄會在 `/home/"your username"/multipass_share` ``` ubuntu@foo1:~$ cd /home/"your username" ubuntu@foo1:/home/"your username"$ ls multipass_share ``` ``` $ multipass stop foo1 ``` ``` $ multipass delete foo1 ``` ``` $ multipass purge ``` [ftrace api](https://www.kernel.org/doc/html/latest/trace/ftrace-uses.html?highlight=ftrace_set_filter_ip) [ftrace](https://www.kernel.org/doc/html/latest/trace/ftrace.html) ### 執行 pidof 時,使用 ftrace 追蹤 find_ge_pid 建立 soft link ``` ubuntu@foo3:~$ sudo ln -s /sys/kernel/tracing/ /tracing ``` 進到 root mode ``` ubuntu@foo3:~$ sudo su root@foo3:/home/ubuntu# ``` 進到 /tracing ``` root@foo3:/home/ubuntu# cd /tracing root@foo3:/tracing# ``` 查看目前 `set_ftrace_filter` ``` root@foo3:/tracing# cat set_ftrace_filter #### all functions enabled #### ``` 設定 filter ``` root@foo3:/tracing# echo find_ge_pid > set_ftrace_filter root@foo3:/tracing# cat set_ftrace_filter find_ge_pid ``` 清空 trace,並查看 trace 結果 ``` root@foo3:/tracing# echo 0 > trace root@foo3:/tracing# cat trace # tracer: function # # entries-in-buffer/entries-written: 0/0 #P:4 # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / delay # TASK-PID CPU# |||| TIMESTAMP FUNCTION # | | | |||| | | ``` 查看目前 tracer ``` root@foo3:/tracing# cat current_tracer nop ``` 查看目前可用 tracer ``` root@foo3:/tracing# cat available_tracers hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop ``` 設定 function 為 tracer ``` root@foo3:/tracing# echo function > current_tracer root@foo3:/tracing# cat current_tracer function ``` 查看目前 trace,仍為空 ``` root@foo3:/tracing# cat trace # tracer: function # # entries-in-buffer/entries-written: 0/0 #P:4 # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / delay # TASK-PID CPU# |||| TIMESTAMP FUNCTION # | | | |||| | | ``` 執行 `pidof cron`,並查看 trace,發現 pidof 會觸發到 `find_ge_pid` ``` root@foo3:/tracing# pidof cron 716 root@foo3:/tracing# cat trace # tracer: function # # entries-in-buffer/entries-written: 158/158 #P:4 # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / delay # TASK-PID CPU# |||| TIMESTAMP FUNCTION # | | | |||| | | pidof-8346 [000] .... 80903.284103: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284120: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284140: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284142: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284144: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284146: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284148: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284150: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284152: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284154: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284156: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284157: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284159: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284168: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284170: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284172: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284180: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284182: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284185: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284188: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284202: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284206: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284214: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284216: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284224: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284226: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284229: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284231: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284233: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284234: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284236: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284237: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284239: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284241: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284242: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284244: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284247: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284256: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284263: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284271: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284273: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284275: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284276: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284279: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284281: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284289: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284291: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284293: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284294: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284296: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284298: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284299: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284301: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284302: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284304: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284307: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284317: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284320: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284322: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284323: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284326: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284335: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284352: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284359: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284374: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284376: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284377: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284380: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284382: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284392: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284395: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284397: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284399: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284401: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284470: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284483: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284485: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284486: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284486: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284487: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284488: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284491: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284497: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284501: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284503: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284505: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284508: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284510: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284513: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284515: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284518: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284519: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284522: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284524: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284527: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284540: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284542: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284545: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284547: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284547: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284549: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284551: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284570: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284572: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284576: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284578: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284580: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284582: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284597: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284606: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284610: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284612: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284616: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284636: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284647: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284650: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284652: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284666: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284668: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284671: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284673: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284681: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284681: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284682: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284684: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284692: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284695: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284698: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284701: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284704: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284706: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284708: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284708: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284709: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284710: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284711: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284719: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284720: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284721: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284721: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284724: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284724: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284725: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284727: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284727: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284729: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284739: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284742: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284744: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284746: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284749: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284751: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284796: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284841: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284844: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284847: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284858: find_ge_pid <-next_tgid pidof-8346 [000] .... 80903.284862: find_ge_pid <-next_tgid ``` 此 kernel module 主要透過 character device 與 ftrace hook 運作。 ### kernel module ```click= 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; } ``` install kernel module 時,會創建一個 character device,並初始化 ftrace hook ### character device 當 character device 被讀寫時,`device_write` 會被呼叫: ```click= static ssize_t device_write(struct file *filep, const char *buffer, size_t len, loff_t *offset) { long pid; char *message; 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)) { kstrtol(message + sizeof(add_message), 10, &pid); hide_process(pid); } else if (!memcmp(message, del_message, sizeof(del_message) - 1)) { kstrtol(message + sizeof(del_message), 10, &pid); unhide_process(pid); } else { kfree(message); return -EAGAIN; } *offset = len; kfree(message); return len; } ``` 依照寫入字串,若是 `add pid`,則呼叫 `hide_process(pid)`,若是 `del pid`,則呼叫 `unhide_process(pid)` ### ftrace hook initialize hook: ```click= static void init_hook(void) { real_find_ge_pid = (find_ge_pid_func) kallsyms_lookup_name("find_ge_pid"); hook.name = "find_ge_pid"; hook.func = hook_find_ge_pid; hook.orig = &real_find_ge_pid; hook_install(&hook); } ``` `init_hook()` 會先呼叫 `kallsyms_lookup_name` 來搜尋 `find_ge_pid` 的所在位址,並將此位址存於 `hook.orig` 中,並將函式 `hook_find_ge_pid` 賦予 `hook.func`,最後呼叫 `hook_install(&hook)` hook_install: ```click= static int hook_install(struct ftrace_hook *hook) { int err = hook_resolve_addr(hook); 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); return err; } return 0; } ``` `hook_install` 會先呼叫 `hook_resolve_addr(hook)` : ```click= static int hook_resolve_addr(struct ftrace_hook *hook) { hook->address = kallsyms_lookup_name(hook->name); if (!hook->address) { printk("unresolved symbol: %s\n", hook->name); return -ENOENT; } *((unsigned long *) hook->orig) = hook->address; return 0; } ``` `hook_resolve_addr` 會呼叫 `kallsyms_lookup_name(hook->name)` ,在 `init_hook` 中,可知 `hook->name` 為 `"find_ge_pid"`,也就是搜尋 `"find_ge_pid"` 所在位址並存於 `hook->address` 與 `hook->orig` 中。 接著,將 `hook_ftrace_thunk` 賦予 `hook->ops.func` ,作為 ftrace 的 callback function,並賦予 `hook->ops.flags`,FTRACE_OPS_FL_SAVE_REGS , FTRACE_OPS_FL_RECURSION_SAFE ,FTRACE_OPS_FL_IPMODIFY,關於[此三個 flag](https://www.kernel.org/doc/html/v4.18/trace/ftrace-uses.html),分別代表: FTRACE_OPS_FL_SAVE_REGS >If the callback requires reading or modifying the pt_regs passed to the callback, then it must set this flag. Registering a ftrace_ops with this flag set on an architecture that does not support passing of pt_regs to the callback will fail. FTRACE_OPS_FL_RECURSION_SAFE >By default, a wrapper is added around the callback to make sure that recursion of the function does not occur. That is, if a function that is called as a result of the callback’s execution is also traced, ftrace will prevent the callback from being called again. But this wrapper adds some overhead, and if the callback is safe from recursion, it can set this flag to disable the ftrace protection. Note, if this flag is set, and recursion does occur, it could cause the system to crash, and possibly reboot via a triple fault. It is OK if another callback traces a function that is called by a callback that is marked recursion safe. Recursion safe callbacks must never trace any function that are called by the callback itself or any nested functions that those functions call. FTRACE_OPS_FL_IPMODIFY >Requires FTRACE_OPS_FL_SAVE_REGS set. If the callback is to “hijack” the traced function (have another function called instead of the traced function), it requires setting this flag. This is what live kernel patches uses. Without this flag the pt_regs->ip can not be modified. Note, only one ftrace_ops with FTRACE_OPS_FL_IPMODIFY set may be registered to any given function at a time. 接著,呼叫 `ftrace_set_filter_ip(&hook->ops, hook->address, 0, 0)`, [ftrace_set_filter_ip](https://www.kernel.org/doc/html/latest/trace/ftrace-uses.html) >Sometimes more than one function has the same name. To trace just a specific function in this case, ftrace_set_filter_ip() can be used. ret = ftrace_set_filter_ip(&ops, ip, 0, 0); 設置 filter,使 ftrace 只追蹤特定函式,在此為 `hook->address`,也就是 `find_ge_pid`, 接著,呼叫 `register_ftrace_function(&hook->ops)`, [register_ftrace_function](https://www.kernel.org/doc/html/latest/trace/ftrace-uses.html) >To enable tracing call: register_ftrace_function(&ops); 啟動追蹤。 當 `find_ge_pid` 被執行時,ftrace 會被觸發,並呼叫存於 `ops` 的 callback function,`hook_ftrace_thunk` hook_ftrace_thunk: ```click= static void notrace hook_ftrace_thunk(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct pt_regs *regs) { struct ftrace_hook *hook = container_of(ops, struct ftrace_hook, ops); if (!within_module(parent_ip, THIS_MODULE)) regs->ip = (unsigned long) hook->func; } ``` 當 `ftrace` 開始追蹤時,會呼叫 `hook_ftrace_thunk`,並將 `ops` 作為參數傳入 `hook_ftrace_thunk`,在 `hook_ftrace_thunk` 中,會利用 container_of 來取得全域宣告的 `hook`,再藉由 `hook` 來存取 `hook->func`,此 `hook->func` 為 `hook_find_ge_pid`,並將 `hook_find_ge_pid` 賦予 `regs->ip`。 關於 [regs](https://www.kernel.org/doc/html/latest/trace/ftrace-uses.html) >If the FTRACE_OPS_FL_SAVE_REGS or FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED flags are set in the ftrace_ops structure, then this will be pointing to the pt_regs structure like it would be if an breakpoint was placed at the start of the function where ftrace was tracing. Otherwise it either contains garbage, or NULL. 目前沒有找到更多關於 `regs` 的運作 ... ### hideproc is_hidden_proc: ```click= static bool is_hidden_proc(pid_t pid) { pid_node_t *proc, *tmp_proc; list_for_each_entry_safe (proc, tmp_proc, &hidden_proc, list_node) { if (proc->id == pid) return true; } return false; } ``` `is_hidden_proc` 會從 `hidden_proc` 中,確認 pid 是否存在。 hook_find_ge_pid: ```click= 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; } ``` `hook_find_ge_pid` 會呼叫 `real_find_ge_pid`,也就是 `find_ge_pid`,依次走訪目前存在的 pid,若搜尋到被隱藏的 pid,則忽略,並繼續走訪下一個 pid,直到發現一個沒被隱藏的 pid,並回傳此 pid,若沒有多餘的 pid,則直接回傳目前走訪到的 pid。 ### 運作 使用者藉由 'echo',將 `add pid` 寫入 hideproc 這個 character device,因為 hideproc 被寫入,呼叫 `device_write`,依照寫入字串呼叫 `hide_process` 或 `unhide_process`,當使用者輸入 `pidof` 時,由上述可知,利用 `ftrace` 追蹤 `find_ge_pid` 時,若執行 `pidof`,`find_ge_pid` 會被呼叫,因此,當使用者輸入 `pidof` 時,ftrace 的 hook 的 callback function 就會被執行,也就是 `hook_ftrace_thunk`,`hook_ftrace_thunk` 會將 `hook_find_ge_pid` 賦予 `regs->ip`,接下來的運作我就沒找到相關資料了,希望有高人能夠指點。 [kmalloc](https://www.kernel.org/doc/htmldocs/kernel-api/API-kmalloc.html) [list](https://elixir.bootlin.com/linux/latest/source/include/linux/list.h#L23) [disable secure boot](https://wiki.ubuntu.com/UEFI/SecureBoot/DKMS)