I know that if a process is run setuid that it's protected against various things that could subvert the process, like LD_PRELOAD and ptrace (debugging). But I haven't been able to find anything on the same being done for capabilities. I assume the same sorts of things are done with capabilities, since otherwise it would have huge security holes, but I haven't been able to find it documented/verified.
Linux – Security of capabilities vs setuid (LD_PRELOAD, etc)
capabilitieslinuxSecuritysetcapsetuid
Related Solutions
File system capabilities in Linux were added to allow more fine-grained control than setuid alone will allow. With setuid it's a full escalation of effective privileges to the user (typically root). The capabilities(7) manpage provides the following description:
For the purpose of performing permission checks, traditional Unix implementations distinguish two categories of pro‐ cesses: privileged processes (whose effective user ID is 0, referred to as superuser or root), and unprivileged pro‐ cesses (whose effective UID is nonzero). Privileged processes bypass all kernel permission checks, while unprivi‐ leged processes are subject to full permission checking based on the process's credentials (usually: effective UID, effective GID, and supplementary group list).
Starting with kernel 2.2, Linux divides the privileges traditionally associated with superuser into distinct units, known as capabilities, which can be independently enabled and disabled. Capabilities are a per-thread attribute.
If an application needs the ability to call chroot(), which is typically only allowed for root, CAP_SYS_CHROOT
can be set on the binary rather than setuid. This can be done using the setcap command:
setcap CAP_SYS_CHROOT /bin/mybin
As of RPM version 4.7.0, capabilities can be set on packaged files using %caps
.
Fedora 15 had a release goal of removing all setuid binaries tracked in this bug report. According to the bug report, this goal was accomplished.
The wikipedia article on Capability-based security is good read for anyone interested.
It turns out that setting +i on the wrapper does not add the capability to the CAP_INHERITABLE
set for the wrapper process, thus it is not passed through exec
. I therefore had to manually add CAP_DAC_OVERRIDE
to CAP_INHERITABLE
before calling execl
:
#include <sys/capability.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv[]) {
cap_t caps = cap_get_proc();
printf("Capabilities: %s\n", cap_to_text(caps, NULL));
cap_value_t newcaps[1] = { CAP_DAC_OVERRIDE, };
cap_set_flag(caps, CAP_INHERITABLE, 1, newcaps, CAP_SET);
cap_set_proc(caps);
printf("Capabilities: %s\n", cap_to_text(caps, NULL));
cap_free(caps);
return execl("/usr/bin/net", "net", "ads", "dns", "register", "-P", NULL);
}
In addition, I had to add cap_dac_override
to the permitted file capabilities set on /usr/bin/net
and set the effective bit:
~ $ sudo setcap cap_dac_override=p ./registerdns
~ $ sudo setcap cap_dac_override=ei /usr/bin/net
~ $ ./registerdns
Capabilities = cap_dac_override+p
Capabilities = cap_dac_override+ip
Successfully registered hostname with DNS
I think I now fully understand what's happening:
- The wrapper needs
CAP_DAC_OVERRIDE
in its permitted set so it can add it to its inheritable set. - The wrapper's process inheritable set is different than its file inheritable set, so setting +i on the file is useless; the wrapper must explicitly add
CAP_DAC_OVERRIDE
toCAP_INHERITABLE
usingcap_set_flag
/cap_set_proc
. - The
net
file needs to haveCAP_DAC_OVERRIDE
in its inheritable set so that it can in fact inherit the capability from the wrapper into itsCAP_PERMITTED
set. It also needs the effective bit to be set so that it will be automatically promoted toCAP_EFFECTIVE
.
Best Answer
As mentioned in this Kernel Mailing List message, whether a process needs extra security is checked in
cap_bprm_secureexec()
of the kernel filesecurity/commoncap.c
, which does check for capabilities. This is then exported to the process via the auxiliary vector. This can be accessed/tested viagetauxval(AT_SECURE)
. I insertedgetauxval(AT_SECURE)
into a test program, and it did indeed return 1 when it was running with any capabilities set and usable, the same as it would if running setuid, so capabilities have the same security protections as setuid.