Linux权限管理之Capabilities

对root 权限进行细粒度的控制

Linux capability详解

linux capabilities

在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

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 机制

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

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

  • Permitted

    它是EffectiveInheritable的超集。进程拥有的权限不会超过这个集合。如果一个进程在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 具有如下特性:

    • PermittedInheritable 未设置的 capabilities,Ambient 也不能设置。

    • PermittedInheritable 关闭某权限后,Ambient 也随之关闭对应权限。这样就确保了降低权限后子进程也会降低权限。

    • 非特权用户如果在 Permitted 集合中有一个 capability,那么可以添加到 Ambient 集合中,这样它的子进程便可以在 AmbientPermittedEffective 集合中获取这个 capability。

文件的capabilities有三种。

  • Permitted

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

  • Inheritable

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

  • Effective

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

capabilities继承

通过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,则文件的InheritablePermitted的能力集被全部置位为1,且Effective被置为1。所以此时新线程的InheritableEffective的能力集计算可简化为:

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

查看/修改capabilities

  • 命令行方式

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

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

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

    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可以通过setcapgetcap来设置和查询

    $ sudo setcap CAP_DAC_OVERRIDE+eip bash
    $ getcap bash
    bash = cap_dac_override+eip
    123
  • libcap.so

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

    $ sudo apt-get install libcap-dev
    1

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

    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

    例子:

    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

提权

设置了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

CAP_SETUID

允许改变进程的 UID

CAP_SYS_ADMIN

允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等

CAP_SYS_MODULE

允许插入和删除内核模块

CAP_SYS_PTRACE

允许跟踪任何进程

CAP_SYS_RAWIO

允许直接访问 /devport、/dev/mem、/dev/kmem 及原始块设备

</article>

最后更新于