Home > Mobile >  What is the Linux capability(7) to write to /proc/sys/net/ipv6/conf/$IF/disable_ipv6?
What is the Linux capability(7) to write to /proc/sys/net/ipv6/conf/$IF/disable_ipv6?

Time:01-05

I've got a test that I'm writing for a larger program that needs to (1) create a tap device, (2) bind a raw socket, and (3) make a sysctl to disable IPv6. I'm writing to find the set of Linux capabilities to do all of these things so I don't have to run the test as root. The first two are easy: CAP_NET_ADMIN and CAP_NET_RAW, but try as I might, I cannot seem to figure out the capability needed to run:

echo 1 > /proc/sys/net/ipv6/conf/$if/disable_ipv6   # e.g., for 'if=eth0',etc.

I've tried CAP_SYS_ADMIN and CAP_DAC_OVERRIDE and neither of those are sufficient. I've tried to read through the kernel source but am not making headway, so I'm going to cop out and ask for help.

Thank you in advance!

[edit]

$ getcap ./target/debug/deps/tap_tests-e43c717a6e86b805
./target/debug/deps/tap_tests-e43c717a6e86b805 
cap_net_admin,cap_net_raw,cap_sys_admin=eip
$ ./target/debug/deps/tap_tests-e43c717a6e86b805
[snip]
--- test_conntrack_active_probe stdout ----
thread 'test_conntrack_active_probe' panicked at 'safe_run_command FAILED: 'sysctl -w net.ipv6.conf.testtap1.disable_ipv6=1' command returned stderr 'Ok(
    "sysctl: permission denied on key \"net.ipv6.conf.testtap1.disable_ipv6\"\n",
)'', tests/tap_tests.rs:275:13

Also, I had to do this to debug:

$ cp `which strace` ./strace
$ setcap CAP_NET_ADMIN=epi ./strace
$ ./strace -f <test>     # normal strace doesn't inherit the test's capabilities

Posting here in case it helps others.

[edit2]

It looks like this is the core problem/solution: https://unix.stackexchange.com/questions/128394/passing-capabilities-through-exec

CodePudding user response:

It looks like only CAP_NET_ADMIN is necessary.

We can verify that using a simple C program that, given a list of interfaces as arguments, sets the disable_ipv6 sysctl for each interface:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>

#define SYSCTL_TEMPLATE "/proc/sys/net/ipv6/conf/%s/disable_ipv6"

int main(int argc, char **argv) {
    int template_len = strlen(SYSCTL_TEMPLATE);

    for (int i=1; i<argc; i  ) {
        int path_len, fd, nb;
        char path[1024];

        printf("interface name: %s\n", argv[i]);
        path_len = template_len   strlen(argv[i]);
        if (path_len > 1024) {
            fprintf(stderr, "path too long\n");
            exit(1);
        }

        sprintf(path, SYSCTL_TEMPLATE, argv[i]);
        
        if ((fd = open(path, O_WRONLY)) < 0) {
            perror("open");
            exit(1);
        }

        if ((nb = write(fd, "1", 1)) < 0) {
            perror("write");
            exit(1);
        }
    }
    return 0;
}

I'm going to be using an interface named vlan1 as my test interface; initially, it looks like:

$ sysctl net.ipv6.conf.vlan1.disable_ipv6
net.ipv6.conf.vlan1.disable_ipv6 = 0

If I run the compiled binary as a normal user, it fails with a "permission denied" error:

$ ./disable_ipv6 vlan1
interface name: vlan1
open: Permission denied

If I set the CAP_NET_ADMIN capability on this binary:

$ sudo setcap cap_net_admin eip disable_ipv6

And then re-run it, it succeeds:

$ ./disable_ipv6 vlan1
interface name: vlan1

After which we can see the value of the sysctl has been modified:

$ sysctl net.ipv6.conf.vlan1.disable_ipv6
net.ipv6.conf.vlan1.disable_ipv6 = 1

If your goal is explicitly to set this sysctl using echo, then you'll need to arrange to run a shell with the necessary privileges. It looks like we can do this using the --addamb option to capsh (to add the capability to the ambient capability set):

$ sudo env HOME=$HOME capsh --user=$USER --inh=cap_net_admin --addamb=cap_net_admin --

This gives us the necessary capability set:

$ getpcaps $$
1496078: cap_net_admin=eip

And allows us to modify the desired sysctl without errors:

$ echo 1 > /proc/sys/net/ipv6/conf/vlan1/disable_ipv6
$ echo 0 > /proc/sys/net/ipv6/conf/vlan1/disable_ipv6
  • Related