程序锅

  • 首页
  • 分类
  • 标签
  • 归档
  • 关于

  • 搜索
基础知识 Etcd LeetCode 计算机体系结构 Kubernetes Containerd Docker 容器 云原生 Serverless 项目开发维护 ELF 深入理解程序 Tmux Vim Linux Kernel Linux numpy matplotlib 机器学习 MQTT 网络基础 Thrift RPC OS 操作系统 Clang 研途 数据结构和算法 Java 编程语言 Golang Python 个人网站搭建 Nginx 计算机通用技术 Git

Linux Kernel | Linux 权限介绍

发表于 2021-09-15 | 分类于 Linux Kernel | 0 | 阅读次数 2220

进程权限控制是指进程能否有权限访问某个文件、能否访问其他进程、能否进行某些操作,以及进程能否被其他项目组访问。task_struct 中关于进程权限的成员变量有如下这些,其中 cred 表示我这个进程可以操作谁,实质上就是我操作别人时具有的权限是什么;real_cred 表示谁能操作我这个进程。

操作其实就是一个对象对另一个对象进行某些动作。当动作要实施的时候,需要审核权限,当两边的权限匹配上了,那么就可以实施操作。

// include\linux\sched.h

/* Objective and real subjective task credentials (COW): */
const struct cred __rcu         *real_cred;
/* Effective (overridable) subjective task credentials (COW): */
const struct cred __rcu         *cred;

其中 struct cred 的定义如下所示:

// include\linux\cred.h

struct cred {
......
        kuid_t          uid;            /* real UID of the task */
        kgid_t          gid;            /* real GID of the task */
        kuid_t          suid;           /* saved UID of the task */
        kgid_t          sgid;           /* saved GID of the task */
        kuid_t          euid;           /* effective UID of the task */
        kgid_t          egid;           /* effective GID of the task */
        kuid_t          fsuid;          /* UID for VFS ops */
        kgid_t          fsgid;          /* GID for VFS ops */
......
        kernel_cap_t    cap_inheritable; /* caps our children can inherit */
        kernel_cap_t    cap_permitted;  /* caps we're permitted */
        kernel_cap_t    cap_effective;  /* caps we can actually use */
        kernel_cap_t    cap_bset;       /* capability bounding set */
        kernel_cap_t    cap_ambient;    /* Ambient capability set */
......
} __randomize_layout;

主要分为两大块:

  • 第一块是关于用户和用户所属的用户组信息;
  • 第二块是 capabilities 相关的信息;

1. 用户和用户组

uid、gid 一般情况下是谁启动的进程,就是谁的 ID。但是权限审核的时候,又往往不比较这两个,也就是说不大起作用。

euid、egid 这两个是真正起作用的。当一个进程要操作消息队列、共享内存、信号量等对象的时候,就是在比较这个。

fsuid、fsgid(filesystem user/group id),这个是对文件操作时会审核的权限。

suid、sgid 是用来干什么的呢?一般来说 uid、euid、fsuid 这三者是一样的,gid、egid、fsgid 也是一样的,因为一般谁启动的进程,那么就应该审核启动的用户到底有没有这个权限。但是,也有特殊情况。一个程序是用户 B的,这个程序所拥有的权限是 rwxr-xr-x。这个程序会操作一个文件,而这个文件的权限是 rw-r--r--。此时,用户 A 可以运行该程序,A 用户启动的进程中 uid、euid、fsuid 都是用户 A 的。这个时候,启动的进程无法写这个文件。此时,我们可以通过 chmod u+s program 给这个程序设置 set-user-ID 的标识位,也就是把程序的权限设置为 rwsr-xr-x。那么,用户 A 再次启动这个程序的时候,uid 还是用户 A,但是 euid、fsuid 就不是用户 A 了,因为看到了 set-user-ID 标识,所以 euid、fsuid 就变成了程序的所有者,也就是用户 B 的 ID 了。

在 Linux 里面,一个进程可以随时通过 setuid 来设置 uid。程序的拥有者 ID 会被保存在一个地方,这就是 suid、sgid(saved uid、saved gid)。这样,就可以使用 setuid 来方便地设置 uid 了。

2. Linux capabilities

除了使用用户和用户组控制权限,Linux 的另一个机制就是 capabilities。capabilities 相关的成员变量也在 struct cred 中。那么为什么需要 capabilities 呢?

在 Linux capabilities 出现前,进程的权限可以简单分为两类,第一类是特权用户的进程(进程的有效用户 ID 是 0,简单来说,你可以认为它就是 root 用户的进程),第二类是非特权用户的进程(进程的有效用户 ID 是非 0,可以理解为非 root 用户进程)。特权用户进程可以执行 Linux 系统上的所有操作,而非特权用户在执行某些操作的时候就会被内核限制执行(其实这个概念,也是我们通常对 Linux 中 root 用户与非 root 用户的理解)。然而这个时候 root 用户权限太大,而普通用户权限太小。有时候,一个普通用户只想做一点高权限的事情,但是却必须给他整个 root 的权限,这有点不安全。

从 kernel 2.2 开始,Linux 把特权用户所有的这些“特权”做了更详细的划分,从而可以更加细粒度地给进程赋予不同权限,而被划分出来的每个单元就被称为 capability。对于一个 capability,有的对应一个特权操作,有的可以对应很多个特权操作。而每个特权操作都有一个对应的 capability。所有的 capabilities 都在 Linux capabilities 手册列出来了,你也可以在内核的文件capability.h 中看到所有 capabilities 的定义。

这样,对于任意一个进程,在做任意一个特权操作的时候,都需要有这个特权操作对应的 capability,也就是说当有相应权限的时候,就能做这些操作;没有的时候,就不能做,从而把权限的粒度给减小了很多。比如说,运行 iptables 命令,对应的进程需要有 CAP_NET_ADMIN 这个 capability。如果要 mount 一个文件系统,那么对应的进程需要有 CAP_SYS_ADMIN 这个 capability(需要注意的是:CAP_SYS_ADMIN 这个 capability 里允许了大量的特权操作,包括文件系统,交换空间,还有对各种设备的操作,以及系统调试相关的调用等等)。

"Linux Programmer's Manual"中关于Linux capabilities的描述:https://man7.org/linux/man-pages/man7/capabilities.7.html

2.1. capabilities 表示

capabilities 机制使用位图来表示权限。

// include\uapi\linux\capability.h

#define CAP_CHOWN            0
#define CAP_KILL             5
#define CAP_NET_BIND_SERVICE 10
#define CAP_NET_RAW          13
#define CAP_SYS_MODULE       16
#define CAP_SYS_RAWIO        17
#define CAP_SYS_BOOT         22
#define CAP_SYS_TIME         25
#define CAP_AUDIT_READ       37
#define CAP_LAST_CAP         CAP_AUDIT_READ

task_struct 中关于 capabilities 的成员变量的解释如下:

  • cap_permitted 表示进程能够使用的权限,但是真正起作用的是 cap_effective。cap_permitted 中包含了 cap_effective 中没有的权限。一个进程可以在必要的时候,放弃自己的某些权限,从而可以更加安全。

  • cap_bset(capability bounding set),是系统中所有进程允许保留的权限。如果这个集合中不存在某个权限,那么系统中的所有进程都没有这个权限,即使以 root 用户执行的进程也是一样的。

  • cap_inheritable 表示当可执行文件的扩展属性设置了 inheritable 位时,调用 exec 执行该程序时会继承调用者的 inheritable 集合,并将其加入到 permitted 集合中。但是在非 root 用户下执行 exec 时,通常不会保留 inheritable 集合。(但是往往是非 root 用户才想保留权限,所以非常鸡肋)。

  • cap_ambient 是比较新加入内核的,主要是为了解决 cap_inheritable 鸡肋的情况。也就是当一个非 root 用户进程使用 exec 执行一个程序的时候,如何保留权限的问题。当执行 exec 的时候,cap_ambient 会被添加到 cap_permitted 中,同时设置到 cap_effective。

2.2. root 和非 root 用户

在普通 Linux 节点上,非 root 用户启动的进程缺省没有任何 Linux capabilities,而 root 用户启动的进程缺省包含了所有的 Linux capabilities。

