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.
Great explanation, thanks you very much
Cheers Brigo.
Complete and elegant technical explanation! Thank you very much.
`root@localhost:~# setcap cap_net_raw+p /bin/ping
root@localhost:~# ping localhost
ping: icmp open socket: Operation not permitted
root@localhost:~# ls -l $(which ping)
-rwsr-xr-x. 1 root root 34752 Nov 8 2014 /bin/ping`
Very nice explanation! But, not quite working for me.
Hi bulbuntu. Something is not right about the ping commands shown in your comment. Your ping programme (/bin/ping) is already setuid to root, as shown by the permissions. Moreover, you are invoking ping as the root user, as indicated by the hash prompt. Therefore the ping process should be running as root, and it is hard to see why you would get an “Operation not permitted” error in this case.
I wonder why cap_net_raw+p is OK? And I checked the process capabilities of ping, where there was no capablity in cap_effective set.
In my opinion cap_net_raw+ep should be the right solution.
Hi Yanzhoa, it is slightly difficult to check now. Later versions of Raspbian, based on Debian 9, seem to have reverted to using setuid by default. Ping thus works out of the box. Slightly annoying though, as it is a backward step for security.
The Raspbian Stretch (Debian 9) derived images that I’ve got don’t have setuid root on ping, but do have capabilities set:
`getcap /bin/ping
/bin/ping = cap_net_raw+ep`
Annoyingly, though this means that pxe booting these images and using nfs for the root filesystem means that ping doesn’t work for normal users 🙁
Hi Tim C. Which image is that exactly? Mine all seem to be setuid again.
$ sudo ping somehost
the easiest )
Hi Igor, yes that would work. However it doesn’t help ordinary users who have no access to root and no applicable sudo abilities. Cheers, Jim.