遵循规范

没有任何标准可以管理功能,但是Linux功能的实现是基于已废止的POSIX.1e标准草案。看到

CAPABILITIES - Linux手册页

Linux程序员手册 第7部分
更新日期: 2020-08-13

说明

为了执行权限检查,传统的UNIX实现将进程分为两类:特权进程(其有效用户ID为0,称为超级用户或root)和非特权进程(其有效UID为非零)。特权进程绕过所有内核权限检查,而无特权的进程则根据进程的凭据(通常是:有效的UID,有效的GID和补充组列表)接受完全的权限检查。

从内核2.2开始,Linux将传统上与超级用户相关联的特权划分为不同的单元,称为功能,可以独立地启用和禁用这些功能。功能是每个线程的属性。

Capabilities list

以下列表显示了在Linux上实现的功能,以及每种功能允许的操作或行为:

CAP_AUDIT_CONTROL(since Linux 2.6.11)
启用和禁用内核审核;更改审核过滤器规则;检索审核状态和过滤规则。
CAP_AUDIT_READ(since Linux 3.16)
允许通过多播netlink套接字读取审核日志。
CAP_AUDIT_WRITE(since Linux 2.6.11)
将记录写入内核审核日志。
CAP_BLOCK_SUSPEND(since Linux 3.5)
使用可以阻止系统挂起的功能(epoll(7)EPOLLWAKEUP,/ proc / sys / wake_lock)。
CAP_BPF(since Linux 5.8)
采用特权BPF操作;参见bpf(2)和bpf-helpers(7)。
Linux 5.8中添加了此功能,以将BPF功能与过载的CAP_SYS_ADMIN功能区分开。
CAP_CHOWN
对文件UID和GID进行任意更改(请参阅chown(2))。
CAP_DAC_OVERRIDE
绕过文件读取,写入和执行权限检查。 (DAC是"自由访问控制"的缩写。)
CAP_DAC_READ_SEARCH
*
绕过文件读取权限检查以及目录读取和执行权限检查;
*
调用open_by_handle_at(2);
*
使用linkat(2)AT_EMPTY_PATH标志创建到文件描述符引用的文件的链接。
CAP_FOWNER
*
绕过权限检查通常需要进程的文件系统UID与文件的UID匹配的操作(例如chmod(2),utime(2)),但CAP_DAC_OVERRIDE和CAP_DAC_READ_SEARCH覆盖的那些操作除外;
*
在任意文件上设置inode标志(请参阅ioctl_iflags(2));
*
在任意文件上设置访问控制列表(ACL);
*
在删除文件时忽略目录粘贴位;
*
修改任何用户拥有的粘性目录上的用户扩展属性;
*
open(2)和fcntl(2)中的任意文件指定O_NOATIME。
CAP_FSETID
*
修改文件时,请勿清除set-user-ID和set-group-ID模式位。
*
将GID与文件系统或调用过程的任何补充GID不匹配的文件的set-group-ID位置1。
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(since Linux 2.4)
在任意文件上建立租约(请参阅fcntl(2))。
CAP_LINUX_IMMUTABLE
设置FS_APPEND_FL和FS_IMMUTABLE_FL inode标志(请参阅ioctl_iflags(2))。
CAP_MAC_ADMIN(since Linux 2.6.25)
允许MAC配置或状态更改。为Smack Linux安全模块(LSM)实现。
CAP_MAC_OVERRIDE(since Linux 2.6.25)
覆盖强制访问控制(MAC)。为Smack LSM实施。
CAP_MKNOD(since Linux 2.4)
使用mknod(2)创建特殊文件。
CAP_NET_ADMIN
Perform various network-related operations:
*
接口配置;
*
IP防火墙的管理,伪装和计费;
*
修改路由表;
*
绑定到任何地址以进行透明代理;
*
设置服务类型(TOS);
*
清除驾驶员统计信息;
*
设置混杂模式;
*
启用多播;
*
使用setsockopt(2)设置以下套接字选项:SO_DEBUGSO_MARKSO_PRIORITY(优先级在0到6之外),SO_RCVBUFFORCE和SO_SNDBUFFORCE。
CAP_NET_BIND_SERVICE
将套接字绑定到Internet域特权端口(端口号小于1024)。
CAP_NET_BROADCAST
(未使用)进行套接字广播,并收听多播。
CAP_NET_RAW
*
使用RAW和PACKET插槽;
*
绑定到任何地址以进行透明代理。
CAP_PERFMON(since Linux 5.8)
Employ various performance-monitoring mechanisms, including:
*2
调用perf_event_open(2);
*
使用各种对性能有影响的BPF操作。
Linux 5.8中添加了此功能,以将性能监视功能与过载的CAP_SYS_ADMIN功能区分开。
CAP_SETGID
*
任意处理进程GID和补充GID列表;
*
通过UNIX域套接字传递套接字凭证时伪造GID;
*
在用户名称空间中编写组ID映射(请参阅user_namespaces(7))。
CAP_SETFCAP(since Linux 2.6.24)
在文件上设置任意功能。
CAP_SETPCAP
如果支持文件功能(即从Linux 2.6.24开始):将调用线程的边界集中的任何功能添加到其可继承集中;从边界集中删除功能(通过prctl(2)PR_CAPBSET_DROP);更改securebits标志。
如果不支持文件功能(例如,Linux 2.6.24之前的内核):在任何其他进程中调用者的允许功能集中授予或删除任何功能。 (当内核配置为支持文件功能时,CAP_SETPCAP的此属性不可用,因为CAP_SETPCAP的语义完全不同。)
CAP_SETUID
*
对进程UID(setuid(2),setreuid(2),setresuid(2),setfsuid(2))进行任意操作;
*
通过UNIX域套接字传递套接字凭证时,伪造UID;
*
在用户名称空间中编写用户ID映射(请参阅user_namespaces(7))。
CAP_SYS_ADMIN
注意:此功能过载;请参阅下面的内核开发人员说明。
*
执行一系列系统管理操作,包括:quotactl(2),mount(2),umount(2),pivot_root(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操作;
*
覆盖RLIMIT_NPROC资源限制;
*
对可信和安全扩展属性执行操作(请参阅xattr(7));
*
使用lookup_dcookie(2);
*
使用ioprio_set(2)分配IOPRIO_CLASS_RT和(在Linux 2.6.25之前)IOPRIO_CLASS_IDLE I / O调度类;
*
通过UNIX域套接字传递套接字凭证时伪造PID;
*
超过/ proc / sys / fs / file-max,即系统范围内打开文件数量的限制,在打开文件的系统调用中(例如accept(2),execve(2),open(2),pipe( 2));
*
使用CLONE_ *标志创建带有clone(2)和unshare(2)的新名称空间(但是,从Linux 3.8开始,创建用户名称空间不需要任何功能);
*
采用各种性能监视机制(对于CAP_PERFMON);
*
访问特权性能事件信息;
*
调用setns(2)(在目标名称空间中需要CAP_SYS_ADMIN);
*
呼叫fanotify_init(2);
*
执行各种BPF操作;见CAP_BPF;
*
执行特权KEYCTL_CHOWN和KEYCTL_SETPERM keyctl(2)操作;
*
执行madvise(2)MADV_HWPOISON操作;
*
使用TIOCSTI ioctl(2)将字符插入到呼叫者控制终端以外的终端的输入队列中;
*
使用过时的nfsservctl(2)系统调用;
*
使用过时的bdflush(2)系统调用;
*
执行各种特权块设备ioctl(2)操作;
*
执行各种特权文件系统ioctl(2)操作;
*
在/ dev / random设备上执行特权ioctl(2)操作(请参阅random(4));
*
安装seccomp(2)过滤器,而无需首先设置no_new_privs线程属性;
*
修改设备控制组的允许/拒绝规则;
*
使用ptrace(2)PTRACE_SECCOMP_GET_FILTER操作来转储Tracee的seccomp过滤器;
*
使用ptrace(2)PTRACE_SETOPTIONS操作来挂起跟踪的seccomp保护(即PTRACE_O_SUSPEND_SECCOMP标志);
*
在许多设备驱动程序上执行管理操作。
*
通过写入/ proc / [pid] / autogroup修改autogroup nice值(请参阅sched(7))。
CAP_SYS_BOOT
使用reboot(2)和kexec_load(2)。
CAP_SYS_CHROOT
*
使用chroot(2);
*
使用setns(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),sched_setattr(2));
*
为任意进程设置CPU关联性(sched_setaffinity(2));
*
为任意进程设置I / O调度类和优先级(ioprio_set(2));
*
将migration_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)应用于任意进程;
*
使用process_vm_readv(2)和process_vm_writev(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 / bus / pci中映射文件;
*
打开/ dev / mem和/ dev / kmem;
*
执行各种SCSI设备命令;
*
hpsa(4)和cciss(4)设备上执行某些操作;
*
在其他设备上执行一系列特定于设备的操作。
CAP_SYS_RESOURCE
*
在ext2文件系统上使用保留空间;
*
进行ioctl(2)调用以控制ext3日记记录;
*
覆盖磁盘配额限制;
*
增加资源限制(请参阅setrlimit(2));
*
覆盖RLIMIT_NPROC资源限制;
*
在控制台分配中覆盖最大控制台数;
*
覆盖最大按键映射数;
*
允许来自实时时钟的超过64hz的中断;
*
将System V消息队列的msg_qbytes限制提高到/ proc / sys / kernel / msgmnb中的限制(请参见msgop(2)和msgctl(2));
*
当通过UNIX域套接字将文件描述符传递到另一个进程时,允许绕过"运行中"文件描述符数量的RLIMIT_NOFILE资源限制(请参见unix(7));
*
使用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,/ proc / sys / fs / mqueue / msg_max和/ proc / sys / fs / mqueue / msgsize_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(since Linux 2.6.37)
*
执行特权的syslog(2)操作。有关哪些操作需要特权的信息,请参见syslog(2)。
*
当/ proc / sys / kernel / kptr_restrict的值为1时,查看通过/ proc和其他接口公开的内核地址。(请参阅proc(5)中有关kptr_restrict的讨论。)
CAP_WAKE_ALARM(since Linux 3.0)
触发一些将唤醒系统的事件(设置CLOCK_REALTIME_ALARM和CLOCK_BOOTTIME_ALARM计时器)。

Past and current implementation

全面实施功能需要:

1.
对于所有特权操作,内核必须检查线程在其有效集中是否具有所需的功能。
2.
内核必须提供系统调用,以允许更改和检索线程的功能集。
3.
文件系统必须支持将功能附加到可执行文件,以便在执行文件时进程获得这些功能。

在内核2.6.24之前,仅满足前两个要求;从内核2.6.24开始,所有这三个要求都得到满足。

Notes to kernel developers

在添加应由功能控制的新内核功能时,请考虑以下几点。

*
功能的目标是将超级用户的权限分成多个部分,这样,如果具有一个或多个功能的程序受到损害,则其破坏系统的能力将小于具有root特权的同一程序。
*
您可以选择是为新功能创建新功能,还是将功能与现有功能之一相关联。为了使功能集保持在可管理的大小,后一种选择是可取的,除非有充分的理由采用前一种选择。 (还有一个技术限制:功能集的大小当前限制为64位。)
*
要确定哪些现有功能最可能与您的新功能相关联,请查看上面的功能列表,以找到最适合您的新功能的"筒仓"。采取的一种方法是确定是否还有其他功能需要与新功能一起使用的功能。如果没有这些其他功能,新功能将无用,则应使用与其他功能相同的功能。
*
如果可以避免,请不要选择CAP_SYS_ADMIN!现有功能的大部分检查都与此功能相关联(请参阅上面的部分列表)。它可以合理地称为"新根",因为一方面它赋予了广泛的权力,另一方面,它的广泛范围意味着这是许多特权程序所需要的功能。不要让问题变得更糟。应该与CAP_SYS_ADMIN关联的唯一新功能是那些与该筒仓中的现有用途紧密匹配的功能。
*
如果您确定确实有必要为您的功能创建新功能,请不要将其创建或命名为"一次性使用"功能。因此,例如,添加高度特定的CAP_SYS_PACCT可能是一个错误。取而代之的是,尝试将您的新功能标识为更广泛的孤岛,并在其中命名其他相关的未来用例。

Thread capability sets

每个线程具有以下功能集,其中包含零个或多个上述功能:

Permitted
这是线程可能承担的有效功能的一个限制超集。对于在有效集中没有CAP_SETPCAP功能的线程可能添加到可继承集中的功能,它也是一个限制超集。
如果线程从其允许的集合中删除了一项功能,则它将永远无法重新获得该功能(除非它执行setve-(2)一个set-user-ID-root程序或相关文件功能授予该功能的程序)。
Inheritable
这是在execve(2)中保留的一组功能。当执行任何程序时,可继承功能保持可继承的状态,而当执行文件可继承集中具有相应位的程序时,可继承功能会添加到允许的集合中。
因为当以非root用户身份运行时,可继承功能通常不会跨execve(2)保留,因此希望运行具有增强功能的帮助程序的应用程序应考虑使用环境功能,如下所述。
Effective
这是内核用于对线程执行权限检查的功能集。
Bounding(per-thread since Linux 2.6.25)
功能边界集是一种可用于限制execve(2)期间获得的功能的机制。
从Linux 2.6.25开始,这是每个线程的功能集。在较早的内核中,功能边界集是系统上所有线程共享的系统范围属性。
有关功能边界集的更多详细信息,请参见下文。
Ambient(since Linux 4.3)
这是在非特权程序的execve(2)中保留的一组功能。环境能力集服从不变性,即如果既不允许又不能继承它,那么就不会有环境能力。
可以使用prctl(2)直接修改环境功能集。如果相应的允许或可继承功能中的任何一个降低,环境功能将自动降低。
执行由于设置用户ID或设置组ID位而更改UID或GID的程序,或者执行具有任何文件功能集的程序,将会清除环境设置。当调用execve(2)时,环境功能会添加到允许的集合中并分配给有效的集合。如果环境能力导致在execve(2)期间进程的允许和有效能力增加,则这不会触发ld.so(8)中描述的安全执行模式。

通过fork(2)创建的子代继承其父代功能集的副本。有关execve(2)期间功能处理的讨论,请参见下文。

使用capset(2),线程可以操纵其自身的功能集(请参见下文)。

从Linux 3.2开始,文件/ proc / sys / kernel / cap_last_cap公开了正在运行的内核所支持的最高功能的数值。这可用于确定功能集中可能设置的最高位。

File capabilities

从内核2.6.24开始,内核支持使用setcap(8)将功能集与可执行文件相关联。文件功能集存储在名为security.capability的扩展属性(请参见setxattr(2)和xattr(7))中。写入此扩展属性需要CAP_SETFCAP功能。文件功能集与线程的功能集一起确定execve(2)之后的线程的功能。

三个文件功能集是:

Permitted(formerly known as forced):
无论线程的可继承功能如何,这些功能都会自动授予该线程。
Inheritable(formerly known as allowed):
该集合与线程的可继承集合进行"与"运算,以确定在execve(2)之后的线程的允许集合中启用了哪些可继承功能。
Effective:
这不是一个集合,而是一个位。如果设置了此位,则在execve(2)期间,还将在有效集中提高线程的所有新允许功能。如果未设置此位,则在execve(2)之后,新的有效功能中都没有新的允许功能。
启用文件有效功能位意味着,导致线程在execve(2)(请参阅下面描述的转换规则)期间获取相应的允许功能的任何文件允许或可继承功能,也将在其有效集中获取该功能。因此,在将功能分配给文件(setcap(8),cap_set_file(3),cap_set_fd(3))时,如果我们将有效标志指定为对任何功能启用,则还必须将有效标志指定为对所有功能均启用启用了相应的允许或可继承标志的其他功能。

File capability extended attribute versioning

为了允许扩展,内核支持一种方案,用于在security.capability扩展属性内编码版本号,该版本号用于实现文件功能。这些版本号是实现的内部内容,对用户空间应用程序不直接可见。迄今为止,支持以下版本:

VFS_CAP_REVISION_1
这是原始的文件功能实现,支持文件功能的32位掩码。
VFS_CAP_REVISION_2(since Linux 2.6.25)
该版本允许文件功能掩码的大小为64位,并且在受支持的功能数量增加到32以上时是必需的。内核透明地继续支持具有32位版本1功能掩码的文件的执行,但是在添加时对于以前不具有功能的文件或修改现有文件的功能,它会自动使用版本2方案(或可能使用版本3方案,如下所述)。
VFS_CAP_REVISION_3(since Linux 4.14)
提供版本3文件功能以支持命名空间文件功能(如下所述)。
与版本2文件功能一样,版本3功能掩码的大小为64位。但此外,名称空间的根用户ID编码在security.capability扩展属性中。 (名称空间的根用户ID是该名称空间内的用户ID 0映射到初始用户名称空间中的值。)
版本3文件功能旨在与版本2功能共存。也就是说,在现代Linux系统上,可能有些文件具有版本2功能,而另一些文件具有版本3功能。

在Linux 4.14之前,可以附加到文件的唯一一种文件功能扩展属性是VFS_CAP_REVISION_2属性。从Linux 4.14开始,附加到文件的security.capability扩展属性的版本取决于创建该属性的环境。

从Linux 4.14开始,如果满足以下两个条件,则会将security.capability扩展属性自动创建为(或转换为)版本3(VFS_CAP_REVISION_3)属性:

(1)
写入属性的线程位于非初始用户名称空间中。 (更准确地说:该线程驻留在用户名称空间中,而不是从其安装基础文件系统的名称空间中。)
(2)
线程在文件索引节点上具有CAP_SETFCAP功能,这意味着(a)线程在其自己的用户名称空间中具有CAP_SETFCAP功能; (b)文件inode的UID和GID在编写者的用户名称空间中具有映射。

创建VFS_CAP_REVISION_3 security.capability扩展属性后,创建线程的用户名称空间的根用户ID将保存在扩展属性中。

相比之下,从位于安装基础文件系统的名称空间中的特权(CAP_SETFCAP)线程创建或修改security.capability扩展属性会自动导致创建版本2(VFS_CAP_REVISION_2) )属性。

