# Linux权限管理之Capabilities

## Linux capability详解 <a href="#articlecontentid" id="articlecontentid"></a>

![](https://csdnimg.cn/release/blogv2/dist/pc/img/original.png)[弥敦道人](https://blog.csdn.net/weixin_39219503) 2020-06-21 17:23:49 ![](https://csdnimg.cn/release/blogv2/dist/pc/img/articleReadEyes.png) 3216 ![](https://csdnimg.cn/release/blogv2/dist/pc/img/tobarCollect.png) ![](https://csdnimg.cn/release/blogv2/dist/pc/img/tobarCollectionActive.png) 收藏 5分类专栏： [linux](https://blog.csdn.net/weixin_39219503/category_10125138.html) 文章标签： [linux](https://so.csdn.net/so/search/s.do?q=linux\&t=blog\&o=vip\&s=\&l=\&f=\&viparticle=)版权声明：本文为博主原创文章，遵循[ CC 4.0 BY-SA ](http://creativecommons.org/licenses/by-sa/4.0/)版权协议，转载请附上原文出处链接和本声明。本文链接：<https://blog.csdn.net/weixin_39219503/article/details/106888174>版权[![](https://img-blog.csdnimg.cn/20201014180756738.png?x-oss-process=image/resize,m_fixed,h_64,w_64) linux ](https://blog.csdn.net/weixin_39219503/category_10125138.html)专栏收录该内容1 篇文章 0 订阅订阅专栏

## [linux](https://so.csdn.net/so/search?from=pc_blog_highlight\&q=linux) capabilities <a href="#t0" id="t0"></a>

在Linux内核2.2之前，为了检查进程权限，将进程区分为两类：特权进程(euid=0)和非特权进程。特权进程(通常为带有suid的程序)可以获取完整的root权限来对系统进行操作。

在linux内核2.2之后引入了capabilities机制，来对root权限进行更加细粒度的划分。如果进程不是特权进程，而且也没有root的有效id，系统就会去检查进程的capabilities，来确认该进程是否有执行特权操作的的权限。

可以通过`man capabilities`来查看具体的capabilities。

| 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](http://man7.org/linux/man-pages/man7/capabilities.7.html) |
| 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 计时器)                                        |

## capabilities 机制 <a href="#t1" id="t1"></a>

Linux capabilities 分为进程 capabilities 和文件 capabilities。对于进程来说，capabilities 是细分到线程的，即每个线程可以有自己的capabilities。对于文件来说，capabilities 保存在文件的扩展属性中。

linux的线程拥有的capabilities一共有五种。

* Permitted

  它是`Effective`和`Inheritable`的超集。进程拥有的权限不会超过这个集合。如果一个进程在`Permitted`集合中丢失一个能力，它无论如何不能再次获取该能力(除非特权用户再次赋予它)
* Inheritable

  它是表明该进程可以通过`execve`继承给新进程的能力。包含在该集合中的 capabilities 并不会自动继承给新的可执行文件，即不会添加到新线程的 `Effective` 集合中，它只会影响新线程的 `Permitted` 集合。
* Effecitive

  进程的有效能力集，Linux内核真正检查的能力集。
* Bounding

  它是 `Inheritable` 集合的超集，如果某个 capability 不在 `Bounding` 集合中，即使它在 `Permitted` 集合中，该线程也不能将该 capability 添加到它的 `Inheritable` 集合中。

  Bounding 集合的 capabilities 在执行 `fork()` 系统调用时会传递给子进程的 Bounding 集合，并且在执行 `execve` 系统调用后保持不变。

  * 当线程运行时，不能向 `Bounding` 集合中添加 capabilities。
  * 一旦某个 capability 被从 `Bounding` 集合中删除，便不能再添加回来。
  * 将某个 capability 从 Bounding 集合中删除后，如果之前 `Inherited` 集合包含该 capability，将继续保留。但如果后续从 `Inheritable` 集合中删除了该 capability，便不能再添加回来。
