Linux x86 64內核終止D狀態的進程
說實話,64位系統上做這樣的事是比較難的,因為你無法通過修改p->thread.ip來到達將進程拽出死循環的目的。要想知道64位系統上到底該怎麽把進程執行緒引出,我們得先看看”標準“的做法是什麽。
標準的做法就是fork時的行為,一個新進程剛剛被創建,它第一次進入運行狀態之前,並不是通過switch_to切出的,為了讓它”看起來像“是被切出而後被切入,就需要ret_from_fork來制造現場。問題是既然無法修改p->thread.ip,那又如何把執行緒引導到ret_from_fork裏。
答案在於,64位(這裏特指x86_64)系統是在switch_to中直接通過標誌位判斷跳轉的,其過程如下:
1.在copy_thread中設置TIF_FORK標誌2.在switch_to中判斷TIF_FORK標誌是否存在,若存在則直接跳轉到ret_from_fork
因此ret_from_fork在64位系統中是硬編碼到switch_to中的,不像32位系統中那樣是可以隨意修改的。
到這裏,想通過修改堆棧上保存的PC寄存器來達到跳出循環的這條心也該死了。一個進程被切入,要麽循著被切出之前的路徑走,要麽進入ret_from_fork,只有這兩條路。如果循著之前的路,那還是在死循環裏面,那麽只能給D進程設置TIF_FORK標記,引導它進入ret_from_fork!然而我們並不是真的希望它return from fork,而是因為這是不得已的辦法,它只能到ret_from_fork裏面。接下來怎麽辦?
接下來的技術涉及到inline hook,我們希望hook掉ret_from_fork這個entry!具體如何inline hook,本文不講,不然本文又要很長很長了。本文僅僅給出ret_from_fork被hook後的樣子:
ENTRY(ret_from_fork) DEFAULT_FRAME LOCK ; btr $TIF_FORK,TI_flags(%r8) push kernel_eflags(%rip) CFI_ADJUST_CFA_OFFSET 8 popf # reset kernel eflags CFI_ADJUST_CFA_OFFSET -8 call schedule_tail # rdi: ‘prev‘ task parameter GET_THREAD_INFO(%rcx) testl $_TIF_D, TI_flags(%rcx) # 這裏判斷是不是有新增的TIF_D標識,如果有,就直接do_exit jnz do_exit RESTORE_REST testl $3, CS-ARGOFFSET(%rsp) # from kernel_thread? je int_ret_from_sys_call testl $_TIF_IA32, TI_flags(%rcx) # 32-bit compat task needs IRET jnz int_ret_from_sys_call RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET jmp ret_from_sys_call # go to the SYSRET fastpath CFI_ENDPROC END(ret_from_fork)
然後,模塊裏非常簡單的設置TIF_FORK和TIF_D即可:
if (pid > 0) { for_each_process(p) { if (task_pid_vnr(p) == pid) { set_task_state(p, TASK_INTERRUPTIBLE); // 設置TIF_FORK,目的是執行流導入ret_from_fork set_tsk_thread_flag(p, TIF_FORK); // 設置TIF_D,目的是將執行流在hook後的ret_from_fork裏進行區分 set_tsk_thread_flag(p, TIF_D); wake_up_process(p); break; } } }
和32位系統的實驗方法一樣,D進程將被拉出死循環,然後死掉!
註意,用kprobe/jprobe技術進行hook事實上就是一種inline hook的應用,然而我們不方便用它來hook ret_from_fork,因為你既不能在ret_from_fork之前執行hook,也不能之後執行hook,而必須在其中間,即調用完schedule_tail之後去執行do_exit,因此,正確的做法是hook別的函數而不是hook ret_from_fork這個函數。仔細觀察ret_from_fork的匯編碼,就會發現在int_ret_from_sys_call,ret_from_sys_call的pre handler中進行TIF_D的判斷並且執行do_exit應該是正確的做法!
溫州皮鞋,下雨進水不會胖!
再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!https://blog.csdn.net/jiangjunshow
Linux x86 64內核終止D狀態的進程