




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、選題要求:在Linux內(nèi)核中增加一個系統(tǒng)調(diào)用,并編寫對應(yīng)的linux應(yīng)用程序。利用該系統(tǒng)調(diào)用能夠遍歷系統(tǒng)當(dāng)前所有進(jìn)程的任務(wù)描述符,并按進(jìn)程父子關(guān)系將這些描述符所對應(yīng)的進(jìn)程id(PID)組織成樹形結(jié)構(gòu)顯示。目錄一.程序的主要設(shè)計思路,實現(xiàn)方式11.1 添加系統(tǒng)調(diào)用的兩種方法11.1.1編譯內(nèi)核法11.1.2內(nèi)核模塊法11.2 程序的主要設(shè)計思路11.3 環(huán)境2二.程序的模塊劃分,及對每個模塊的說明22.1 通過內(nèi)核模塊實現(xiàn)添加系統(tǒng)調(diào)用22.1.1修改系統(tǒng)調(diào)用的模塊22.1.2獲取sys_call_table的地址22.1.3清除內(nèi)存區(qū)域的寫保護(hù)32.2 編寫系統(tǒng)調(diào)用指定自己的系統(tǒng)調(diào)用42.2.1
2、內(nèi)核的初始化函數(shù)42.2.2自己的系統(tǒng)調(diào)用服務(wù)例程42.2.3移除內(nèi)核模塊時,將原有的系統(tǒng)調(diào)用進(jìn)行還原62.2.4模塊注冊相關(guān)62.3 編寫用戶態(tài)的測試程序62.4 編寫Makefile文件7三.所遇到的問題及解決的方法83.1 進(jìn)程個數(shù)確定83.2 被更改的系統(tǒng)調(diào)用號的選擇83.3 獲取系統(tǒng)調(diào)用表的地址83.4 內(nèi)核和用戶態(tài)數(shù)據(jù)交換8四.程序運(yùn)行結(jié)果及使用說明84.1 將編譯出來的內(nèi)核模塊hello.ko加載到內(nèi)核中84.2通過dmesg查看輸出信息是否正確94.3運(yùn)行測試程序,輸出樹狀打印結(jié)果(部分結(jié)果截圖)94.4卸載自定義模塊10五.附錄115.1 內(nèi)核模塊程序hello.c115.2
3、 測試程序hello_test.c145.3 Makefile文件14Linux內(nèi)核分析課程大作業(yè)一.程序的主要設(shè)計思路,實現(xiàn)方式1.1 添加系統(tǒng)調(diào)用的兩種方法1.1.1編譯內(nèi)核法編寫好源碼之后· 修改內(nèi)核的系統(tǒng)調(diào)用庫函數(shù) /usr/include/asm-generic/unistd.h,在這里面可以使用在syscall_table中沒有用到的223號· 添加系統(tǒng)調(diào)用號,讓系統(tǒng)根據(jù)這個號,去找到syscall_table中的相應(yīng)表項。在/arch/x86/kernel/syscall_table_32.s文件中添加系統(tǒng)調(diào)用號和調(diào)用函數(shù)的對應(yīng)關(guān)系· 接著就是my_
4、syscall的實現(xiàn)了,在這里有兩種方法:第一種方法是在kernel下自己新建一個目錄添加自己的文件,但是要編寫Makefile,而且要修改全局的Makefile。第二種比較簡便的方法是,在kernel/sys.c中添加自己的服務(wù)函數(shù),這樣子不用修改Makefile.以上準(zhǔn)備工作做完之后,然后就要進(jìn)行編譯內(nèi)核了,以下是編譯內(nèi)核的一個過程1. make menuconfig (使用圖形化的工具,更新.config文件)2. make -j3 bzImage(編譯,-j3指的是同時使用3個cpu來編譯,bzImage指的是更新grub,以便重新引導(dǎo))3. make modules(對模塊進(jìn)行編譯)
5、4. make modules_install(安裝編譯好的模塊)5. depmod(進(jìn)行依賴關(guān)系的處理)6. reboot (重啟看到自己編譯好的內(nèi)核)1.1.2內(nèi)核模塊法內(nèi)核模塊可以作為獨立程序來編譯的函數(shù)和數(shù)據(jù)類型的集合。之所以提供模塊機(jī)制,是因為Linux本身是一個單內(nèi)核。單內(nèi)核由于所有內(nèi)容都集成在一起,效率很高,但可擴(kuò)展性和可維護(hù)性相對較差,模塊機(jī)制可以彌補(bǔ)這一缺陷。Linux模塊可以通過靜態(tài)或動態(tài)的方法加載到內(nèi)核空間,靜態(tài)加載是指在內(nèi)核啟動過程中加載;動態(tài)加載是指在內(nèi)核運(yùn)行的過程中隨時加載。一個模塊被加載到內(nèi)核中時,就成為內(nèi)核代碼的一部分。模塊加載入系統(tǒng)時,系統(tǒng)修改內(nèi)核中的符號表,
6、將新加載的模塊提供的資源和符號添加到內(nèi)核符號表中,以便模塊間通信。這種方法是采用系統(tǒng)調(diào)用攔截的一種方式,改變某一個系統(tǒng)調(diào)用號對應(yīng)的服務(wù)程序為我們自己的編寫的程序,從而相當(dāng)于添加了我們自己的系統(tǒng)調(diào)用。下面的內(nèi)容,會詳述用內(nèi)核模塊法實現(xiàn)目標(biāo)的過程。1.2 程序的主要設(shè)計思路程序分三部分,一部分是通過內(nèi)核模塊實現(xiàn)添加系統(tǒng)調(diào)用,二是編寫系統(tǒng)調(diào)用指定自己的系統(tǒng)調(diào)用,最后是編寫用戶態(tài)的測試程序。1.3 環(huán)境Ubuntu14.04 + 3.13.0內(nèi)核版本內(nèi)核版本:二.程序的模塊劃分,及對每個模塊的說明2.1 通過內(nèi)核模塊實現(xiàn)添加系統(tǒng)調(diào)用這種方法其實是系統(tǒng)調(diào)用攔截的實現(xiàn)。系統(tǒng)調(diào)用服務(wù)程序的地址是放在sys_
7、call_table中通過系統(tǒng)調(diào)用號定位到具體的系統(tǒng)調(diào)用地址,那么我們通過編寫內(nèi)核模塊來修改sys_call_table中的系統(tǒng)調(diào)用的地址為我們自己定義的函數(shù)的地址,就可以實現(xiàn)系統(tǒng)調(diào)用的攔截。通過模塊加載時,將系統(tǒng)調(diào)用表里面的那個系統(tǒng)調(diào)用號的那個系統(tǒng)調(diào)用號對應(yīng)的系統(tǒng)調(diào)用服務(wù)例程改為我們自己實現(xiàn)的系統(tǒng)歷程函數(shù)地址。2.1.1修改系統(tǒng)調(diào)用的模塊在/usr/include/i386-linux-gnu/asm/unistd_32.h文件中查看系統(tǒng)調(diào)用序號:找到結(jié)果(部分截圖):可以看到,222號和223號系統(tǒng)調(diào)用是空的,因此選取223作為新的系統(tǒng)調(diào)用號。2.1.2獲取sys_call_table的地
8、址在/boot/System.map-3.16.0-30-generic查看系統(tǒng)調(diào)用表的內(nèi)存地址:找到結(jié)果:為0xc165e1402.1.3清除內(nèi)存區(qū)域的寫保護(hù)得到了sys_call_table的地址,該符號對應(yīng)的內(nèi)存區(qū)域是只讀的。所以我們要修改它,必須對它進(jìn)行清除寫保護(hù),這里介紹兩種方法:第一種方法:我們知道控制寄存器cr0的第16位是寫保護(hù)位。cr0的第16位置為了禁止超級權(quán)限,若清零了則允許超級權(quán)限往內(nèi)核中寫入數(shù)據(jù),這樣我們可以再寫入之前,將那一位清零,使我們可以寫入。然后寫完后,又將那一位復(fù)原就行了。/使cr0寄存器的第17位設(shè)置為0(即是內(nèi)核空間可寫)unsigned int cle
9、ar_and_return_cr0(void) unsigned int cr0 = 0; unsigned int ret; asm("movl %cr0, %eax":"=a"(cr0); /將cr0寄存器的值移動到eax寄存器中,同時輸出到cr0變量中 ret = cr0; cr0 &= 0xfffeffff;/將cr0變量的第17位清0 asm("movl %eax, %cr0":"a"(cr0); /將cr0變量的值放入寄存器eax中,并且放入cr0寄存器中 return ret;/讀取val的值
10、到eax寄存器,再將eax寄存器的值放入cr0寄存器中-改變內(nèi)核地址空間參數(shù)void setback_cr0(unsigned int val) asm volatile("movl %eax, %cr0":"a"(val);第二種方法:通過設(shè)置虛擬地址對應(yīng)的也表項的讀寫屬性來設(shè)置。int make_rw(unsigned long address) unsigned int level; pte_t *pte = lookup_address(address, &level);/查找虛擬地址所在的頁表地址 if (pte->pte &am
11、p; _PAGE_RW) /設(shè)置頁表讀寫屬性pte->pte |= _PAGE_RW; return 0; int make_ro(unsigned long address) unsigned int level; pte_t *pte = lookup_address(address, &level); pte->pte &= _PAGE_RW; /設(shè)置只讀屬性return 0; 2.2 編寫系統(tǒng)調(diào)用指定自己的系統(tǒng)調(diào)用2.2.1內(nèi)核的初始化函數(shù)此函數(shù)內(nèi)采用的是2.1.3中的第一種方法。static int _init init_addsyscall(void)
12、printk("hello,yinyu kerneln"); /獲取系統(tǒng)調(diào)用服務(wù)首地址 sys_call_table = (unsigned long *)sys_call_table_address;printk("%xn",sys_call_table);/保存系統(tǒng)調(diào)用表中的NUM位置上的系統(tǒng)調(diào)用 anything_saved = (int(*)(void) (sys_call_tablemy_syscall_num); /使內(nèi)核地址空間可寫orig_cr0 = clear_and_return_cr0();/用自己的系統(tǒng)調(diào)用替換NUM位置上的系統(tǒng)調(diào)
13、用sys_call_tablemy_syscall_num= (unsigned long)&sys_mycall; /使內(nèi)核地址空間不可寫setback_cr0(orig_cr0); return 0;2.2.2自己的系統(tǒng)調(diào)用服務(wù)例程部分一:創(chuàng)建進(jìn)程樹void processtree(struct task_struct * p,int b);結(jié)果需要以樹狀形式展示所有進(jìn)程的父子關(guān)系。為此,我們定義processtree()遞歸函數(shù)來訪問遍歷,并且將結(jié)果存儲在數(shù)組中,以便提供給用戶態(tài)訪問。void processtree(struct task_struct * p,int b)/創(chuàng)
14、建進(jìn)程樹(進(jìn)程,深度) struct list_head * l; acounter.pid = p -> pid; acounter.depth = b; counter +; for(l = p -> children.next; l != &(p->children); l = l->next) struct task_struct *t = list_entry(l,struct task_struct,sibling); processtree(t,b+1); 其中,特別使用了宏:#define list_entry(ptr, type, member
15、) / (type *)(char *)(ptr)-(unsigned long)(&(type *)0)->member) ptr是指向list_head類型鏈表的指針;type為一個結(jié)構(gòu);member為結(jié)構(gòu)type中的一個域,類型為list_head;這個宏返回指向type結(jié)構(gòu)的指針。目的:從一個結(jié)構(gòu)的成員指針找到其容器的指針部分二:創(chuàng)建自己的系統(tǒng)調(diào)用服務(wù)asmlinkage long sys_mycall(char _user * buf);在sys_mycall()中,從當(dāng)前進(jìn)程開始,遞歸調(diào)用processtree()函數(shù),將進(jìn)程信息存儲在數(shù)組中。然后利用copy_to_
16、user函數(shù)將內(nèi)核信息傳遞給用戶態(tài)下,用戶態(tài)下的測試程序?qū)Y(jié)果進(jìn)行展示。asmlinkage long sys_mycall(char _user * buf) int b = 0; struct task_struct * p; printk("This is yinyu_syscall!n"); for(p = current; p != &init_task; p = p->parent ); processtree(p,b); if(copy_to_user(struct process *)buf,a,512*sizeof(struct proces
17、s) return -EFAULT; else return sizeof(a);2.2.3移除內(nèi)核模塊時,將原有的系統(tǒng)調(diào)用進(jìn)行還原static void _exit exit_addsyscall(void) /設(shè)置cr0中對sys_call_table的更改權(quán)限。 orig_cr0 = clear_and_return_cr0(); /恢復(fù)原有的中斷向量表中的函數(shù)指針的值。 sys_call_tablemy_syscall_num= (unsigned long)anything_saved; /恢復(fù)原有的cr0的值 setback_cr0(orig_cr0); printk("
18、call yinyu exit n");2.2.4模塊注冊相關(guān)l 模塊構(gòu)造函數(shù)module_init(init_addsyscall);執(zhí)行insmod或modprobe指令加載內(nèi)核模塊時會調(diào)用的初始化函數(shù)。函數(shù)原型必須是module_init(),內(nèi)是函數(shù)指針。l 模塊析構(gòu)函數(shù)module_exit(exit_addsyscall);執(zhí)行rmmod指令卸載模塊時調(diào)用的函數(shù)。函數(shù)原型是module_exit();l 模塊許可聲明MODULE_LICENSE("GPL");函數(shù)原型是MODULE_LICENSE(),告訴內(nèi)核程序使用的許可證,不然在加載時它會提示該模
19、塊污染內(nèi)核。一般會寫GPL。2.3 編寫用戶態(tài)的測試程序#include <linux/unistd.h>#include <syscall.h>/asmlinkage#include <sys/types.h>#include <stdio.h>struct process int pid; int depth;struct process a512;int main() int i,j; /在內(nèi)核中將223本來對應(yīng)的系統(tǒng)調(diào)用,臨時鏈到我們自定義的sys_mycall()中。通過該系統(tǒng)調(diào)用后獲得數(shù)組a printf("the resu
20、lt is:%dn",syscall(223,&a); for(i = 0; i < 512; i+) for(j = 0; j < ai.depth; j+) printf("|-"); printf("%dn",ai.pid); if(ai+1.pid = 0) break; return 0;2.4 編寫Makefile文件KVERS = $(shell uname -r)# Kernel modulesobj-m += hello.o# Specify flags for the module compilation
21、.#EXTRA_CFLAGS=-g -O0build: kernel_modules user_testkernel_modules:make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modulesuser_test:gcc -o hello_test hello_test.cclean:make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean三.所遇到的問題及解決的方法3.1 進(jìn)程個數(shù)確定系統(tǒng)可運(yùn)行的最大進(jìn)程數(shù),通過ulimit u 查看有7863個我們通過ps ef|wc l命令實際查看當(dāng)前運(yùn)行
22、進(jìn)程數(shù)量為191個存儲進(jìn)程信息的數(shù)組大小為512是夠用的。3.2 被更改的系統(tǒng)調(diào)用號的選擇見2.1.1。3.3 獲取系統(tǒng)調(diào)用表的地址見2.1.2。3.4 內(nèi)核和用戶態(tài)數(shù)據(jù)交換我們在內(nèi)核模塊程序中,將進(jìn)程遍歷信息存儲在數(shù)組中,然后需要將其傳遞給用戶態(tài)下。采用copy_from_user()和copy_to_user()這兩個函數(shù),這兩個函數(shù)負(fù)責(zé)在用戶空間和內(nèi)核空間傳遞數(shù)據(jù)。因此我們在測試程序中,將空數(shù)組a的地址作為參數(shù)傳遞給內(nèi)核模塊程序,在內(nèi)核中使用copy_to_user()函數(shù)將內(nèi)核中的數(shù)組信息傳遞給用戶態(tài)下的地址。四.程序運(yùn)行結(jié)果及使用說明4.1 將編譯出來的內(nèi)核模塊hello.ko加載到
23、內(nèi)核中加載內(nèi)核模塊命令:insmod hello.ko4.2通過dmesg查看輸出信息是否正確4.3運(yùn)行測試程序,輸出樹狀打印結(jié)果(部分結(jié)果截圖)4.4卸載自定義模塊卸載內(nèi)核模塊命令:insmod hello.ko五.附錄5.1 內(nèi)核模塊程序hello.c#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>/list_head#include <linux/unistd.h>#include <asm/uaccess.h>#include &
24、lt;linux/sched.h>/task_struct#define my_syscall_num 223#define sys_call_table_address 0xc165e140static int counter = 0;struct process int pid; int depth;struct process a512;unsigned int clear_and_return_cr0(void);void setback_cr0(unsigned int val);asmlinkage long sys_mycall(char _user *buf);int o
25、rig_cr0;unsigned long *sys_call_table = 0;static int (*anything_saved)(void);void processtree(struct task_struct * p,int b)/創(chuàng)建進(jìn)程樹(進(jìn)程,深度) struct list_head * l; acounter.pid = p -> pid; acounter.depth = b; counter +; for(l = p -> children.next; l != &(p->children); l = l->next) struct
26、task_struct *t = list_entry(l,struct task_struct,sibling); processtree(t,b+1); unsigned int clear_and_return_cr0(void)/使cr0寄存器的第17位設(shè)置為0(即是內(nèi)核空間可寫) unsigned int cr0 = 0; unsigned int ret; asm("movl %cr0, %eax":"=a"(cr0); /將cr0寄存器的值移動到eax寄存器中,同時輸出到cr0變量中 ret = cr0; cr0 &= 0xfffe
27、ffff;/將cr0變量的第17位清0 asm("movl %eax, %cr0":"a"(cr0); /將cr0變量的值放入寄存器eax中,并且放入cr0寄存器中 return ret;void setback_cr0(unsigned int val)/讀取val的值到eax寄存器,再將eax寄存器的值放入cr0寄存器中-改變內(nèi)核地址空間參數(shù) asm volatile("movl %eax, %cr0":"a"(val);static int _init init_addsyscall(void)/保存原來系統(tǒng)
28、調(diào)用表中此地址中的系統(tǒng)調(diào)用 printk("hello,yinyu kerneln"); sys_call_table = (unsigned long *)sys_call_table_address;/獲取系統(tǒng)調(diào)用服務(wù)首地址 printk("%xn",sys_call_table); anything_saved = (int(*)(void) (sys_call_tablemy_syscall_num);/保存系統(tǒng)調(diào)用表中的NUM位置上的系統(tǒng)調(diào)用 orig_cr0 = clear_and_return_cr0();/使內(nèi)核地址空間可寫 sys_ca
29、ll_tablemy_syscall_num= (unsigned long)&sys_mycall;/用自己的系統(tǒng)調(diào)用替換NUM位置上的系統(tǒng)調(diào)用 setback_cr0(orig_cr0);/使內(nèi)核地址空間不可寫 return 0;asmlinkage long sys_mycall(char _user * buf) int b = 0; struct task_struct * p; printk("This is yinyu_syscall!n"); for(p = current; p != &init_task; p = p->parent
30、 ); processtree(p,b); if(copy_to_user(struct process *)buf,a,512*sizeof(struct process)/將內(nèi)核空間內(nèi)容復(fù)制到用戶空間 return -EFAULT; else return sizeof(a);static void _exit exit_addsyscall(void) /設(shè)置cr0中對sys_call_table的更改權(quán)限。 orig_cr0 = clear_and_return_cr0(); /恢復(fù)原有的中斷向量表中的函數(shù)指針的值。 sys_call_tablemy_syscall_num= (unsigned long)anything_saved; /恢復(fù)原有的cr0的值 setback_cr0(orig_cr0); printk("call yinyu exit n");/模塊入口函數(shù)為init_addsyscall(),由module_init()宏指定,在模塊被加載的時候被調(diào)用向系統(tǒng)注冊。入口函數(shù)的返回值:0表示成功,非0表示失敗
溫馨提示
- 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度美容院美容美發(fā)服務(wù)入股協(xié)議
- 2025年度電線電纜綠色包裝與供貨合同
- 股權(quán)代持協(xié)議書標(biāo)準(zhǔn)模板:2025年度股權(quán)收購執(zhí)行范本
- 二零二五年度交通事故車輛損失保險理賠協(xié)議
- 二零二五年度汽車展覽會參展商環(huán)保責(zé)任合同
- Unit 1 Going to Beijing 單元基礎(chǔ)知識復(fù)習(xí)(含答案)
- 2025年度溫室大棚承包與農(nóng)業(yè)科技成果轉(zhuǎn)化合作協(xié)議
- 二零二五年度手車過戶買賣與車輛上牌服務(wù)協(xié)議
- 兒童國畫入門課堂
- 中級消防設(shè)施操作員速記口訣
- 《英語語言史》課程教學(xué)大綱
- 醫(yī)療機(jī)構(gòu)負(fù)責(zé)人簽字確認(rèn)表
- 復(fù)工復(fù)產(chǎn)安全生產(chǎn)培訓(xùn)試卷
- access上機(jī)練習(xí)題題庫
- 2023年茂名市人民醫(yī)院護(hù)士招聘考試歷年高頻考點試題含答案
- 山東教育出版社(魯教版)八年級化學(xué)全一冊教學(xué)課件
- 《外貿(mào)風(fēng)險管理》完整全套課件
- 綜合性學(xué)習(xí)《我的語文生活》優(yōu)課一等獎?wù)n件
- 公路水運(yùn)工程施工企業(yè)主要負(fù)責(zé)人和安全生產(chǎn)管理人員大綱和題庫
- 榜樣7航天追夢人王亞平事跡介紹PPT英雄航天員王亞平事跡介紹PPT課件(帶內(nèi)容)
- 物理word版2023山東高考答題卡涂準(zhǔn)考證號和條形碼
評論
0/150
提交評論