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

本文详细介绍了如何跟踪分析Linux内核5.0中的系统调用处理过程,包括编译内核、制作根文件系统、启动内核及修改test.c进行系统调用调试。实验中,通过int $0x80指令触发系统调用,使用eax寄存器传递系统调用号,内核在接收到请求后执行相应的处理函数。
摘要由CSDN通过智能技术生成

学号271原创作品转载请注明出处
本实验来源 https://github.com/mengning/linuxkernel/


实验说明

编译内核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/ ”,博客内容的具体要求如下:

    题目自拟,内容围绕系统调用进行;
    博客中需要使用实验截图
    博客内容中需要仔细分析系统调用、保护现场与恢复现场、系统调用号及参数传递过程
    总结部分需要阐明自己对系统调用工作机制的理解。
编译环境:
    Ubuntu 18
    gcc 4.8

 1.编译内核

cd mykernel
wget https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.0.1.tar.xz 
xz -d linux-5.0.1.tar.xz 
tar -xvf linux-5.0.1.tar 
cd linux-5.0.1 
make menuconfig // 找到kernel hacking,->Compile-time checks and compiler options, 
                        //选择 [*]compile the kernel with debug info
make -j8      //make -j 增加并行编译的速度

2.制作根文件系统

cd mykernel
mkdir rootfs
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



注释:可能在编译时,由于用64位编译32位文件,可能会出现找不到一些库函数,就需要安装一些库函数。比如本人在编译时找不到-lgcc。方法:sudo apt install gcc-4.8 gcc-4.8-multilib g++-4.8 g++-4.8-multilib

3.启动内核

4.增加系统调试并调用

查看系统调用
    gedit /linux-5.0.x/arch/x86/include/generated/uapi/asm/unistd_32.h
我的学号后两位是71,满足要求的有:
    #define __NR_setregid 71
    #define __NR_getresgid 171
    #define __NR_utimes 271
    #define __NR_recvfrom 371

其中 setresgid
相关函数:setgid, setegid, setfsgid

头文件:#include <unistd.h>

定义函数:int setregid(gid_t rgid, gid_t egid);

函数说明:setregid()用来将参数rgid 设为目前进程的真实组识别码, 将参数egid 设置为目前进程的有效组识别码. 如果参数rgid 或egid 值为-1, 则对应的识别码不会改变。

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

修改test.c

int setGIDASM()
{
	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 setGID()
{
	gid_t rgid=1000;
	gid_t egid=1002;
	printf("gid: %d\n",setresgid(rgid,egid));
        printf("gid: %d  %d \n",rgid,egid);
	return 0;
}

setresgid()函数的两个参数分别存入寄存器ebx和ecx中 

 

 实验总结:

  当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数,在Linux中是通过执行int $0x80来执行系统调用的,这条汇编指令产生向量为128的编程异常。内核实现了很多不同的系统调用,进程必须指明需要哪个系统调用,这需要传递一个名为系统调用号的参数,使用eax寄存器。在使用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(宏),系统调用过程到这里结束

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值