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 訊號不能被忽略