當在內核空間中希望執行用戶空間的程序時,我們通常會調用call_usermodehelper函數或者kernel_execve。實際上,call_usermodehelper最終也執行了kernel_execve。但call_usermodehelper所多做的是將該執行請求添加到工作隊列中,待處理器執行。
函數實現在/include/linux/kmod.h中,該函數首先調用call_usermodehelper_setup初始化subprocess_info(其中包含工作隊列對象)並將__call_usermodehelper作為工作隊列的處理函數。然後調用call_usermodehelper_exec將工作隊列對象加入到khelper_wq隊列中,並等待其執行完成。__call_usermodehelper處理函數中將調用kernel_execve函數以在用戶空間執行所要執行的程序。至於kernel_execve的實現,在/arch/x86/kernel/entry_64.S中實現,其將調用sys_execve系統調用。
- ENTRY(kernel_execve)
- CFI_STARTPROC
- FAKE_STACK_FRAME $0
- SAVE_ALL
- movq %rsp,%rcx
- call sys_execve
- movq %rax, RAX(%rsp)
- RESTORE_REST
- testq %rax,%rax
- je int_ret_from_sys_call
- RESTORE_ARGS
- UNFAKE_STACK_FRAME
- ret
- CFI_ENDPROC
- END(kernel_execve)
這裡有個小技巧:subprocess_info中的第一個字段必須為work_struct結構,因為在工作隊列執行__call_usermodehelper時,其可以獲取到subprocess_info的全部內容。
分析:這裡為什麼要使用call_usermodehelper來執行程序呢,個人認為執行用戶空間程序時,不需要占用調用者的資源和時間,由工作隊列來處理即可。
遺留的問題:所要執行的程序是執行在用戶空間,還是內核空間呢?個人認為應該執行在用戶空間,原因很簡單,當我們在用戶態程序中調用該系統調用時,所執行的程序執行在用戶空間。所以我推測sys_execve系統調用中,肯定會有將內核棧指針更換為用戶棧指針的處理。只是猜測,需要後續找到證據。