请注意,版本3 security.capability扩展属性的创建是自动的。也就是说,当用户空间应用程序以版本2格式写入(setxattr(2))security.capability属性时,如果在上述情况下创建了属性,则内核将自动创建版本3属性。相应地,当驻留在由根用户ID(或该用户名称空间的后代)创建的用户名称空间中的进程检索到版本3 security.capability属性(getxattr(2))时,返回的属性为(自动)以显示为版本2属性(即,返回值是版本2属性的大小,并且不包括root用户ID)。这些自动转换意味着无需对用户空间工具(例如setcap(1)和getcap(1))进行任何更改,即可将这些工具用于创建和检索版本3 security.capability属性。

请注意,文件可以具有与之关联的版本2或版本3的security.capability扩展属性,但不能同时具有两者:创建或修改security.capability扩展属性将根据扩展的情况自动修改版本。属性被创建或修改。

Transformation of capabilities during execve()

execve(2)期间,内核使用以下算法计算流程的新功能:

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)    [i.e., unchanged]

P'(bounding)    = P(bounding)       [i.e., unchanged]

哪里:

P()
表示在execve(2)之前设置的线程功能的值
P'()
表示在execve(2)之后设置的线程功能的值
F()
表示文件功能集

请注意与上述能力转换规则有关的以下详细信息:

