深入理解系统调用

深入理解系统调用

  • 找一个系统调用,系统调用号为学号最后2位相同的系统调用
  • 通过汇编指令触发该系统调用
  • 通过gdb跟踪该系统调用的内核处理过程
  • 重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化

一、查找系统调用

  学号后两位为92,对应的十六进制数位0x5c(后面汇编有用)

  在linux内核中查找系统调用,路径为 arch/x86/entry/syscalls/syscall_64.tbl,对应的是64位的系统调用;

  

 

 

  如图92号系统调用,92对应的系统调用为__x64_sys_chown,其对应的API函数为chown

  由文档可知chown可以用来改变文件的所有者或组。

  使用示例:

  1,更改文件的所有者:

  Chown tim program.c

  文件 program.c 的所有者更改为tim。作为所有者,tim 可以使用 chmod 命令允许或拒绝其他用户访问 program.c。

  2,更改目录的所有者:

  chown -R john:build /tmp/src

  将目录 /tmp/src 中所有文件的所有者和组更改为用户 john 和组 build

  - R 递归式地改变指定目录及其下的所有子目录和文件的拥有者。

  - v 显示chown命令所做的工作。

  

  接着如下图在./linux-5.4.34/tools/include/nolibc/nolibc.h中找到了chown的实现

  深入理解系统调用_第1张图片

 

 

   深入理解系统调用_第2张图片

 

 深入理解系统调用_第3张图片

 

 

二、通过汇编指令触发92号系统调用

  首先使用C语言出发系统调用,测试效果

  深入理解系统调用_第4张图片

  本系统中有两个用户分别为akira 和 root,

  username           user id                  group id

  akira                      1000                       1000

  root                       0                              0

  

  chown_test.c

#include 
#include 
#include 

int main(){
    chown("/home/akira/Downloads/test.txt", 0, 0);
    printf("Done!\n");    
    return 0;
}

  chown_test2.c

#include 
#include 
#include 

int main(){
    chown("/home/akira/Downloads/test.txt", 1000, 1000);
    printf("Done!\n");    
    return 0;
}

 

 

 编译,记得加-static参数

Test_chown1 用来将所有者和组变为0              0,即root root;

Test_chown2 用来将所有者和组变为1000        1000, 即 akira akira;

因为涉及到root用户和组,所以执行chown_test的时候需要使用sudo,提升权限;

测试结果如图所示:

深入理解系统调用_第5张图片

 

 

 

使用内嵌汇编进行系统调用

系统调用号一定要转成16进制形式

代码如下:

asm_chown.c

#include 
#include 
#include 

int main(){
    char path[] = "/home/akira/Downloads/test.txt";
    int ret = -15;
    unsigned int owner = 0, group = 0;
    //chown("/home/akira/Downloads/test.txt", 0, 0);
    unsigned long number = 92;    
     
    asm volatile(
        "movq %1, %%rdi\n"
        "movq %2, %%rsi\n"
        "movq %3, %%rdx\n"    
        "movl $0x5c, %%eax\n\t"

                "syscall\n\t"
        "movq %%rax,%0\n\t"
                :"=m"(ret)
                :"p"(path), "m"(owner), "m"(group)
        //:"rax", "rdi", "rsi", "rdx"
        );    

    //if(ret)
    printf("Done: %d\n", ret);    
    return 0;
}

asm_chown2.c

#include 
#include 
#include 

int main(){
    char path[] = "/home/akira/Downloads/test.txt";
    int ret = -15;
    unsigned int owner = 1000, group = 1000;
    //chown("/home/akira/Downloads/test.txt", 0, 0);
//    unsigned long number = 92;    
     
    asm volatile(
        "movq %1, %%rdi\n"
        "movq %2, %%rsi\n"
        "movq %3, %%rdx\n"    
        "movl $0x5c, %%eax\n\t"

                "syscall\n\t"
        "movq %%rax,%0\n\t"
                :"=m"(ret)
                :"p"(path), "m"(owner), "m"(group)
        //:"rax", "rdi", "rsi", "rdx"
        );    

    //if(ret)
    printf("Done: %d\n", ret);    
    return 0;
}

 

编译

 

 深入理解系统调用_第6张图片

 

 

 上图即为测试结果。

三、通过gdb跟踪该系统调用的内核处理过程

首先将之前的编译好的asmChown1和asmChown2以及测试文件test.txt复制到rootfs/home/ 目录下,然后重新打包文件系统

terminal1
$ find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz $ qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s -nographic -append "console=ttyS0"
terminal2 $ cd linux
-5.4.34 $ gdb vmlinux $ target remote:1234

因为实验环境无法添加用户以及组,这里直接运行asmChown1,设置断点查看效果;

 

首先可以用返回变查看使用此代码触发92号系统调用的内部汇编代码,如下图,可见和之前的汇编代码类似,

直接调用了0x5c,即92号系统调用。

 

启动调试后,模拟实验环境home目录

深入理解系统调用_第7张图片

 

设置断点   __x64_sys_chown(chown对应的entry_point)

 深入理解系统调用_第8张图片

 

执行asmChown1

 深入理解系统调用_第9张图片

 可见程序直接返回了do_fchownat();

触发断点时的内核堆栈

深入理解系统调用_第10张图片

 

结束运行时的内核堆栈

 深入理解系统调用_第11张图片

 

 

在linux代码中1寻找do_fchownat(),实现如下

int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
        int flag)
{
    struct path path;
    int error = -EINVAL;
    int lookup_flags;

    if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
        goto out;

    lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
    if (flag & AT_EMPTY_PATH)
        lookup_flags |= LOOKUP_EMPTY;
retry:
    error = user_path_at(dfd, filename, lookup_flags, &path);
    if (error)
        goto out;
    error = mnt_want_write(path.mnt);
    if (error)
        goto out_release;
    error = chown_common(&path, user, group);
    mnt_drop_write(path.mnt);
out_release:
    path_put(&path);
    if (retry_estale(error, lookup_flags)) {
        lookup_flags |= LOOKUP_REVAL;
        goto retry;
    }
out:
    return error;
}

阅读代码可以发现,chown除了92号系统调用,并没有触发其他的系统调用。

 

你可能感兴趣的:(深入理解系统调用)