[关闭]
@windmelon 2019-03-19T16:04:42.000000Z 字数 3652 阅读 2197

Linux系统分析实验(二):Linux内核5.0系统调用处理过程

Linux系统分析实验

原创作品转载请注明出处https://github.com/mengning/linuxkernel/
sa18225465


实验环境

ubuntu 18.04 虚拟机
VMware workstation 14 Player

实验目的

实验步骤

下载linux5.0内核并编译

下载linux3.9.4内核源码

wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.tar.xz

解压并编译

cd linux-5.0
make menuconfig #选择compile the kernel with debug info
make

下载menuOS

git clone https://github.com/mengning/menu.git

image.png-40.6kB

Makefile内容如下

  1. CC_PTHREAD_FLAGS = -lpthread
  2. CC_FLAGS = -c
  3. CC_OUTPUT_FLAGS = -o
  4. CC = gcc
  5. RM = rm
  6. RM_FLAGS = -f
  7. TARGET = test
  8. OBJS = linktable.o menu.o test.o
  9. all: $(OBJS)
  10. $(CC) $(CC_OUTPUT_FLAGS) $(TARGET) $(OBJS)
  11. rootfs:
  12. gcc -o init linktable.c menu.c test.c -m32 -static -lpthread
  13. gcc -o hello hello.c -m32 -static
  14. find init hello | cpio -o -Hnewc |gzip -9 > ../rootfs.img
  15. qemu -kernel ../linux-5.0/arch/x86/boot/bzImage -initrd ../rootfs.img
  16. .c.o:
  17. $(CC) $(CC_FLAGS) $<
  18. clean:
  19. $(RM) $(RM_FLAGS) $(OBJS) $(TARGET) *.bak

编译

cd menu-master
make
cd ..

启动menuOS

qemu -kernel linux-5.0/arch/x86/boot/bzImage -initrd rootfs.img

image.png-28.3kB

修改menuOS使用系统调用

这里选择65号系统调用,65号系统调用glibc中接口为int getpgrp(void),作用是获得当前进程组识别码

在menu-master/main.c中增加两个函数

  1. int Gprp(int argc, char *argv[])
  2. {
  3. int prp;
  4. prp = getpgrp();
  5. printf("pgrp:%d\n",prp);
  6. return 0;
  7. }
  8. int GprpAsm(int argc, char *argv[])
  9. {
  10. int prp;
  11. asm volatile(
  12. "mov $0x41,%%eax\n\t"
  13. "int $0x80\n\t"
  14. "mov %%eax,%0\n\t"
  15. : "=m" (prp)
  16. );
  17. printf("pgrp:%d\n",prp);
  18. return 0;
  19. }

并在main函数中注册

  1. MenuConfig("getpgrp","Get process group id",Gprp);
  2. MenuConfig("getpgrp-asm","Get process group id(asm)",GprpAsm);

测试效果

image.png-63kB

使用gdb逐步跟踪系统调用

打开两个终端,其中一个输入命令

qemu -kernel linux-5.0/arch/x86/boot/bzImage -initrd rootfs.img -s -S -append nokaslr

注意:这里必须加-append nokaslr,因为kaslr是linux的防御机制,会对运行的代码进行随机地址映射,使用这个命令禁用随机地址映射,否则和符号表对不上,导致断点设置失效

另一个使用gdb,并设置断点

gdb
(gdb)file linux-5.0/vmlinux
(gdb)target remote:1234
(gdb)b sys_getpgrp
(gdb)c

image.png-141.2kB
image.png-112.9kB

此时在QEMU窗口中

getpgrp

image.png-27.7kB

image.png-109.4kB

image.png-77.8kB

发现此时已经进入到内核态,运行内核函数,获取grp了,我们需要知道的是我们运行API函数getpgrp()或者通过汇编代码调用65号中断到进入内核态到返回用户态的过程中发生了什么

系统调用的过程

linux5.0内核好像更改了系统调用函数的名字,内核源代码和网上资料的都不太一样,这里参考的是
系统调用system_call的处理过程
在使用int 0x80中断之后,CPU会运行arch/x86/entry/entry_32.S中的指令

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

image.png-200.5kB

实验总结

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注