*
仅从Linux 4.3开始提供环境功能集。在execve(2)期间确定环境集的转换时,特权文件是具有功能或具有set-user-ID或set-group-ID位的文件。
*
在Linux 2.6.25之前,边界集是所有线程共享的系统范围的属性。该系统范围的值用于以与上述P(bounding)相同的方式在execve(2)期间计算新的允许集。

注意:在上述功能转换期间,出于忽略设置用户ID和设置组ID位的相同原因,可以忽略文件功能(将其视为空)。请参阅execve(2)。如果使用no_file_caps选项引导内核,则文件功能同样会被忽略。

注意:根据上述规则,如果具有非零用户ID的进程执行execve(2),则将清除其允许和有效集中存在的任何功能。对于当用户ID为零的进程执行execve(2)时的功能处理,请参阅下面的"功能和根执行程序"下的内容。

Safety checking for capability-dumb binaries

功能笨拙的二进制文件是一种已标记为具有文件功能的应用程序,但尚未转换为使用libcap(3)API来操纵其功能。 (换句话说,这是一个传统的set-user-ID-root程序,已切换为使用文件功能,但尚未修改其代码以了解功能。)对于此类应用程序,有效功能位设置在文件,以便在执行文件时在过程有效集中自动启用文件允许的功能。内核将具有有效功能位设置为"能力哑"的文件识别为此处描述的检查目的。

