1. 程式人生 > >Linux使用者態用訊號定位異常退出訪問非法記憶體問題

Linux使用者態用訊號定位異常退出訪問非法記憶體問題

repost from:http://www.cjjjs.com/paper/xmkf/2017817141130842.html

很多使用者認為程序異常終止情況無從分析,但實際上程序異常終止情況都是有跡可尋的. 所有的程序異常終止行為,都是通過核心發訊號給特定程序或程序組實現的. 可分成幾個型別進行描述:

    - SIGKILL. SIGKILL最特殊,因為該訊號不可被捕獲,同時SIGKILL不會導致被終止的程序產生core檔案, 但如果真正的是由核心中發出的SIGKILL,則核心一定會在dmesg中記錄下資訊. 另外在核心中使用SIGKILL的地方屈指可數,如oom_kill_process()中, 所以通過dmesg記錄並且分析核心中使用SIGKILL的程式碼,並不難分析原因
    - SIGQUIT, SIGILL, SIGABRT, SIGBUS, SIGFPE, SIGSEGV. 這幾個訊號在保留情況下會終止程序並會產生core檔案, 使用者根據core中的stack trace資訊,能直接定位出導致終止訊號的程式碼位置. 另外, SIGQUIT,SIGABRT一般是由使用者程式碼自己使用的,好的程式碼一般會記錄日誌. SIGILL, SIGBUS, SIGFPE, SIGSEGV, 都是由核心中產生的,搜尋核心原始碼,不難列出核心中使用這幾個訊號的地方, 如SIGILL 是非法指令,可能是浮點運算產生的程式碼被corrupted或文字區域的實體記憶體corruption; SIGBUS多由MCE故障定位導致; SIGSEGV多由應用程式碼的指標變數被corrupted導致. 對於應用的heap或stack的記憶體被corrupted, 可用valgrind工具對應用進行profile, 通常能直接發現導致corruption的程式碼
    - SIGINT, SIGPIPE, SIGALRM, SIGTERM. 這幾個訊號在保留情況下終止程序但不會產生core檔案. 對這幾個訊號,建議使用者一定要定義一個handler,以記錄產生問題的上下文. 比較容易忽略的是SIGPIPE, 很多使用者程式在使用select()或poll()時只監聽read/write描述符,不監聽exception描述符,在對方TCP已經關閉的情況下,仍然向socket中寫入,導致SIGPIPE.

    - 對於惡意的代嗎產生的程序終止行為,如合作的一些程序中,A向B發SIGKILL, 而沒做日誌記錄,或者B直接判斷某條件而呼叫exit(), 也沒有做日誌記錄.在應用程式碼量很大的情況下,通過分析程式碼故障定位這種情形也許很難. SystemTap提供瞭解決這個問題的一個比較好的方法,就是寫使用者層的probes, 追蹤程序對signal(), exit() 等系統呼叫的使用.

Signal Description
SIGABRT 由呼叫abort函式產生,程序非正常退出
SIGALRM 用alarm函式設定的timer超時或setitimer函式設定的interval timer超時
SIGBUS 某種特定的硬體異常,通常由記憶體訪問引起
SIGCANCEL 由Solaris Thread Library內部使用,通常不會使用
SIGCHLD 程序Terminate或Stop的時候,SIGCHLD會發送給它的父程序。預設情況下該Signal會被忽略
SIGCONT 當被stop的程序恢復執行的時候,自動傳送
SIGEMT 和實現相關的硬體異常
SIGFPE 數學相關的異常,如被0除,浮點溢位,等等
SIGFREEZE Solaris專用,Hiberate或者Suspended時候傳送
SIGHUP 傳送給具有Terminal的Controlling Process,當terminal被disconnect時候傳送
SIGILL 非法指令異常
SIGINFO BSD signal。由Status Key產生,通常是CTRL+T。傳送給所有Foreground Group的程序
SIGINT 由Interrupt Key產生,通常是CTRL+C或者DELETE。傳送給所有ForeGround Group的程序
SIGIO 非同步IO事件
SIGIOT 實現相關的硬體異常,一般對應SIGABRT
SIGKILL 無法處理和忽略。中止某個程序
SIGLWP 由Solaris Thread Libray內部使用
SIGPIPE 在reader中止之後寫Pipe的時候傳送
SIGPOLL 當某個事件傳送給Pollable Device的時候傳送
SIGPROF Setitimer指定的Profiling Interval Timer所產生
SIGPWR 和系統相關。和UPS相關。
SIGQUIT 輸入Quit Key的時候(CTRL+\)傳送給所有Foreground Group的程序
SIGSEGV 非法記憶體訪問
SIGSTKFLT Linux專用,數學協處理器的棧異常
SIGSTOP 中止程序。無法處理和忽略。
SIGSYS 非法系統呼叫
SIGTERM 請求中止程序,kill命令預設傳送
SIGTHAW Solaris專用,從Suspend恢復時候傳送
SIGTRAP 實現相關的硬體異常。一般是除錯異常
SIGTSTP Suspend Key,一般是Ctrl+Z。傳送給所有Foreground Group的程序
SIGTTIN 當Background Group的程序嘗試讀取Terminal的時候傳送
SIGTTOU 當Background Group的程序嘗試寫Terminal的時候傳送
SIGURG 當out-of-band data接收的時候可能傳送
SIGUSR1 使用者自定義signal 1
SIGUSR2 使用者自定義signal 2
SIGVTALRM setitimer函式設定的Virtual Interval Timer超時的時候
SIGWAITING Solaris Thread Library內部實現專用
SIGWINCH 當Terminal的視窗大小改變的時候,傳送給Foreground Group的所有程序
SIGXCPU 當CPU時間限制超時的時候
SIGXFSZ 程序超過檔案大小限制
SIGXRES Solaris專用,程序超過資源限制的時候傳送