* Ambient

  在Linux内核4.3后增加，用来弥补`Inheritable` 的不足。它可以用`prctl`来直接修改。`Ambient` 具有如下特性：

  * `Permitted` 和 `Inheritable` 未设置的 capabilities，`Ambient` 也不能设置。
  * 当 `Permitted` 和 `Inheritable` 关闭某权限后，`Ambient` 也随之关闭对应权限。这样就确保了降低权限后子进程也会降低权限。
  * 非特权用户如果在 `Permitted` 集合中有一个 capability，那么可以添加到 `Ambient` 集合中，这样它的子进程便可以在 `Ambient`、`Permitted` 和 `Effective` 集合中获取这个 capability。

文件的capabilities有三种。

* Permitted

  这个集合中包含的 capabilities，在文件被执行时，会与线程的 Bounding 集合计算交集，然后添加到线程的 `Permitted` 集合中。
* Inheritable

  这个集合与线程的 `Inheritable` 集合的交集，会被添加到执行完 `execve()` 后的线程的 `Permitted` 集合中。
* Effective

  这不是一个集合，仅仅是一个标志位。如果设置开启，那么在执行完 `execve()` 后，线程 `Permitted` 集合中的 capabilities 会自动添加到它的 `Effective` 集合中。对于一些旧的可执行文件，由于其不会调用 capabilities 相关函数设置自身的 `Effective` 集合，所以可以将可执行文件的 Effective bit 开启，从而可以将 `Permitted` 集合中的 capabilities 自动添加到 `Effective` 集合中。

## capabilities继承 <a href="#t2" id="t2"></a>

通过`execve`，后capabilities有如下关系来进行继承

```
P'(ambient) = (file is privileged) ? 0 : P(ambient)
P'(permitted) = (P(inheritable) & F(inheritable)) | (F(permitted) & P(Bounding)) | P'(ambient)
P'(effective) = F(effective) ? P'(permitted) : P'(ambient)
P'(inheritable) = P(inheritable)
1234567
```

其中`P`表示当前线程，`P'`表示被执行的线程，`F`表示可执行文件。

* 如果是`root`执行的`execve`，或者可执行文件带有`suid`，或者可执行文件拥有全部的能力集，则`Ambient`被置空，否则继承原始进程的`Ambient`
* 如果是`root`执行的`execve`，或者可执行文件带有`suid`，则文件的`Inheritable`和`Permitted`的能力集被全部置位为1，且`Effective`被置为1。所以此时新线程的`Inheritable`和`Effective`的能力集计算可简化为：

  ```
  P'(permitted) = P(inheritable) | P(Bounding)
  P'(effective) = P'(permitted)
  123
  ```

## 查看/修改capabilities <a href="#t3" id="t3"></a>

* 命令行方式

  线程的capabilities可以直接查看`status`文件。

  ```
  CapInh:	0000000000000000
  CapPrm:	0000000000000000
  CapEff:	0000000000000000
  CapBnd:	0000003fffffffff
  CapAmb:	0000000000000000
  12345
  ```

  然后可以通过`capsh`命令来解码拥有的权限

  ```shell
  nathan@nathan-VirtualBox:/bin$ capsh --decode=0000003fffffffff
  0x0000003fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,37
  12
  ```

  文件的capabilities可以通过`setcap`和`getcap`来设置和查询

  ```shell
  $ sudo setcap CAP_DAC_OVERRIDE+eip bash
  $ getcap bash
  bash = cap_dac_override+eip
  123
  ```
