An incredibly underused but oh-so-amazing feature in Linux is capabilities. Everyone should use it to make their lives simpler.
By default, a user does not have many permissions on a system. Some are granted
automatically through different means, such as reading and writing files in
your home directory. As developers, we may regularly have to reach for sudo
to
allow us to do what we want. Writing our password over and over again, or
constantly forgetting to prefix your command with sudo. It can get tiring.
On the other end, you could do like ye olden days and start a shell as a superuser; run everything with sudo. However, sudo was specifically invented to not have users run everything as a superuser, as it is inherently a bad idea. Using sudo gives you access to everything. Not using it gives you access to very little. But what if there was a middle ground?
Enter capabilities. All of the actions that normally require sudo have one or more capabilities associated with them. Sudo grants you all capabilities, allowing for any kind of mayhem when running commands with it. However, you can also grant yourself only some of these capabilities. It is assigned per user and application. This means that to run a command that normally requires sudo without it, both the user and the command must have the required capabilities. This gives the bonus of safety, an application cannot do actions you explicitly haven’t given it access to. It also allows system administrators to give users access to run certain applications without the need to give them sudo rights.
Using capabilities
As mentioned above, capabilities are given to both users and applications. Let’s
start with users. This is stored in the file /etc/security/capability.conf
.
Edit the file and add a line like this but with your username.
cap_net_raw,cap_net_admin casan
This gives the user casan
the two capabilities cap_net_raw
and
cap_net_admin
and should take effect immediately. Next, we need some
application. Let’s use the ip
command. To find where the command is located we
can use which ip
. An important detail here is that you can’t give capabilities
to symlinks, so if a command is symlinked the capability must be given to the
actual executable file.
But before we add the capability, let’s try doing a command without sudo. It
should fail with ioctl(TUNSETIFF): Operation not permitted
.
ip tuntap add tap99 mod tap
Now add the capability cap_net_admin
to the command.
sudo setcap cap_net_admin+ep /bin/ip
Try the previous command again and it should work. And just to clean up our mess
we can delete the newly created tap99
interface with ip link del dev tap99
(which we can also do without sudo).
Now you know how to add capabilities to avoid using sudo. But how do we know
which capabilities a command needs? It can depend on which arguments you pass
the command, depending on what the arguments do. If you use the commands of ip netns
you need different capabilities than the example above. You can always
read the manpage
capabilities(7) to
get a better understanding of the individual capabilities. But if you don’t
fully understand how a command works it can be difficult to figure out. It can
also be the case of one command starting another subprocess, where the
subprocess is the one that needs the capability.
Capmon: figuring out capabilities
Introducing Capmon - a Linux capabilities
monitor. A tool that monitors your process
and shows a report over which capabilities it looked for. You simply pass your
command as an argument to Capmon and it will execute it. But before you get
started, Capmon does require the capabilities cap_dac_override
and
cap_sys_admin
, running it with sudo does not work correctly because that
bypasses certain checks. Now that you’ve added those capabilities to yourself
and Capmon, let’s try it out.
capmon 'ip tuntap add tap99 mod tap'
Assuming you did everything correctly, this should output the following text
indicating that the ip
application accessed the cap_net_admin
capability
successfully.
[ip]
- [PASS] CAP_NET_ADMIN
Now take what you’ve learnt here and use more commands without sudo.
Some things to keep in mind
- If a command is failing but you are not seeing any FAIL output from Capmon,
try running with the flag
-a
. This adds some additional monitoring points. - It is recommended to use quotes around your command, otherwise dash-arguments arguments will be interpreted as arguments to Capmon.
- Commands that require multiple capabilities will usually stop and return an error on the first failed check. In this case, add the first capability, then run it again and it will fail on the second.
Footnote
The title of this post is a homage to a blogpost by a former colleague who taught me about capabilities and a ton of other things, which in turn inspired me to create Capmon. You can read his post at A life without sudo.