Linux Basics 15: Advanced Permissions — sudoers Wildcards, ACLs And Capabilities

Published 2022-04-23 20:30 Updated 2022-04-23 22:10 1080 words 6 min read ... Page views Handwritten Every word here was typed by me.

Linux Basics 25: Wrapping Up — Self-Audit Checklists And Where To Go DeeperLinux Basics 24: Boot And Rescue — UEFI, GRUB, initramfs And Emergency ModeLinux Basics 23: Containers And Kernel Boundaries — Namespaces, Cgroups And What docker exec DoesLinux Basics 22: Logs And A Debugging Method — Six Steps From Symptom To Root CauseLinux Basics 21: Scheduled Tasks — The Traps Of crontab And systemd TimersLinux Basics 20: Shell Scripting, Part Two — trap, Logging, Idempotence And LockingLinux Basics 19: Shell Scripting, Part One — Quoting, Tests And Exit CodesLinux Basics 18: Performance And Tracing — Where Is The Machine Actually StuckLinux Basics 17: Firewalls — How iptables, nftables, firewalld And ufw RelateLinux Basics 16: SELinux — When Every Permission Is Correct And The Service Is Still DeniedLinux Basics 15: Advanced Permissions — sudoers Wildcards, ACLs And CapabilitiesLinux Basics 14: SSH And Remote Operations — Keys, Permissions And Three Kinds Of TunnelLinux Basics 13: Networking Fundamentals — Troubleshoot From The Bottom UpLinux Basics 12: Disks And Filesystems — From Block Device To Mount PointLinux Basics 11: systemd — units, systemctl And journalctl Done ProperlyLinux Basics 10: Package Management — What apt Actually Does, And The Four Common ErrorsLinux Basics 09: Users And Groups — passwd, shadow And sudoersLinux Basics 08: Environment Variables And Shell Startup Files — Why ssh Cannot Find Your PATHLinux Basics 07: Processes And Signals — The Real Difference Between TERM And KILLLinux Basics 06: Pipelines And Redirection — Three Streams, One Ordering TrapLinux Basics 05: Text Processing — Turning grep/sort/uniq Into Your Analysis ToolkitLinux Basics 04: Permissions And Ownership — rwx Is Not The Same On Files And DirectoriesLinux Basics 03: The Real Semantics Of ls, cp, mv, rm — And The * That The Shell ExpandsLinux Basics 02: Why / Looks Like This, and What An Inode Really StoresLinux Basics 01: Terminals, Shells, and How Commands Are Actually Found
Why a wildcard in sudoers hands over root, how ACLs interact with their mask, what the trailing + in ls -l means, default ACLs that directories inherit, and how capabilities split root into fine-grained powers — including when setcap silently stops working.

What This Chapter Solves

Chapter 04 covered classic rwx, but those nine bits only express three buckets: owner, group, others. Real needs are finer — read/write for one specific person (ACLs), one specific privilege (capabilities), root for one specific command (sudoers, written correctly). This chapter adds those three layers, each with its own failure mode.

1. sudoers: A Wildcard Is A Handover Of Root

# ❌ dangerous: allows restarting *any* service — and "systemctl edit" too
deploy ALL=(root) NOPASSWD: /bin/systemctl restart *
# ✅ pinned to an exact unit, with interactive editing excluded
deploy ALL=(root) NOPASSWD: /bin/systemctl restart nginx.service
deploy ALL=(root) NOPASSWD: /bin/systemctl status nginx.service
sudo -l                     # what the current identity may do (with source files)
sudo -ll                    # long form
sudo visudo -c              # syntax-check every sudoers file
sudo -u deploy sudo -l      # verify the rule as the target identity

Notes:

  • The risk of a wildcard is not semantics but the space of argument combinations. systemctl restart * can be steered into edit to overwrite unit files, or into restarting whatever security boundary you built. /usr/bin/vi * is even more direct — vi can spawn a shell.
  • The safe form lists specific commands with specific arguments, and uses Cmnd_Alias to manage them centrally. Be careful with Defaults env_keep: keeping variables like LD_PRELOAD or PATH is the same as handing over a bypass.

2. ACLs: Permissions For One Specific Person

The nine bits cannot name a third party; ACLs can:

