实验内容:
- 找一个系统调用,系统调用号为学号最后2位相同的系统调用
- 通过汇编指令触发该系统调用
- 通过gdb跟踪该系统调用的内核处理过程
- 重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化
本人学号为SA19225403
故查找系统调用号为03的系统调用
由上图可知3号系统调用为__x64_sys_close
在Linux开发者手册中查找函数close
可知要调用该函数需要
#include
函数参数为int型变量的文件描述符。
函数用于将此文件描述符关闭,使之不再指向任何文件。
函数执行成功将返回0,失败将返回-1。
一、实验环境准备
实验环境沿用实验一的环境
配置内核选项:
make defconfig make menuconfig
选择进入kernel hacking的子菜单
选择进入compile-time checks and compiler options的子菜单
选中如图选项,退回到初始的主菜单界面
进入processor type and features子菜单
将如图选项exclude
之后编译内核
make -j$(nproc)
qemu-system-x86_64 -kernel arch/x86/boot/bzImage
接下来着手制作根文件系统
axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2 tar -jxvf busybox-1.31.1.tar.bz2 cd busybox-1.31.1 make menuconfig
安装busybox并修改设置
进入setting子菜单
选中build static binary
保存退出后执行编译
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脚本并为之添加可执行权限
#!/bin/sh mount -t proc none /proc mount -t sysfs none /sys echo "WWWWWWrrrrrryyyyyyyyy" cd home /bin/sh
打包成镜像
find . -print0 | cpio --null -ov --format=newc | gzip -9 > rootfs.cpio.gz
测试挂载
qemu-system-x86_64 -kernel arch/x86/boot/bzImage -initrd rootfs.cpio.gz
二、系统调用
接下来我们编写一段简单的代码来调用close函数
在根文件系统目录rootfs下创建文件close.c
编写完之后编译运行一下
gcc -o close close.c -static
./close
之后将代码改写为内嵌汇编的代码,使用汇编代码来替换close函数
继续编译测试一下,一切正常
接下来我们将利用gdb来跟踪系统调用的内核处理过程
重新制作根文件系统的镜像
find . -print0 | cpio --null -ov --format=newc | gzip -9 > new_rootfs.cpio.gz
cd ..
qemu-system-x86_64 -kernel arch/x86/boot/bzImage -initrd new_rootfs.cpio.gz -S -s -nographic -append "console=ttyS0"
由于这次的qemu指令中加入了-nographic选项,所以不会有界面弹出
之后再打开一个终端启动gdb输入
gdb vmlinux
target remote:1234
输入上述指令连接gdb server
再输入c,使虚拟机继续运行
尝试在qemu中运行asmclose
在gdb中对3号系统调用打断点
b __x64_sys_close
然后在qemu中再次./asmclose
在gdb中逐步键入n键进行单语句的调试
三、分析
现在我们来重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回
系统调用过程中寄存器的用途如下:
函数do_syscall_64:可以推测该函数用以获取系统调用号并存放至rax寄存器中
函数syscall_return_slowpath负责启用中断以及捕获异常系统调用
每个系统调用在启用中断的情况下调用。 此外,它还必须在启用了中断的情况下返回。
任何有问题的syscall实现都会被syscall_return_slowpath捕获
触发系统调用之后,也即调用函数entry_SYSCALL_64之后,系统在进入内核之前将syscall
之后的指令的地址存储到RCX中(详见arch/x86/entry/entry_64.S)
同时调用swapgs 指令保存现场,swapgs指令如下:
系统调用返回的详细过程见下: