capabilities(7) - Linux 手册页
名称
capabilities - Linux capabilities 概述
描述
为了执行权限检查,传统的 UNIX 实现将进程分为两类:特权进程(其有效用户 ID 为 0,称为超级用户或 root)和非特权进程(其有效 UID 为非零值)。特权进程绕过所有内核权限检查,而非特权进程则受制于基于进程凭证(通常为:有效 UID、有效 GID 和补充组列表)的完整权限检查。
从 2.2 内核开始,Linux 将传统上与超级用户关联的特权划分为不同的单元,称为能力(capabilities),可以独立地启用或禁用。能力是线程级的属性。
能力列表
- 以下列表显示了在 Linux 上实现的能力,以及每种能力所允许的操作或行为:
- CAP_AUDIT_CONTROL (自 Linux 2.6.11 起)
- 启用和禁用内核审计;更改审计过滤规则;检索审计状态和过滤规则。
- CAP_AUDIT_WRITE (自 Linux 2.6.11 起)
- 向内核审计日志写入记录。
- CAP_BLOCK_SUSPEND (自 Linux 3.5 起)
- 使用可以阻止系统挂起的功能(epoll(7) EPOLLWAKEUP, /proc/sys/wake_lock)。
- CAP_CHOWN
- 对文件 UID 和 GID 进行任意更改(参见 chown(2))。
- CAP_DAC_OVERRIDE
- 绕过文件读取、写入和执行权限检查。(DAC 是“自主访问控制”的缩写。)
- CAP_DAC_READ_SEARCH
- 绕过文件读取权限检查以及目录读取和执行权限检查。
- CAP_FOWNER
- *
绕过那些通常要求进程的文件系统 UID 与文件 UID 相匹配的操作的权限检查(例如,chmod(2)、utime(2)),但不包括 CAP_DAC_OVERRIDE 和 CAP_DAC_READ_SEARCH 所涵盖的操作;
*
在任意文件上设置扩展文件属性(参见 chattr(1));
*
在任意文件上设置访问控制列表 (ACL);
*
文件删除时忽略目录的粘滞位(sticky bit);
*
- CAP_FSETID
- 当文件被修改时不清除 set-user-ID 和 set-group-ID 权限位;为 GID 与文件系统或调用进程的任何补充 GID 不匹配的文件设置 set-group-ID 位。
- CAP_IPC_LOCK
- 锁定内存(mlock(2)、mlockall(2)、mmap(2)、shmctl(2))。
- CAP_IPC_OWNER
- 绕过 System V IPC 对象操作的权限检查。
- CAP_KILL
- 绕过发送信号的权限检查(参见 kill(2))。这包括使用 ioctl(2) 的 KDSIGACCEPT 操作。
- CAP_LEASE (自 Linux 2.4 起)
- 在任意文件上建立租约(参见 fcntl(2))。
- CAP_LINUX_IMMUTABLE
- 设置 FS_APPEND_FL 和 FS_IMMUTABLE_FL i-node 标志(参见 chattr(1))。
- CAP_MAC_ADMIN (自 Linux 2.6.25 起)
- 覆盖强制访问控制 (MAC)。为 Smack Linux 安全模块 (LSM) 实现。
- CAP_MAC_OVERRIDE (自 Linux 2.6.25 起)
- 允许 MAC 配置或状态更改。为 Smack LSM 实现。
- CAP_MKNOD (自 Linux 2.4 起)
- 使用 mknod(2) 创建特殊文件。
- CAP_NET_ADMIN
- 执行各种网络相关操作:
- *
接口配置;
*
IP 防火墙、伪装(masquerading)和计费管理;
*
修改路由表;
*
为透明代理绑定到任意地址;
*
设置服务类型 (TOS);
*
清除驱动程序统计信息;
*
设置混杂模式;
*
启用多播;
*
使用 setsockopt(2) 设置以下套接字选项:SO_DEBUG、SO_MARK、SO_PRIORITY(对于 0 到 6 范围之外的优先级)、SO_RCVBUFFORCE 和 SO_SNDBUFFORCE。
- CAP_NET_BIND_SERVICE
- 将套接字绑定到 Internet 域特权端口(端口号小于 1024)。
- CAP_NET_BROADCAST
- (未使用)进行套接字广播,并监听多播。
- CAP_NET_RAW
- *
使用 RAW 和 PACKET 套接字;
*
为透明代理绑定到任意地址。
- CAP_SETGID
- 对进程 GID 和补充 GID 列表进行任意操作;通过 UNIX 域套接字传递套接字凭证时伪造 GID。
- CAP_SETFCAP (自 Linux 2.6.24 起)
- 设置文件能力。
- CAP_SETPCAP
- 如果不支持文件能力:授予或从调用者的许可能力集中移除任何能力给其他进程。(当内核配置为支持文件能力时,此 CAP_SETPCAP 的属性不可用,因为对于此类内核,CAP_SETPCAP 具有完全不同的语义。)
如果支持文件能力:从调用线程的边界集中添加任何能力到其可继承集中;从边界集中丢弃能力(通过 prctl(2) PR_CAPBSET_DROP);对 securebits 标志进行更改。
- CAP_SETUID
- 对进程 UID 进行任意操作(setuid(2)、setreuid(2)、setresuid(2)、setfsuid(2));通过 UNIX 域套接字传递套接字凭证时伪造 UID。
- CAP_SYS_ADMIN
- *
执行一系列系统管理操作,包括:quotactl(2)、mount(2)、umount(2)、swapon(2)、swapoff(2)、sethostname(2) 和 setdomainname(2);
*
执行特权 syslog(2) 操作(自 Linux 2.6.37 起,应使用 CAP_SYSLOG 来允许此类操作);
*
执行 VM86_REQUEST_IRQ vm86(2) 命令;
*
在任意 System V IPC 对象上执行 IPC_SET 和 IPC_RMID 操作;
*
对受信任和安全扩展属性执行操作(参见 attr(5));
*
使用 lookup_dcookie(2);
*
使用 ioprio_set(2) 分配 IOPRIO_CLASS_RT 和(在 Linux 2.6.25 之前)IOPRIO_CLASS_IDLE I/O 调度类;
*
在传递套接字凭证时伪造 UID;
*
在打开文件的系统调用(例如 accept(2)、execve(2)、open(2)、pipe(2))中,超过系统范围的文件打开限制 /proc/sys/fs/file-max;
*
使用 clone(2) 和 unshare(2) 创建新命名空间的 CLONE_* 标志;
*
调用 perf_event_open(2);
*
访问特权 perf 事件信息;
*
调用 setns(2);
*
调用 fanotify_init(2);
*
执行 KEYCTL_CHOWN 和 KEYCTL_SETPERM keyctl(2) 操作;
*
执行 madvise(2) 的 MADV_HWPOISON 操作;
*
使用 TIOCSTI ioctl(2) 将字符插入非调用者控制终端的输入队列中;
*
使用已废弃的 nfsservctl(2) 系统调用;
*
使用已废弃的 bdflush(2) 系统调用;
- *
执行各种特权块设备 ioctl(2) 操作;
*
执行各种特权文件系统 ioctl(2) 操作;
*
对许多设备驱动程序执行管理操作。
- CAP_SYS_BOOT
- 使用 reboot(2) 和 kexec_load(2)。
- CAP_SYS_CHROOT
- 使用 chroot(2)。
- CAP_SYS_MODULE
- 加载和卸载内核模块(参见 init_module(2) 和 delete_module(2));在 2.6.25 之前的内核中:从系统范围的能力边界集中丢弃能力。
- CAP_SYS_NICE
- *
提高进程 nice 值(nice(2)、setpriority(2))并更改任意进程的 nice 值;
*
设置调用进程的实时调度策略,并设置任意进程的调度策略和优先级(sched_setscheduler(2)、sched_setparam(2));
- *
为任意进程设置 CPU 亲和性(sched_setaffinity(2));
*
为任意进程设置 I/O 调度类和优先级(ioprio_set(2));
*
对任意进程应用 migrate_pages(2) 并允许将进程迁移到任意节点;
*
对任意进程应用 move_pages(2);
*
在 mbind(2) 和 move_pages(2) 中使用 MPOL_MF_MOVE_ALL 标志。
- CAP_SYS_PACCT
- 使用 acct(2)。
- CAP_SYS_PTRACE
- 使用 ptrace(2) 跟踪任意进程;对任意进程应用 get_robust_list(2);使用 kcmp(2) 检查进程。
- CAP_SYS_RAWIO
- *
执行 I/O 端口操作(iopl(2) 和 ioperm(2));
*
访问 /proc/kcore;
*
使用 FIBMAP ioctl(2) 操作;
*
打开用于访问 x86 模型特定寄存器 (MSR) 的设备(参见 msr(4));
*
更新 /proc/sys/vm/mmap_min_addr;
*
在小于 /proc/sys/vm/mmap_min_addr 指定值的地址处创建内存映射;
*
映射 /proc/pci/bus 中的文件;
*
打开 /dev/mem 和 /dev/kmem;
*
执行各种 SCSI 设备命令;
*
对 hpsa(4) 和 cciss(4) 设备执行某些操作;
*
对其他设备执行一系列特定于设备的操作。
- CAP_SYS_RESOURCE
- *
使用 ext2 文件系统上的保留空间;
*
进行控制 ext3 日志记录的 ioctl(2) 调用;
*
覆盖磁盘配额限制;
*
增加资源限制(参见 setrlimit(2));
*
覆盖 RLIMIT_NPROC 资源限制;
*
在控制台分配时覆盖控制台的最大数量;
*
覆盖键盘映射的最大数量;
*
允许来自实时时钟的超过 64Hz 的中断;
*
将 System V 消息队列的 msg_qbytes 限制提高到高于 /proc/sys/kernel/msgmnb 中的限制(参见 msgop(2) 和 msgctl(2));
*
当使用 F_SETPIPE_SZ fcntl(2) 命令设置管道容量时,覆盖 /proc/sys/fs/pipe-size-max 限制。
*
使用 F_SETPIPE_SZ 将管道容量增加到高于 /proc/sys/fs/pipe-max-size 指定的限制;
- *
创建 POSIX 消息队列时覆盖 /proc/sys/fs/mqueue/queues_max 限制(参见 mq_overview(7));
*
使用 prctl(2) PR_SET_MM 操作;设置
- /proc/PID/oom_score_adj 为低于具有 CAP_SYS_RESOURCE 的进程最后设置的值。
- CAP_SYS_TIME
- 设置系统时钟(settimeofday(2)、stime(2)、adjtimex(2));设置实时(硬件)时钟。
- CAP_SYS_TTY_CONFIG
- 使用 vhangup(2);在虚拟终端上使用各种特权 ioctl(2) 操作。
- CAP_SYSLOG (自 Linux 2.6.37 起)
- *
执行特权 syslog(2) 操作。有关哪些操作需要特权,请参阅 syslog(2)。
*
当 /proc/sys/kernel/kptr_restrict 的值为 1 时,查看通过 /proc 和其他接口暴露的内核地址。(参见 proc(5) 中关于 kptr_restrict 的讨论。)
- CAP_WAKE_ALARM (自 Linux 3.0 起)
- 触发唤醒系统的操作(设置 CLOCK_REALTIME_ALARM 和 CLOCK_BOOTTIME_ALARM 定时器)。
过去和当前的实现
- 能力的完整实现要求:
- 1.
对于所有特权操作,内核必须检查线程在其有效集中是否具有所需的能力。
2.
内核必须提供允许更改和检索线程能力集的系统调用。
3.
文件系统必须支持将能力附加到可执行文件,以便进程在执行文件时获得这些能力。
- 在内核 2.6.24 之前,仅满足前两个要求;从 2.6.24 内核开始,满足全部三个要求。
线程能力集
- 每个线程都有三个能力集,包含零个或多个上述能力:
- Permitted(许可集):
- 这是线程可以承担的有效能力的一个限制性超集。它也是线程(如果没有在有效集中拥有 CAP_SETPCAP 能力)添加到可继承集中的能力的一个限制性超集。
如果线程从其许可集中丢弃了一个能力,除非它 execve(2) 一个 set-user-ID-root 程序,或一个关联的文件能力授予该能力,否则它永远无法重新获得该能力。
- Inheritable(可继承集):
- 这是一组在 execve(2) 期间保留的能力。它提供了一种机制,允许进程在 execve(2) 期间为新程序的许可集分配能力。
- Effective(有效集):
- 这是内核用于执行线程权限检查的能力集。
- 通过 fork(2) 创建的子进程继承父进程的能力集副本。有关 execve(2) 期间能力处理的讨论,请参阅下文。
使用 capset(2),线程可以操作自己的能力集(参见下文)。
文件能力
- 从 2.6.24 内核开始,内核支持使用 setcap(8) 将能力集与可执行文件相关联。文件能力集存储在名为 security.capability 的扩展属性(参见 setxattr(2))中。写入此扩展属性需要 CAP_SETFCAP 能力。文件能力集与线程的能力集结合,决定了 execve(2) 之后线程的能力。
三个文件能力集是:
- Permitted(以前称为 forced)
- 无论线程的可继承能力如何,这些能力都会自动许可给线程。
- Inheritable(以前称为 allowed)
- 此集合与线程的可继承集进行 AND 运算,以确定在 execve(2) 之后,线程的许可集中启用了哪些可继承能力。
- Effective(有效集):
- 这不是一个集合,而仅仅是一个位。如果设置了此位,则在 execve(2) 期间,线程的所有新许可能力也会在有效集中提升。如果未设置此位,则在 execve(2) 之后,有效集中不会包含任何新的许可能力。
启用文件有效能力位意味着任何导致线程在 execve(2) 期间获得相应许可能力的许可或可继承能力(参见下述转换规则),也会在其有效集中获得该能力。因此,在为文件分配能力(setcap(8)、cap_set_file(3)、cap_set_fd(3))时,如果我们指定为任何能力启用了有效标志,则对于任何启用了相应许可或可继承标志的能力,也必须指定有效标志为启用。
execve() 期间的能力转换
- 在 execve(2) 期间,内核使用以下算法计算进程的新能力:
-
P'(permitted) = (P(inheritable) & F(inheritable)) | (F(permitted) & cap_bset) P'(effective) = F(effective) ? P'(permitted) : 0 P'(inheritable) = P(inheritable) [i.e., unchanged] - 其中
- P
表示 execve(2) 之前线程能力集的值
P'
表示 execve(2) 之后能力集的值
F
表示文件能力集
cap_bset
是能力边界集的值(下文描述)。
root 执行程序时的能力
- 为了通过能力集提供全能的 root,在 execve(2) 期间:
- 1.
如果正在执行 set-user-ID-root 程序,或者进程的实际用户 ID 为 0 (root),则文件可继承集和许可集被定义为全为 1(即启用所有能力)。
2.
如果正在执行 set-user-ID-root 程序,则文件有效位被定义为 1(启用)。
- 上述规则与所描述的能力转换相结合的结果是:当进程 execve(2) 一个 set-user-ID-root 程序,或者有效 UID 为 0 的进程 execve(2) 一个程序时,它会获得其许可和有效能力集中的所有能力,除非这些能力被能力边界集屏蔽。这提供了与传统 UNIX 系统相同的语义。
能力边界集
- 能力边界集是一种安全机制,可用于限制在 execve(2) 期间可以获得的能力。边界集的使用方式如下:
- *
在 execve(2) 期间,能力边界集与文件许可能力集进行 AND 运算,该运算的结果分配给线程的许可能力集。因此,能力边界集对可执行文件可能授予的许可能力设置了上限。
*
(自 Linux 2.6.25 起) 能力边界集充当线程可以使用 capset(2) 添加到其可继承集中的能力的限制性超集。这意味着如果一个能力不在边界集中,则线程无法将此能力添加到其可继承集中,即使它在许可能力中,因此在它 execve(2) 一个在可继承集中具有该能力的文件时,该能力也无法保留在许可集中。
- 请注意,边界集屏蔽了文件许可能力,但不屏蔽继承能力。如果线程在其继承集中维护一个不在其边界集中的能力,它仍然可以通过执行在继承集中具有该能力的文件来在许可集中获得该能力。
根据内核版本,能力边界集要么是系统范围的属性,要么是进程级的属性。
Linux 2.6.25 之前:能力边界集
在 2.6.25 之前的内核中,能力边界集是影响系统上所有线程的系统范围属性。边界集可通过文件 /proc/sys/kernel/cap-bound 访问。(令人困惑的是,此位掩码参数在 /proc/sys/kernel/cap-bound 中表示为带符号的十进制数。)
只有 init 进程可以设置能力边界集中的能力;除此之外,超级用户(更准确地说是具有 CAP_SYS_MODULE 能力的程序)只能从该集合中清除能力。
在标准系统上,能力边界集总是屏蔽 CAP_SETPCAP 能力。要移除此限制(危险!),请修改 include/linux/capability.h 中 CAP_INIT_EFF_SET 的定义并重新编译内核。
系统范围的能力边界集功能是从内核版本 2.2.11 开始添加到 Linux 中的。
Linux 2.6.25 及更高版本:能力边界集
从 Linux 2.6.25 开始,能力边界集是线程级的属性。(不再有系统范围的能力边界集。)
边界集在 fork(2) 时从父线程继承,并在 execve(2) 期间保留。
线程可以使用 prctl(2) 的 PR_CAPBSET_DROP 操作从其能力边界集中移除能力,前提是它具有 CAP_SETPCAP 能力。一旦从边界集中丢弃了某个能力,就无法将其恢复到该集合。线程可以使用 prctl(2) 的 PR_CAPBSET_READ 操作确定某个能力是否在其边界集中。
仅当将文件能力编译进内核时,才支持从边界集中移除能力。在 Linux 2.6.33 之前的内核中,文件能力是一个可通过 CONFIG_SECURITY_FILE_CAPABILITIES 选项配置的可选功能。从 Linux 2.6.33 开始,此配置选项已被移除,文件能力始终是内核的一部分。当文件能力编译进内核时,init 进程(所有进程的祖先)以完整的边界集开始。如果文件能力未编译进内核,则 init 以完整的边界集减去 CAP_SETPCAP 开始,因为当没有文件能力时,此能力具有不同的含义。
从边界集中移除能力不会将其从线程的继承集中移除。但是,它确实阻止了未来将该能力添加回线程的继承集中。
用户 ID 更改对能力的影响
- 为了保持 0 和非零用户 ID 之间转换的传统语义,内核在线程的实际、有效、保存的集合和文件系统用户 ID 发生更改(使用 setuid(2)、setresuid(2) 或类似函数)时,会对线程的能力集进行以下更改:
- 1.
如果实际、有效或保存的集合用户 ID 中的一个或多个以前为 0,并且由于 UID 更改,所有这些 ID 现在都具有非零值,则从许可和有效能力集中清除所有能力。
2.
如果有效用户 ID 从 0 更改为非零值,则从有效集中清除所有能力。
3.
如果有效用户 ID 从非零值更改为 0,则将许可集复制到有效集。
4.
如果文件系统用户 ID 从 0 更改为非零值(参见 setfsuid(2)),则从有效集中清除以下能力:CAP_CHOWN、CAP_DAC_OVERRIDE、CAP_DAC_READ_SEARCH、CAP_FOWNER、CAP_FSETID、CAP_LINUX_IMMUTABLE(自 Linux 2.2.30 起)、CAP_MAC_OVERRIDE 和 CAP_MKNOD(自 Linux 2.2.30 起)。如果文件系统 UID 从非零值更改为 0,则在许可集中启用的这些能力中的任何一个都会在有效集中启用。
- 如果具有一个或多个 0 值的用户 ID 的线程想要防止其许可能力集在将其所有用户 ID 重置为非零值时被清除,可以使用 prctl(2) 的 PR_SET_KEEPCAPS 操作来实现。
以编程方式调整能力集
- 线程可以使用 capget(2) 和 capset(2) 系统调用检索和更改其能力集。但是,首选使用 libcap 包中提供的 cap_get_proc(3) 和 cap_set_proc(3)。以下规则管理对线程能力集的更改:
- 1.
如果调用者没有 CAP_SETPCAP 能力,则新的可继承集必须是现有可继承集和许可集组合的子集。
2.
(自 2.6.25 内核起) 新的可继承集必须是现有可继承集和能力边界集组合的子集。
3.
新的许可集必须是现有许可集的子集(即,不可能获得线程当前没有的许可能力)。
4.
新的有效集必须是新许可集的子集。
Securebits 标志:建立仅能力的运行环境
- 从 2.6.26 内核开始,且在启用了文件能力的内核中,Linux 实现了一组线程级的 securebits 标志,可用于禁用对 UID 0 (root) 的能力的特殊处理。这些标志如下:
- SECBIT_KEEP_CAPS
- 设置此标志允许具有一个或多个 0 UID 的线程在将其所有 UID 切换为非零值时保留其能力。如果未设置此标志,则此类 UID 切换会导致线程丢失所有能力。此标志在 execve(2) 时总是被清除。(此标志提供与旧的 prctl(2) PR_SET_KEEPCAPS 操作相同的功能。)
- SECBIT_NO_SETUID_FIXUP
- 设置此标志会阻止内核在线程的有效用户 ID 和文件系统用户 ID 在零和非零值之间切换时调整能力集。(参见 用户 ID 更改对能力的影响 小节。)
- SECBIT_NOROOT
- 如果设置了此位,则在执行 set-user-ID-root 程序时,或者当有效或实际 UID 为 0 的进程调用 execve(2) 时,内核不会授予能力。(参见 root 执行程序时的能力 小节。)
- 上述每个“基本”标志都有一个伴随的“锁定”标志。设置任何“锁定”标志都是不可逆的,并且会防止对相应的“基本”标志进行进一步更改。锁定标志为:SECBIT_KEEP_CAPS_LOCKED、SECBIT_NO_SETUID_FIXUP_LOCKED 和 SECBIT_NOROOT_LOCKED。
securebits 标志可以使用 prctl(2) 的 PR_SET_SECUREBITS 和 PR_GET_SECUREBITS 操作进行修改和检索。修改标志需要 CAP_SETPCAP 能力。
securebits 标志由子进程继承。在 execve(2) 期间,除 SECBIT_KEEP_CAPS 外的所有标志都会被保留,后者总是会被清除。
应用程序可以使用以下调用将自身及其所有后代锁定在一个环境中,在该环境中获得能力的唯一方法是执行具有相关文件能力的程序:
-
prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS_LOCKED | SECBIT_NO_SETUID_FIXUP | SECBIT_NO_SETUID_FIXUP_LOCKED | SECBIT_NOROOT | SECBIT_NOROOT_LOCKED);
符合
没有任何标准管理能力,但 Linux 能力实现基于已撤回的 POSIX.1e 草案标准;参见:
说明
从 2.5.27 内核开始,能力是一个可选的内核组件,可以通过 CONFIG_SECURITY_CAPABILITIES 内核配置选项启用/禁用。
/proc/PID/task/TID/status 文件可用于查看线程的能力集。/proc/PID/status 文件显示进程主线程的能力集。在 Linux 3.8 之前,不存在的能力在这些集中显示为已启用 (1)。从 Linux 3.8 开始,所有不存在的能力(高于 CAP_LAST_CAP)都显示为已禁用 (0)。
libcap 包提供了一套用于设置和获取能力的例程,比 capset(2) 和 capget(2) 提供的接口更舒适且不易更改。此包还提供了 setcap(8) 和 getcap(8) 程序。它可以在以下位置找到:
在 2.6.24 内核之前,以及如果未启用文件能力,从 2.6.24 内核开始,具有 CAP_SETPCAP 能力的线程可以操作除其自身以外的线程的能力。然而,这只是理论上的可能性,因为在这些情况下没有任何线程拥有 CAP_SETPCAP:
- *
在 2.6.25 之前的实现中,系统范围的能力边界集 /proc/sys/kernel/cap-bound 总是屏蔽此能力,并且如果不修改内核源码并重新编译,就无法更改这一点。
*
如果当前实现中禁用了文件能力,则 init 启动时此能力会从其进程级边界集中移除,并且该边界集被系统上创建的所有其他进程继承。
参见
capget(2)、prctl(2)、setfsuid(2)、cap_clear(3)、cap_copy_ext(3)、cap_from_text(3)、cap_get_file(3)、cap_get_proc(3)、cap_init(3)、capgetp(3)、capsetp(3)、libcap(3)、credentials(7)、pthreads(7)、getcap(8)、setcap(8)
Linux 内核源码树中的 include/linux/capability.h