举例跟踪分析Linux内核5.0系统调用处理过程
学号后三位<126>
原创作品转载请注明出处https://github.com/mengning/linuxkernel/
一、编译内核5.0
// 安装所需依赖 sudo apt install bison flex libssl-dev gcc-multilib // 下载并编译内核 wget https://github.com/mengning/linux/archive/v5.0.tar.gz tar -zxvf v5.0.tar.gz cd v5.0.tar.gz make i386_defconfig // 制作文件系统 cd .. mkdir rootfs git clone https://github.com/mengning/menu.git cd menu gcc -pthread -o init linktable.c menu.c test.c -m32 -static cd ../rootfs cp ../menu/init ./ find . | cpio -o -Hnewc | gzip -9 > ../rootfs.img
二、启动MenuOS准备跟踪分析
qemu-system-i386 -kernel bzImage -initrd rootfs.img
// 通过gdb跟踪调试内核启动 qemu-system-i386 -kernel bzImage -initrd rootfs.img -S -s -append nokaslr cd linux-5.0 gdb vmlinux
三、选择系统调用进行分析
选择学号后两位的系统调用<26>
编写分析用的test.c
/*test.c*/ #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <linux/user.h> int main() { pid_t child; long orig_eax; child = fork(); if(child == 0) { ptrace(PTRACE_TRACEME, 0, NULL, NULL); execl("/bin/ls", "ls", NULL); } else { wait(NULL); orig_eax = ptrace(PTRACE_PEEKUSER, child, 4 * ORIG_EAX, NULL); printf("The child made a " "system call %ld ", orig_eax); ptrace(PTRACE_CONT, child, NULL, NULL); } return 0; }
得到输出入下:
The child made a system call 11
系统调用分析:
在上述输出中,父进程fork了一个子进程并跟踪。在调用exec前,子进程使用PTRACE_TRACEME作第一个参数调用ptrace,它告诉内核:让别人跟踪我吧!然后,在子进程调用execve()后,它将控制权交还给父进程。当时父进程正使用wait()函数来等待来自内核的通知,现在它得到了通知,于是它可以开始察看子进程都作了些什么,比如看看寄存器的值之类。
四、实验总结
本次实验中,系统调用主要就是一种用户态到内核态最后再到用户态的一种过程,用户态可以说成间接操作内存的程序,而内核态也就是通过汇编代码直接操作内存,而他们再转换过程中,由于涉及上下文的切换问题,所以需要对内容进行保护,所以再进入中断程序前,将内核态寄存器的值放入栈中,在程序结束后再进行出栈。而且中断有两个重要的属性,中断号和中断处理程序。中断号用来标识不同的中断,不同的中断具有不同的中断处理程序。在操作系统内核中维护着一个中断向量表(Interrupt Vector Table)。这个数组存储了全部中断处理程序的地址,而中断号就是对应中断在中断向量表中的偏移量。