当执行能力哑二进制文件时,内核将在执行上述能力转换后,检查进程是否获得了文件许可集中指定的所有许可能力。 (之所以不会发生这种情况,典型的原因是功能限制集掩盖了文件允许集中的某些功能。)如果进程未获得文件允许的完整功能集,则execve(2)将失败,并且错误EPERM。这样可以防止以功能弱的应用程序以所需的较少特权执行该应用程序时可能出现的安全风险。请注意,根据定义,应用程序本身无法识别此问题,因为它未使用libcap(3)API。

Capabilities and execution of programs by root

为了反映传统的UNIX语义,当具有UID 0(根)的进程执行程序时,并且在执行set-user-ID-root程序时,内核对文件功能进行特殊处理。

在执行了由二进制文件的设置用户ID模式位触发的对过程有效ID的任何更改后,例如,由于设置用户ID根程序,将有效用户ID切换为0(root)已执行-内核按以下方式计算文件功能集:

1.
如果该进程的实际或有效用户ID为0(root),那么将忽略文件的可继承集和允许集;否则,将忽略该文件。相反,它们在概念上被认为是全部(即,所有功能均已启用)。 (此行为有一个例外,下面在具有文件功能的Set-user-ID-root程序中对此进行了描述。)
2.
如果进程的有效用户ID为0(root)或实际上启用了文件有效位,则从概念上将文件有效位定义为1(启用)。

