zoukankan      html  css  js  c++  java
  • 深入理解系统调用

    深入理解系统调用

    一.实验要求

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

    二.实验过程

    1. 实验准备
    • 配置内核选项

      •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)

    配置完成后, 将源码重新编译, 然后运行qemu:

    qemu-system-x86_64 -kernel arch/x86/boot/bzImage
    
    • 制作根文件系统

      • 下载busybox源码

        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
        
      • 配置

        配置编译成静态链接库

        •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脚本⽂件放在根⽂件系统跟⽬录下(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

      • 打包根文件系统 , 测试

        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
        

      可以看到我们的脚本 已经顺利的被打包到根文件系统中运行了

    1. 调试75号系统调用

      我的学号后两位是75, 查看系统调用表

      arch/x86/syscalls/syscall_64.tbl

    该系统调用的功能 是将数据刷新到磁盘上面

    fdatasync:

    Linux的文件存储的是将数据文件信息inode 分别存储的,在inode中保存了如:名称、文件大小size、修改时间、访问时间等信息我们称作metadata元数据。数据和文件信息inode在物理上是分开存储的,innode修改时需要一次磁盘IO的

    • 编写一个简单的代码来触发fdatasync系统调用

      int main()
      {
          asm volatile(
              "movl $0x4B,%eax
      	" //使用EAX传递系统调号75
              "syscall
      	" //触发系统调用;
              );
          return 0;
      }
      
      

      编译这个代码生成可执行文件fdatasync_test(一定要加上-static参数使用静态编译, 因为我们设置了在内核中设置了静态编译选项)

    • 重新打包根文件系统

      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"
      
    • 调试

      • 启动系统后会暂时停止, 这时我们新开一个终端, 输入命令:
      gdb vmlinux
      target remote:1234
      
      • 接着我们输入c, 虚拟机会继续运行, 完成初始化并进入初始界面

      ​ 因为fdatasync对应的函数入口是_x64_sys_fdatasync, 所以我们在这个打下断点:

      • qemu运行后, 我们在qemu的终端的home目录下, 运行我们之前编译好的fdatasync_test可执行文件, 此时虚拟机会卡主, 我们在调试终端查看调试信息

        可以看到gdb成功的捕捉到了断点

      • 接着我们进入单步调试, 看看系统调用做了哪些工作

        系统首先执行的 syscall_return_slowpath 函数, 准备恢复现场
        接下来, 执行用于恢复现场的汇编指令


        现场恢复完成

    三.总结

    1. syscall首先通过MSR寄存器查找中断向量表, 找到中断函数的入口位置, 随后执行swags进行压栈和保存现场的动作
    2. 接着执行do_syscall_64函数, 在ax寄存器中获得系统调用号去执行系统调用
    3. 接着调用我们的75号系统调用
    4. 系统调用完结束后执行yscall_return_slowpath(regs), 准备恢复现场
    5. 恢复现场工作
  • 相关阅读:
    Vue.js——vue-router 60分钟快速入门
    史上最全最强SpringMVC详细示例实战教程
    介绍用C#和VS2015开发基于Unity架构的2D、3D游戏的技术
    iphone导入照片不显示,不同步怎么整
    Unity 3D入门简介
    Vue + Element UI 实现权限管理系统
    Spring Boot + Spring Cloud 构建微服务系统
    linux下文件的复制、移动与删除
    2017年全球AI芯片公司大盘点
    人工智能爆发 中美AI芯片大比拼
  • 原文地址:https://www.cnblogs.com/sa19225475/p/12965056.html
Copyright © 2011-2022 走看看