跟踪分析Linux5.0内核处理系统调用的过程

跟踪分析Linux5.0内核处理系统调用的过程

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


实验要求

  • 下载并编译Linux5.0内核
  • 选择一个系统调用进行跟踪

实验步骤

一. 编译Linux5.0内核
1. tar -xvf linux-5.0.tar
2. cd linux-5.0
3. make menuconfig
4. make -j 8  //据说速度很快

出现以下字样说明编译成功在这里插入图片描述

二. 制作根目录
1. mkdir rootfs
2. git clone https://github.com/mengning/menu.git
3. cd menu
4. sudo apt install gcc-multilib
5. gcc -pthread -o init linktable.c menu.c test.c -m32 -static
6. cd ../rootfs
7. cp ../menu/init ./
8. find . | cpio -o -Hnewc | gzip -9 > ../rootfs.img

在这里插入图片描述

cd /usr/include/asm/unistd_64.h

在这里插入图片描述
我学号对应的系统调用是lchown,lchown是更改符号链接本身的所有者,而不是符号链接所指向的实际文件。不同的系统规定不一样:
1、BSD系统:规定只有超级用户才能更改一个文件的所有者。
2、System V:允许任意用户更改他们所拥有的所有者。
3、POSIX.1标准:取决于具体文件系统,需要用_POSIX_CHOWN_RESTRICTED调用pathconf或fpathconf函数来判断具体要操作的文件是否有限制,也就是该文件只允许超级用户更改还是允许任意用户更改他们所拥有的文件的所有者。
即使是允许更改也有以下严格规定:
(1)只有超级用户进程才能更改该文件的用户ID。
(2)满足系列条件,一个非超级用户进程就可以更改该文件的组ID:
(a)进程拥有此文件(其有效用户ID等于该文件的用户ID)。
(b)参数owner等于-1或者文件的用户ID,并且参数group等于进程的有效组ID或者进程的附加组ID之一。也就是说,你不能更改其他用户的用户ID,只能更改你所拥有的文件的组ID,并且只能更改到你所属的组。

现在要跟踪lchown,需要将以下内容加在test.c中。
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
 
int main (int argc, char *argv[])
{
   if ( argc != 2 )
    {
       printf("Usage: %s filename\n", argv[0]);
       return (1);
   }  
   if ( chown(argv[1], 0, 0) < 0 )
    {
       perror("Cannot change the owner!");
       return (1);
   }   
   return (0);
}

在menuOS中调用封装了chown的自定义函数。
在这里插入图片描述

实验截图

在这里插入图片描述

总结

系统调用概念

是操作系统为用户态运行的进程和硬件设备之间进行交互提供了一组接口,编程人员通过向内核发出系统调用,向操作系统提出服务请求,由操作系统代为完成。
系统调用是用户态进入内核态的唯一接口,本身并非内核函数,但是由内核函数实现。进入内核之后,不同的系统调用会找到各自对应的内核处理函数,这些内核函数称为系统调用的“服务例程”。例如系统调用creat实际调用的服务例程为sys_creat(),或者说系统调用creat是服务例程sys_creat()的封装例程。
在这里插入图片描述
使用系统调用的优点是:首先使得编程更加容易,把用户从学习硬件设备的低级编程特性之中解放了出来;其次,极大地提高了系统的安全性,使得内核在满足用户的某个服务请求之前,能够事先检查用户请求的准确性。
保护现场就是进入中断服务程序之前,保存需要用到的寄存器数据; 恢复现场就是进入中断服务程序之前,恢复之前保存的寄存器数据。
应用编程接口(API)只是一个函数定义,说明了如何获得一个给定的服务;而系统调用是通过软中断向内核态发出一个明确的服务请求。通常情况下,每个系统调用对应一个封装例程,而封装例程定义了应用程序所使用的API。

Int $0x80指令

Linux中实现系统调用利用了i386体系结构中的软件中断,即通过int $0x80这条汇编指令来发出系统调用。这条汇编指令将用户态的执行模式转变为内核态,并且把控制权交给系统调用处理程序的入口:system_call()处理函数。

system_call()函数

首先将系统调用号(eax)和可能用到的所有CPU寄存器保存到相应的堆栈中(由SAVE_ALL来完成)。对用户态进程传递过来的系统调用号进行有效性检查(eax是系统调用号)。
如果是合法的系统调用,根据eax中的系统调用号,内核进程查看系统调用表(sys_call_table),并且找到相应的服务例程。服务例程结束以后,从eax获得系统调用的返回值,并且把这个返回值存放在曾经保存用户态eax寄存器栈单元的那个位置上。跳转到ret_from_sys_call(),终止系统调用程序的执行。当进程恢复它在用户态的执行之前,RESTORE_ALL宏定义会恢复用户进入内核前被保存到堆栈中的寄存器的值。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值