然后,如上所述,使用文件功能集的这些概念值来计算execve(2)期间进程功能的转换。

因此,当具有非零UID的execve(2)进程是没有附加功能的设置用户ID根程序时,或者当实际和有效UID为零的进程execve(2)成为程序时,计算流程的新允许功能简化为:

P'(permitted)   = P(inheritable) | P(bounding)

P'(effective)   = P'(permitted)

因此,该过程将获得其许可的有效能力集中的所有能力,但能力边界集所掩盖的能力除外。 (在计算P'(允许)时,可以简化P'(环境)项,因为根据定义,它是P(可继承)的适当子集。)

可以使用下面描述的securebits机制来禁用本小节中描述的用户ID 0(root)的特殊处理。

Set-user-ID-root programs that have file capabilities

"功能和根执行程序"下描述的行为有一个例外。如果(a)正在执行的二进制文件具有附加功能,并且(b)进程的实际用户ID不为0(root),并且(c)进程的有效用户ID为0(root),则文件能力位是受尊重的(即,从概念上讲,它们并不是全部)。发生这种情况的通常方式是在执行还具有文件功能的set-UID-root程序时。当执行这样的程序时,该过程仅获得该程序授予的功能(即,并非所有功能,如执行不具有任何相关文件功能的set-user-ID-root程序时所发生的那样)。

