sudo命令实现原理简析

作者: 不鱼儿 | 来源:发表于2019-12-19 09:47 被阅读0次

    sudo是Linux上的常用命令,其目的是为了给普通用户提升操作权限,完成一些需要root权限才能完成的任务。那么sudo是如何提升权限的呢?

    linux操作系统有着严格、灵活的权限访问控制。主要体现在两方面:

    1、文件权限
    2、进程权限

    文件权限

    文件权限包括五种:

    r:可读取文件内容或目录结构
    w:可修改文件的内容或目录的结构(但不包括删除)
    x:文件可被系统执行或目录可被作文工作目录
    s:文件在执行阶段具有文件所有者的权限
    t:使一个目录既能够让任何用户写入文档,又不让用户删除这个目录下他人的文档

    一个文件拥有三组权限,所有者权限、所属组权限、其他人权限

    进程权限

    进程就是用户访问计算机资源的代理,用户执行的操作其实是带有用户身份信息的进程执行的操作。这里介绍两个最重要的进程权限id

    reaal user id(ruid):执行进程者的 user id,一般情况下就是用户登录时的 user id
    effective user id(euid):决定进程是否对某个文件有操作权限,默认为ruid

    在文件权限和进程权限id里,s文件权限和euid权限id是sudo实现提升权限的根本。一个进程是否能操作某个文件,取决于进程的euid是否拥有这个文件的相应权限,而不是ruid。也就是说,如果想要让进程获得某个用户的权限,只要把进程的euid设置为该用户id就可以了。在具体一点,我们想要让进程拥有root用户的权限,我只要想办法把进程的euid设置成root的id:0就可以了。

    Linux提供了一个seteuid的函数,可以更改进程的euid。函数声明在头文件<unistd.h>里。

    int seteuid(uid_t euid);

    但是,如果一个进程本身没有root权限,也就是说euid不是0,是无法通过调用seteuid将进程的权限提升的,调用seteuid会出现错误。
    那该怎么把进程的euid该为root的id:0呢?那就是通过s权限。

    如果一个文件拥有x权限,表示这个文件可以被执行。shell执行命令或程序的时候,先fork一个进程,再通过exec函数族执行这个命令或程序,这样的话,执行这个文件的进程的ruid和euid就是当前登入shell的用户id。

    当这个文件拥有x权限和s权限时,在shell进行fork后调动exec函数族执行这个文件的时候,这个进程的euid将被系统更改为这个文件的拥有者id。

    比如,一个文件的拥有者为user_1,权限为rwsr-xr-x,那么你用user_2的文件执行他的时候,执行这个文件的进程的ruid为user_2的id,euid为user_1的id。

    创建一个main.c文件,并写入如下代码:

    #include <stdio.h>
    #include <unistd.h>
    
    int main(int argc, char* argv[])
    {
            printf("ruid: %d\n",getuid());
            printf("euid: %d\n",geteuid());
            return 0;
    }
    

    gcc ./main.c -o ./main

    编译运行,结果如下:

    ruid: 1000
    euid: 1000
    

    通过chmod和chown为文件更改拥有者和添加s权限

    sudo chown root ./main
    sudo chmod +s ./main
    

    再次运行,结果如下:

    ruid: 1000 
    euid: 0
    

    此时由于文件的s权限,euid已经变为了root的id:0

    将代码修改如下:

    #include <stdio.h>
    #include <unistd.h>
    
    int maind(int argc, char* argv[])
    {
        printf("ruid: %d\n",getuid());
        printf("euid: %d\n",geteuid());
       
        if(execvp(argv[1], argv+1) == -1){
            perror("execvp error");
        };
        return 0;
    }
    

    gcc ./main.c --o main,编译后,执行

    sudo chown root ./main
    sudo chmod +s ./main
    ./main sudo apt update
    

    可以看到,已经成功运行apt并进行了软件列表的更新。

    查看sudo的权限

    ls -al /usr/bin/sudo
    

    输出如下

    -rwsr-xr-x 1 root root
    

    可以看到,sudo就是一个拥有者为root且拥有s权限的可执行文件。

    当然sudo的实现要比这复杂的很多,比如sudo通过检查配置文件,来决定哪些用户可以使用sudo,为了安全考虑sudo还要求验证ruid的用户密码等。

    相关文章

      网友评论

        本文标题:sudo命令实现原理简析

        本文链接:https://www.haomeiwen.com/subject/abtmnctx.html