为了执行权限检查,Linux 区分两类进程:特权进程(其有效用户标识为 0,也就是超级用户 root)和非特权进程(其有效用户标识为非零)。 特权进程绕过全部内核权限检查,而非特权进程则根据进程凭证(一般为有效 UID,有效 GID 和补充组列表)进行彻底权限检查。html
以经常使用的 passwd 命令为例,修改用户密码须要具备 root 权限,而普通用户是没有这个权限的。可是实际上普通用户又能够修改本身的密码,这是怎么回事?在 Linux 的权限控制机制中,有一类比较特殊的权限设置,好比 SUID(Set User ID on execution),不了解 SUID 的同窗请参考《Linux 特殊权限 SUID,SGID,SBIT》。由于程序文件 /bin/passwd 被设置了 SUID 标识,因此普通用户在执行 passwd 命令时,进程是以 passwd 的全部者,也就是 root 用户的身份运行,从而修改密码。linux
SUID 虽然能够解决问题,却带来了安全隐患。当运行设置了 SUID 的命令时,一般只是须要很小一部分的特权,可是 SUID 给了它 root 具备的所有权限。所以一旦 被设置了 SUID 的命令出现漏洞,就很容易被利用。也就是说 SUID 机制在增大了系统的安全攻击面。git
Linux 引入了 capabilities 机制对 root 权限进行细粒度的控制,实现按需受权,从而减少系统的安全攻击面。本文将介绍 capabilites 机制的基本概念和用法。github
说明:本文的演示环境为 Ubuntu 18.04。安全
从内核 2.2 开始,Linux 将传统上与超级用户 root 关联的特权划分为不一样的单元,称为 capabilites。Capabilites 做为线程(Linux 并不真正区分进程和线程)的属性存在,每一个单元能够独立启用和禁用。如此一来,权限检查的过程就变成了:在执行特权操做时,若是进程的有效身份不是 root,就去检查是否具备该特权操做所对应的 capabilites,并以此决定是否能够进行该特权操做。好比要向进程发送信号(kill()),就得具备 capability CAP_KILL;若是设置系统时间,就得具备 capability CAP_SYS_TIME。网络
下面是从 capabilities man page 中摘取的 capabilites 列表:socket
capability 名称 | 描述 |
CAP_AUDIT_CONTROL | 启用和禁用内核审计;改变审计过滤规则;检索审计状态和过滤规则 |
CAP_AUDIT_READ | 容许经过 multicast netlink 套接字读取审计日志 |
CAP_AUDIT_WRITE | 将记录写入内核审计日志 |
CAP_BLOCK_SUSPEND | 使用能够阻止系统挂起的特性 |
CAP_CHOWN | 修改文件全部者的权限 |
CAP_DAC_OVERRIDE | 忽略文件的 DAC 访问限制 |
CAP_DAC_READ_SEARCH | 忽略文件读及目录搜索的 DAC 访问限制 |
CAP_FOWNER | 忽略文件属主 ID 必须和进程用户 ID 相匹配的限制 |
CAP_FSETID | 容许设置文件的 setuid 位 |
CAP_IPC_LOCK | 容许锁定共享内存片断 |
CAP_IPC_OWNER | 忽略 IPC 全部权检查 |
CAP_KILL | 容许对不属于本身的进程发送信号 |
CAP_LEASE | 容许修改文件锁的 FL_LEASE 标志 |
CAP_LINUX_IMMUTABLE | 容许修改文件的 IMMUTABLE 和 APPEND 属性标志 |
CAP_MAC_ADMIN | 容许 MAC 配置或状态更改 |
CAP_MAC_OVERRIDE | 覆盖 MAC(Mandatory Access Control) |
CAP_MKNOD | 容许使用 mknod() 系统调用 |
CAP_NET_ADMIN | 容许执行网络管理任务 |
CAP_NET_BIND_SERVICE | 容许绑定到小于 1024 的端口 |
CAP_NET_BROADCAST | 容许网络广播和多播访问 |
CAP_NET_RAW | 容许使用原始套接字 |
CAP_SETGID | 容许改变进程的 GID |
CAP_SETFCAP | 容许为文件设置任意的 capabilities |
CAP_SETPCAP | 参考 capabilities man page |
CAP_SETUID | 容许改变进程的 UID |
CAP_SYS_ADMIN | 容许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等 |
CAP_SYS_BOOT | 容许从新启动系统 |
CAP_SYS_CHROOT | 容许使用 chroot() 系统调用 |
CAP_SYS_MODULE | 容许插入和删除内核模块 |
CAP_SYS_NICE | 容许提高优先级及设置其余进程的优先级 |
CAP_SYS_PACCT | 容许执行进程的 BSD 式审计 |
CAP_SYS_PTRACE | 容许跟踪任何进程 |
CAP_SYS_RAWIO | 容许直接访问 /devport、/dev/mem、/dev/kmem 及原始块设备 |
CAP_SYS_RESOURCE | 忽略资源限制 |
CAP_SYS_TIME | 容许改变系统时钟 |
CAP_SYS_TTY_CONFIG | 容许配置 TTY 设备 |
CAP_SYSLOG | 容许使用 syslog() 系统调用 |
CAP_WAKE_ALARM | 容许触发一些能唤醒系统的东西(好比 CLOCK_BOOTTIME_ALARM 计时器) |
getcap 命令和 setcap 命令分别用来查看和设置程序文件的 capabilities 属性。下面咱们演示如何使用 capabilities 代替 ping 命令的 SUID。
由于 ping 命令在执行时须要访问网络,这就须要得到 root 权限,常规的作法是经过 SUID 实现的(和 passwd 命令相同):函数
红框中的 s 说明应用程序文件被设置了 SUID,这样普通用户就能够执行这些命令了。ui
移除 ping 命令文件上的 SUID 权限:spa
$ sudo chmod 755 /bin/ping
在移除 SUID 权限后,普通用户在执行 ping 命令时碰到了 "ping: socket: Operation not permitted" 错误。
为 ping 命令文件添加 capabilities
执行 ping 命令所需的 capabilities 为 cap_net_admin 和 cap_net_raw,经过 setcap 命令能够添加它们:
$ sudo setcap cap_net_admin,cap_net_raw+ep /bin/ping
被赋予合适的 capabilities 后,ping 命令又能够正常工做了,相比 SUID 它只具备必要的特权,在最大程度上减少了系统的安全攻击面。
若是要移除刚才添加的 capabilities,执行下面的命令:
命令中的 ep 分别表示 Effective 和 Permitted 集合(接下来会介绍),+ 号表示把指定的 capabilities 添加到这些集合中,- 号表示从集合中移除(对于 Effective 来讲是设置或者清除位)。
在上面的示例中咱们经过 setcap 命令修改了程序文件 /bin/ping 的 capabilities。在可执行文件的属性中有三个集合来保存三类 capabilities,它们分别是:
在进程执行时,Permitted 集合中的 capabilites 自动被加入到进程的 Permitted 集合中。
Inheritable 集合中的 capabilites 会与进程的 Inheritable 集合执行与操做,以肯定进程在执行 execve 函数后哪些 capabilites 被继承。
Effective 只是一个 bit。若是设置为开启,那么在执行 execve 函数后,Permitted 集合中新增的 capabilities 会自动出如今进程的 Effective 集合中。
进程中有五种 capabilities 集合类型,分别是:
相比文件的 capabilites,进程的 capabilities 多了两个集合,分别是 Bounding 和 Ambient。
/proc/[pid]/status 文件中包含了进程的五个 capabilities 集合的信息,咱们能够经过下面的命名查看当前进程的 capabilities 信息:
$ cat /proc/$$/status | grep 'Cap'
可是这中方式得到的信息没法阅读,咱们须要使用 capsh 命令把它们转义为可读的格式:
$ capsh --decode=0000003fffffffff
把特权用户仅仅分为 root 和普通用户显然是过于粗糙了,这会带来安全问题。Capabilities 为解决这一问题而生,它能提供精细粒度的特权集,从而有效的减少系统的安全攻击面。
参考:
capability man page
Linux的capabilities机制
How Linux Capability Works in 2.6.25
getcap, setcap and file capabilities
Linux capabilities 101
getcap man page
setcap man page