linuxlinux-capabilitiessuid

Why many Linux distros use setuid instead of capabilities?


capabilities(7) are a great way for not giving all root privileges to a process and AFAIK can be used instead of setuid(2). According to this and many others,

"Unfortunately, still many binaries have the setuid bit set, while they should be replaced with capabilities instead."

As a simple example, on Ubuntu,

$ ls -l `which ping`
-rwsr-xr-x 1 root root 44168 May  8  2014 /bin/ping

As you know, setting suid/guid on a file, changes the effective user ID to root. So if there the suid-enabled program contains a flaw, the non-privileged user can break-out and become the equivalent of the root user.

My question is why many Linux distributions still use setuid method while setting capabilities can be used instead with less security concerns?


Solution

  • This may not give the reason why some dudes somewhere decided one way or another, but some auditing tools and interfaces may not yet know about capabilities.

    An example is the proc_connector netlink interface and the programs based on it (like forkstat): there are events for a process changing its credentials, but not for it changing its capabilities.


    FWIW, the cause why you may not get eg a net_raw+ep ping(8) instead of a setuid one on a Debian-like distro is because that depends on the setcap(8) utility from the libcap2-bin package already existing before you install ping. From iputils-ping.postinst:

        if command -v setcap > /dev/null; then
            if setcap cap_net_raw+ep /bin/ping; then
                chmod u-s /bin/ping
            else
                echo "Setcap failed on /bin/ping, falling back to setuid" >&2
                chmod u+s /bin/ping
            fi
        else
            echo "Setcap is not installed, falling back to setuid" >&2
            chmod u+s /bin/ping
        fi
    

    Also notice that ping itself will drop any setuid privileges and switch to use capabilities on Linux upon starting, so your concerns about it may be a bit exagerated. From ping.c:

    int
    main(int argc, char **argv)
    {
            struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_protocol = IPPROTO
    _UDP, .ai_socktype = SOCK_DGRAM, .ai_flags = getaddrinfo_flags };
            struct addrinfo *result, *ai;
            int status;
            int ch;
            socket_st sock4 = { .fd = -1 };
            socket_st sock6 = { .fd = -1 };
            char *target;
    
            limit_capabilities();
    

    From ping_common.c

    void limit_capabilities(void)
    {
            ...
            if (setuid(getuid()) < 0) {
                    perror("setuid");
                    exit(-1);
            }