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

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

 



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