深入理解Linux系统调用

一 实验目标

1.本人学号尾号为70,找到编号为70的系统调用号,通过汇编指令触发该系统调用;

2.通过gdb跟踪该系统调用的内核处理过程;

3.重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化。

二 预备知识

1.什么是系统调用?

系统调用是用户空间请求内核服务。操作系统内核提供很多服务。当程序读写文件,开始监听连接的socket , 删除或创建目录或程序结束时,都会执行系统调用。换句话说,系统调用仅仅是一些 [C] (https://en.wikipedia.org/wiki/C_%28programming_language%29) 内核空间函数,用户空间程序调用其处理一些请求。

Linux 内核提供一系列的函数并且这些函数与CPU架构相关。 例如:x86_64 提供 322 个系统调用,x86 提供 358 个不同的系统调用。 系统调用仅仅是一些函数。

2.系统调用的过程

普通应用程序运行在用户态下,其诸多操作都受到限制,比如改变特权级别、访问硬件等。特权高的代码能将自己降至低等级的级别,但反之则是不行的。而系统调用是运行在内核态的,那么运行在用户态的应用程序如何运行内核态的代码呢?操作系统一般是通过中断来从用户态切换到内核态的。学过操作系统课程的同学对中断这个词肯定都不陌生。

中断一般有两个属性,一个是中断号,一个是中断处理程序。不同的中断有不同的中断号,每个中断号都对应了一个中断处理程序。在内核中有一个叫中断向量表的数组来映射这个关系。当中断到来时,cpu会暂停正在执行的代码,根据中断号去中断向量表找出对应的中断处理程序并调用。中断处理程序执行完成后,会继续执行之前的代码。

中断分为硬件中断和软件中断,我们这里说的是软件中断,软件中断通常是一条指令,使用这条指令用户可以手动触发某个中断。例如在i386下,对应的指令是int,在int指令后指定对应的中断号,如int 0x80代表你调用第0x80号的中断处理程序。

中断号是有限的,所有不会用一个中断来对应一个系统调用(系统调用有很多)。Linux下用int 0x80触发所有的系统调用,那如何区分不同的调用呢?对于每个系统调用都有一个系统调用号,在触发中断之前,会将系统调用号放入到一个固定的寄存器,0x80对应的中断处理程序会读取该寄存器的值,然后决定执行哪个系统调用的代码。

引用链接:https://www.jianshu.com/p/9c62a65b6162
 

三 操作流程

首先安装开发模拟工具

1 sudo apt install build-essential
2 sudo apt install qemu # install QEMU
3 sudo apt install libncurses5-dev bison flex libssl-dev libelf-dev
4 sudo apt install axel

获取内核源码

1 sudo apt install axel
2 axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/
3 linux-5.4.34.tar.xz
4 xz -d linux-5.4.34.tar.xz
5 tar -xvf linux-5.4.34.tar
6 cd linux-5.4.34

对内核相关参数进行配置

make defconfig # Default configuration is based on 'x86_64_defconfig' 
make menuconfig 
# 打开debug相关选项
Kernel hacking ---> 
       Compile-time checks and compiler options ---> 
           [*] Compile the kernel with debug info 
           [*] Provide GDB scripts for kernel debugging 
 [*] Kernel debugging 
# 关闭KASLR,否则会导致打断点失败
Processor type and features ----> 
    [] Randomize the address of the kernel image (KASLR)

编译并测试内核是否能正常运行

1 make -j$(nproc)
2 qemu-system-x86_64 -kernel arch/x86/boot/bzImage

然后制作根文件系统 

1 axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2 
2 tar -jxvf busybox-1.31.1.tar.bz2 
3 cd busybox-1.31.1
make menuconfig
记得要编译成静态链接,不用动态链接库。
Settings --->
    [*] Build static binary (no shared libs)
然后编译安装,默认会安装到源码目录下的 _install 目录中。
make -j$(nproc) && make install
制作内存根⽂件系统镜像:
mkdir rootfs
cd rootfs
cp ../busybox-1.31.1/_install/* ./ -rf
mkdir dev proc sys home
sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/

然后制作init脚本

将init脚本⽂件放在根⽂件系统跟⽬录下(rootfs/init),添加如下内容到init⽂件。
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo "Wellcome MengningOS!"
echo "--------------------"
cd home
/bin/sh
给init脚本添加可执⾏权限
chmod +x init

启动内核并执行init脚本

打包成内存根⽂件系统镜像(rootfs目录下)
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz 
测试挂载根⽂件系统,看内核启动完成后是否执⾏init脚本
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz
 
可以看到init已经被执行

 

 

四 系统调用探究

1.找到70号系统调用函数

 

 msgrcv函数用于从消息队列中读取msqid指定的消息。

2.测试代码编译(调试预处理)

1.首先安装GDB调试工具

如果系统自带该工具,建议先卸载再重新安装,并且修改其gdb/remote.c的文件,防止出现Remote 'g' packet reply is too long的问题。

具体的修改方法请参考如下链接:

http://blog.sina.com.cn/s/blog_79ba23780101rzk4.html

2.编写脚本用于进行代码调试

 编写测试代码test.c

1 int main()
2 {
3     asm volatile(
4     "movl $0x46,%eax\n\t" //使⽤EAX传递系统调⽤号70
5     "syscall\n\t" //触发系统调⽤ 
6     );
7     return 0;
8 }

3.编译代码

使用gcc进行静态编译

gcc test.c -o test -static

4.重新制作根文件系统

find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz

3.使用GDB进行调试

1.首先启动qemu

qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s -nographic -append "console=ttyS0"

2.启动GDB工具并设置断点

cd linux-5.4.34
# 启动
gdb vmlinux
target remote:1234
# 在semctl调用处打断点
b __64x_sys_msgrcv

输入c执行下一步。

 

 通过下图可以看到,调用了do_syscall_64和entry_SYSCALL_64两个内核函数,分别表示获得系统调用号和进入系统调用。

 

 

 4.流程分析

syscall指令触发系统调用,通过MSR寄存器找到了中断函数入口,系统调用入口为entry_SYSCALL_64,其中使用了swapgs这一方法来快照式的保存现场,加快了系统调用,随后对一些相关寄存器进行压栈操作。

 

第一个框表示获取系统调用号。

第二个框表示进入系统调用。

第三个则是采取快照的方式现场,如堆栈信息。

五 实验总结

通过本次实验,了解了70号系统调用号__64_sys_msgrcv的使用,学习了对Linux内核进行断点调试的相关技巧,加深了对系统调用知识以及流程的理解。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
posted @ 2020-05-27 12:45  bfyq_coder  阅读(380)  评论(0)    收藏  举报