Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linux inheritable capability cleared on program start

I am trying to start a program with network permissions so that it can execute iptables without being the root user. I need CAP_NET_ADMIN to be inheritable and permitted. It seems that the inheritable flag is cleared when the executable is started, but not effective or permitted:

Script started on Thu 25 Oct 2018 11:09:45 PM UTC
[ec2-user@ip-172-31-16-197 cap_question]$ cat caps.c 
#include <stdio.h>
#include <stdlib.h>
#include <sys/capability.h>

int main(int argc, char **argv) {
    cap_t caps = cap_get_proc();
    printf("Inside the executable [%s]\n", argv[0]);
    char *cap_text = cap_to_text(caps, NULL);
    printf("capabilities %s\n", cap_text);
    cap_free(cap_text);
    cap_free(caps);
}
[ec2-user@ip-172-31-16-197 cap_question]$ cc caps.c -o caps -lcap
[ec2-user@ip-172-31-16-197 cap_question]$ sudo setcap cap_net_admin=eip caps
[ec2-user@ip-172-31-16-197 cap_question]$ getcap caps
caps = cap_net_admin+eip
[ec2-user@ip-172-31-16-197 cap_question]$ ./caps
Inside the executable [./caps]
capabilities = cap_net_admin+ep
[ec2-user@ip-172-31-16-197 cap_question]$ exit

Script done on Thu 25 Oct 2018 11:10:25 PM UTC

As you can see, the executable file as cap_net_admin=eip. But when I actually run it, the permission set is cap_net_admin=ep. I don't understand why the executable drops inheritable when it starts. If I were to fork/exec iptables, it would not receive those permissions.

I've read threads like these and man capabilities many times and the best explanation I can come up with is that my shell does not have cap_net_admin=i, and so the child process does not. How can I start a process with the inheritable flag set as desired?

like image 956
Spencer Avatar asked Sep 21 '25 02:09

Spencer


1 Answers

According to capabilities(7)

During an execve(2), the kernel calculates the new capabilities of the process using the following algorithm:

   P'(permitted) = (P(inheritable) & F(inheritable)) |
                    (F(permitted) & cap_bset)

   P'(effective) = F(effective) ? P'(permitted) : 0

   P'(inheritable) = P(inheritable)    [i.e., unchanged]

P(inheritable) means the inheritable bit in the process, F(inheritable) is the inheritable bit of the file being executed. As you can see, F(inheritable) is only used to determine the permitted capabilities of the process, it's not used to determine the inheritable capabilities.

The inheritable capabilities of a file is ANDed with the inheritable capabilities of the process -- this allows you to use this flag to prevent some capabilities from being set in the new process, it's not used to add anything to the new process.

If you want to make the capablility inheritable from your process, you can call cap_set_proc(). When a capability is permitted, you're allowed to make it inheritable.

like image 187
Barmar Avatar answered Sep 22 '25 18:09

Barmar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!