On 11/01/2018 03:02 PM, Marcus Gelderie wrote: > Hi Michael, > > I saw your additions and of course they make sense. Thanks for checking them over, Marcus! Cheers, Michael > On 18-11-01 14:44:37, Michael Kerrisk (man-pages) wrote: >> Hi Marcus, >> >> On 10/31/2018 10:35 AM, Marcus Gelderie wrote: >>> 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 >> >> Thanks for the detailed commit message. Of course you are correct. >> The manual page also says that SECBIT_KEEP_CAPS provides the same >> functionality as the prctl() PR_SET_KEEPCAPS flag, and the prctl(2) >> manual page has the correct description of the semantics (i.e., that >> the flag affects the treatment of onlt the permitted capability set). >> >> Patch applied. (And I made some further changes as well. You may >> like to take a look.) >> >> Thanks, >> >> Michael >> >>> #define _GNU_SOURCE 1 >>> #include <linux/securebits.h> >>> #include <stdio.h> >>> #include <string.h> >>> #include <sys/capability.h> >>> #include <sys/prctl.h> >>> #include <unistd.h> >>> >>> 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; >>> } >>> >>> --- >>> man7/capabilities.7 | 7 +++++++ >>> 1 file changed, 7 insertions(+) >>> >>> diff --git a/man7/capabilities.7 b/man7/capabilities.7 >>> index e5a3ce50d..c9fd45718 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 >>> >> >> >> -- >> Michael Kerrisk >> Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ >> Linux/UNIX System Programming Training: http://man7.org/training/ > -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/