Linux Capabilities and Ping

If you are running a recent version of Linux (time of writing May 2016), you might encountered this error with ping:

$ ping somehost
ping: icmp open socket: Operation not permitted

It happens because the ping binary is no longer installed with setuid root rights. It doesn’t have the required priveliges to open the socket, and fails. The quick fix is to type:

$ sudo setcap cap_net_raw+p /bin/ping

Assuming your ping binary is at /bin/ping. Now it works:

$ ping somehost
PING somehost (123.123.123.123) 56(84) bytes of data.
64 bytes from 123.123.123.123: icmp_seq=1 ttl=53 time=9.14 ms

You have just added a Linux “capability” to the ping binary, which has given ping the rights to open a raw socket, which has allowed it to ping the target system.

Linux Capabilities

Linux Capabilities provide fine-grained control over the sorts of privileged activities a process or thread can perform. Traditionally there have been only two levels of privilege: root and non-root. A process executing as root, or super user, could do most things on the system. A non-root process had control only over the elements that it owned or was granted access to.

In the past, before Capabilities, ping and other system tools were installed with setuid root permissions, like this:

$ ls -l /bin/ping
-rwsr-xr-x 1 root root 44168 May  7  2014 /bin/ping

The “s” in the permission string represents the setuid bit, and it means that ping will be executed with root level permissions, even if invoked by a non-root user. Ping needs higher privileges to work properly. Here are some other programs installed as setuid root on Red Hat 6.5, by default:

$ find /bin -perm +4000 -ls
652330   76 -rwsr-xr-x   1 root     root        77336 Aug  6  2013 /bin/mount
656520   32 -rwsr-x---   1 root     fuse        32336 Nov  3  2011 /bin/fusermount
652317   36 -rwsr-xr-x   1 root     root        36488 Sep 17  2013 /bin/ping6
652333   56 -rwsr-xr-x   1 root     root        53472 Aug  6  2013 /bin/umount
652316   40 -rwsr-xr-x   1 root     root        40760 Sep 17  2013 /bin/ping
651661   36 -rwsr-xr-x   1 root     root        34904 Oct 17  2013 /bin/su

Dangers of Setuid Programs

The setuid mechanism works well and is quite widespread. However, it represents poor security. A process running as setuid obtains far greater permissions than it actually needs. Ping needs to open a raw network socket, and root rights conferred through setuid allow it to do that, but they also give ping many other powers which it doesn’t need. If the ping binary were overwritten by a hacked version, for example, malicious code could run with full superuser privileges.

That is one reason why capabilities are more desirable than simple setuid solutions, and are being used more widely with each Linux release.

Capability Sets

Above, a capability called cap_net_raw was given to the ping binary. Cap_net_raw is one of a large number of available capabilities, about 38 according to the capabilities man page.

Each thread, or process, has three sets of capabilities associated with it: Permitted, Inheritable and Effective. In the example above, the “+p” in our “setcap cap_net_raw+p /bin/ping” command added the cap_net_raw capability to the ping binary’s Permitted capability set, meaning that a subsequent ping process (or thread) would obtain the corresponding rights. Capability sets, as they belong to files and threads, are quite well explained in the above man page.

CAP_NET_RAW

One question. If ping needs this special capability to work, or previously the setuid stuff, why don’t other network tools need it, like ssh, ftp, wget and so on ? And for that matter, web browsers like Firefox and Safari ? Don’t they have to open network sockets too? Yes they do, but not in the same way.

First, use strace see ping opening its socket:

$ strace -e socket ping 192.168.1.254
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 3
...

Ping opens a socket of type SOCK_RAW.

Do the same test with FTP, and it becomes clear that FTP does not open a SOCK_RAW socket. It uses SOCK_STREAM instead:

$ strace -e socket ftp 192.168.1.254
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
ftp: connect: Connection refused

It is as expected. SOCK_STREAM creates a full transport-oriented TCP socket connection for extended communication. SOCK_RAW on the other hand, is just a pass through to the lower levels of IP, allowing ping to send out ICMP packets directly.

Therefore, CAP_NET_RAW gives the ability to open a socket of type SOCK_RAW, but is not needed for SOCK_STREAM sockets.

Ping in Various Linux Disros

Ping is a useful tool for users, administrators and developers. It doesn’t really make sense that by default, only root can execute it. Some Linux disros seem to agree, and have given ping necessary Capability by default. In older releases, capabilities are often installed in the kernel but not set up for ping.

Releases that have the ping capability already set:

  • Red Hat 7.0, where ping has capabilities cap_net_admin,cap_net_raw+ep
  • Raspbian (Debian 8 Jessie) May 2016 release (but not the Feb 2016 release)

Releases where it is not set:

  • Red Hat 6.5
  • SLES 12 (getcap/setcap not installed by default)
  • Ubuntu 14.04/Mint 17

Acknowledgements

The information at Linux Audit was useful in the writing of this article.

Leave a Reply

Your email address will not be published. Required fields are marked *