Linux系統(tǒng)調(diào)用.doc_第1頁
Linux系統(tǒng)調(diào)用.doc_第2頁
Linux系統(tǒng)調(diào)用.doc_第3頁
Linux系統(tǒng)調(diào)用.doc_第4頁
Linux系統(tǒng)調(diào)用.doc_第5頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

Printf從函數(shù)庫到OS跟蹤流程printf和標準輸出z Linux系統(tǒng)調(diào)用z摘要:本期重點和大家討論系統(tǒng)調(diào)用機制。其中涉及到了一些及系統(tǒng)調(diào)用的性能、上下文深層問題,同時也穿插著講述了一些內(nèi)核調(diào)試方法。并且最后試驗部分我們利用系統(tǒng)調(diào)用與相關(guān)內(nèi)核服務(wù)完成了一個搜集系統(tǒng)調(diào)用序列的特定任務(wù),該試驗具有較強的實用和教學(xué)價值。什么是系統(tǒng)調(diào)用顧 名思意,系統(tǒng)調(diào)用說的是操作系統(tǒng)提供給用戶程序調(diào)用的一組“特殊”接口。用戶程序可以通過這組“特殊”接口來獲得操作系統(tǒng)內(nèi)核提供的服務(wù),比如用戶可以通 過文件系統(tǒng)相關(guān)的調(diào)用請求系統(tǒng)打開文件、關(guān)閉文件或讀寫文件,可以通過時鐘相關(guān)的系統(tǒng)調(diào)用獲得系統(tǒng)時間或設(shè)置系統(tǒng)時間等。從邏輯上來說,系統(tǒng)調(diào)用可被看成是一個內(nèi)核與用戶空間程序交互的接口它好比一個中間人,把用戶進程的請求傳達給內(nèi)核,待內(nèi)核把請求處理完畢后再將處理結(jié)果送回給用戶空間。系統(tǒng)服務(wù)之所以需要通過系統(tǒng)調(diào)用提供給用戶空間的根本原因是為了對系統(tǒng)“保護”,因為我們知道Linux的運行空間分為內(nèi)核空間與用戶空間,它們各自運行在不同的級別中,邏輯上相互隔離。所以用戶進程在通常情況下不允許訪問內(nèi)核數(shù)據(jù),也無法使用內(nèi)核函數(shù),它們只能在用戶空間操作用戶數(shù)據(jù),調(diào)用戶用空間函數(shù)。比如我們熟悉的“hello world”程序(執(zhí)行時)就是標準的戶空間進程,它使用的打印函數(shù)printf就屬于用戶空間函數(shù),打印的字符“hello word”字符串也屬于用戶空間數(shù)據(jù)。但 是很多情況下,用戶進程需要獲得系統(tǒng)服務(wù)(調(diào)用系統(tǒng)程序),這時就必須利用系統(tǒng)提供給用戶的“特殊”接口系統(tǒng)調(diào)用了,它的特殊性主要在于規(guī)定了用戶進 程進入內(nèi)核的具體位置;換句話說用戶訪問內(nèi)核的路徑是事先規(guī)定好的,只能從規(guī)定位置進入內(nèi)核,而不準許肆意跳入內(nèi)核。有了這樣的陷入內(nèi)核的統(tǒng)一訪問路徑限 制才能保證內(nèi)核安全無虞。我們可以形象地描述這種機制:作為一個游客,你可以買票要求進入野生動物園,但你必須老老實實的坐在觀光車上,按照規(guī)定的路線觀 光游覽。當(dāng)然,不準下車,因為那樣太危險,不是讓你丟掉小命,就是讓你嚇壞了野生動物。Linux的系統(tǒng)調(diào)用對于現(xiàn)代操作系統(tǒng),系統(tǒng)調(diào)用是一種內(nèi)核與用戶空間通訊的普遍手段,Linux系統(tǒng)也不例外。但是Linux系統(tǒng)的系統(tǒng)調(diào)用相比很多Unix和windows等系統(tǒng)具有一些獨特之處,無處不體現(xiàn)出Linux的設(shè)計精髓簡潔和高效。Linux系統(tǒng)調(diào)用很多地方繼承了Unix的系統(tǒng)調(diào)用(但不是全部),但Linux相比傳統(tǒng)Unix的系統(tǒng)調(diào)用做了很多揚棄,它省去了許多Unix系統(tǒng)冗余的系統(tǒng)調(diào)用,僅僅保留了最基本和最有用的系統(tǒng)調(diào)用,所以Linux全部系統(tǒng)調(diào)用只有250個左右(而有些操作系統(tǒng)系統(tǒng)調(diào)用多達1000個以上)。這些系統(tǒng)調(diào)用按照功能邏輯大致可分為“進程控制”、“文件系統(tǒng)控制”、“系統(tǒng)控制”、“存管管理”、“網(wǎng)絡(luò)管理”、“socket控制”、“用戶管理”、“進程間通信”幾類,詳細情況可參閱文章系統(tǒng)調(diào)用列表如果你想詳細看看系統(tǒng)調(diào)用的說明,可以使用man 2 syscalls 命令查看,或干脆到 /include/asm-i386/unistd.h源文件種找到它們的原本。熟練了解和掌握上面這些系統(tǒng)調(diào)用是對系統(tǒng)程序員的必備要求,但對于一個開發(fā)內(nèi)核者或內(nèi)核開發(fā)者來1說死記硬背下這些調(diào)用還遠遠不夠。如果你僅僅知道存在的調(diào)用而不知道為什么它們會存在,或只知道如何使用調(diào)用而不知道這些調(diào)用在系統(tǒng)中的主要用途,那么你離駕馭系統(tǒng)還有不小距離。要彌補這個鴻溝,第一,你必須明白系統(tǒng)調(diào)用在內(nèi)核里的主要用途。雖然上面給出了數(shù)種分類,不過總的概括來講系統(tǒng)調(diào)用主要在系統(tǒng)中的用途無非以下幾類:l 控制硬件系統(tǒng)調(diào)用往往作為硬件資源和用戶空間的抽象接口,比如讀寫文件時用到的write/read調(diào)用。l 設(shè)置系統(tǒng)狀態(tài)或讀取內(nèi)核數(shù)據(jù)因為系統(tǒng)調(diào)用是用戶空間和內(nèi)核的唯一通訊手段2,所以用戶設(shè)置系統(tǒng)狀態(tài),比如開/關(guān)某項內(nèi)核服務(wù)(設(shè)置某個內(nèi)核變量),或讀取內(nèi)核數(shù)據(jù)都必須通過系統(tǒng)調(diào)用。比如getpgid、getpriority、setpriority、sethostnamel 進程管理一系列調(diào)用接口是用來保證系統(tǒng)中進程能以多任務(wù),在虛擬內(nèi)存環(huán)境下得以運行。比如 fork、clone、execve、exit等第二,什么服務(wù)應(yīng)該存在于內(nèi)核;或者說什么功能應(yīng)該實現(xiàn)在內(nèi)核而不是在用戶空間。這個問題并不沒有明確的答案,有些服務(wù)你可以選擇在內(nèi)核完成,也可以在用戶空間完成。選擇在內(nèi)核完成通?;谝韵驴紤]:l 服務(wù)必須獲得內(nèi)核數(shù)據(jù),比如一些服務(wù)必須獲得中斷或系統(tǒng)時間等內(nèi)核數(shù)據(jù)。l 從安全角度考慮,在內(nèi)核中提供的服務(wù)相比用戶空間提供的毫無疑問更安全,很難被非法訪問到。l 從效率考慮,在內(nèi)核實現(xiàn)服務(wù)避免了和用戶空間來回傳遞數(shù)據(jù)以及保護現(xiàn)場等步驟,因此效率往往要比實現(xiàn)在用戶空間高許多。比如,httpd等服務(wù)。l 如果內(nèi)核和用戶空間都需要使用該服務(wù),那么最好實現(xiàn)在內(nèi)核空間,比如隨機數(shù)產(chǎn)生。理解上述道理對掌握系統(tǒng)調(diào)用本質(zhì)意義很大,希望網(wǎng)友們能從使用中多總結(jié),多思考。系統(tǒng)調(diào)用、用戶編程接口(API)、系統(tǒng)命令、和內(nèi)核函數(shù)的關(guān)系系統(tǒng)調(diào)用并非直接和程序員或系統(tǒng)管理員打交道,它僅僅是一個通過軟中斷機制(我們后面講述)向內(nèi)核提交請求,獲取內(nèi)核服務(wù)的接口。而在實際使用中程序員調(diào)用的多是用戶編程接口API,而管理員使用的則多是系統(tǒng)命令。用戶編程接口其實是一個函數(shù)定義,說明了如何獲得一個給定的服務(wù),比如read()、malloc()、free()、abs()等。它有可能和系統(tǒng)調(diào)用形式上一致,比如read()接口就和read系統(tǒng)調(diào)用對應(yīng),但這種對應(yīng)并非一一對應(yīng),往往會出現(xiàn)幾種不同的API內(nèi)部用到統(tǒng)一個系統(tǒng)調(diào)用,比如malloc()、free()內(nèi)部利用brk( )系統(tǒng)調(diào)用來擴大或縮小進程的堆;或一個API利用了好幾個系統(tǒng)調(diào)用組合完成服務(wù)。更有些API甚至不需要任何系統(tǒng)調(diào)用因為它不必需要內(nèi)核服務(wù),如計算整數(shù)絕對值的abs()接口。另外要補充的是Linux的用戶編程接口遵循了在Unix世界中最流行的應(yīng)用編程界面標準POSIX標準,這套標準定義了一系列API。在Linux中(Unix也如此)這些API主要是通過C庫(libc)實現(xiàn)的,它除了定義的一些標準的C函數(shù)外,一個很重要的任務(wù)就是提供了一套封裝例程(wrapper routine)將系統(tǒng)調(diào)用在用戶空間包裝后供用戶編程使用。不過封裝并非必須的,如果你愿意直接調(diào)用,Linux內(nèi)核也提供了一個syscall()函數(shù)來實現(xiàn)調(diào)用,我們看個例子來對比一下通過C庫調(diào)用和直接調(diào)用的區(qū)別。#include #include #include #include int main(void) long ID1, ID2;/*/* 直接系統(tǒng)調(diào)用*/* SYS_getpid (func no. is 20) */*/ID1 = syscall(SYS_getpid);printf (“syscall(SYS_getpid)=%ldn”, ID1);/*/* 使用”libc”封裝的系統(tǒng)調(diào)用 */* SYS_getpid (Func No. is 20) */*/ID2 = getpid();printf (“getpid()=%ldn”, ID2);return(0);系統(tǒng)命令相對編程接口更高了一層,它是內(nèi)部引用API的可執(zhí)行程序,比如我們常用的系統(tǒng)命令ls、hostname等。Linux的系統(tǒng)命令格式遵循系統(tǒng)V的傳統(tǒng),多數(shù)放在/bin和/sbin下(相關(guān)內(nèi)容可看看shell等章節(jié))。有興趣的話可以通過strace ls或strace hostname 命令查看一下它們用到的系統(tǒng)調(diào)用,你會發(fā)現(xiàn)諸如open、brk、fstat、ioctl 等系統(tǒng)調(diào)用被用在系統(tǒng)命令中。下一個需要解釋一下的問題是內(nèi)核函數(shù)和系統(tǒng)調(diào)用的關(guān)系,內(nèi)核函數(shù)大家不要想像的過于復(fù)雜,其實它們和普通函數(shù)很像,只不過在內(nèi)核實現(xiàn),因此要滿足一些內(nèi)核編程的要求3。系統(tǒng)調(diào)用是一層用戶進入內(nèi)核的接口,它本身并非內(nèi)核函數(shù),進入內(nèi)核后,不同的系統(tǒng)調(diào)用會找到對應(yīng)到各自的內(nèi)核函數(shù)換個專業(yè)說法就叫:系統(tǒng)調(diào)用服務(wù)服務(wù)例程。實際對請求服務(wù)的是內(nèi)核函數(shù)而非調(diào)用接口。比如系統(tǒng)調(diào)用 getpid實際就是調(diào)用內(nèi)核函數(shù)sys_getpid。asmlinkage long sys_getpid(void)return current-tpid;Linux系統(tǒng)種存在許多的內(nèi)核函數(shù),有些是內(nèi)核文件種自己使用的,有些則是可以export出來供內(nèi)核其他部分共同使用的,具體情況自己決定。內(nèi)核公開的內(nèi)核函數(shù)export出來的可以使用命令ksyms 或 cat /proc/ksyms來查看。另外網(wǎng)上還有一本歸納分類內(nèi)核函數(shù)的書叫作The Linux Kernel API Book,有興趣的讀者可以去看看??偠灾瑥挠脩艚嵌认騼?nèi)核看,依次是系統(tǒng)命令、編程接口、系統(tǒng)調(diào)用和內(nèi)核函數(shù)。再講述了系統(tǒng)調(diào)用實現(xiàn)后,我們會回過頭來看看整個執(zhí)行路徑。系統(tǒng)調(diào)用實現(xiàn)Linux中實現(xiàn)系統(tǒng)調(diào)用利用了086體系結(jié)構(gòu)中的軟件中斷4。軟件中斷和我們常說的中斷(硬件中斷)不同之處在于它是通過軟件指令觸發(fā)而并非外設(shè),也就是說又編程人員出發(fā)的一種異常,具體的講就是調(diào)用int $080匯編指令,這條匯編指令將產(chǎn)生向量為128的編程異常。之所以系統(tǒng)調(diào)用需要借助異常實現(xiàn),是因為當(dāng)用戶態(tài)的進程調(diào)用一個系統(tǒng)調(diào)用時,CPU便被切換到內(nèi)核態(tài)執(zhí)行內(nèi)核函數(shù)5,而我們在i386體系結(jié)構(gòu)部分已經(jīng)講述過了進入內(nèi)核進入高特權(quán)級別必須經(jīng)過系統(tǒng)的門機制,這里異常實際上就是通過系統(tǒng)門陷入內(nèi)核(除了int 080外用戶空間還可以通過int3向量3、into向量4 、bound向量5等異常指令進入內(nèi)核,而其他異常用戶空間程序無法利用,都是由系統(tǒng)使用的)。我們更詳細的解釋一下這個過程。int $080指令目的是產(chǎn)生一個編號為128的編程異常,這個編程異常對應(yīng)的中斷描述符表IDT中的第128項也就是對應(yīng)的系統(tǒng)門描述符。門描述符中含有一個預(yù)設(shè)的內(nèi)核空間地址,它指向了系統(tǒng)調(diào)用處理程序:system_call()(別和系統(tǒng)調(diào)用服務(wù)程序混淆,這個程序在entry.S文件中用匯編語言編寫)。很顯然所有的系統(tǒng)調(diào)用都會統(tǒng)一的轉(zhuǎn)到這個地址,但Linux一共有2、3百個系統(tǒng)調(diào)用都從這里進入內(nèi)核后又該如何派發(fā)它們到各自的服務(wù)程序去呢?別發(fā)昏,解決這個問題的方法非常簡單:首先Linux為每個系統(tǒng)調(diào)用都進行了編號(0NR_syscall),同時在內(nèi)核中保存了一張系統(tǒng)調(diào)用表,該表中保存了系統(tǒng)調(diào)用編號和其對應(yīng)的服務(wù)例程,因此在系統(tǒng)調(diào)入通過系統(tǒng)門陷入內(nèi)核前,需要把系統(tǒng)調(diào)用號一并傳入內(nèi)核,在x86上,這個傳遞動作是通過在執(zhí)行int0x80前把調(diào)用號裝入eax寄存器實現(xiàn)的。這樣系統(tǒng)調(diào)用處理程序一旦運行,就可以從eax中得到數(shù)據(jù),然后再去系統(tǒng)調(diào)用表中尋找相應(yīng)服務(wù)例程了。除了需要傳遞系統(tǒng)調(diào)用號以外,許多系統(tǒng)調(diào)用還需要傳遞一些參數(shù)到內(nèi)核,比如sys_write(unsigned int fd, const char * buf, size_t count)調(diào)用就需要傳遞文件描述符號fd和要寫入的內(nèi)容buf和寫入字節(jié)數(shù)count等幾個內(nèi)容到內(nèi)核。碰到這種情況,Linux會有6個寄存器使用來傳遞這些參數(shù):eax (存放系統(tǒng)調(diào)用號)、 ebx、ecx、edx、esi及edi來存放這些額外的參數(shù)(以字母遞增的順序)。具體做法是在system_call( )中使用SAVE_ALL宏把這些寄存器的值保存在內(nèi)核態(tài)堆棧中。有始便有終,當(dāng)服務(wù)例程結(jié)束時,system_call( ) 從eax獲得系統(tǒng)調(diào)用的返回值,并把這個返回值存放在曾保存用戶態(tài) eax寄存器棧單元的那個位置上。然后跳轉(zhuǎn)到ret_from_sys_call( ),終止系統(tǒng)調(diào)用處理程序的執(zhí)行。當(dāng)進程恢復(fù)它在用戶態(tài)的執(zhí)行前,RESTORE_ALL宏會恢復(fù)用戶進入內(nèi)核前被保留到堆棧中的寄存器值。其中eax返回時會帶回系統(tǒng)調(diào)用的返回碼。(負數(shù)說明調(diào)用錯誤,0或正數(shù)說明正常完成)我們可以通過分析一下getpid系統(tǒng)調(diào)用的真是過程來將上述概念具體化,分析getpid系統(tǒng)調(diào)用一個辦法是查看entry.s中的代碼細節(jié),逐步跟蹤源碼來分析運行過程,另外就是可借助一些內(nèi)核調(diào)試工具,動態(tài)跟蹤運行路徑。假設(shè)我們的程序源文件名為getpid.c,內(nèi)容是:#include #include #include #include int main(void) long ID;ID = getpid();printf (“getpid()=%ldn”, ID);return(0);將其編譯成名為getpid的執(zhí)行文件”gcc o getpid /getpid.c”, 我們使用KDB來產(chǎn)看它進入內(nèi)核后的執(zhí)行路徑。l 激活KDB (按下pause鍵,當(dāng)然你必須已經(jīng)給內(nèi)核打了KDB補丁);設(shè)置內(nèi)核斷點 “bp sys_getpid” ;退出kdb “go”;然后執(zhí)行./getpid 。瞬間,進入內(nèi)核調(diào)試狀態(tài),執(zhí)行路徑停止在斷點sys_getpid處。l 在KDB提示符下,執(zhí)行bt命令觀察堆棧,發(fā)現(xiàn)調(diào)用的嵌套路徑,可以看到在sys_getpid是在內(nèi)核函數(shù)system_call中被嵌套調(diào)用的。l 在KDB提示符下,執(zhí)行rd命令查看寄存器中的數(shù)值,可以看到eax中存放的getpid調(diào)用號000000014(=20).l 在KDB提示符下,執(zhí)行ssb(或ss)命令跟蹤內(nèi)核代碼執(zhí)行路徑,可以發(fā)現(xiàn)sys_getpid執(zhí)行后,會返回system_call函數(shù),然后接者轉(zhuǎn)入ret_from_sys_call例程。(再往后還有些和調(diào)度有關(guān)其他例程,我們這里不說了它們了。)結(jié)合用戶空間的執(zhí)行路徑,大致該程序可歸結(jié)為一下幾個步驟:1 該程序調(diào)用libc庫的封裝函數(shù)getpid。該封裝函數(shù)中將系統(tǒng)調(diào)用號_NR_getpid(第20個)壓入EAX寄存器,2 調(diào)用軟中斷 int 080 進入內(nèi)核。(以下進入內(nèi)核態(tài)) 3 在內(nèi)核中首先執(zhí)行system_call,接著執(zhí)行根據(jù)系統(tǒng)調(diào)用號在調(diào)用表中查找到對應(yīng)的系統(tǒng)調(diào)用服務(wù)例程sys_getpid。4執(zhí)行sys_getpid服務(wù)例程。5執(zhí)行完畢后,轉(zhuǎn)入ret_from_sys_call例程,系統(tǒng)調(diào)用中返回。內(nèi)核調(diào)試是一個很有趣的話題,方法多種多樣,我個人認為比較好用的是UML(user mode linux+gdb)和 KDB 這兩個工具。尤其KDB對于調(diào)試小規(guī)模內(nèi)核模塊或查看內(nèi)核運行路徑很有效,對于它的使用方法可以看看Linux 內(nèi)核調(diào)試器內(nèi)幕這片文章。系統(tǒng)調(diào)用思考系統(tǒng)調(diào)用的內(nèi)在過程并不復(fù)雜,我們不再多說了,下面這節(jié)我們主要就系統(tǒng)調(diào)用所涉及的一些重要問題作一些討論和分析,希望這樣能更有助了解系統(tǒng)調(diào)用的精髓。調(diào)用上下文分析系統(tǒng)調(diào)用雖說是要進入內(nèi)核執(zhí)行,但它并非一個純粹意義上的內(nèi)核例程。首先它是代表用戶進程的,這點決定了雖然它會陷入內(nèi)核執(zhí)行,但是上下文仍然是處于進程上下文中,因此可以訪問進程的許多信息(比如current結(jié)構(gòu)當(dāng)前進程的控制結(jié)構(gòu)),而且可以被其他進程搶占(在從系統(tǒng)調(diào)用返回時,由system_call函數(shù)判斷是否該再調(diào)度),可以休眠,還可接收信號6等等。所 有這些特點都涉及到了進程調(diào)度的問題,我們這里不做深究,只要大家明白系統(tǒng)調(diào)用完成后,再回到或者說把控制權(quán)交回到發(fā)起調(diào)用的用戶進程前,內(nèi)核會有一次調(diào) 度。如果發(fā)現(xiàn)有優(yōu)先級別更高的進程或當(dāng)前進程的時間片用完,那么就會選擇高優(yōu)先級的進程或重新選擇進程運行。除了再調(diào)度需要考慮外,再就是內(nèi)核需要檢查是 否有掛起的信號,如果發(fā)現(xiàn)當(dāng)前進程有掛起的信號,那么還需要先返回用戶空間處理信號處理例程(處于用戶空間),然后再回到內(nèi)核,重新返回用戶空間,有些麻 煩但這個反復(fù)過程是必須的。調(diào)用性能問題系統(tǒng)調(diào)用需要從用戶空間陷入內(nèi)核空間,處理完后,又需要返回用戶空間。其中除了系統(tǒng)調(diào)用服務(wù)例程的實際耗時外,陷入/返回過程和系統(tǒng)調(diào)用處理程序(查系統(tǒng)調(diào)用表、存儲恢復(fù)用戶現(xiàn)場)也需要花銷一些時間,這些時間加起來就是一個系統(tǒng)調(diào)用的響應(yīng)速度。系統(tǒng)調(diào)用不比別的用戶程序,它對性能要求很苛刻,因為它需要陷入內(nèi)核執(zhí)行,所以和其他內(nèi)核程序一樣要求代碼簡潔、執(zhí)行迅速。幸好Linux具有令人難以置信的上下文切換速度,使得其進出內(nèi)核都被優(yōu)化得簡潔高效;同時所有Linux系統(tǒng)調(diào)用處理程序和每個系統(tǒng)調(diào)用本身也都非常簡潔。絕大多數(shù)情況下,Linux系統(tǒng)調(diào)用性能是可以接受的,但是對于一些對性能要求非常高的應(yīng)用來說,它們雖然希望利用系統(tǒng)調(diào)用的服務(wù),但卻希望加快相應(yīng)速度,避免陷入/返回和系統(tǒng)調(diào)用處理程序帶來的花銷,因此采用由內(nèi)核直接調(diào)用系統(tǒng)調(diào)用服務(wù)例程,最好的例子就HTTPD它為了避免上述開銷,從內(nèi)核調(diào)用socket等系統(tǒng)調(diào)用服務(wù)例程。什么時候添加系統(tǒng)調(diào)用系統(tǒng)調(diào)用是用戶空間和內(nèi)核空間交互的唯一手段,但是這并非時說要完成交互功能非要添加新系統(tǒng)調(diào)用不可。添加系統(tǒng)調(diào)用需要修改內(nèi)核源代碼、重新編譯內(nèi)核,因此如果想靈活的和內(nèi)核交互信息,最好使用一下幾種方法。l 編寫字符驅(qū)動程序利用字符驅(qū)動程序可以完成和內(nèi)核交互數(shù)據(jù)的功能。它最大的好處在于可以模塊式加載,這樣以來就避免了編譯內(nèi)核等手續(xù),而且調(diào)用接口固定,容易操作。l 使用proc 文件系統(tǒng)利用proc文件系統(tǒng)修訂系統(tǒng)狀態(tài)是一種很常見的手段,比如通過修改proc文件系統(tǒng)下的系統(tǒng)參數(shù)配置文件(/proc/sys),我們可以直接在運行時動態(tài)更改內(nèi)核參數(shù);再如,通過下面這條指令:echo 1 /proc/sys/net/ip_v4/ip_forward開啟內(nèi)核中控制IP轉(zhuǎn)發(fā)的開關(guān)。類似的,還有許多內(nèi)核選項可以直接通過proc文件系統(tǒng)進行查詢和調(diào)整。l 使用虛擬文件系統(tǒng)有些內(nèi)核開發(fā)者認為利用ioctl()系統(tǒng)調(diào)用(字符設(shè)備驅(qū)動接口)往往會似的系統(tǒng)調(diào)用意義不明確,而且難控制。而將信息放入到proc文件系統(tǒng)中會使信息組織混亂,因此也不贊成過多使用。他們建議實現(xiàn)一種孤立的虛擬文件系統(tǒng)來代替ioctl()和/proc,因為文件系統(tǒng)接口清楚,而且便于用戶空間訪問,同時利用虛擬文件系統(tǒng)使得利用腳本執(zhí)行系統(tǒng)管理任務(wù)更家方便、有效。實驗部分代碼功能介紹我們希望收集Linux系統(tǒng)運行時系統(tǒng)調(diào)用被執(zhí)行的信息,既實時獲取系統(tǒng)調(diào)用日志。這些日志信息將能以可讀形式實時的返回給用戶空間,以便用戶觀察或做近一步的日志分析(如入侵檢測等)。所以簡單的講實驗代碼集需要完成以下幾個基本功能:第一:記錄系統(tǒng)調(diào)用日志,將其寫入緩沖區(qū)(內(nèi)核中),以便用戶讀取;第二:建立新的系統(tǒng)調(diào)用,以便將內(nèi)核緩沖中的系統(tǒng)調(diào)用日志返回到用戶空間。第三:循環(huán)利用系統(tǒng)調(diào)用,以便能動態(tài)實時返回系統(tǒng)調(diào)用日志。代碼結(jié)構(gòu)體系介紹基本函數(shù)代碼功能一節(jié)介紹中的基本功能對應(yīng)程序代碼集中的三個子程序。它們分別是syscall_auydit、Sys_audit和auditd。接下來我們介紹代碼具體結(jié)構(gòu)。日志記錄例程Syscall_auditsyscall_audit該程序是一個內(nèi)核態(tài)的服務(wù)例程,該例程負責(zé)記錄系統(tǒng)調(diào)用的運行日志。記錄系統(tǒng)調(diào)用日志的具體做法是在內(nèi)核中修改系統(tǒng)調(diào)用處理程序system_call7,在其中需要監(jiān)控的每個調(diào)用(在我們例子鐘222個系統(tǒng)調(diào)用都監(jiān)控了,當(dāng)然你也可以根據(jù)自己需求有選擇的監(jiān)控)執(zhí)行完畢后都插入一個日志記錄指令,該指令會轉(zhuǎn)去調(diào)用內(nèi)核服務(wù)函數(shù)syscall_audit來記錄該次調(diào)用的信息8。Syscall_audit內(nèi)核服務(wù)例程會建立了一個內(nèi)核緩沖區(qū)來存放被記錄的函數(shù)。當(dāng)搜集的數(shù)據(jù)量到達一定閥值時(比如設(shè)定為到達緩沖區(qū)總大小的%80,這樣作可避免在丟失新調(diào)用),喚醒系統(tǒng)調(diào)用進程取回數(shù)據(jù)。否則繼續(xù)搜集,這時系統(tǒng)調(diào)用程序會堵塞在一個等待隊列上,直到被喚醒,也就是說如果緩沖區(qū)還沒接近滿時,系統(tǒng)調(diào)用會等待(被掛起)它被填充。系統(tǒng)調(diào)用Sys_audit由于系統(tǒng)調(diào)用是在內(nèi)核中被執(zhí)行,因此記錄其執(zhí)行日志也應(yīng)該在內(nèi)核態(tài)收集,所以我們需要利用一個新的系統(tǒng)調(diào)用來完成將內(nèi)核信息帶回到用戶空間sys_audit就是我們新填加的系統(tǒng)調(diào)用,它功能非常簡單,就是從緩沖區(qū)中取數(shù)據(jù)返回用戶空間。為了保證數(shù)據(jù)連續(xù)性,防止丟失。我們會建立一個內(nèi)核緩沖區(qū)存放每刻搜集到的日志數(shù)據(jù),并且當(dāng)搜集的數(shù)據(jù)量到達一定閥值時(比如設(shè)定為到達緩沖區(qū)總大小的%80),系統(tǒng)調(diào)用進程就會被喚醒9,以取回數(shù)據(jù)。否則在日志搜集時,系統(tǒng)調(diào)用程序會堵塞在等待隊列上,直到被喚醒,也就是說如果緩沖區(qū)還沒接近滿時,系統(tǒng)調(diào)用會等待它被填充。用戶空間服務(wù)程序auditd不用多說,我們需要一個用戶空間服務(wù)進程來不斷的調(diào)用audit系統(tǒng)調(diào)用,取回系統(tǒng)中搜集到的的調(diào)用日志信息。要知道,長時間的調(diào)用日志序列對于分析入侵或系統(tǒng)行為等才有價值。把代碼集成到內(nèi)核中除了上面介紹的內(nèi)容外,我們還需要一些輔助性,但卻很必要的工作,這些工作將幫助我們將上述代碼靈活地機結(jié)成一體,完成需要的功能。n 其一是修改entry.S匯編代碼,該代碼中含有系統(tǒng)調(diào)用表和系統(tǒng)調(diào)用入口代碼system_call。我們首先需要在系統(tǒng)調(diào)用表中加入新的系統(tǒng)調(diào)用(名為sys_audit,223號。.long SYMBOL_NAME(sys_audit));下來在系統(tǒng)調(diào)用入口中加入跳轉(zhuǎn)到日志記錄服務(wù)例程中(跳轉(zhuǎn) “je auditsys”, 而auditsys代碼段會真正調(diào)用系統(tǒng)調(diào)用記錄例程syscall_audit);n 其 二是填加代碼文件audit.c,該文件中包含syscall_audit與系統(tǒng)調(diào)用sys_audit兩個函數(shù)體,我們這里只說包含函數(shù)體,而并非函 數(shù),是因為這里我們并不想把函數(shù)的實現(xiàn)在內(nèi)核中寫死,而是希望利用了函數(shù)指針,即做了兩個鉤子函數(shù),來完成把具體函數(shù)實現(xiàn)放在模塊中完成,以便能動態(tài)加 載,方便調(diào)試(請見下一節(jié)介紹)。u 其三是修改i386_ksyms.c文件,再最后加入extern void (*my_audit)(int,int);EXPORT_SYMBOL(my_audit);extern int(*my_sysaudit)(unsigned char,unsigned char*,unsigned short,unsigned char);EXPORT_SYMBOL(my_sysaudit);,這樣做是為了導(dǎo)出內(nèi)核符號表,以便能模塊代碼中能掛接上以上函數(shù)指針。n 其四是修改內(nèi)核原代碼目錄下/kernel自目錄下的Makefile文件,很簡單,只需要在obj-y := 。最后加上audit.o,告訴編譯內(nèi)核是把audit.o編進去。關(guān)鍵代碼解釋我們的日志收集例程與取日志系統(tǒng)調(diào)用這兩個關(guān)鍵函數(shù)的實現(xiàn)是放在內(nèi)核模塊中實現(xiàn)。其中有些需要解釋的地方:1. 模塊編程的必要原則,如初始化、注銷等都應(yīng)該實現(xiàn),所不同的是我們在初始化與注銷時會分別掛上或卸下10了兩個鉤子函數(shù)的實現(xiàn)。2. 我們系統(tǒng)調(diào)用日志記錄采用了一個結(jié)構(gòu)體:syscall_buf,它含有諸如系統(tǒng)調(diào)用號syscall、進程IDpid、調(diào)用程序名commCOMM_SIZE等字段,共52字節(jié);我們的內(nèi)核緩沖區(qū)為audit_buf,它是一個可容納100個syscall_buf的數(shù)組。3. 系統(tǒng)調(diào)用實現(xiàn)極簡單,要做的僅僅是利用_copy_to_user11將內(nèi)核緩沖中的日志數(shù)據(jù)取到用戶空間。為了提高效率,在緩沖區(qū)未滿時(未到%80的閥值時),系統(tǒng)調(diào)用會掛起等待wait_event_interruptible(buffer_wait, current_pos = AUDIT_BUF_SIZE*8/10);相應(yīng)地當(dāng)緩沖區(qū)收集快滿時,則喚醒系統(tǒng)調(diào)用繼續(xù)收集日志wake_up_interruptible(&buffer_wait)。4. 最后要補充說明一下,在auditd用戶服務(wù)程序中調(diào)用我們新加的系統(tǒng)調(diào)用前必須利用宏_syscall4(int, audit, u8, type, u8 *, buf, u16, len, u8, reset)來“聲明”該調(diào)用展開成audit函數(shù)原形,以便進行格式轉(zhuǎn)換和參數(shù)傳遞,否則系統(tǒng)不能識別。取回數(shù)據(jù)Audit系統(tǒng)調(diào)用用戶程序auditd系統(tǒng)調(diào)用服務(wù)例程sys_audit系統(tǒng)調(diào)用日志緩沖Audit.o模塊my_sysaudit鉤子函數(shù)my_audit鉤子函數(shù)用戶空間內(nèi)核空間日志記錄例程syscall_audit描述日志數(shù)據(jù)流向描述系統(tǒng)調(diào)用關(guān)系程序體系圖STEP BY STEP下面具體講述一下如何添加這個調(diào)用。1 修改entry.S 在其中的添加audit調(diào)用,并且在system_call中加入搜集例程。(該函數(shù)位于/arch/i386/kernel/下)2 添加audit.c文件到/arch/i386/kernel/下該文件中定義了sys_audit和syscall_audit 兩個函數(shù)需要的鉤子函數(shù)(my_audit和my_sysaudit),它們會在entry.S中被使用。3 修改/arch/i386/kernel/i386-kysms.c文件,在其中導(dǎo)出my_audit與my_sysaudit兩個鉤子函數(shù)。因為只有在內(nèi)核符號表里導(dǎo)出,才可被其他內(nèi)核函數(shù)使用,也就是說才能在模塊中被掛上。4 修改/arch/i386/kernel/Makefile文件,將audit.c編譯入內(nèi)核。到這可以重新編譯內(nèi)核了,新內(nèi)核已經(jīng)加入了檢測點了。下一步是編寫模塊來實現(xiàn)系統(tǒng)調(diào)用與內(nèi)核搜集服務(wù)例程的功能了。1 編寫名為audit的模塊,其中除了加載、卸載模塊函數(shù)以外主要實現(xiàn)了mod_sys_audit與mod_syscall_audit兩個函數(shù)。它們會分別掛載到my_sysaudit和my_audit兩個鉤子上。2 編譯后將模塊加載 insmod aud

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論