Linux is celebrated for its robust security architecture, powering everything from enterprise servers to embedded devices. While tools like iptables, SSH keys, and ufw are household names, the Linux ecosystem hides a wealth of lesser-known security features that provide granular control over system access, isolation, and monitoring. These hidden gems are not just for kernel developers—they are practical tools that harden systems against modern threats, from privilege escalation to data exfiltration. In this blog, we’ll uncover seven such features, explaining how they work, how to implement them with real-world examples, and best practices to integrate them into your security workflow. By the end, you’ll be equipped to leverage these tools to build more resilient Linux environments.
Table of Contents
- 1. Linux Namespaces: Beyond Containers
- 2. Capabilities: Limiting Root’s Power
- 3. seccomp: Restricting System Calls
- 4. Landlock: Path-Based Access Control
- 5. Linux Audit Framework: Monitoring the System
- 6. Protected Symlinks/Hardlinks: Mitigating TOCTOU Attacks
- 7. AppArmor Profiles for Desktop Apps
- Conclusion
- References
1. Linux Namespaces: Beyond Containers
Overview
Linux namespaces are a kernel feature that isolate system resources, enabling processes to run in their own “view” of the system. While famous as the foundation of containers (Docker, Kubernetes), namespaces provide security benefits for everyday use by preventing processes in one namespace from interfering with others.
Key security-relevant namespaces:
- PID Namespace: Isolates process IDs (PIDs), so processes in a namespace cannot see or interact with those outside.
- Mount Namespace: Isolates the filesystem mount table, ensuring processes in a namespace use a separate set of mounts.
- User Namespace: Maps user/group IDs (UIDs/GIDs) between the host and namespace, allowing non-root users on the host to act as “root” inside the namespace (without real root privileges).
Usage Examples
Isolating Processes with unshare
The unshare command creates new namespaces. Let’s isolate a shell in a PID namespace:
# Create a new PID namespace (-p) and fork (-f) to keep the shell running
unshare -fp /bin/bash
Inside the new shell, run ps aux. You’ll only see the bash process and its children (e.g., ps), even though the host has hundreds of processes. To confirm isolation:
- Inside the namespace:
echo $$(e.g., output1). - On the host:
ps aux | grep bash(shows the actual host PID, e.g.,1234).
Mount Namespace Isolation
Create a temporary filesystem isolated from the host:
# Create a mount namespace (-m) and shell
unshare -m /bin/bash
# Mount a tmpfs inside the namespace (not visible on the host)
mount -t tmpfs none /mnt/isolated
# Create a file in the isolated mount
echo "Secret data" > /mnt/isolated/secret.txt
On the host, /mnt/isolated remains empty—the mount is confined to the namespace.
Best Practices
- Combine Namespaces: For strong isolation, use PID + Mount + User namespaces (e.g.,
unshare -pmu /bin/bash). - Avoid Root Inside Namespaces: Use user namespaces to map host UIDs to unprivileged UIDs inside (e.g.,
unshare --map-root-userto act as “root” without real privileges).
2. Capabilities: Limiting Root’s Power
Overview
Linux capabilities split the “all-powerful” root user into granular privileges (e.g., CAP_NET_BIND_SERVICE for binding to ports <1024, CAP_SYS_ADMIN for system administration). This allows services to run with only the privileges they need, reducing attack surface if compromised.
Usage Examples
Dropping Capabilities with setcap
Allow a non-root binary to bind to port 80 (requires CAP_NET_BIND_SERVICE):
# Grant CAP_NET_BIND_SERVICE to a web server binary
sudo setcap 'CAP_NET_BIND_SERVICE=+ep' /usr/local/bin/mywebserver
# Now, run the binary as a non-root user—it can bind to port 80
./mywebserver --port 80
Systemd Service with Limited Capabilities
Restrict a systemd service to only necessary capabilities in /etc/systemd/system/myapp.service:
[Service]
ExecStart=/usr/local/bin/myapp
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SYSLOG # Allow only these
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_SYSLOG # Pass to the process
NoNewPrivileges=yes # Prevent gaining new capabilities
User=appuser # Run as non-root
Reload and restart:
sudo systemctl daemon-reload
sudo systemctl restart myapp
Best Practices
- Least Privilege: Drop all capabilities except those explicitly needed (e.g., a static file server may only need
CAP_NET_BIND_SERVICE). - Audit Capabilities: Use
getcapto check binaries (e.g.,getcap /usr/bin/pingshowsCAP_NET_RAW).
3. seccomp: Restricting System Calls
Overview
seccomp (Secure Computing Mode) restricts the system calls (syscalls) a process can make, blocking dangerous operations (e.g., execve, mount). seccomp-bpf extends this with custom filters, making it a powerful tool to limit attack surface.
Usage Examples
seccomp with Systemd
Restrict syscalls for a service in its systemd unit file:
[Service]
ExecStart=/usr/local/bin/myapp
SystemCallFilter=@system-service @network-io ~@privileged # Allow common syscalls, block privileged
SystemCallArchitectures=native # Restrict to native CPU architecture
NoNewPrivileges=yes
@system-service: Allows syscalls used by standard services.~@privileged: Blocks syscalls likemountorptrace.
seccomp in Docker
Docker uses seccomp by default. Customize with --security-opt seccomp=profile.json:
{
"defaultAction": "SCMP_ACT_ERRNO", # Deny by default
"syscalls": [
{"name": "read", "action": "SCMP_ACT_ALLOW"},
{"name": "write", "action": "SCMP_ACT_ALLOW"},
{"name": "exit", "action": "SCMP_ACT_ALLOW"}
]
}
Run with:
docker run --security-opt seccomp=profile.json myimage
Best Practices
- Whitelist, Don’t Blacklist: Allow only required syscalls (use
straceto audit:strace -c ./myapp). - Test Rigorously: Blocking critical syscalls (e.g.,
mmap) will crash processes.
4. Landlock: Path-Based Access Control
Overview
Landlock (Linux 5.13+) enforces path-based access control, allowing processes to restrict their own access to files/directories. Unlike AppArmor/SELinux, it’s user-space controlled and doesn’t require root, making it flexible for applications.
Usage Example
Restricting a Process to /tmp with Landlock
This C example uses Landlock to allow writing only to /tmp:
#define _GNU_SOURCE
#include <fcntl.h>
#include <linux/landlock.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <unistd.h>
int main() {
// Enable Landlock (requires no new privileges)
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
// Define allowed access rights (read/write/execute files)
struct landlock_ruleset_attr ruleset = {
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_WRITE_FILE |
LANDLOCK_ACCESS_FS_EXECUTE,
};
int ruleset_fd = landlock_create_ruleset(&ruleset, sizeof(ruleset), 0);
// Allow access to /tmp
int tmp_fd = open("/tmp", O_PATH | O_DIRECTORY);
struct landlock_path_beneath_attr path_attr = {
.parent_fd = tmp_fd,
.allowed_access = ruleset.handled_access_fs,
};
landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_attr, sizeof(path_attr));
// Enforce the ruleset
landlock_restrict_self(ruleset_fd, 0);
// Test: Write to /tmp (allowed), /etc (denied)
system("echo 'Allowed' > /tmp/ok.txt"); // Succeeds
system("echo 'Denied' > /etc/not_ok.txt"); // Fails (Permission denied)
return 0;
}
Compile and run:
gcc -o landlock-example landlock-example.c
./landlock-example
Best Practices
- Use Modern Kernels: Landlock improves with each kernel version (e.g., Linux 6.2+ adds
LANDLOCK_ACCESS_FS_REMOVE_DIR). - Combine with seccomp: Restrict syscalls and paths for defense in depth.
5. Linux Audit Framework: Monitoring the System
Overview
The Linux Audit Framework (auditd) logs security-relevant events (e.g., file modifications, syscalls, user logins). It’s critical for incident response and compliance (e.g., PCI-DSS).
Usage Examples
Auditing File Writes
Monitor changes to /etc/passwd (user account data):
# Install auditd (Debian/Ubuntu)
sudo apt install auditd audispd-plugins
# Add a rule to log writes to /etc/passwd
sudo auditctl -w /etc/passwd -p w -k passwd-changes
# Simulate a change (e.g., change a user's shell)
sudo chsh -s /bin/zsh $(whoami)
# Search logs for the event
sudo ausearch -k passwd-changes
Output will show the chsh command, UID, and timestamp.
Auditing SSH Logins
Track failed SSH attempts:
sudo auditctl -a always,exit -F arch=b64 -S execve -F path=/usr/sbin/sshd -k ssh-login
sudo ausearch -k ssh-login | grep "FAILED_LOGIN"
Best Practices
- Avoid Log Spam: Audit only critical files/syscalls (e.g., don’t audit
/tmp). - Rotate Logs: Configure
/etc/audit/auditd.confto rotate logs (e.g.,max_log_file_action = rotate).
6. Protected Symlinks/Hardlinks: Mitigating TOCTOU Attacks
Overview
Time-of-Check to Time-of-Use (TOCTOU) attacks exploit race conditions with symlinks/hardlinks (e.g., a process checks a file’s permissions, then a malicious symlink replaces it). Linux mitigates this with fs.protected_symlinks and fs.protected_hardlinks sysctl settings.
Usage Examples
Enabling Protected Links
Check current settings:
sysctl fs.protected_symlinks fs.protected_hardlinks
Enable persistently (modern distros do this by default):
# Add to /etc/sysctl.d/99-security.conf
echo "fs.protected_symlinks = 1" | sudo tee -a /etc/sysctl.d/99-security.conf
echo "fs.protected_hardlinks = 1" | sudo tee -a /etc/sysctl.d/99-security.conf
# Apply immediately
sudo sysctl -p /etc/sysctl.d/99-security.conf
Best Practices
- Enable by Default: These settings have minimal performance impact and block common TOCTOU vectors.
- Audit sysctls: Use
sysctl -a | grep protectedto verify protections.
7. AppArmor Profiles for Desktop Apps
Overview
AppArmor enforces mandatory access control (MAC) via profiles. While often used for system services (e.g., nginx), it secures desktop apps (e.g., Firefox, Chrome) by restricting access to sensitive files (e.g., ~/.ssh).
Usage Examples
Creating a Firefox Profile
Generate a profile for Firefox using aa-genprof:
# Install AppArmor utils
sudo apt install apparmor-utils
# Start profiling Firefox
sudo aa-genprof firefox
Follow the prompts to:
- Start Firefox and browse normally (to build a baseline).
- Allow/deny access to resources (e.g., block
~/.ssh).
The profile is saved to /etc/apparmor.d/firefox. Enforce it:
sudo aa-enforce firefox
Best Practices
- Test in Complain Mode: Use
aa-complain firefoxfirst to log violations without blocking. - Use Upstream Profiles: Leverage profiles from AppArmor Profiles for common apps.
Conclusion
Linux’s security toolbox extends far beyond firewalls and SSH keys. By leveraging namespaces, capabilities, seccomp, Landlock, auditd, protected links, and AppArmor, you can harden systems against sophisticated attacks. The key is to combine these features for defense in depth—e.g., restrict syscalls with seccomp, paths with Landlock, and monitor with auditd.
Start small: Enable protected links, audit critical files with auditd, and restrict capabilities for a single service. As you gain confidence, expand to more advanced features like Landlock and custom AppArmor profiles. With these tools, you’ll transform your Linux systems from “secure enough” to truly resilient.