跟踪分析Linux内核5.0系统调用处理过程

ID:371
原创作品转载请注明出处
本实验来源 https://github.com/mengning/linuxkernel/
一、实验要求
举例跟踪分析Linux内核5.0系统调用处理过程
1.编译内核5.0
qemu -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img
2.选择系统调用号后两位与您的学号后两位相同的系统调用进行跟踪分析
https://github.com/mengning/menu
3.给出相关关键源代码及实验截图,撰写一篇博客(署真实姓名或学号最后3位编号),并在博客文章中注明“原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/ ”,博客内容的具体要求如下:
A.题目自拟,内容围绕系统调用进行;
B.博客中需要使用实验截图
C.博客内容中需要仔细分析系统调用、保护现场与恢复现场、系统调用号及参数传递过程
D.总结部分需要阐明自己对系统调用工作机制的理解。
二、实验环境
1.ubuntu 18.04 虚拟机
2.VMware workstation 14 Player
三、实验步骤
1.编译内核
首先下载Linux5.0.2源码 https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.2.tar.xz放到指定文件夹下,之后配置并编译Linux内核,使其具备调试功能。命令如下:

wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.tar.xz
cd linux-5.0
make menuconfig,找到kernel hacking,->Compile-time checks and compiler options,选择 [*]compile the kernel with debug info
(执行过程中若发生错误,根据提示进行安装:
sudo apt-get install libncurses-dev
sudo apt-get install flex
sudo apt-get install bison
sudo apt-get install libssl-dev)
make -4j

在这里插入图片描述
2.制作根文件系统
根据如下命令制作根文件系统:

git clone https://github.com/mengning/menu.git
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

3.启动Menu OS
根据如下命令启动Menu:

qemu-system-x86_64 -kernel ../arch/x86/boot/bzImage -initrd ../rootfs.img

在这里插入图片描述
4.启动gdb
根据如下命令启动gdb:

cd ~
gdb
(gdb) file linux-5.0.2/vmlinux
(gdb) target remote:1234

在这里插入图片描述
5.增加系统调用
如下命令查看系统调用
gedit /linux-5.0.x/arch/x86/include/generated/uapi/asm/unistd_32.h
我的学号后两位是71,即选择 #define __NR_setregid 71。通过网上查找可得知:函数说明:setregid()用来将参数rgid 设为目前进程的真实组识别码, 将参数egid 设置为目前进程的有效组识别码。如果参数rgid 或egid 值为-1, 则对应的识别码不会改变。返回值:执行成功则返回0, 失败则返回-1, 错误代码存于errno。
在MenuOS的test.c中插入setGIDASM()系统调用的代码

int SetreGid()
{
	int ret;
	gid_t rgid=1000;
	gid_t egid=1002;
    asm volatile(
        "movl %2,%%ecx\n\t"
	"movl %1,%%ebx\n\t"
        "mov $0x47,%%eax\n\t" 
        "int $0x80\n\t" 
        "mov %%eax,%0\n\t"  
        : "=m" (ret) 
	: "b"(rgid),"c"(egid)
    );
	printf("gid: %d\n",ret);
        printf("gid: %d  %d \n",rgid,egid);
	return 0;
 
}
int SetSetreGid()
{
	gid_t rgid=1000;
	gid_t egid=1002;
	printf("gid: %d\n",setresgid(rgid,egid));
        printf("gid: %d  %d \n",rgid,egid);
	return 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

利用gdb追踪系统调用

cd ~/LinuxKernel/linux-5.0.1
sudo gdb
file vmlinux  
target remote:1234 
b sys_setregid
C

在这里插入图片描述
在这里插入图片描述

四、总结
系统调用过程分析:
在使用int 0x80中断之后,CPU会运行arch/x86/entry/entry_32.S中的指令:

//这段代码就是系统调用处理的过程,其它的中断过程也是与此类似
//系统调用就是一个特殊的中断,也存在保护现场和回复现场
ENTRY(system_call)//这是0x80之后的下一条指令
 RING0_INT_FRAME         # can't unwind into user space anyway
 ASM_CLAC
 pushl_cfi %eax          # save orig_eax
 SAVE_ALL//保护现场
 GET_THREAD_INFO(%ebp)
                 # system call tracing in operation / emulation
 testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
 jnz syscall_trace_entry
 cmpl $(NR_syscalls), %eax
 jae syscall_badsys
syscall_call:
 // 调用了系统调用处理函数,实际的系统调用服务程序
 call *sys_call_table(,%eax,4)//定义的系统调用的表,eax传递过来的就是系统调用号,在例子中就是调用的systime
syscall_after_call:
 movl %eax,PT_EAX(%esp)      # store the return value
syscall_exit:
 LOCKDEP_SYS_EXIT
 DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don't miss an interrupt
                 # setting need_resched or sigpending
                 # between sampling and the iret
 TRACE_IRQS_OFF
 movl TI_flags(%ebp), %ecx
 testl $_TIF_ALLWORK_MASK, %ecx  # current->work
 jne syscall_exit_work//退出之前,syscall_exit_work 
 //进入到syscall_exit_work里边有一个进程调度时机
restore_all:
 TRACE_IRQS_IRET
restore_all_notrace://返回到用户态
#ifdef CONFIG_X86_ESPFIX32
 movl PT_EFLAGS(%esp), %eax  # mix EFLAGS, SS and CS
 # Warning: PT_OLDSS(%esp) contains the wrong/random values if we
 # are returning to the kernel.
 # See comments in process.c:copy_thread() for details.
 movb PT_OLDSS(%esp), %ah
 movb PT_CS(%esp), %al
 andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
 cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
 CFI_REMEMBER_STATE
 je ldt_ss           # returning to user-space with LDT SS
#endif
restore_nocheck:
 RESTORE_REGS 4          # skip orig_eax/error_code
irq_return:
 INTERRUPT_RETURN//iret(宏),系统调用过程到这里结束

计算机系统的各种硬件资源是有限的,在现代多任务操作系统上同时运行的多个进程都需要访问这些资源,为了更好的管理这些资源进程是不允许直接操作的,所有对这些资源的访问都必须有操作系统控制。也就是说操作系统是使用这些资源的唯一入口,而这个入口就是操作系统提供的系统调用。而且通过这次的实验,我了解到 系统调用是属于操作系统内核的一部分的,必须以某种方式提供给进程让它们去调用。CPU可以在不同的特权级别下运行,而相应的操作系统也有不同的运行级别,用户态和内核态。运行在内核态的进程可以毫无限制的访问各种资源,而在用户态下的用户进程的各种操作都有着限制,比如不能随意的访问内存、不能开闭中断以及切换运行的特权级别。显然,属于内核的系统调用一定是运行在内核态下,但是如何切换到内核态呢?当然是中断,一般情况下,系统调用都是通过中断实现的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值