Linux内核分析实验(二):跟踪分析Linux内核的启动过程

学号末位:446
原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/

一、实验要求
实验:举例跟踪分析Linux内核5.0系统调用处理过程
编译内核5.0
qemu -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img
选择系统调用号后两位与您的学号后两位相同的系统调用进行跟踪分析
https://github.com/mengning/menu
给出相关关键源代码及实验截图,撰写一篇博客(署真实姓名或学号最后3位编号),并在博客文章中注明“原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/ ”,博客内容的具体要求如下:
题目自拟,内容围绕系统调用进行;
博客中需要使用实验截图
博客内容中需要仔细分析系统调用、保护现场与恢复现场、系统调用号及参数传递过程
总结部分需要阐明自己对系统调用工作机制的理解。

二、实验准备
实验平台:ubuntu18.04+vm workstation 12 pro
实验内核:linux 5.0

三、编译内核
1.下载并解压linux内核5.0
2.由于编译过程繁琐且问题多多,最好先将所需依赖库装好

sudo apt-get install bison
sudo apt-get install flex
sudo apt install gcc-4.8 gcc-4.8-multilib g++-4.8 g++-4.8-multilib #补全GCC
sudo apt install libssl-dev 
sudo apt-get install libc6-dev-i386


3.编译配置

make i386_defconfig #编译为32位,因为我们qemu是32位的
make menuconfig
#在menu中依次选择 Kernel_hacking > compile-time checks and compiler options>
#勾选comoile the kernel with debug info

在这里插入图片描述
4.完成后开始编译内核

cd kernel-5.0 
make -j4//4表示4核编译

在这里插入图片描述
注:编译时间很长同时会占用很大的硬盘容量,建议先扩展虚拟机的硬盘,保证有30G的空闲容量,否则编译完又得重做(都是泪)

四、准备文件系统
从孟宁老师的github上下载menu

mkdir rootfs
git clone https://github.com/mengning/menu.git
cd menu
gcc -lpthread -o init linktable.c menu.c test.c -m32 -static
cd ../rootfs
cp ../menu/init ./
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img

五、运行qemu并启用gdb调试

qemu-system-i386 -kernel '/home/isition/linux-5.0/arch/x86/boot/bzImage'  -initrd /home/isition/linux-5.0/rootfs.img

在这里插入图片描述
运行已编译好的内核,并启动我们的程序,可以看到menuos的界面,接下来我们来试试使用gdb调试。
先关掉这个界面,在linux-5.0界面再次启动虚拟机,不同的这次的命令会使虚拟机等待我们的远程命令

qemu-system-i386 -kernel '/home/isition/linux-5.0/arch/x86/boot/bzImage'  -initrd /home/isition/linux-5.0/rootfs.img -S -s -append nokaslr

打开另一个terminal,进行gdb通信

cd linux-5.0
gdb
file vmlinux
target remote:1234 #TCP通信,端口号1234
b start_kernel # 在启动内核时设置断点
c #continue

在这里插入图片描述
六、监控系统调用
我的学号是446,故监控46号系统调用,可在下面的文件里发现系统调用
在这里插入图片描述
在这里插入图片描述
可以发现46号系统调用为setgid,经过网上的调查,该系统调用定义与作用如下:

头文件:

#include <unistd.h>

定义函数:

int setgid(gid_t gid);

函数说明:setgid()用来将目前进程的真实组识别码(real gid)设成参数gid 值. 如果是以超级用户身份执行此调用,
则real、effective 与savedgid 都会设成参数gid。

返回值:设置成功则返回0, 失败则返回-1, 错误代码存于errno 中.

错误代码: EPERM:并非以超级用户身份调用, 而且参数gid 并非进程的effective gid 或saved gid 值之一.

参考: https://www.jb51.net/article/71673.htm
http://c.biancheng.net/view/870.html

搞清楚了条用的作用后,开始添加的自己的代码:
在这里插入图片描述
添加头文件unistd.h并将myset()函数添加进代码中,重新编译并启动qemu,再如上所述启动gdb监控:

cd linux-5.0
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
qemu-system-i386 -kernel '/home/isition/linux-5.0/arch/x86/boot/bzImage'  -initrd /home/isition/linux-5.0/rootfs.img -S -s -append nokaslr

#another window
cd linux-5.0
gdb
file vmlinux
target remote:1234 #TCP通信,端口号1234

在这里插入图片描述
准备工作完成后,在系统调用处设置断点并执行。
查询该调用的入口点为sys_setgid(),在此处设置断点:
在这里插入图片描述
在这里插入图片描述
继续后陷入中断
在这里插入图片描述
总结

通过这次实验加深了对linux系统、文件系统、系统调用的理解。一般情况下进程是不能访问内核的。通过中断的方式保存现场从用户态进入内核态,然后执行调用后再恢复现场并返回用户态。

猜你喜欢

转载自blog.csdn.net/weixin_42107987/article/details/88668979