我最近正在使用 and 编写程序,libcap
并且libseccomp
在将它们一起使用时发现了一个问题。
在下面的最小可重现示例中,我首先将当前流程的能力设置为P(inheritable) = CAP_NET_RAW
only,其他能力集被清除。然后,我使用操作初始化一个 seccomp 过滤器SCMP_ACT_ALLOW
(默认情况下允许所有系统调用),加载它并清理它。
最后,这个程序打印它当前的能力,并在执行capsh --print
后执行以显示它的能力execve()
。
#include <linux/capability.h>
#include <sys/capability.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <seccomp.h>
#define CAPSH "/usr/sbin/capsh"
int main(void) {
cap_value_t net_raw = CAP_NET_RAW;
cap_t caps = cap_init();
cap_set_flag(caps, CAP_INHERITABLE, 1, &net_raw, CAP_SET);
if (cap_set_proc(caps)) {
perror("cap_set_proc");
}
cap_free(caps);
scmp_filter_ctx ctx;
if ((ctx = seccomp_init(SCMP_ACT_ALLOW)) == NULL) {
perror("seccomp_init");
}
int rc = 0;
rc = seccomp_load(ctx); // comment this line later
if (rc < 0)
perror("seccomp_load");
seccomp_release(ctx);
ssize_t y = 0;
printf("Process capabilities: %s\n", cap_to_text(cap_get_proc(), &y));
char *argv[] = {
CAPSH,
"--print",
NULL
};
execve(CAPSH, argv, NULL);
return -1;
}
-lcap
用and编译,-lseccomp
在root用户(UID=EUID=0)下执行,得到:
Process capabilities: = cap_net_raw+i
Current: = cap_net_raw+i
Bounding set =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,cap_audit_read
Securebits: 00/0x0/1'b0
secure-noroot: no (unlocked)
secure-no-suid-fixup: no (unlocked)
secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=0(root)
它表明当前进程和执行的capsh
所有进程都具有可继承集而不是空的。但是,如果我评论 line rc = seccomp_load(ctx);
,情况会有所不同:
Process capabilities: = cap_net_raw+i
Current: = cap_net_raw+eip 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_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,cap_audit_read+ep
Bounding set =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,cap_audit_read
Securebits: 00/0x0/1'b0
secure-noroot: no (unlocked)
secure-no-suid-fixup: no (unlocked)
secure-keep-caps: no (unlocked)
uid=0(root)
gid=0(root)
groups=0(root)
之前execve()
,结果与上面相同。但在那之后,所有其他能力都回到了允许和有效的集合中。
我查找了capabilities(7),并在手册中找到了以下内容:
Capabilities and execution of programs by root
In order to mirror traditional UNIX semantics, the kernel performs
special treatment of file capabilities when a process with UID 0
(root) executes a program and when a set-user-ID-root program is exe‐
cuted.
After having performed any changes to the process effective ID that
were triggered by the set-user-ID mode bit of the binary—e.g.,
switching the effective user ID to 0 (root) because a set-user-ID-
root program was executed—the kernel calculates the file capability
sets as follows:
1. If the real or effective user ID of the process is 0 (root), then
the file inheritable and permitted sets are ignored; instead they
are notionally considered to be all ones (i.e., all capabilities
enabled). (There is one exception to this behavior, described
below in Set-user-ID-root programs that have file capabilities.)
2. If the effective user ID of the process is 0 (root) or the file
effective bit is in fact enabled, then the file effective bit is
notionally defined to be one (enabled).
These notional values for the file's capability sets are then used as
described above to calculate the transformation of the process's
capabilities during execve(2).
Thus, when a process with nonzero UIDs execve(2)s a set-user-ID-root
program that does not have capabilities attached, or when a process
whose real and effective UIDs are zero execve(2)s a program, the cal‐
culation of the process's new permitted capabilities simplifies to:
P'(permitted) = P(inheritable) | P(bounding)
P'(effective) = P'(permitted)
Consequently, the process gains all capabilities in its permitted and
effective capability sets, except those masked out by the capability
bounding set. (In the calculation of P'(permitted), the P'(ambient)
term can be simplified away because it is by definition a proper sub‐
set of P(inheritable).)
The special treatments of user ID 0 (root) described in this subsec‐
tion can be disabled using the securebits mechanism described below.
这就是我感到困惑的地方:可继承集不为空,根据简化规则,允许和有效集都不应为空。但是,“加载 seccomp 过滤器”似乎违反了这条规则。