getfacl /srv/app/log              # inspect (including default rules and the mask)
setfacl -m u:alice:rw /srv/app/log        # read/write for alice alone
setfacl -m g:devs:r /srv/app/log          # read-only for a group
setfacl -x u:alice /srv/app/log           # remove one entry
setfacl -b /srv/app/log                   # clear all ACLs
setfacl -R -m u:alice:rwX /srv/app/shared # recursive (capital X: execute only on directories)
setfacl -d -m u:alice:rwX /srv/app/team   # -d = default: future files inherit these rules
getfacl /srv/app/team | sed -n '/^default/,$p'
# result: every new file and subdirectory under team automatically carries alice's entry

mask is the confusing part of ACLs. The mask::rwx line in getfacl caps the effective permissions of all named user and named group entries:

setfacl -m u:alice:rw file
setfacl -m m::r file          # mask allows r only → alice effectively gets r (shown as #effective:r--)

So when “I granted rw but it does not apply”, read the mask first. Either set it explicitly (setfacl -m m::rw) or use -n so setfacl does not recompute it.

One signal worth knowing: a + at the end of the mode column in ls -l means the file carries ACLs.

ls -l /srv/app/log     # -rw-rw----+  ← the + means “there is more than the nine bits show”
getfacl /srv/app/log   # the whole story

3. Capabilities: Splitting Root Into Pieces

Root can do everything because it carries a whole set of capabilities (cap_net_bind_service, cap_sys_admin, cap_chown, and others). Split them out and many tasks stop needing root:

getcap -r / 2>/dev/null | head            # which files carry capabilities
getcap /usr/bin/ping                       # the classic: ping needs cap_net_raw
sudo setcap cap_net_bind_service=+ep /usr/local/bin/myapp   # bind ports below 1024
getcap /usr/local/bin/myapp
sudo setcap -r /usr/local/bin/myapp        # remove it
CapabilityEffectTypical use
cap_net_bind_servicebind ports below 1024let a non-root process listen on 80/443
cap_net_rawraw socketsping, packet capture
cap_sys_adminmounts and other heavy rightscontainer tooling — half of root, grant rarely
cap_chownchange file ownershipbackup and sync tools

Notes on setcap, two traps:

  1. A package upgrade wipes the capability: replacing the binary loses the setcap setting (the xattr is not guaranteed to survive), so this action belongs in deployment automation — otherwise it silently stops working after the next update.
  2. For services, prefer systemd’s AmbientCapabilities= / CapabilityBoundingSet= over tagging a binary: it is more controllable, more auditable, and configuration-as-code friendly.

4. Where Each Tool Belongs (One Table)

ToolGranularityTypical problemWhen to use
chmod/chownowner / group / othersmissing x on a directory; 644 filesdaily work (chapter 04)
ACLa specific user or group“only alice may read and write this”shared directories, collaboration
capabilitiesa specific privilege“non-root binding 80”dropping service privilege, containers
SELinuxa specific label (context)“the service cannot read its own directory”mandatory access control (next chapter)
sudoerscommand-level elevation“restarting exactly this one service”operations delegation

5. Hands-On Checklist

mkdir -p /tmp/acl && touch /tmp/acl/f
setfacl -m u:"$(whoami)":rw /tmp/acl/f; getfacl /tmp/acl/f | head    # 1. add an ACL entry
ls -l /tmp/acl/f                                        # 2. the trailing +
setfacl -m m::r /tmp/acl/f; getfacl /tmp/acl/f | grep -E 'mask|effective'  # 3. the mask at work
setfacl -b /tmp/acl/f; ls -l /tmp/acl/f                 # 4. clearing it removes the +
sudo setcap cap_net_bind_service=+ep /usr/bin/env; getcap /usr/bin/env  # 5. set and read back (test box)
sudo setcap -r /usr/bin/env                              # 6. remove immediately
sudo visudo -c                                           # 7. sudoers syntax self-check

Summary

  • A wildcard in sudoers hands over root; pin rules to exact commands and arguments, then self-check with visudo -c.
  • ACLs grant permissions to specific users and groups; the mask caps named entries — when a grant “does not apply”, read the mask; a trailing + in ls -l signals ACLs.
  • Default ACLs (setfacl -d) make new files in a directory inherit permissions — the right answer for shared directories.
  • Capabilities split root into fine-grained powers (cap_net_bind_service, cap_net_raw); setcap settings are lost on package upgrades.
  • Four layers: chmod (three buckets) → ACL (to a person) → capabilities (to a privilege) → SELinux (to a label).

Next Up

SELinux: the enforcing/permissive/disabled modes, what a context looks like in ls -Z, the difference between chcon, restorecon and semanage fcontext, boolean switches, and the standard procedure for “the service cannot read its own directory”.

Written by Handwritten

If you enjoyed this, leave a comment~

Loading...