signal對應的值:

POSIX.1中列出的訊號:

SIGHUP 1 A 終端掛起或者控制程序終止 
SIGINT 2 A 鍵盤中斷(如break鍵被按下) 
SIGQUIT 3 C 鍵盤的退出鍵被按下 
SIGILL 4 C 非法指令 
SIGABRT 6 C 由abort(3)發出的退出指令 
SIGFPE 8 C 浮點異常 
SIGKILL 9 AEF Kill訊號 
SIGSEGV 11 C 無效的記憶體引用 
SIGPIPE 13 A 管道破裂: 寫一個沒有讀埠的管道 
SIGALRM 14 A 由alarm(2)發出的訊號 
SIGTERM 15 A 終止訊號 
SIGUSR1 30,10,16 A 使用者自定義訊號1 
SIGUSR2 31,12,17 A 使用者自定義訊號2 
SIGCHLD 20,17,18 B 子程序結束訊號 
SIGCONT 19,18,25 程序繼續(曾被停止的程序) 
SIGSTOP 17,19,23 DEF 終止程序 
SIGTSTP 18,20,24 D 控制終端(tty)上按下停止鍵 
SIGTTIN 21,21,26 D 後臺程序企圖從控制終端讀 
SIGTTOU 22,22,27 D 後臺程序企圖從控制終端寫 

沒在POSIX.1中列出,而在SUSv2列出

SIGBUS 10,7,10 C 匯流排錯誤(錯誤的記憶體訪問) 
SIGPOLL A Sys V定義的Pollable事件,與SIGIO同義 
SIGPROF 27,27,29 A Profiling定時器到 
SIGSYS 12,-,12 C 無效的系統呼叫 (SVID) 
SIGTRAP 5 C 跟蹤/斷點捕獲 
SIGURG 16,23,21 B Socket出現緊急條件(4.2 BSD) 
SIGVTALRM 26,26,28 A 實際時間報警時鐘訊號(4.2 BSD) 
SIGXCPU 24,24,30 C 超出設定的CPU時間限制(4.2 BSD) 
SIGXFSZ 25,25,31 C 超出設定的檔案大小限制(4.2 BSD) 

(對於SIGSYS,SIGXCPU,SIGXFSZ,以及某些機器體系結構下的SIGBUS,Linux預設的動作是A (terminate),SUSv2 是C (terminate and dump core))。 

下面是其它的一些訊號 

訊號 值 處理動作 發出訊號的原因 
---------------------------------------------------------------------- 
SIGIOT 6 C IO捕獲指令,與SIGABRT同義 
SIGEMT 7,-,7 
SIGSTKFLT -,16,- A 協處理器堆疊錯誤 
SIGIO 23,29,22 A 某I/O操作現在可以進行了(4.2 BSD) 
SIGCLD -,-,18 A 與SIGCHLD同義 
SIGPWR 29,30,19 A 電源故障(System V) 
SIGINFO 29,-,- A 與SIGPWR同義 
SIGLOST -,-,- A 檔案鎖丟失 
SIGWINCH 28,28,20 B 視窗大小改變(4.3 BSD, Sun) 
SIGUNUSED -,31,- A 未使用的訊號(will be SIGSYS) 

(在這裡,- 表示訊號沒有實現;有三個值給出的含義為,第一個值通常在Alpha和Sparc上有效,中間的值對應i386和ppc以及sh,最後一個值對應mips。訊號29在Alpha上為SIGINFO / SIGPWR ,在Sparc上為SIGLOST。) 

處理動作一項中的字母含義如下 
A 預設的動作是終止程序 
B 預設的動作是忽略此訊號 
C 預設的動作是終止程序並進行核心映像轉儲(dump core) 
D 預設的動作是停止程序 
E 訊號不能被捕獲 
F 訊號不能被忽略