aboutsummaryrefslogtreecommitdiffstats
path: root/man7
diff options
context:
space:
mode:
authorMarcus Gelderie <marcus.gelderie@gmail.com>2018-10-31 10:35:47 +0100
committerMichael Kerrisk <mtk.manpages@gmail.com>2018-11-01 14:39:25 +0100
commit7d32b135d65817ee2157355565c80c2f2beb4fd9 (patch)
tree0ad39fd1fb0504fada5c43f606618650a2c40d09 /man7
parent8e7e9720f6aa7b4395390fe9d276db8d6878ed2e (diff)
downloadman-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.77
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