[PATCH] capabilities.7: Add details about SECBIT_KEEP_CAPS

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

 



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


#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
-- 
2.19.1




[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