Chapter 36 — The permission model, beyond chmod 777
In one sentence
Standard owner/group/other permissions (Chapter 25) are a blunt instrument — Linux CAPABILITIES let you grant a program a specific, narrow slice of root's power instead of all of it, and ACLs let you grant fine-grained permissions to specific individual users beyond just "owner" and "group."
Why this matters
"This program needs a LITTLE bit of extra privilege, so I made it full SUID root" is a real, common, and often unnecessary security trade-off — modern Linux gives you much narrower tools for exactly this problem.
How it actually works
LINUX CAPABILITIES split "what root can do" into roughly 40
independent, individually-grantable PRIVILEGES, instead of the
old all-or-nothing model (either you're root, with EVERY privilege,
or you're not, with NONE of them). A few examples:
CAP_NET_RAW create raw network sockets (needed by `ping`,
packet capture tools)
CAP_NET_BIND_SERVICE bind to a port below 1024 (historically
root-only)
CAP_SYS_TIME change the system clock
CAP_CHOWN change file ownership
CAP_SYS_ADMIN a large, famously broad grab-bag of
administrative operations (genuinely close to
"basically root" on its own -- treated with
real caution)
You can grant a SPECIFIC capability to a specific binary, instead of
making it SUID-root (Chapter 25):
sudo setcap cap_net_raw+ep /path/to/mytool
getcap /path/to/mytool # confirm what was granted
This means a program with a BUG can, at worst, misuse the ONE
narrow capability it was granted -- not read every file on the
system, not create arbitrary users, not do anything else root could
do. This same mechanism (Linux capabilities) is exactly what
container runtimes use to run containers with a much smaller,
scoped set of privileges than genuine root, rather than either "full
root" or "no privileges at all" (Phase 3 covers this properly).
ACLs (Access Control Lists) extend the basic owner/group/other model
to allow permissions for SPECIFIC, ADDITIONAL individual users or
groups on a single file -- something the basic three-category model
simply cannot express (e.g. "the owner and the finance group can
both write to this file, but ALSO grant read-only to this one
specific contractor's account, without adding them to the finance
group at all"):
setfacl -m u:bob:r-- shared_report.csv # grant bob read-only,
# specifically
getfacl shared_report.csv # see all ACL entries
Real-world example
The `ping` command is a genuinely useful, concrete real illustration
of this chapter's improvement over the blunt SUID model (Chapter
25): `ping` NEEDS to create a raw network socket to send ICMP
packets, an operation that historically required root privileges
entirely -- which is exactly why, for decades, `/bin/ping` on most
Unix-like systems was SUID-root: an ordinary user could run it, and
it would run WITH root's full power, purely to get the one specific
permission (creating a raw socket) it actually needed.
On modern Linux systems, this is commonly implemented instead using
the CAP_NET_RAW capability specifically (`getcap /bin/ping` on many
current distributions shows exactly this, rather than the SUID bit)
-- `ping` gets precisely the one privilege it actually requires, and
NOTHING else. If a bug were ever found in `ping`'s code (and
real vulnerabilities HAVE been found in ping implementations over
the years, across various Unix systems, historically), the
worst-case blast radius with capabilities is "misuse of raw socket
creation" -- not "arbitrary code execution as full root," which is
what a SUID-root `ping` bug would have granted. This is a small,
concrete, verifiable-on-your-own-machine example of the exact
principle -- least privilege, applied precisely instead of broadly --
that runs through this entire guide and Phase 3's container security
material.
Try it yourself
# See ping's actual privilege model on your system
which ping
ls -l $(which ping) # look for the SUID bit (an 's' in the
# owner-execute position) -- may or may
# not be present, depending on your distro
getcap $(which ping) 2>/dev/null # or see the capability-based approach
# -- many modern distros use this instead
# Try capabilities yourself, safely, on a harmless test binary
cat > /tmp/captest.c << 'EOF'
#include <stdio.h>
int main() { printf("hello from a capability-scoped binary\n"); return 0; }
EOF
gcc -o /tmp/captest /tmp/captest.c
getcap /tmp/captest # nothing granted yet
sudo setcap cap_net_raw+ep /tmp/captest
getcap /tmp/captest # now shows the granted capability
rm /tmp/captest /tmp/captest.c
# See ACLs in action
touch shared_report.csv
setfacl -m u:$(whoami):r-- shared_report.csv 2>/dev/null || \
echo "(setfacl not installed -- try: sudo apt install acl)"
getfacl shared_report.csv 2>/dev/null
rm -f shared_report.csv
Common mistakes
- Reaching for SUID-root as the default fix for "this needs extra privilege." Check whether a specific capability covers exactly what's needed first — it's a strictly smaller, safer grant.
- Granting
CAP_SYS_ADMINcasually. It's broad enough to be close to "full root" in practice — treat it with the same caution as SUID-root itself, not as "just another capability." - Forgetting ACLs exist and fighting the owner/group/other model to express something it can't. If you find yourself creating a new GROUP just to grant one person access to one file, an ACL is usually the more precise tool.
Check yourself
- What problem do Linux capabilities solve that SUID doesn't?
- What does
CAP_NET_RAWgrant, and why doespingneed it (or its SUID-root equivalent)? - What can an ACL express that basic owner/group/other permissions cannot?
Further reading
- Reference:
man 7 capabilities,man 1 setcap,man 1 getcap,man 1 setfacl,man 5 acl. - Guide: this wiki's security guides cover container capability-dropping
(
--cap-drop ALL, adding back only what's needed) in operational depth — the direct Phase 3 continuation of this chapter. - Article: search "linux capabilities vs suid" for clear comparative writeups.