Re: [PATCH] capabilities.7: Add details about SECBIT_KEEP_CAPS

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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/



[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux