深入理解系统调用

一、实验要求

  • 找一个系统调用,系统调用号为学号最后2位相同的系统调用,本实验选取第151号系统调用
  • 通过汇编指令触发该系统调用
  • 通过gdb跟踪该系统调用的内核处理过程
  • 重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化

二、实验内容

1.实验环境搭建

基于上次实验的linux,配置内核编译选项:

make menuconfig  

打开debug相关选项:

深入理解系统调用_第1张图片

关闭KASLR:

 深入理解系统调用_第2张图片

重新编译内核:

make -j$(nproc)

制作根⽂件系统:

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 

编译成静态链接:

编译安装:

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 "Wellcome MyOS!"
 echo "--------------------" 
 cd home
 /bin/sh 

给init脚本添加可执⾏权限:

chmod +x init

打包成内存根⽂件系统镜像:

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

深入理解系统调用_第3张图片

2.选取系统调用,汇编改写

打开/linux-5.4.34/arch/x86/entry/syscalls/syscall_64.tbl,查看要选择进行实验的系统调用。

深入理解系统调用_第4张图片

系统调用 mlockall,函数入口为 __x64_sys_mlockall。编写程序调用mlockall:

深入理解系统调用_第5张图片

gcc编译(这里采用静态编译)后运行,输出结果:

gcc -o gsn gsn.c -static

mlockall 的功能是将进程使用的部分或者全部的地址空间锁定在物理内存中,防止其被交换到swap空间。

这个系统调用接受一个参数;如果指定 MCL_CURRENT,则仅仅当前已分配的内存会被锁定,之后分配的内存则不会;MCL_FUTURE 则会锁定之后分配的所有内存。使用 MCL_CURRENT|MCL_FUTURE 将已经及将来分配的所有内存锁定在物理内存中。

汇编改写手动触发系统调用:

深入理解系统调用_第6张图片

 gcc编译后查看执行结果:

gcc -o gsn_asm gsn_asm.c -static

3.gdb调试与分析

重新打包根文件目录

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

纯命令⾏下启动虚拟机

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

此时虚拟机会暂停在启动界面:

 在另一个terminal中开启gdb调试 gdb vmlinux:

深入理解系统调用_第7张图片

连接进行调试,target remote:1234:

gdb输入命令c,使得虚拟机继续执行:

深入理解系统调用_第8张图片

 通过gdb在函数入口做如下断点,然后监听:

 

在虚拟机中执行 gsn,在gdb界面查看断点分析:

 

 首先断点定位为到/home/linux-5.4.34/mm/mlock: 799:

深入理解系统调用_第9张图片

 执行完这个函数,回到了函数堆栈上一层的do_sys_call_64 中 ,接下来要执行的 syscall_return_slowpath 函数要为恢复现场做准备:

继续执行,再次回到了函数堆栈的上一层,entry_SYSCALL_64 ,接下来执行的是用于恢复现场的汇编指令,最后随着两个popq出栈指令,恢复了rdirsp寄存器,系统调用完成

 深入理解系统调用_第10张图片

深入理解系统调用_第11张图片

 4.分析

1.触发系统调用后,代码执行了/linux-5.4.34/arch/x86/entry/entry_64.S 目录下的ENTRY(entry_SYSCALL_64)入口,然后开始通过swapgs 和压栈动作保存现场:

深入理解系统调用_第12张图片

 2.然后跳转到了/linux-5.4.34/arch/x86/entry/common.c 目录下的 do_syscall_64 函数,在ax寄存器中获取到系统调用号,然后去执行系统调用内容:

深入理解系统调用_第13张图片

3.查看entry_syscall_64后续的代码,在完成执行现场的恢复,最后的两个popq出栈指令恢复原 rdi 和 rsp的内容,也就是完成了堆栈的切换。

深入理解系统调用_第14张图片

你可能感兴趣的:(深入理解系统调用)