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/