Hi Michael, I saw your additions and of course they make sense. Thanks for applying, Marcus 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/