Linux defines approximately 40 distinct capabilities. Each one guards a specific category of operations. When the kernel needs to check whether a process can perform a privileged operation, it does not check if the process has UID 0 โ it checks whether the process has the specific capability associated with that operation.
Understanding which capability covers which operation is essential both for system security hardening (so you can give programs the minimum required capabilities) and for debugging (when a program fails with EPERM, you need to know which capability to add).
These capabilities control what a process can do with files and directories on the filesystem, independently of the normal read/write/execute permission bits.
| Capability | What it Permits |
|---|---|
CAP_CHOWN |
Change a file’s user ID (owner) or change a file’s group ID to a group the process is not a member of. Normally, only root can transfer file ownership. |
CAP_DAC_OVERRIDE |
Bypass file read, write, and execute permission checks entirely (DAC = Discretionary Access Control). This is an extremely powerful capability โ it allows reading/writing any file regardless of permissions. |
CAP_DAC_READ_SEARCH |
Bypass file read permission checks and directory read/execute (search) permission checks. Less powerful than CAP_DAC_OVERRIDE โ cannot bypass write checks. |
CAP_FOWNER |
Ignore permission checks on operations that normally require the process’s file-system UID to match the file’s owner UID. Allows chmod(), utime(), setting i-node flags, setting ACLs, and deleting files from sticky directories on arbitrary files. |
CAP_FSETID |
Modify a file without having the kernel automatically clear the set-user-ID and set-group-ID bits. Also enables setting the set-group-ID bit for a file whose group doesn’t match the process’s GID or supplementary GIDs. |
CAP_LINUX_IMMUTABLE |
Set the append-only and immutable i-node flags on files. Once a file is made immutable, even root cannot modify it without this capability. |
These capabilities govern what a process can do to other processes โ sending signals, changing user/group IDs, and tracing.
| Capability | What it Permits |
|---|---|
CAP_KILL |
Bypass permission checks for sending signals via kill() and sigqueue(). Normally a process can only send signals to processes with the same UID. With this capability, it can signal any process. |
CAP_SETUID |
Make arbitrary changes to process user IDs using setuid(), seteuid(), setreuid(), setresuid(), setfsuid(). Also allows forging user ID when passing credentials via UNIX domain sockets. |
CAP_SETGID |
Make arbitrary changes to process group IDs and supplementary group lists using setgid(), setgroups(), etc. Also allows forging group ID when passing credentials over UNIX domain sockets. |
CAP_SETPCAP |
With file capabilities: add any capability in the bounding set to the inheritable set, drop capabilities from the bounding set, and change securebits flags. Without file capabilities: theoretically grant/remove capabilities from other processes. |
CAP_SETFCAP |
(Since Linux 2.6.24) Set file capabilities on any executable. This is the capability needed to run setcap(8). |
CAP_SYS_PTRACE |
Trace arbitrary processes using ptrace(). Access /proc/PID/environ for any process. Apply get_robust_list() to any process. |
These capabilities control privileged network operations โ binding to low-numbered ports, using raw sockets, configuring network interfaces.
| Capability | What it Permits |
|---|---|
CAP_NET_BIND_SERVICE |
Bind to privileged socket ports (ports below 1024). Essential for services like HTTP (80), HTTPS (443), SSH (22), DNS (53) that run as non-root users. |
CAP_NET_RAW |
Use raw and packet sockets. Required by tools like ping (ICMP), tcpdump, and network scanning tools. This is why ping has historically required elevated privileges. |
CAP_NET_ADMIN |
Perform various network administration operations: setting privileged socket options, enabling multicasting, configuring network interfaces (like ifconfig), and modifying routing tables. |
CAP_NET_BROADCAST |
Perform socket broadcasts and listen to multicasts. (Currently unused in the kernel โ kept for API compatibility.) |
These are the most powerful and broad capabilities. CAP_SYS_ADMIN in particular is sometimes called “the new root” because it covers such a wide range of operations.
| Capability | What it Permits |
|---|---|
CAP_SYS_ADMIN |
An extremely broad capability covering: mounting/unmounting filesystems, setting hostname and domain name, disk quota operations, syslog operations, IPC operations on arbitrary objects, forging credentials, namespace operations (CLONE_NEWNS), device-specific operations, and much more. Often called “the new root.” |
CAP_SYS_TIME |
Modify the system clock using settimeofday(), stime(), adjtime(), adjtimex(). Also allows setting the hardware clock. |
CAP_SYS_BOOT |
Use reboot() to reboot the system and call kexec_load() to load a new kernel image. |
CAP_SYS_MODULE |
Load and unload kernel modules using init_module(), delete_module(), create_module(). A process with this capability can load arbitrary kernel code. |
CAP_SYS_CHROOT |
Use chroot() to set the process’s root directory to an arbitrary directory. Used by container and sandbox implementations. |
CAP_SYS_NICE |
Raise nice value for any process, set real-time scheduling policies (SCHED_RR, SCHED_FIFO), set CPU affinity for arbitrary processes, and control NUMA memory policy for arbitrary processes. |
CAP_SYS_RESOURCE |
Use reserved filesystem space, override disk quota limits, increase hard resource limits, raise message queue byte limits, and bypass various POSIX message queue limits. |
CAP_SYS_RAWIO |
Perform direct I/O port operations using iopl() and ioperm(). Access /proc/kcore, /dev/mem, and /dev/kmem (raw kernel memory). Very dangerous capability. |
CAP_SYS_PACCT |
Use acct() to enable or disable process accounting (recording of process resource usage to a file). |
CAP_SYS_TTY_CONFIG |
Perform virtual hangup of a terminal or pseudoterminal using vhangup(). |
| Capability | What it Permits |
|---|---|
CAP_IPC_LOCK |
Override memory-locking restrictions โ use mlock(), mlockall(), shmctl(SHM_LOCK). Also allows use of huge page mappings. Needed by databases and real-time applications that must lock memory to prevent paging. |
CAP_IPC_OWNER |
Bypass permission checks for operations on System V IPC objects (message queues, semaphores, shared memory segments). |
CAP_LEASE |
(Since Linux 2.4) Establish file leases on arbitrary files using fcntl(F_SETLEASE). File leases allow a process to be notified before another process opens or truncates a file. |
CAP_MKNOD |
(Since Linux 2.4) Use mknod() to create special device files (block devices, character devices, FIFOs, sockets). |
CAP_AUDIT_WRITE |
(Since Linux 2.6.11) Write records directly to the kernel auditing log. |
CAP_AUDIT_CONTROL |
(Since Linux 2.6.11) Enable/disable kernel audit logging, change filtering rules for auditing, and retrieve auditing status and rules. |
CAP_MAC_ADMIN |
(Since Linux 2.6.25) Configure or make state changes for Mandatory Access Control (MAC), as implemented by Linux security modules like SELinux or AppArmor. |
CAP_MAC_OVERRIDE |
(Since Linux 2.6.25) Override MAC policy as implemented by Linux security modules. |
Here is a visual summary grouping all capabilities by their primary domain:
CAP_DAC_OVERRIDE
CAP_DAC_READ_SEARCH
CAP_FOWNER
CAP_FSETID
CAP_LINUX_IMMUTABLE
CAP_LEASE
CAP_MKNOD
CAP_SETFCAP
CAP_NET_BIND_SERVICE
CAP_NET_BROADCAST
CAP_NET_RAW
CAP_SETUID
CAP_SETGID
CAP_SETPCAP
CAP_SYS_PTRACE
CAP_SYS_NICE
CAP_SYS_PACCT
CAP_SYS_BOOT
CAP_SYS_CHROOT
CAP_SYS_MODULE
CAP_SYS_RAWIO
CAP_SYS_RESOURCE
CAP_SYS_TIME
CAP_SYS_TTY_CONFIG
CAP_IPC_OWNER
CAP_AUDIT_WRITE
CAP_AUDIT_CONTROL
CAP_MAC_ADMIN
CAP_MAC_OVERRIDE
Often you want to check whether the current process has a specific capability before attempting a privileged operation. This avoids failing with a cryptic EPERM error. The libcap API provides cap_get_flag() to inspect individual capabilities within any of the three sets.
This program demonstrates checking for CAP_NET_BIND_SERVICE (needed to bind to port 80) and CAP_SYS_TIME (needed to change the system clock), before attempting those operations.
/*
* check_specific_cap.c
*
* Shows how to check for specific capabilities using libcap
* before attempting privileged operations.
*
* Compile:
* gcc -o check_specific_cap check_specific_cap.c -lcap
*
* Usage:
* ./check_specific_cap
* sudo ./check_specific_cap
* sudo setcap cap_net_bind_service+ep ./check_specific_cap
* ./check_specific_cap
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/capability.h>
#include <unistd.h>
/*
* has_capability() - Test if the calling process has a specific
* capability in a specific set (effective, permitted, or inheritable).
*
* @cap_value: The capability to check (e.g., CAP_NET_BIND_SERVICE)
* @cap_set: Which set to check: CAP_EFFECTIVE, CAP_PERMITTED,
* or CAP_INHERITABLE
*
* Returns:
* 1 if the capability is set
* 0 if the capability is NOT set
* -1 on error
*/
int has_capability(cap_value_t cap_value, cap_flag_t cap_set)
{
cap_t caps;
cap_flag_value_t flag_value; /* Will be CAP_SET or CAP_CLEAR */
int result;
/*
* Step 1: Get the capability sets of the current process.
* cap_get_proc() allocates a cap_t structure and fills it
* with the three capability sets from the kernel.
*/
caps = cap_get_proc();
if (caps == NULL) {
perror("cap_get_proc");
return -1;
}
/*
* Step 2: Check the flag for a specific capability in a specific set.
*
* cap_get_flag(cap_t, cap_value_t, cap_flag_t, cap_flag_value_t *)
* - caps: the capability structure from cap_get_proc()
* - cap_value: which capability (e.g. CAP_NET_BIND_SERVICE)
* - cap_set: which set (CAP_EFFECTIVE, CAP_PERMITTED, CAP_INHERITABLE)
* - &flag_value: OUTPUT โ set to CAP_SET or CAP_CLEAR
*
* Returns 0 on success, -1 on error.
*/
if (cap_get_flag(caps, cap_value, cap_set, &flag_value) == -1) {
perror("cap_get_flag");
cap_free(caps);
return -1;
}
result = (flag_value == CAP_SET) ? 1 : 0;
/* Step 3: Always free the cap_t structure when done */
cap_free(caps);
return result;
}
/*
* print_cap_status() - Print a yes/no status line for a capability check
*/
void print_cap_status(const char *cap_name, cap_value_t cap_val)
{
int in_effective = has_capability(cap_val, CAP_EFFECTIVE);
int in_permitted = has_capability(cap_val, CAP_PERMITTED);
printf(" %-30s Permitted: %-3s Effective: %-3s\n",
cap_name,
(in_permitted == 1) ? "YES" : "NO",
(in_effective == 1) ? "YES" : "NO");
}
int main(void)
{
printf("Capability check for PID=%d (UID=%d, EUID=%d)\n\n",
(int)getpid(), (int)getuid(), (int)geteuid());
printf(" %-30s %-14s %-14s\n", "Capability", "In Permitted", "In Effective");
printf(" %s\n", "---------------------------------------------------------------");
/*
* Check capabilities that are commonly needed by system programs.
*
* CAP_NET_BIND_SERVICE: bind to privileged ports (< 1024)
* CAP_SYS_TIME: change system clock
* CAP_NET_RAW: use raw sockets (ping, tcpdump)
* CAP_DAC_OVERRIDE: bypass file permission checks
* CAP_SYS_ADMIN: broad system administration
* CAP_SYS_MODULE: load/unload kernel modules
* CAP_KILL: send signals to any process
* CAP_CHOWN: change file ownership
*/
print_cap_status("CAP_NET_BIND_SERVICE", CAP_NET_BIND_SERVICE);
print_cap_status("CAP_SYS_TIME", CAP_SYS_TIME);
print_cap_status("CAP_NET_RAW", CAP_NET_RAW);
print_cap_status("CAP_DAC_OVERRIDE", CAP_DAC_OVERRIDE);
print_cap_status("CAP_SYS_ADMIN", CAP_SYS_ADMIN);
print_cap_status("CAP_SYS_MODULE", CAP_SYS_MODULE);
print_cap_status("CAP_KILL", CAP_KILL);
print_cap_status("CAP_CHOWN", CAP_CHOWN);
printf("\n");
/*
* Practical example: decide whether to attempt a privileged
* operation based on capability check, rather than just trying
* and catching EPERM.
*/
printf("--- Practical capability-aware decision making ---\n");
if (has_capability(CAP_NET_BIND_SERVICE, CAP_EFFECTIVE) == 1) {
printf(" OK: Can bind to privileged ports (< 1024). Safe to call bind().\n");
} else {
printf(" WARNING: Missing CAP_NET_BIND_SERVICE.\n");
printf(" Cannot bind to ports below 1024 without running as root\n");
printf(" or setting: sudo setcap cap_net_bind_service+ep <program>\n");
}
if (has_capability(CAP_SYS_TIME, CAP_EFFECTIVE) == 1) {
printf(" OK: Can change the system clock. Safe to call settimeofday().\n");
} else {
printf(" WARNING: Missing CAP_SYS_TIME. Cannot change system clock.\n");
}
return 0;
}
Sample output (normal user):
Capability In Permitted In Effective --------------------------------------------------------------- CAP_NET_BIND_SERVICE NO NO CAP_SYS_TIME NO NO ... WARNING: Missing CAP_NET_BIND_SERVICE. Cannot bind to ports below 1024...
After: sudo setcap cap_net_bind_service+ep ./check_specific_cap
CAP_NET_BIND_SERVICE YES YES OK: Can bind to privileged ports (< 1024).
Q1. What is CAP_DAC_OVERRIDE and why is it considered one of the most dangerous capabilities?
CAP_DAC_OVERRIDE allows a process to bypass all Discretionary Access Control (DAC) checks โ file read, write, and execute permissions. A process with this capability can read any file (including /etc/shadow), write to any file, and execute any file, regardless of the file’s permission bits or ownership. It is essentially equivalent to having root for file access purposes, making it one of the most dangerous capabilities to grant unnecessarily.
Q2. Why does the ping command traditionally need elevated privileges, and how do capabilities fix this?
ping uses ICMP, which requires a raw socket. Creating a raw socket requires CAP_NET_RAW. Traditionally, ping was a set-user-ID-root program so it could create the raw socket. With capabilities, you can assign only CAP_NET_RAW to the ping binary using setcap, so it can create raw sockets without having any other root privileges. Modern Linux distributions do this.
Q3. What is the difference between CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH?
CAP_DAC_OVERRIDE bypasses read, write, AND execute permission checks on files and directories. CAP_DAC_READ_SEARCH bypasses only read permission checks on files and read/execute (search) checks on directories. It does NOT bypass write permission checks. So CAP_DAC_READ_SEARCH is less powerful โ a process with it can read arbitrary files but cannot write to them.
Q4. Why is CAP_SYS_ADMIN often called “the new root”?
CAP_SYS_ADMIN covers an exceptionally broad range of privileged operations: mounting/unmounting filesystems, setting hostname and domain name, disk quota operations, namespace creation, syslog operations, IPC management, device-specific ioctls, and more. Its scope is so wide that a process with CAP_SYS_ADMIN has nearly as much power as a full root process, which is why security hardening guides advise extreme caution when assigning it.
Q5. Which capability does setcap(8) itself require to run?
setcap(8) sets file capabilities, which modifies the security.capability extended attribute on an executable file. To do this, a process needs CAP_SETFCAP in its effective set. Normally this means running setcap as root (since root automatically has all capabilities), but in principle you could give a non-root process exactly CAP_SETFCAP if you trust it to manage file capabilities.
Q6. What libcap function do you use to check if a specific capability is set, and what are its arguments?
Use cap_get_flag(cap_t caps, cap_value_t cap, cap_flag_t which_set, cap_flag_value_t *result). You first call cap_get_proc() to get the process’s capability structure, then pass the capability you want to check (CAP_NET_RAW, etc.), which set to check (CAP_EFFECTIVE, CAP_PERMITTED, or CAP_INHERITABLE), and a pointer to receive the result (CAP_SET or CAP_CLEAR). Always call cap_free() afterwards to release the allocated memory.
โ Part 1: Introduction Next: Process & File Capability Sets โ
