ls -l should show the presence of Linux capabilities

April 17, 2012

The other day I discovered that /bin/ping is not setuid on Fedora 16 machines, in particular on my machines. But it still worked, and trying to strace it showed that somehow it still had some sort of setuid permissions (because it didn't work any more, failing with permissions errors).

(Ping normally needs to be setuid root in order to send raw ICMP packets. You can question why this is a privileged operation and not just another socket type, but that's the historical practice.)

On a regular Fedora 16 machine I might have said 'oh, SELinux' and left it at that. But my machines have SELinux disabled, so something more was clearly going on. By prodding my fading memory and doing some searching with man -k, I eventually found capabilities and especially getcap, and it told me most of the answer:

/bin/ping = cap_net_raw+ep

Now here's the problem with this picture: when I did an ls -l of ping, there was no sign that ping also had capabilities. In fact there was no sign that ping had anything beyond normal permissions (and the normal permissions were showing that it had no setuid).

I don't expect ls to have shown me the capabilities themselves. But I've come to feel strongly that ls -l should always indicate if a file has additional attributes of some sort. If a file has ACLs, or capabilities, or even extended attributes, ls -l should display this. The reason is straightforward pragmatics; putting something in ls -l creates visibility, while having ls -l silent makes it more or less invisible.

(I was able to work out what was going on because I'm lucky and reasonably well informed, but plenty of people are not.)

This is especially important on a modern Linux system because modern Linux systems are already completely overgrown with special permission systems for having things magically happen or magically acquire privileges (and most of these systems are effectively invisible). The last thing modern Linux needs is more invisible permission systems; instead, programs such as ls should be working to make them visible.

(All of this was sparked by a Twitter conversation with @aderixon.)

Sidebar: why ls -l having a marker would work

The goal of putting a marker in ls -l output is twofold. If you already know about capabilities it would tell you that the file has them and you can get additional information with getcap and so on. If you don't know about capabilities, seeing something odd in the ls -l output would at least tell you that there's something odd about the file. You could then read the ls manpage to find out what it means, which would lead you to capabilities and getcap and so on. Or to ACLs, or to whatever else people want to add.

(Note that various versions of ls (Linux's included) have already fiddled around with the textual representation of permissions in ls -l to add various things, so it's not as if the format of this is frozen in stone beyond change.)

Comments on this page:

From at 2012-04-17 13:23:34:

When I do an ls -l my permission bits look like:


the . indicates SE Linux attributes IIRC. And I think a + indicates ACLs. Seems like some another character might be in order for capabilities.

From at 2012-04-17 18:07:28:

ls -l already does this using colors here:

% ls --color=always -F -l /tmp/x /usr/bin/dumpcap
-rwxr-xr-- 1 chris users         0 Apr 18 00:03 /tmp/x*
-rwxr-xr-- 1 root  wireshark 68704 Mar 27 22:50 /usr/bin/dumpcap*
% getcap /usr/bin/dumpcap      
/usr/bin/dumpcap = cap_net_admin,cap_net_raw+eip

The first file has the usual green color, while the second file is black on red, which certainly stands out.

(I know you don't use colors in terminals, but things like these made me give in.)

By cks at 2012-04-18 11:01:24:

If I was modifying ls to do this right, I think I'd change what the setuid bit displays as (perhaps 'c' for capabilities, or 'C' if the file both has capabilities and is setuid). Sticking another character on the end starts getting unwieldy, and SELinux and ACLs are already camping there.

(As far as I know a file can have both capabilities and SELinux attributes.)

The colour thing is interesting behavior on ls's part. However, one problem with it is that it's completely undocumented; when you see a non-setuid executable show up with the setuid red background, how are you supposed to know what it means? Ls's use of colours makes this somewhat visible but it doesn't really help to make it discoverable.

(And at least for my version of ls with my terminal colours, the only difference between setuid files and files with capabilities is that one has white text on red and the other has black text on red, where black text is my normal text colour.)

From at 2012-04-20 12:04:10:

For those of us that are neither lucky nor well informed, how does ping elevate privs in F16?

By cks at 2012-04-20 13:54:55:

My best understanding is that cap_net_raw is the capability to send and receive 'raw' network packets, ones that are completely created by yourself. Ping uses this to create and receive ICMP packets. The magic flags at the end are sort of documented in the cap_to_text(3) manpage and mean that ping is both given this capability and permitted to have it.

It turns out that the capabilities(7) manpage at least vaguely covers all of the capabilities (under the same names that getcap uses), so you can at least sort of decode what any special capabilities based privileges a program has.

I believe that capabilities require filesystem support and a suitably enabled kernel. They evidently don't require SELinux.

Written on 17 April 2012.
« What you need for migrating web content
Why you should never use file (or libmagic) to identify files »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Tue Apr 17 00:30:19 2012
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.