* libcap.so

  ubuntu下可以直接通过如下命令安装

  ```shell
  $ sudo apt-get install libcap-dev
  1
  ```

  通过如下接口可以对进程和文件的capability进行查询和设置。

  ```c
  cap_t cap_get_proc(void);
  cap_t cap_get_pid(pid_t pid);
  int cap_set_proc(cap_t cap_p);
  cap_t cap_get_file(const char *path_p);
  int cap_set_file(const char *path_p, cap_t cap_p);
  cap_t cap_get_fd(int fd);
  int cap_set_fd(int fd, cap_t caps);
  12345678910111213
  ```

  例子：

  ```c
  int main(int argc, char **argv)
  {
  cap_t caps <span class="token operator">=</span> <span class="token function">cap_init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  cap_value_t caps<span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">]</span> <span class="token operator">=</span><span class="token punctuation">{<!-- --></span> CAP_NET_RAW<span class="token punctuation">,</span> CAP_NET_BIND_SERVICE <span class="token punctuation">,</span> CAP_CHOWN<span class="token punctuation">,</span>CAP_SETPCAP <span class="token punctuation">}</span> <span class="token punctuation">;</span>
  <span class="token keyword">unsigned</span> num_caps <span class="token operator">=</span> <span class="token number">4</span><span class="token punctuation">;</span>
  <span class="token function">cap_set_flag</span><span class="token punctuation">(</span>caps<span class="token punctuation">,</span> CAP_EFFECTIVE<span class="token punctuation">,</span> num_caps<span class="token punctuation">,</span> caps<span class="token punctuation">,</span> CAP_SET<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">cap_set_flag</span><span class="token punctuation">(</span>caps<span class="token punctuation">,</span> CAP_INHERITABLE<span class="token punctuation">,</span> num_caps<span class="token punctuation">,</span> caps<span class="token punctuation">,</span> CAP_SET<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">cap_set_flag</span><span class="token punctuation">(</span>caps<span class="token punctuation">,</span> CAP_PERMITTED<span class="token punctuation">,</span> num_caps<span class="token punctuation">,</span> caps<span class="token punctuation">,</span> CAP_SET<span class="token punctuation">)</span><span class="token punctuation">;</span>

  cap_set_proc(caps);
  cap_free(caps);
  long i = 0;
  caps = cap_get_proc();
  printf("The process has capabilities %s\n",cap_to_text(caps, &i));
  cap_free(caps);
  <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>

  }
  123456789101112131415161718192021
  ```

## 提权 <a href="#t4" id="t4"></a>

设置了capability也并不是万事大吉了。虽然被丢掉了大部分的能力，但是只要还有某些高危的能力，被丢掉的能力还是可以被添加回来。

| capability 名称          | 描述                                                                                   |
| ---------------------- | ------------------------------------------------------------------------------------ |
| CAP\_CHOWN             | 修改文件所有者的权限                                                                           |
| CAP\_DAC\_OVERRIDE     | 忽略文件的 DAC 访问限制                                                                       |
| CAP\_DAC\_READ\_SEARCH | 忽略文件读及目录搜索的 DAC 访问限制                                                                 |
| CAP\_FOWNER            | 忽略文件属主 ID 必须和进程用户 ID 相匹配的限制                                                          |
| CAP\_FSETID            | 允许设置文件的 setuid 位                                                                     |
| CAP\_MAC\_ADMIN        | 允许 MAC 配置或状态更改                                                                       |
| CAP\_MAC\_OVERRIDE     | 覆盖 MAC(Mandatory Access Control)                                                     |
| CAP\_MKNOD             | 允许使用 mknod() 系统调用                                                                    |
| CAP\_SETGID            | 允许改变进程的 GID                                                                          |
| CAP\_SETFCAP           | 允许为文件设置任意的 capabilities                                                              |
| CAP\_SETPCAP           | 参考 [capabilities man page](http://man7.org/linux/man-pages/man7/capabilities.7.html) |
| CAP\_SETUID            | 允许改变进程的 UID                                                                          |
| CAP\_SYS\_ADMIN        | 允许执行系统管理任务，如加载或卸载文件系统、设置磁盘配额等                                                        |
| CAP\_SYS\_MODULE       | 允许插入和删除内核模块                                                                          |
| CAP\_SYS\_PTRACE       | 允许跟踪任何进程                                                                             |
| CAP\_SYS\_RAWIO        | 允许直接访问 /devport、/dev/mem、/dev/kmem 及原始块设备                                            |

```
</article>
```