请注意,可以将空功能集分配给程序文件,因此可以创建一个set-user-ID-root程序,将执行该程序的进程的有效和保存的set-user-ID更改为0,但没有赋予该过程任何功能。

Capability bounding set

功能边界集是一种安全机制,可用于限制execve(2)期间可获得的功能。边界集的使用方式如下:

*
execve(2)期间,将功能边界集与文件允许的能力集进行"与"运算,并将此操作的结果分配给线程的允许的能力集。因此,功能边界集对可执行文件可以授予的允许功能施加了限制。
*
(从Linux 2.6.25开始)功能限制集充当线程可以使用capset(2)添加到其可继承集的功能的限制超集。这意味着,如果功能不在边界集中,则线程无法将其添加到其可继承集中,即使它在其允许的范围内,从而在执行时也无法将其保留在其允许的范围内(2)具有可继承集中功能的文件。

请注意,边界集会屏蔽文件允许的功能,但不会屏蔽可继承的功能。如果线程在其可继承集合中维护的功能不在其边界集中,那么它仍然可以通过执行在其可继承集合中具有该功能的文件来在其允许的集合中获得该功能。

根据内核版本,功能范围集可以是系统范围的属性,也可以是每个进程的属性。

从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将从一个完整的边界集减去CAP_SETPCAP开始,因为在没有文件功能的情况下,此功能具有不同的含义。

从边界集中删除功能不会将其从线程的可继承集中删除。但是,它的确阻止了将来将该功能重新添加到线程的可继承集中。

Linux 2.6.25之前的功能范围设置

在2.6.25之前的内核中,功能边界集是系统范围的属性,会影响系统上的所有线程。可以通过文件/ proc / sys / kernel / cap-bound访问边界集。 (令人困惑的是,此位掩码参数在/ proc / sys / kernel / cap-bound中表示为带符号的十进制数。)

只有初始化过程才能在功能边界集中设置功能;除此之外,超级用户(更精确地说:具有CAP_SYS_MODULE功能的进程)可能仅清除该集合中的功能。

在标准系统上,功能边界集始终掩盖CAP_SETPCAP功能。要删除此限制(危险!),请在include / linux / capability.h中修改CAP_INIT_EFF_SET的定义并重建内核。

从内核版本2.2.11开始,系统范围的功能限制集功能已添加到Linux。

