跟踪分析 Linux 内核 5.0 系统调用处理过程
学号尾号: 155
基于 Ubuntu kylin 18.10 虚拟机
实验准备
下载和编译内核wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.tar.xz # 下载内核
# 解压文件
xz-dLinux-5.0.1.tar.xz
tar-xvfLinux-5.0.tar.xz
cdLinux-5.0
# 编译内核
make i386_defconfig
此处出现报错:
执行以下命令
apt-get install flex
再次执行
make i386_defconfig
出现报错
执行以下命令
apt-get install bison
再次执行make i386_defconfig
make
出现报错
执行以下命令
apt-get install libssl-dev
再次执行
make
等待一段时间后, 控制台会输出如下信息, 表示编译完成
制作根文件系统cd..
mkdir rootfs
Gitclone https://github.com/mengning/menu.git
cd menu
gcc-pthread-o init linktable.c menu.c test.c-m32-static
此处出现问题:
apt install gcc-multilib
gcc-pthread-o init linktable.c menu.c test.c-m32-static
再次出现问题
apt-getinstall gcc-4.8gcc-4.8-multilib g++-4.8g++-4.8-multilib
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
制作成功!
启动 MenuOScd..
qemu-kernelLinux-5.0/arch/x86/boot/bzImage-initrd rootfs.img
启动成功!
---
跟踪系统调用
我的学号尾号是 155, 在查阅系统调用表后, 发现 155 号系统调用是
#define __NR_sched_getparam 155
函数的原型是#include
// 该函数用于根据进程号获取进程的调度参数, pid 用于指定要获取调度参数的进程号, 为 0 时表示获取当前进程的调度参数
//param 用于存储获得的进程调度参数
// 返回 0 时表示成功获得进程的调度参数, 返回 - 1 时表示出错, 并设置 errno
//errno 有两种, EPERM: 调用进程没有足够的权限来获取调度参数. ESRCH: 进程 pid 不存在.
intsched_getparam(pid_tpid,structsched_param*param);
structsched_param
{
int32_tsched_priority;// 获取调度参数时, 此成员将反映分配给线程或进程的优先级
int32_tsched_curpriority;// 获取调度参数时, 此成员将设置为线程或进程当前运行的优先级. 这是内核在进行调度决策时使用的值.
union
{
int32_treserved[8];
struct
{
int32_t__ss_low_priority;
int32_t__ss_max_repl;
structtimespec __ss_repl_period;
structtimespec __ss_init_budget;
}__ss;
}__ss_un;
}
#definesched_ss_low_priority __ss_un.__ss.__ss_low_priority
#definesched_ss_max_repl __ss_un.__ss.__ss_max_repl
#definesched_ss_repl_period __ss_un.__ss.__ss_repl_period
#definesched_ss_init_budget __ss_un.__ss.__ss_init_budget
对于该系统调用, 我们可以写出如下代码对其进行测试// 在 menu 文件夹中的 test.c 文件中加入如下代码
#include
inttest_get_param()
{
structsched_param param;
sched_getparam(0,¶m);
printf("The original priority of the process is %d\n",param.sched_priority);
}
intmain()
{
PrintMenuOS();
SetPrompt("MenuOS>>");
MenuConfig("version","MenuOS V1.0(Based on Linux 3.18.6)",NULL);
MenuConfig("quit","Quit from MenuOS",Quit);
MenuConfig("time","Show System Time",Time);
MenuConfig("time-asm","Show System Time(asm)",TimeAsm);
MenuConfig("get_param","根据进程号获取进程的优先级",test_get_param);
ExecuteMenu();
}
重新制作根文件系统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
使用 gdb 跟踪调试内核cd..
qemu-kernelLinux-5.0/arch/x86/boot/bzImage-initrd rootfs.img-S-s-append nokaslr
此时启动的 qemu 窗口是 stopped 的状态
另开一个 shell 窗口gdb
file vmlinux# target remote 之前加载符号表
target remote:1234# 建立 gdb 和 gdbserver 之间的连接, 按 c 让 qemu 上的 Linux 系统继续运行
b sys_sched_getparam# 打上断点
在 gdb 窗口中输入
c
在 qemu 窗口中输入
get_param
在 gdb 窗口中输入
c
系统调用分析
可以看到, sched_getparam 系统调用的流程如下:
用户调用 sched_getparam 接口
将系统调用号 155 放入 eax 寄存器
执行 int $0x80 指令产生一个向量为 128 的编程异常, 进入内核态
保护现场
根据系统调用号, 查找系统调用表, 找到中断处理程序的地址并执行中断处理程序
恢复现场, 进入用户态
由此可以看出, 用户态进程是无法访问内核的内存空间的, 只有内核态进程才能访问内核. 因此当执行系统调用时, 必须要先将进程转换成内核态才能执行系统调用, 执行完毕后再恢复到用户态.
来源: http://www.bubuko.com/infodetail-2993095.html