User & Group Management
UID/GID, privilege escalation, setuid binaries, and PAM authentication in Linux
User & Group Management
Every process on a Linux system runs as a specific user and group. When you log into a server, you authenticate as a user identity that determines what files you can access, what operations you can perform, and what resources you can consume. This identity model is the foundation of Linux security, yet many administrators treat it as magical incantation rather than engineered system.
Understanding user and group management goes beyond knowing that root can do anything. It requires grasping the mechanics of identity transition, the security implications of privilege escalation mechanisms, and the flexibility of Pluggable Authentication Modules (PAM). When something goes wrong with permissions, often these fundamentals that reveal the root cause.
This post dissects the user and group system from the kernel perspective, examines privilege escalation pathways and their risks, and explores how authentication fits together through PAM.
Overview
Linux identifies users and groups by numeric IDs: User ID (UID) and Group ID (GID). Human-readable names like root, www-data, or pronit are conveniences that map to these numbers. The kernel does not care about names; it only cares about IDs.
UID 0 is the superuser (root) with unrestricted privileges. UID 1-999 are system users, reserved for system services and daemons. UID 1000+ are regular users, typically human accounts. This division is convention, not enforcement. GIDs follow similar patterns with the primary group 0 (root) and system groups in the 1-999 range.
Processes inherit UID and GID from their parent. When you log in, the login program authenticates you and spawns a shell running with your UID. Every command you run, every file you create, carries your identity. This identity determines whether you can read /etc/shadow, bind to port 80, or modify /var/log.
When to Use / When Not to Use
Deep understanding of user and group management becomes critical when designing multi-user systems, troubleshooting permission issues, securing servers against privilege escalation, or configuring single sign-on systems. System administrators, security engineers, and DevOps professionals need this knowledge for daily tasks.
Understanding these mechanisms helps diagnose why a service cannot access a resource, why privilege escalation succeeded or failed, or why a user’s login attempt was rejected. It enables proper configuration of shared systems, container security contexts, and automated deployment pipelines.
For single-user development machines, the default configuration suffices. The system is already set up correctly for your use case. However, understanding still matters when you encounter permission errors or need to run services on privileged ports.
Architecture or Flow Diagram
graph TD
subgraph Authentication
A[User Login] --> B{PAM Authentication}
B -->|Success| C[ PAM Account Check]
B -->|Failure| D[Login Rejected]
C -->|OK| E[Set UID/GID]
C -->|Fail| D
E --> F[Spawn Shell]
end
subgraph Privilege Escalation
G[Regular Process] --> H{Is setuid?}
H -->|No| I[Same UID/GID]
H -->|Yes| J[New UID/GID]
J --> K[Capability Check]
K -->|Has CAP| L[Privileged Op]
K -->|No CAP| M[EPERM Denied]
end
subgraph File Access
N[Process UID/GID] --> O{Check ACL/Permissions}
O -->|Owner Match| P[Owner Permissions]
O -->|Group Match| Q[Group Permissions]
O -->|Neither| R[Other Permissions]
P --> S{Execute Access}
Q --> S
R --> S
S -->|Yes| T[Allow Operation]
S -->|No| U[Permission Denied]
end
style D stroke:#ff6b6b
style M stroke:#ff6b6b
style U stroke:#ff6b6b
The diagram shows how authentication, privilege escalation, and file access interrelate. PAM handles initial authentication and can set the process identity. Setuid binaries run with different UIDs. File access checks the process UID/GID against file permissions at the moment of access.
Core Concepts
UID/GID Types
Linux distinguishes several UID categories within the kernel:
Real UID (RUID): The UID of the user who started the process. Always inherited from parent; only changed on login.
Effective UID (EUID): The UID used for permission checks. This is what matters for file access, capability checks, and privileged operations. Setuid programs run with the file owner’s EUID.
Saved UID (SUID): Allows a process to temporarily drop and restore privileges. When a setuid program changes its EUID, the original EUID is saved here.
Filesystem UID: Used on Linux for permission checks on filesystem operations. Usually identical to EUID, but can differ in certain container scenarios with user namespaces.
# View all UIDs for a process
id
# View specific process UIDs
cat /proc/$$/status | grep -E '^Uid|^Gid'
# Example output:
# Uid: 1000 1000 1000 1000
# Gid: 1000 1000 1000 1000
# (Real EUID Saved-UID Filesystem-UID)
Setuid and Setgid Binaries
Setuid (set user ID) is a permission bit that changes the effective UID of a process when executing a file. When you run /bin/passwd, it runs as root even if you are a regular user, because passwd has the setuid bit set. This allows users to modify their own password in /etc/shadow, which requires root privileges.
# Setuid on a binary
chmod u+s /usr/bin/program
# or
chmod 4755 /usr/bin/program
# Setgid on a binary (runs with group permissions)
chmod g+s /usr/bin/program
# or
chmod 2755 /usr/bin/program
# View setuid files
find /usr -perm /4000 -ls
# View setgid files
find /usr -perm /2000 -ls
Setgid works similarly but changes the effective GID. Setgid binaries are less common but important for group-accessible resources like write command that allows users to send messages to each other’s terminals.
PAM (Pluggable Authentication Modules)
PAM provides a flexible framework for authentication in Linux. Instead of hardcoding authentication logic, programs use PAM through a standard API. System administrators configure which PAM modules to use, enabling everything from simple password authentication to smartcard verification or LDAP integration.
# PAM configuration for a service
/etc/pam.d/sshd
# Typical structure:
# auth - authentication modules
# account - account expiration, access restrictions
# password - password quality and changing
# session - actions around session management
# Example /etc/pam.d/login
auth required pam_securetty.so
auth required pam_stack.so service=system-auth
auth required pam_nologin.so
account required pam_time.so
account required pam_stack.so service=system-auth
password required pam_stack.so service=system-auth
session required pam_selinux.so close
session required pam_selinux.so open
session required pam_stack.so service=system-auth
session optional pam_console.so
Production Failure Scenarios + Mitigations
Scenario: Password Authentication Failures
Problem: Users cannot log in despite correct credentials. PAM configuration or password database issues.
Symptoms: Login attempts fail, secure log shows PAM errors, users locked out.
Mitigation: Check PAM configuration syntax. Verify password database (local /etc/shadow or remote like LDAP) is accessible. Ensure NSS is correctly configured to resolve user information. Test authentication module independently.
# Test PAM authentication
authenticate username password
# Check password database
getent shadow username
# Verify NSS configuration
cat /etc/nsswitch.conf | grep -E 'passwd|group'
# Check if account is locked
passwd -S username
Scenario: Privilege Escalation via Sudo Misconfiguration
Problem: Users can execute commands as root or other users due to overly permissive sudo rules.
Symptoms: Unauthorized root access, security audit failures, unexpected privilege changes.
Mitigation: Audit sudoers file carefully. Follow principle of least privilege. Use specific command paths rather than allowing any command. Avoid NOPASSWD in production. Regularly review who has sudo access.
# View sudo rules for current user
sudo -l
# Safely edit sudoers
visudo
# Example restrictive rule
username ALL=(webapp:webapp) /bin/systemctl status webapp
# Check sudo access logs
grep sudo /var/log/secure
grep sudo /var/log/auth.log
Scenario: setuid Binary Exploitation
Problem: Vulnerable setuid binary allows privilege escalation to root.
Symptoms: Unexpected root shells, suspicious setuid binaries with world write access, privilege escalation alerts.
Mitigation: Remove unnecessary setuid binaries. Keep system updated. Use file integrity monitoring on critical binaries. Audit setuid binaries regularly.
# Find potentially dangerous setuid binaries
# World-writable setuid binaries
find / -perm -4007 -type f 2>/dev/null
# Not owned by root
find / -perm -4000 ! -user root -type f 2>/dev/null
# Monitor for changes
rpm -Va | grep -E '^\.\.5.*s'
Trade-off Table
| Privilege Mechanism | Security Level | Flexibility | Management Complexity |
|---|---|---|---|
| Standard sudo | Good | High | Medium |
| Sudo with NOPASSWD | Lower | High | Low |
| Polkit | Good | Medium | Medium |
| Polkit without password | Lower | Medium | Low |
| setuid binaries | Varies | Low | High (binary vulns) |
| capabilities | High | High | High |
| Authentication Module | Use Case | Security | Complexity |
|---|---|---|---|
| pam_unix | Local password auth | Basic | Low |
| pam LDAP | Network user auth | High (with TLS) | Medium |
| pam_sss | Active Directory/LDAP | High | Medium |
| pam_sepermit | Two-factor auth | High | Medium |
| pam_access | Host-based access | Medium | Low |
| UID Management | Container Support | Performance | Security |
|---|---|---|---|
| Host UID/GID | Poor | Good | Lower |
| User namespaces | Excellent | Good | Higher |
| Remapped UID (LXD style) | Good | Good | Medium |
Implementation Snippets
Creating a Service Account with Restricted Access
#!/bin/bash
# Create service account with minimal privileges
# Create system account (no login shell)
useradd -r -s /sbin/nologin \
-c "Web Application Service" \
-d /var/www/webapp \
webapp
# Set ownership
chown -R webapp:webapp /var/www/webapp
# Restrict login
usermod -L webapp # Lock password
chsh -s /sbin/nologin webapp # No shell access
# Verify
id webapp
passwd -S webapp
Configuring Sudo Access
# /etc/sudoers.d/webapp
# Allow webapp user to manage their service
webapp ALL=(systemd:webapp) /bin/systemctl status webapp.service
webapp ALL=(systemd:webapp) /bin/systemctl start webapp.service
webapp ALL=(systemd:webapp) /bin/systemctl stop webapp.service
webapp ALL=(systemd:webapp) /bin/systemctl restart webapp.service
# Allow reading logs
webapp ALL=(root) /bin/less /var/log/webapp/*.log
# Never allow
webapp ALL=(ALL) ALL # DISALLOWED
PAM Configuration for Two-Factor Authentication
# /etc/pam.d/sshd
# Require both password and OTP
auth required pam_sepermit.so
auth required pam_env.so
auth required pam_unix.so try_first_pass
auth optional pam_permit.so
auth required pam_google_authenticator.so nullok
account required pam_time.so
account required pam_unix.so
account optional pam_permit.so
account required pam_time.so
password required pam_unix.so shadow nullok try_first_pass use_authtok
password optional pam_permit.so
session required pam_selinux.so close
session required pam_selinux.so open
session required pam_unix.so
session optional pam_permit.so
Checking Process Privileges
#!/usr/bin/env python3
"""Check process privileges and capabilities."""
import os
import pwd
def read_status(pid):
"""Read /proc/PID/status for privilege info."""
status_path = f'/proc/{pid}/status'
result = {}
with open(status_path) as f:
for line in f:
if line.startswith(('Uid', 'Gid', 'Cap')):
result[line.split(':')[0]] = line.split(':', 1)[1].strip()
return result
def uid_to_name(uid):
"""Convert UID to username."""
try:
return pwd.getpwuid(int(uid)).pw_name
except KeyError:
return uid
def main():
pid = os.getpid()
status = read_status(pid)
print(f"Process {pid} Privileges")
print("=" * 40)
# Parse UIDs
uids = status['Uid'].split()
print(f"Real UID: {uids[0]} ({uid_to_name(uids[0])})")
print(f"Effective UID: {uids[1]} ({uid_to_name(uids[1])})")
print(f"Saved UID: {uids[2]}")
# Parse GIDs
gids = status['Gid'].split()
print(f"Real GID: {gids[0]}")
print(f"Effective GID: {gids[1]}")
print(f"Saved GID: {gids[2]}")
# Parse capabilities
caps = status.get('CapPermitted', '0')
print(f"\nCapabilities: {caps}")
# Check if running as root
if uids[1] == '0':
print("\nRunning as EUID root!")
else:
print(f"\nRunning as EUID {uid_to_name(uids[1])}")
if __name__ == '__main__':
main()
Observability Checklist
User and Group Activity Monitoring:
- Monitor
/var/log/secureor/var/log/auth.logfor authentication events - Track sudo usage patterns
- Alert on repeated failed login attempts
- Monitor for UID 0 logins from unexpected sources
Privilege Escalation Detection:
- File integrity monitoring on setuid binaries
- Alert on new setuid binaries
- Monitor for unexpected processes running as root
- Track sudo configuration changes
Account Status Monitoring:
- Check for accounts with empty passwords
- Identify accounts with NOPASSWD sudo rules
- Monitor for newly created accounts
- Track account expiration violations
Key Commands for Monitoring:
# View recent logins
last -20
# Failed login attempts
lastb -20
# Who is currently logged in
who
# Sudo command logging
grep sudo /var/log/secure | tail -30
# Check for root-owned processes running from unusual locations
ps aux | grep '^[a-z]* root' | grep -v /usr/sbin | grep -v /sbin
Security/Compliance Notes
Password Policy Enforcement: PAM modules like pam_pwquality enforce password complexity requirements. Configure minimum length, complexity, and rotation policies. Enable password hashing with strong algorithms (SHA-512, yescrypt).
Account Lockout: Prevent brute force attacks by locking accounts after failed attempts. Use pam_faillock to temporarily lock accounts.
# /etc/security/faillock.conf
deny = 5
unlock_time = 900
fail_interval = 600
Session Timeout: Force logout of idle sessions to prevent unauthorized access left behind. Configure TMOUT in bash profile or use pam_session timeout.
Audit Requirements: Many compliance frameworks require logging of authentication events, privilege changes, and administrative actions. Ensure your logging captures these events and retains them appropriately.
Common Pitfalls / Anti-patterns
World-writable setuid Binaries: Setting chmod 4777 on a setuid binary allows any user to become any other user. Always use restrictive permissions like chmod 4755 (root-owned setuid binary).
Misunderstanding Sudo NOPASSWD: Using NOPASSWD for convenience in production enables anyone with account access to run privileged commands without authentication. Reserve NOPASSWD for specific automated scripts with limited scope.
UID Collisions in Containers: When mapping host UIDs to container UIDs, ensure no collision with existing container UIDs. A container UID 0 mapping to host UID 100000 effectively gives container root access to host resources.
Stale sudo Tokens: Sudo caches credentials for 15 minutes by default. A session left unattended remains privileged. Consider timestamp_timeout=0 to require password for each sudo command, or set a shorter timeout.
PAM Misconfiguration: Incorrect PAM configuration can lock everyone out of the system or disable authentication entirely. Always test PAM changes from a separate session before closing your current one.
Quick Recap Checklist
- Linux uses numeric UID/GID for all permission checks
- Real, Effective, and Saved UIDs serve different purposes
- Setuid binaries allow privilege escalation for specific programs
- PAM provides flexible authentication through modular configuration
- Sudo enables controlled privilege escalation without sharing root password
- File permissions (rwx) and ACLs control file access
- Capabilities provide fine-grained privilege control
- User namespaces map UIDs for container isolation
- Monitoring authentication and privilege events is essential
- Principle of least privilege applies to all identity decisions
Interview Questions
Real UID (RUID) is the original user who started the process, inherited from parent and only changed on login. Effective UID (EUID) is used for permission checks and determines what operations the process can perform. Saved UID (SUID) allows a process to temporarily drop and restore privileges; when a setuid program changes its EUID, the original is saved here for later restoration.
A setuid binary has a permission bit that causes it to run with the file owner's effective UID rather than the caller's. When you run /bin/passwd as a regular user, it runs as root, allowing it to modify /etc/shadow. Security risks include vulnerabilities in setuid binaries that can be exploited for privilege escalation. Remove unnecessary setuid binaries, keep systems updated, and use file integrity monitoring on critical binaries.
Pluggable Authentication Modules (PAM) provides a flexible framework for authentication in Linux. Instead of hardcoding authentication logic, programs use PAM through a standard API. Administrators configure which modules to use, enabling everything from simple password auth to smartcard verification or LDAP integration. PAM allows centralized control over authentication policy without modifying applications.
Least privilege means granting a user or process only the minimum permissions required for its function. Service accounts should run with specific UIDs and no login capability. Sudo rules should specify exact commands rather than allowing ALL. Capabilities should be dropped except those explicitly required. This limits damage from compromise and reduces attack surface.
When mapping host UIDs to container UIDs, if container UID 0 maps to host UID 100000, the container's root effectively has host user 100000's permissions. If host UID 100000 owns files, the container root can modify them. A container escape plus UID mapping can give the attacker read/write access to host files owned by that UID. User namespaces mitigate this by providing truly isolated UID mappings.
During execve(), the effective UID and saved UID behave differently depending on whether the executable has a setuid or setgid bit. If the binary has a setuid bit, the kernel sets the process's effective UID to the file's owner UID before executing the new program. The saved UID is updated to copy the effective UID at the moment of execve, so the original caller's UID is preserved for potential privilege dropping.
For setgid binaries, the effective GID similarly changes to the file's group owner. Capabilities are recalculated after execve based on the new effective UID/GID and the file's capability sets. This behavior is why a setuid program can perform privileged operations while still being able to restore the original user's privileges later using the saved UID.
NSS (Name Service Switch) and PAM (Pluggable Authentication Modules) serve different purposes despite both being modular authentication infrastructure. NSS resolves names to values: it maps usernames to UIDs (getpwnam()), group names to GIDs (getgrnam()), and hostnames to IP addresses. NSS uses a stacked configuration in /etc/nsswitch.conf to query sources like files, DNS, LDAP, or NIS in order.
PAM handles the authentication and session setup itself: verifying passwords, checking account validity, managing session setup and cleanup. A program uses PAM to authenticate a user (Is this password correct?) and to establish the session (Set up environment, create home directory). NSS is consulted by PAM to look up the user's UID, GID, and home directory after successful authentication.
Polkit (PolicyKit) and sudo serve different privilege escalation models. Sudo grants specific commands to specific users with full root privileges for those commands. Polkit provides a framework for authorizing actions based on a policy database, where programs (like GNOME's system tools) query whether the current user is authorized to perform an action, and Polkit can prompt for authentication or check session activity.
Polkit's strength is fine-grained, context-aware authorization: it can allow a user to mount disks without a password when they are physically logged into the console, but require a password over SSH. It separates authentication (who are you?) from authorization (are you allowed to do this?). Sudo is simpler and more direct, making it better suited for server environments where specific command grants are needed.
Password hashes in /etc/shadow use configurable algorithms: DES (old, 56-bit key, trivially crackable), MD5 (salt + MD5, too fast for modern GPUs), SHA-256 and SHA-512 (salted, configurable rounds), and yescrypt/bcrypt/argon2 (memory-hard, resistant to GPU and ASIC attacks). The /etc/login.defs or PAM configuration specifies which algorithm is used for new passwords.
Weak hashing algorithms expose passwords to offline cracking attacks if the shadow file is leaked. DES and MD5 are considered broken for password storage. Modern systems should use SHA-512 with a high round count (500000+) or yescrypt/argon2 which are designed to resist brute-force attacks by requiring significant memory and computation. The cracklib library enforces password complexity before hashing.
PAM's pam_faillock module tracks failed authentication attempts per user in /var/run/faillock/ and locks the account after a configurable number of failures within a time window. When the account is locked, any login attempt (even with the correct password) returns authentication failure until the lockout expires or an administrator clears it.
Tradeoffs: lockout prevents brute-force attacks but creates a denial-of-service vector where an attacker can repeatedly try wrong passwords to lock out legitimate users. Some deployments use progressive delays instead of hard lockout. Long lockout durations increase security but also increase support burden. For SSH with key-based authentication, the sshd_config MaxAuthTries limits should be combined with PAM lockout to prevent both password brute-force and key-guessing attacks.
ACLs (Access Control Lists) extend traditional Unix permissions (owner/group/other with rwx) to support arbitrary lists of users and groups with specific permissions. POSIX ACLs use setfacl and getfacl commands, storing additional entries alongside the traditional permission bits. Each file can have a default ACL (inherited by new files in the directory) and an access ACL (effective permissions).
Extended ACL entries specify a qualifier (user or group UID/GID), a permissions set (rwx), and apply to named users, named groups, or the mask (which limits maximum permissions for named entries and group entries). ACLs solve the limitation where a file can only belong to one group and a user can only belong to a fixed number of groups (typically 16-32 per system).
UID 0 (root) bypasses most permission checks in the kernel, but not all. Root can bypass file permission checks (read, write, execute) due to the inode-level check, but certain security mechanisms are independent of UID: SELinux or AppArmor mandatory access controls apply even to root, immutable files cannot be modified even by root (chattr -i), and certain system calls have additional capability checks even for UID 0.
Files with the immutable flag (chattr +i) cannot be deleted or modified regardless of UID 0, requiring the flag to be removed first. The CAP_SYS_RESOURCE capability (which UID 0 typically has) controls overrides of resource limits, core dump size, and filesystem quotas. Understanding that root is not absolutely supreme clarifies why capability dropping and MAC systems add defense in depth.
The sticky bit (chmod +t or 1000 in octal) on a directory prevents users from deleting or renaming files they do not own within that directory. Classic example: /tmp has the sticky bit, allowing all users to create files there but preventing User A from deleting User B's file.
Without the sticky bit, any user with write permission on a directory could delete any file in it (since directory write permission controls deletion, not file write permission). The sticky bit adds a secondary check: the kernel verifies that the user attempting deletion either owns the file or owns the directory. On modern Linux, /tmp without the sticky bit would allow any user to delete any other user's files, causing obvious security and privacy issues.
useradd -r (or useradd --system) creates a system account with a UID in the range 1-999 (or the configured system account range). System accounts are not typically used for human login and are intended for running services. They typically have no valid login shell (/sbin/nologin or /usr/sbin/nologin) and no password.
A regular user account (useradd without -r) gets a UID starting at 1000 (or the configured range minimum). Regular users have password-enabled login capability and typically have functional shells like /bin/bash. Using system accounts for services follows the principle of least privilege: a compromised service running as UID 1-999 has no login capability and limited filesystem access by default.
When a process attempts to access a file, the kernel checks the process's effective UID and GID against the file's owner UID and owner GID. If the process's effective UID matches the file's owner UID, owner permissions apply. If not, the kernel then checks if any of the process's supplementary group IDs (not just the effective GID) match the file's owner GID, applying group permissions on a match.
A process can belong to up to 32 groups (NGROUPS_MAX, typically 65536 in modern kernels, queried with sysconf(_SC_NGROUPS_MAX)). When checking group membership, the kernel compares each supplementary group ID against the file's owner GID. If no group matches, other permissions apply. The groups command and getgrouplist() show which groups a user belongs to, reflecting both the primary group and supplementary groups from /etc/group.
Both fork() and vfork() create child processes that inherit the parent's real, effective, and saved UIDs. However, vfork() was designed for performance in scenarios where the child would immediately call execve(), avoiding the full copy-on-write page table duplication of fork(). The child shares the parent's memory entirely until execve, which requires careful synchronization.
In modern Linux, fork() with copy-on-write is efficient enough that vfork()'s performance advantage is negligible, and vfork()'s strange semantics (the parent is blocked until the child calls execve or exit) make it a footgun. vfork() is still present for POSIX compliance and a few specialized cases, but fork() is the correct choice for nearly all scenarios. UID inheritance is identical in both.
LDAP authentication integrates through two separate mechanisms. PAM (pam_ldap or pam_sss) handles the authentication step: verifying the password by binding to the LDAP server with the user's credentials. NSS (nss_ldap or nsswitch.conf entries) handles name-to-UID resolution: when a program calls getpwnam("alice"), NSS queries LDAP to find Alice's UID, GID, home directory, and shell.
The sssd daemon (System Security Services Daemon) provides a unified interface to multiple identity providers (LDAP, Active Directory) with caching for offline login and reduced LDAP server load. PAM configuration in /etc/pam.d/common-auth stacks authentication modules so that LDAP is consulted along with local /etc/passwd and /etc/shadow.
The kernel maintains a cred structure for each process containing: uid (real UID), gid (real GID), suid (saved UID), sgid (saved GID), euid (effective UID), egid (effective GID), fsuid (filesystem UID used for permission checks), fsgid (filesystem GID), plus capability sets (permitted, effective, inheritable, bounding). All threads in a process share the same cred structure.
The /proc/PID/status shows these as Uid and Gid lines with four values each (real, effective, saved-set, filesystem). The capability value shows the permitted capability bitmask. Process credentials are checked by the kernel at every permission-sensitive operation, and the commit_creds() function atomically replaces a process's credentials.
The Linux keyctl facility provides a kernel-managed keyring that can store arbitrary data (including credential information) with access control based on process UID/GID. Processes can use keyctl_read() and keyctl_write() to pass data between processes with matching UIDs, without the data being visible to other users. This is used by some session management systems to store session credentials securely.
The session keyring (keyctl join_session_keyring) links a keyring to a login session. When a process authenticates (via PAM or similar), credentials can be stored in the session keyring that all processes in the session can access. This allows credential propagation across fork()/execve() without storing sensitive data in environment variables or files.
Setuid root binaries grant full root privilege to any process that executes them, regardless of what the process actually needs. A vulnerable setuid binary can be exploited to spawn a root shell, giving the attacker complete control. The attack surface is the entire binary, not just the specific privileged operation.
Capabilities split root privileges into ~40 discrete units (CAP_NET_BIND_SERVICE, CAP_SYS_TIME, etc.), allowing a process to receive only the specific privileges it requires. A process with only CAP_NET_BIND_SERVICE cannot spawn a root shell even if it is exploited. Capabilities use file-based capability sets: a capability-aware binary's effective capability set at execve is determined by the file's permitted and inheritable sets and the process's inheritable set. This follows the principle of least privilege at a granular level.
Further Reading
- Concurrency Fundamentals — The problem space and why synchronization is needed
- Mutex Implementation — How mutexes are implemented in userspace and kernel
- Semaphores — Counting semaphores for resource management
- Readers-Writer Locks — Optimizing for read-heavy workloads
- Lock-Free Structures — Advanced techniques for highly concurrent systems
Conclusion
Linux user and group management through UID/GID, setuid binaries, PAM, and capabilities forms the identity foundation for system security. Real, Effective, and Saved UIDs each play a distinct role in how privilege transitions happen. Setuid binaries and sudo let you escalate privileges for specific tasks without sharing root passwords. PAM plugs into authentication flexibly, which is why it handles enterprise setups like LDAP or smartcards without touching application code. For deeper study, look at how user namespaces map container UIDs, how Polkit separates authorization from authentication, and how identity management integrates with directories like Active Directory.
Category
Related Posts
ASLR & Stack Protection
Address Space Layout Randomization, stack canaries, and exploit mitigation techniques
Assembly Language Basics: Writing Code the CPU Understands
Learn to read and write simple programs in x86 and ARM assembly, understanding registers, instructions, and the art of thinking in low-level operations.
Boolean Logic & Gates
Understanding AND, OR, NOT gates and how they combine into arithmetic logic units — the building blocks of every processor.