但是,对于 root 用户启动的进程来说,如果将某个 capability 去掉,那么需要相应权限的命令也是无法执行的。比如,对于 root 用户启动的进程,如果把 CAP_NET_ADMIN 这个 capability 移除,那么是无法正常执行 iptables 的。如下所示,我们使用 capsh(https://man7.org/linux/man-pages/man1/capsh.1.html) 这个工具来进行试验。

# sudo /usr/sbin/capsh --keep=1 --user=root   --drop=cap_net_admin  --   -c './iptables -L;sleep 100'
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
 
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
 
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
iptables: Permission denied (you must be root).

可以看到,即使是 root 用户,如果把 root 用户的 "CAP_NET_ADMIN"给移除了,那么在执行 iptables 的时候就会看到"Permission denied (you must be root)."的提示信息。

2.3. capabilities 查看

另外通过 /proc 文件系统,我们可以查看进程对应的 capabilties 的设置,见 /proc/[pid]/status 文件。这个文件里面有 5 个 cap 参数。

# ps -ef | grep sleep
root     22603 22275  0 19:44 pts/1    00:00:00 sudo /usr/sbin/capsh --keep=1 --user=root --drop=cap_net_admin -- -c ./iptables -L;sleep 100
root     22604 22603  0 19:44 pts/1    00:00:00 /bin/bash -c ./iptables -L;sleep 100
 
# cat /proc/22604/status | grep Cap
CapInh:            0000000000000000
CapPrm:          0000003fffffefff
CapEff:             0000003fffffefff
CapBnd:          0000003fffffefff
CapAmb:         0000000000000000

其中,对于当前进程,直接影响某个特权操作是否可以被执行的参数,是"CapEff",也就是"Effective capability sets",这是一个 bitmap,每一个 bit 代表一项 capability 是否被打开。而每一位代表的意思见文件 capability.h。比如,Linux 内核capability.h里把 CAP_NET_ADMIN 的值定义成 12,所以我们可以看到"CapEff"的值是"0000003fffffefff",第 4 个数值是 16 进制的"e",而不是 f。因此,这个进程是没有执行 iptable 命令的权限了。

而对于其他几个 capabilities 相关的参数,它们可以和应用程序文件属性中的 capabilities 协同工作,确定新启动的进程最终的 capabilities 参数的值。比如,要新启动一个程序,在 Linux 里的过程就是先通过 fork() 来创建出一个子进程,然后调用 execve() 系统调用读取文件系统里的程序文件,把程序文件加载到进程的代码段中开始运行。那么这个新运行的进程里的相关 capabilities 参数的值,是由它的父进程以及程序文件中的 capabilities 参数值计算得来的。示意图如下所示:

具体计算过程,可以看 "Linux Programmer's Manual" 中的描述(https://man7.org/linux/man-pages/man7/capabilities.7.html),也可以参考网上这两篇文章:

  • Capabilities: Why They Exist and How They Work:https://blog.container-solutions.com/linux-capabilities-why-they-exist-and-how-they-work
  • Linux Capabilities in Practice:https://blog.container-solutions.com/linux-capabilities-in-practice

综上来说,文件中可以设置 capabilities 参数值,并且这个值会影响到最后运行它的进程。比如,我们如果把 iptables 的应用程序加上 CAP_NET_ADMIN 的 capability,那么即使是非 root 用户也有执行 iptables 的权限了。

$ id
uid=1000(centos) gid=1000(centos) groups=1000(centos),10(wheel)
$ sudo setcap cap_net_admin+ep ./iptables
$ getcap ./iptables
./iptables = cap_net_admin+ep
$./iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
 
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DOCKER-USER  all  --  anywhere             anywhere
DOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
…
卷死我
dawnguo 微信支付

微信支付

dawnguo 支付宝

支付宝

  • 本文作者: dawnguo
  • 本文链接: /archives/113
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# Linux # Linux Kernel
Linux Kernel | Linux task_struct 结构体概述
Linux Kernel | Linux 信号机制介绍
  • 文章目录
  • 站点概览
dawnguo

dawnguo

215 日志
24 分类
37 标签
RSS
Creative Commons
© 2018 — 2025 程序锅
0%