A life without sudo
Please see the latest update, below!
Ever since my first stumbling steps with Linux back in ‘96, I’ve been
learning about UNIX. The first obvious lesson was to not use the root
account. Since then I’ve been using a combination of sudo command
and
suid root binaries to get the job done.
For the last ten years, however, I’ve been meaning to learn about Linux capabilities(7) and thanks to a friend and colleague of mine I now have :)
What you want is to grant capabilities per user and application. Most tutorials only tell you how to do one or the other.
First of all you need to figure out what capabilities an application
requires to perform an action. Let’s use tcpdump
as an example, it
needs raw link access to sniff packets so your user (you), need to be
listed in the system /etc/security/capability.conf
file:
cap_net_raw joachim
Second, you need to set this on the application, so that when joachim
wants to run tcpdump
he is granted the capability:
$ sudo /sbin/setcap cap_net_raw+ep /usr/sbin/tcpdump
Some applications require multiple capabilities, like Qemu when you use
tap networking. Update /etc/security/capability.conf
cap_sys_ptrace,cap_net_bind_service,cap_net_raw,cap_net_admin joachim
Place all capabilities on one line, separated with comma. Then add both capabilities to qemu, like this:
$ sudo /sbin/setcap cap_net_raw,cap_net_admin+ep /usr/bin/qemu-system-arm
Update Sep 15, 2024
As time has progressed so has Linux distributions. On Debian derived distributions like Ubuntu, or my personal favorite, Linux Mint, you now have to adjust your PAM setup slightly:
Edit the file /etc/pam.d/common-auth
and modify the pam_cap.so
line
to include the keepcaps
keyword:
# /etc/pam.d/common-auth
...
auth optional pam_cap.so keepcaps
...
Without it, your inherited capability mask will not be set properly! If
you’re unlucky, you may also have to comment out pam_systemd.so
in the
file /etc/pam.d/common-session
:
# /etc/pam.d/common-session
...
#session optional pam_systemd.so
...
… or, if you want your desktop environment to work like you expect it to, then use this ugly hack instead:
# /etc/pam.d/common-session
...
# This gives *all users* the following capabilities, not what we want.
session optional pam_systemd.so default-capability-ambient-set=CAP_NET_RAW,CAP_NET_ADMIN,CAP_NET_BIND_SERVICE,CAP_SYS_PTRACE,CAP_WAKE_ALARM
...
In the future,
systemd-homed
is supposed to be possible to set up to allow the same fine grained mask per user ascapability.conf
. It is unclear to the undersigned whypam_systemd.so
, or distributions (?), cannot just usepam_cap.so
andcapability.conf
…
Helper Script
Here’s a little script I use to set capabilities. It used to be called
wkz-caps.sh
, but I’ve since refactored it. You need to run it every
time after upgrading any of the packages on your system that provides
the tools you need capabilities for.
#!/bin/sh
set_capabilities()
{
capability="$1"
shift
for cmd in "$@"; do
binary=$(command -v "$cmd" 2>/dev/null) || binary=$cmd
path=$(realpath "$binary") # ip tool may be a symlink
if [ -x "$path" ]; then
sudo setcap "$capability" "$path"
else
echo "Warning: $cmd not found or not executable, skipping." >&2
fi
done
}
set_capabilities 'cap_net_admin,cap_net_raw,cap_net_bind_service+ep' \
gdb-multiarch dnsmasq
set_capabilities 'cap_net_admin+ep' \
ip bridge brctl ifconfig ethtool \
qemu-system-aarch64 qemu-system-arm qemu-system-ppc \
qemu-system-ppc64 qemu-system-x86_64 \
/usr/lib/qemu/qemu-bridge-helper
set_capabilities 'cap_net_raw+ep' \
tcpdump nemesis hping3 trafgen