diff options
| author | Marcus Gelderie <marcus.gelderie@gmail.com> | 2018-10-31 10:35:47 +0100 |
|---|---|---|
| committer | Michael Kerrisk <mtk.manpages@gmail.com> | 2018-11-01 14:39:25 +0100 |
| commit | 7d32b135d65817ee2157355565c80c2f2beb4fd9 (patch) | |
| tree | 0ad39fd1fb0504fada5c43f606618650a2c40d09 /man7 | |
| parent | 8e7e9720f6aa7b4395390fe9d276db8d6878ed2e (diff) | |
| download | man-pages-7d32b135d65817ee2157355565c80c2f2beb4fd9.tar.gz | |
capabilities.7: Add details about SECBIT_KEEP_CAPS
The description of SECBIT_KEEP_CAPS is misleading about the
effects on the effective capabilities of a process during a
switch to nonzero UIDs. The effective set is cleared based on
the effective UID switching to a nonzero value, even if
SECBIT_KEEP_CAPS is set. However, with this bit set, the
effective and permitted sets are not cleared if the real and
saved set-user-ID are set to nonzero values.
This was tested using the following C code and reading the kernel
source at security/commoncap.c: cap_emulate_setxuid.
void print_caps(void) {
cap_t current = cap_get_proc();
if (!current) {
perror("Current caps");
return;
}
char *text = cap_to_text(current, NULL);
if (!text) {
perror("Converting caps to text");
goto free_caps;
}
printf("Capabilities: %s\n", text);
cap_free(text);
free_caps:
cap_free(current);
}
void print_creds(void) {
uid_t ruid, suid, euid;
if (getresuid(&ruid, &euid, &suid)) {
perror("Error getting UIDs");
return;
}
printf("real = %d, effective = %d, saved set-user-ID = %d\n", ruid, euid, suid);
}
void set_caps(int size, const cap_value_t *caps) {
cap_t current = cap_init();
if (!current) {
perror("Error getting current caps");
return;
}
if (cap_clear(current)) {
perror("Error clearing caps");
}
if (cap_set_flag(current, CAP_INHERITABLE, size, caps, CAP_SET)) {
perror("setting caps");
goto free_caps;
}
if (cap_set_flag(current, CAP_EFFECTIVE, size, caps, CAP_SET)) {
perror("setting caps");
goto free_caps;
}
if (cap_set_flag(current, CAP_PERMITTED, size, caps, CAP_SET)) {
perror("setting caps");
goto free_caps;
}
if (cap_set_proc(current)) {
perror("Comitting caps");
goto free_caps;
}
free_caps:
cap_free(current);
}
const cap_value_t caps[] = {CAP_SETUID, CAP_SETPCAP};
const size_t num_caps = sizeof(caps) / sizeof(cap_value_t);
int main(int argc, char **argv) {
puts("[+] Dropping most capabilities to reduce amount of console output...");
set_caps(num_caps, caps);
puts("[+] Dropped capabilities. Starting with these credentials and capabilities:");
print_caps();
print_creds();
if (argc >= 2 && 0 == strncmp(argv[1], "keep", 4)) {
puts("[+] Setting SECBIT_KEEP_CAPS bit");
if (prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS, 0, 0, 0)) {
perror("Setting secure bits");
return 1;
}
}
puts("[+] Setting effective UID to 1000");
if (seteuid(1000)) {
perror("Error setting effective UID");
return 2;
}
print_caps();
print_creds();
puts("[+] Raising caps again");
set_caps(num_caps, caps);
print_caps();
print_creds();
puts("[+] Setting all remaining UIDs to nonzero values");
if (setreuid(1000, 1000)) {
perror("Error setting all UIDs to 1000");
return 3;
}
print_caps();
print_creds();
return 0;
}
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
Diffstat (limited to 'man7')
| -rw-r--r-- | man7/capabilities.7 | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/man7/capabilities.7 b/man7/capabilities.7 index e5a3ce50da..c9fd457187 100644 --- a/man7/capabilities.7 +++ b/man7/capabilities.7 @@ -1450,6 +1450,13 @@ in those sets. This flag is always cleared on an .BR execve (2). .IP +Note that even with the +.B SECBIT_KEEP_CAPS +flag set, the effective capabilities of a thread are cleared when it +switches its effective UID to a nonzero value. However, if the effective +UID is already nonzero and a thread subsequently switches all other UIDs +to nonzero values, then the effective capabilities will not be cleared. +.IP The setting of the .B SECBIT_KEEP_CAPS flag is ignored if the |
