Set and Verify Linux File Capabilities with setcap
You will give one executable a narrowly defined file capability, check that the kernel stored it, and remove it again without touching the original program. The examples use setcap from Ubuntu's libcap2-bin package, version 1:2.66-5ubuntu2.4 on the reference machine.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need a shell, the libcap2-bin package, a regular executable file that you can copy, and elevated privileges for the capability change. The reference container does not have the kernel capability needed to write file capabilities, so its attempted write returns an error. That is a useful boundary to recognise, not a reason to weaken the example.
1. Check the command and choose a disposable copy
Start with read-only checks. The package binary is under /usr/sbin on this system; use the path returned by command -v on your own host rather than assuming that a Homebrew or locally built copy is the same version.
$ command -v setcap
/usr/sbin/setcap
$ dpkg-query -W -f='${Package} ${Version}\n' libcap2-bin
libcap2-bin 1:2.66-5ubuntu2.4
$ setcap -h
usage: setcap [-h] [-q] [-v] [-n <rootid>] (-r|-|<caps>) <filename> [ ... ]
Make a copy of a harmless executable so the first experiment cannot alter a system-owned file. This copy is an ordinary, unprivileged file operation:
$ DEMO=/tmp/setcap-demo
$ cp --preserve=mode /usr/bin/true "$DEMO"
$ file "$DEMO"
/tmp/setcap-demo: ELF ... executable ...
The exact file wording varies by architecture. The important checks are that the path exists, it is a regular file, and it is not a symbolic link. Keep the original executable untouched.
2. Understand the capability string
setcap accepts the capability text format documented by cap_text_formats(7). A useful example is cap_net_bind_service=ep: it names the capability that permits binding to privileged TCP or UDP ports, then requests the effective and permitted file sets. This is a specific privilege, not a general replacement for root.
Do not copy a capability from an example merely because its name sounds related to your service. File capabilities change the privilege a program can gain at execution time. Review the program, its arguments, its writable files and its update path before applying one. Grant the smallest capability set that the program genuinely needs.
The = operator resets the named capability's flags before applying the flags that follow. The letters are case-sensitive: e is effective, p is permitted and i is inheritable. A malformed or unsupported capability string is rejected.
3. Apply one capability
This is the first security-sensitive step. It changes extended file metadata and normally needs an administrator account with the kernel's file-capability privilege. Run it only against the disposable copy until you have reviewed the result:
$ sudo setcap cap_net_bind_service=ep "$DEMO"
$ printf 'setcap status: %s\n' "$?"
setcap status: 0
A successful setcap normally prints nothing. The status belongs to the command immediately before printf. If you see Operation not permitted, the account or container lacks permission to write file capabilities. Do not work around that by granting a broader capability or making the file setuid. Check the host's security policy and container restrictions instead.
Checkpoint: if the status was not zero, stop here. There is nothing useful to verify, and the next command should not be treated as proof that the change succeeded.
4. Inspect and verify the stored value
Use getcap to display the metadata. This is a separate command and is safe to run without elevated privileges when the file and directory are readable:
$ getcap "$DEMO"
/tmp/setcap-demo cap_net_bind_service=ep
The path and capability text should match your command. Now ask setcap to verify the value instead of setting it:
$ sudo setcap -v cap_net_bind_service=ep "$DEMO"
$ printf 'verification status: %s\n' "$?"
verification status: 0
Verification status zero means the requested capability is associated with the file. A non-zero result means the stored value differs or the file cannot be inspected. Re-run getcap, check that you named the same file, and inspect permissions before changing anything else.
5. Know the difference between empty and removed
setcap = file sets an explicitly empty capability set. That is not the same as having no file capability at all. An empty set can suppress privilege that might otherwise arrive through ambient and inheritable capability rules when the file is executed. Treat it as an intentional security control, not as a tidy-up command.
To remove the file capability metadata, use -r:
$ sudo setcap -r "$DEMO"
$ getcap "$DEMO"
$ printf 'remove status: %s\n' "$?"
remove status: 0
With no capability displayed, the removal is complete. If you had deliberately set an empty set and need to remove that suppression, -r is the relevant undo operation. Do not replace it with setcap =, which creates the state you meant to remove.
6. Handle common failure modes
- Operation not permitted: the process cannot write file capabilities. This can happen even when
sudosucceeds, particularly in a restricted container withoutCAP_SETFCAP. - Symbolic link or non-regular file: the installed command requires a regular, non-symlink target. Resolve the path and operate on the intended file, not a link in a service directory.
- Verification differs: compare the exact capability text and filename. Do not assume that a zero status from a different command proves the intended file changed.
- Unexpected service behaviour: remove the capability with
sudo setcap -r /path/to/file, then restart the service only if its manager requires a restart. Keep a copy of the original metadata and record the change before production work.
Use -q when a script needs less diagnostic output, but still test the exit status. Use -n ROOTUID only when you understand user-namespace ownership: the capability is then limited to a user namespace with that root user ID. It is not a general-purpose way to avoid host permission checks.
Done means
- The target is a disposable or reviewed regular file, not a system binary chosen by guesswork.
- The capability string names only the privilege the program needs.
getcapshows the expected value andsetcap -vreturns status 0.- You can explain whether the file has a capability, an explicitly empty set, or no capability metadata.
- The rollback command is known:
sudo setcap -r FILE.