Effect of user ID changes on capabilities

为了保留传统的语义,以实现0和非零用户ID之间的转换,内核会根据对线程的实际,有效,已保存的集和文件系统用户ID的更改(使用setuid(2),setresuid( 2)或类似):

1.
如果一个或多个真实,有效或已保存的用户ID先前为0,并且由于UID更改而所有这些ID均具有非零值,则将从许可的,有效的和环境的能力集中清除所有能力。
2.
如果有效用户ID从0更改为非零,那么将从有效集中清除所有功能。
3.
如果有效用户ID从非零更改为0,则将允许的集复制到有效集。
4.
如果文件系统用户ID从0更改为非零(请参阅setfsuid(2)),那么将从有效集中清除以下功能:CAP_CHOWNCAP_DAC_OVERRIDECAP_DAC_READ_SEARCHCAP_FOWNERCAP_FSETIDCAP_LINUX_IMMUTABLE(从Linux 2.6.30OVER起)和CAP_MKNOD(从Linux 2.6.30开始)。如果文件系统UID从非零更改为0,则在有效集中启用在允许集中启用的所有功能。

如果一个线程的一个或多个用户ID的值为0,则当它希望将其所有用户ID重置为非零值时希望阻止清除其允许的功能集时,可以使用下面所述的SECBIT_KEEP_CAPS securebits标志来实现。

Programmatically adjusting capability sets

线程可以使用capget(2)和capset(2)系统调用来检索和更改其允许的,有效的和可继承的功能集。但是,为此目的,最好使用libcap软件包中都提供的cap_get_proc(3)和cap_set_proc(3)。以下规则控制线程功能集的更改:

1.
如果调用者不具有CAP_SETPCAP功能,则新的可继承集必须是现有可继承集和允许集的组合的子集。
2.
(从Linux 2.6.25开始)新的可继承集必须是现有可继承集和功能边界集的组合的子集。
3.
新的允许集必须是现有允许集的子集(即,不可能获取线程当前不具有的允许功能)。
4.
新的有效集必须是新的允许集的子集。

The securebits flags: establishing a capabilities-only environment

从内核2.6.26开始,并在启用了文件功能的内核中,Linux实现了一组每线程安全位标志,这些标志可用于禁用对UID 0(根)的功能的特殊处理。这些标志如下:

SECBIT_KEEP_CAPS
设置此标志允许具有一个或多个0 UID的线程在将其所有UID都切换为非零值时将能力保留在其允许的集合中。如果未设置此标志,则此类UID开关将导致线程丢失所有允许的功能。始终在execve(2)上清除此标志。
请注意,即使设置了SECBIT_KEEP_CAPS标志,当线程将其有效UID切换为非零值时,也会清除其有效功能。但是,如果线程设置了此标志并且其有效UID已经为非零,并且线程随后将所有其他UID切换为非零值,则将不会清除有效功能。
如果设置了SECBIT_NO_SETUID_FIXUP标志,则将忽略SECBIT_KEEP_CAPS标志的设置。 (后一个标志提供了前一个标志的效果的超集。)
该标志提供的功能与早期的prctl(2)PR_SET_KEEPCAPS操作相同。
SECBIT_NO_SETUID_FIXUP
当线程的有效UID和文件系统UID在零和非零值之间切换时,设置此标志将阻止内核调整进程的允许,有效和环境能力设置。 (请参阅小节用户ID更改对功能的影响。)
SECBIT_NOROOT
如果设置了此位,则当执行设置用户ID根程序或有效或实际UID为0的进程调用execve(2)时,内核将不授予功能。 (请参阅"能力和程序执行根"小节。)
SECBIT_NO_CAP_AMBIENT_RAISE
设置此标志不允许通过prctl(2)PR_CAP_AMBIENT_RAISE操作提高环境功能。

上面的每个"基本"标志都有一个伴随的"已锁定"标志。设置任何"锁定"标志都是不可逆的,并且具有防止进一步更改相应"基本"标志的作用。锁定的标志是:SECBIT_KEEP_CAPS_LOCKEDSECBIT_NO_SETUID_FIXUP_LOCKED,SECBIT_NOROOT_LOCKED和SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED。

可以使用prctl(2)PR_SET_SECUREBITS和PR_GET_SECUREBITS操作来修改和检索安全位标志。需要CAP_SETPCAP功能才能修改标志。请注意,只有在包含头文件之后,SECBIT_ *常量才可用。

