# by Stanley ## task_struct 是什麼, 在哪? 在linux/sched.h裡面定義了task_struct,裡面定義了一個task/process所有的內容 ## sched.h 我只放與作業有關的內容 ```c #include <uapi/linux/sched.h> #include <asm/current.h> #include <linux/thread_info.h> ... struct task_struct { struct thread_info thread_info; unsigned int __state; ... randomized_struct_fields_start void *stack; ... unsigned int flags; unsigned int ptrace; pid_t pid; pid_t tgid; ... int prio; int static_prio; // 靜態優先度 int normal_prio; unsigned int rt_priority; struct task_struct __rcu *parent; // 有可能重新配給新的parent struct task_struct __rcu *real_parent; // 真正被fork出來的parent struct list_head children; struct list_head sibling; start_time; // start time bootstart_time utime; // user time stime; // system time ... }; ... static inline int task_nice(const struct task_struct *p) { return PRIO_TO_NICE((p)->static_prio); } #ifdef CONFIG_THREAD_INFO_IN_TASK # define task_thread_info(task) (&(task)->thread_info) #elif !defined(__HAVE_THREAD_FUNTIONS) # define task_thread_info(task) ((struct thread_info *)(task)->stack) ``` ![image](https://hackmd.io/_uploads/S1FLMzzbkl.png) ## deep into <thread_info.h> <linux/thread_info.h> 路徑在linux-x.x.x/include/linux ```c #include <asm/thread_info.h> struct thread_info { struct task_struct *task; /* main task structure */ unsigned long flags; /* low level flags */ unsigned long syscall_work; /* SYSCALL_WORK_ flags */ u32 status; /* thread synchronous flags */ #ifdef CONFIG_SMP u32 cpu; /* current CPU */ #endif }; #define current_thread_info() ((struct thread_info *)current) ``` 這邊的current指向一個stack當中的task_struct的結構 ## 此current是什麼? 在<include/asm-generic/current.h>當中有這麼一段code ```c #include <linux/thread_info.h> #define get_current() (current_thread_info()->task) #define current get_current() ``` 我們呼叫的current其實就是一個 ```c struct task_struct *task ``` ## uaccess.h 需要從kernel把struct傳入user space,就需要用到copy_to_user的system call,實際是用_copy_to_user去實作的,內容細節會用到 ```c unsigned long copy_to_user(void *to, const void *from, unsigned long n); ``` 可以看到這部分是直接傳bit當作parameter(帶void型別) >**_NOTE:_** copy_to_user 為x86的函數,跟arch版本的會不同,別用錯了 ## linux list ```c struct list_head { struct list_head *next, *prev; }; #define list_first_entry(head, type, member) \ list_entry((head)->next, type, member) #define list_last_entry(head, type, member) \ list_entry((head)->prev, type, member) ``` 例如取得task這個process/thread所生的children也就是`task_struct`當中`list_head children`中最新的child,會是children中最後一個,可以使用`list_last_entry(&current->children, struct task_struct, children)` 記得這邊的為task_struct current # 開始實作吧~ ## step1 我的entry 464改成你們自己的~ cd /usr/src/linux-6.10.9/arch/x86/entry/syscall sudo gedit syscall_64.tbl 加入一個system call entry ![image](https://hackmd.io/_uploads/HyK9XszWJe.png) ![image](https://hackmd.io/_uploads/Syh2AczZJl.png) ## step2 cd /usr/src/linux-6.10.9/include/linux 新增header sudo gedit printfo.h ![image](https://hackmd.io/_uploads/HyNdjoGW1l.png) cd /usr/src/linux-6.10.9/kernel gedit sys.c ### 加入system call define 確認uaccess.h,不然copy_to_user權限檢查的時候可能編譯錯誤 string.h : strncpy 不要用strcpy很容易overflow printfo.h : 作業要用到的struct ![image](https://hackmd.io/_uploads/Hy_m8ifW1l.png) ![image](https://hackmd.io/_uploads/H1Ncmaz-Jx.png) ## step3 cd /usr/src/linux-6.10.9/include/linux sudo gedit syscalls.h 加入header "linux/prinfo.h" ![image](https://hackmd.io/_uploads/rkwHHTfZ1g.png) 往下加入syscall linkage ![image](https://hackmd.io/_uploads/r1wqOozZyg.png) ## step4 make 回到linux-x.x.x路徑 sudo make -j8 如果這時候編譯的時候有bug 再po群組問也可以! 若沒問題安裝編譯好的image sudo make install reboot ## step5 已經重啟選好編譯完的kernel版本 隨便找個路徑測試system call 我是在/home底下測試 ![image](https://hackmd.io/_uploads/r1rc_QQZJg.png) # Output * nice值應該要藉於-19~20 * 如果是用static_prio輸出結果會是120,但這個並不是我們要的,我們要把static priority轉換成nice value,這個API在sched.h裡面可以找到,傳入task_struct型別的pointer,會從task當中把static_prio轉換成nice value then return。 * 若轉換成nice則這次的作業的值應該是 nice = 0 * 再來我們原本的shell視窗 * 可以嘗試用sudo ./test2 或是 ./test2 可以查看到uid不一樣 uid = 0為supervisor * 再多開一個shell測試一次,比對看看 ![image](https://hackmd.io/_uploads/ByfjFQXbJe.png) ![image](https://hackmd.io/_uploads/ry78YQQWyx.png) # 總結 還是希望去github找相對應的kernel版本來看source code比較快,可以查到想要的結構、函數內部結構是怎麼寫的,Linux某些函數被包裝得很隱密,必須先了解linux怎麼實作的再來做會比較容易。 # Reference [task_struct講解](https://www.cnblogs.com/yungyu16/p/13023982.html) [task struct mapping 技術](https://hackmd.io/@PIFOPlfSS3W_CehLxS3hBQ/S14tx4MqP) https://hackmd.io/@sakuraiiii/r1gFubKkF) [關於linux list_head, list這邊說明得很清楚 : Linux list wrapper](https://hackmd.io/@RinHizakura/HkEuhNwGO) [nice val](https://deepinout.com/linux-kernel-api/linux-kernel-api-process-scheduling/linux-kernel-api-task_nice.html)