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 (184.108.40.206) 56(84) bytes of data. 64 bytes from 220.127.116.11: 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 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.
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.
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
The information at Linux Audit was useful in the writing of this article.