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

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

 



On 11/01/2018 03:02 PM, Marcus Gelderie wrote:
> Hi Michael,
> 
> I saw your additions and of course they make sense.

Thanks for checking them over, Marcus!

Cheers,

Michael

> 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/
> 


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