securebits标志由子进程继承。在execve(2)期间,将保留所有标志,但始终清除的SECBIT_KEEP_CAPS除外。

应用程序可以使用以下调用将自身及其所有后代锁定到一个环境中,其中唯一获得能力的方法是通过执行具有关联文件功能的程序:

prctl(PR_SET_SECUREBITS,
        /* SECBIT_KEEP_CAPS off */
        SECBIT_KEEP_CAPS_LOCKED |
        SECBIT_NO_SETUID_FIXUP |
        SECBIT_NO_SETUID_FIXUP_LOCKED |
        SECBIT_NOROOT |
        SECBIT_NOROOT_LOCKED);
        /* Setting/locking SECBIT_NO_CAP_AMBIENT_RAISE
           is not required */

Per-user-namespace set-user-ID-root programs

UID与创建用户名称空间的UID匹配的set-user-ID程序,当由该名称空间或任何后代用户名称空间中的任何进程执行时,将在该进程的允许和有效集中赋予功能。

关于execve(2)期间过程能力转换的规则完全与小节execve()中的能力转换和按功能执行的能力和程序执行小节中所述,不同之处在于,在后一小节中," root "是用户名称空间创建者的UID。

Namespaced file capabilities

传统(即版本2)文件功能仅将一组功能掩码与二进制可执行文件相关联。当进程执行具有此类功能的二进制文件时,它会根据上文" execve()期间功能的转换"中所述的规则获得关联的功能(在其用户名称空间内)。

因为版本2文件功能将功能授予执行过程,而不管它驻留在哪个用户名称空间中,所以仅允许特权进程将功能与文件相关联。此处,"特权"是指在安装了文件系统的用户名称空间(通常是初始用户名称空间)中具有CAP_SETFCAP功能的进程。此限制使文件功能在某些使用情况下无用。例如,在以用户名隔开的容器中,可能希望能够创建一个二进制文件,该二进制文件仅将功能赋予该容器内部执行的进程,而不赋予该容器外部执行的进程。

Linux 4.14添加了所谓的命名空间文件功能来支持此类用例。命名空间文件功能记录为版本3(即VFS_CAP_REVISION_3)security.capability扩展属性。在上述情况下,在"文件功能扩展属性版本控制"下会自动创建这样的属性。创建版本3 security.capability扩展属性时,内核不仅在扩展属性中记录功能掩码,还记录名称空间根用户ID。

与具有VFS_CAP_REVISION_2文件功能的二进制文件一样,具有VFS_CAP_REVISION_3文件功能的二进制文件在execve()期间将功能授予进程。但是,仅当二进制文件由驻留在其UID 0映射到扩展属性中保存的根用户ID的用户名称空间中的进程执行时,或者由驻留在此类后代中的进程执行时,才赋予功能。命名空间。

Interaction with user namespaces

有关功能和用户名称空间交互的更多信息,请参见user_namespaces(7)。

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/

名称

功能-Linux功能概述

另外参见

capsh(1),setpriv(1),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),proc(5),凭据(7),pthreads(7),user_namespaces(7),captest(8),filecap(8),getcap(8), getpcaps(8),netcap(8),pscap(8),setcap(8)

Linux内核源代码树中的include / linux / capability.h

备注

尝试使用strace(1)具有功能的二进制文件(或set-user-ID-root二进制文件)时,您可能会发现-u选项很有用。就像是:

$ sudo strace -o trace.log -u ceci ./myprivprog

从内核2.5.27到内核2.6.26,功能是可选的内核组件,可以通过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到内核2.6.32(如果未启用文件功能),具有CAP_SETPCAP功能的线程可以操纵其自身以外的线程的功能。但是,这仅是理论上可行的,因为在以下两种情况下,没有线程具有CAP_SETPCAP

*
在2.6.25之前的实现中,系统范围的功能限制集/ proc / sys / kernel / cap-bound始终掩盖CAP_SETPCAP功能,并且在不修改内核源代码和重建内核的情况下无法更改此功能。
*
如果文件功能被禁用(即内核CONFIG_SECURITY_FILE_CAPABILITIES选项被禁用),则init首先从其每个进程的边界集中删除CAP_SETPCAP能力,然后该边界集将被系统上创建的所有其他进程继承。
日期:2019-08-20 18:01:52 来源:oir作者:oir