dotlinux guide

Security Features You Didn't Know Existed in Linux

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

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., output 1).
  • 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-user to 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 getcap to check binaries (e.g., getcap /usr/bin/ping shows CAP_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 like mount or ptrace.

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 strace to 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.conf to rotate logs (e.g., max_log_file_action = rotate).

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

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 protected to 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:

  1. Start Firefox and browse normally (to build a baseline).
  2. 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 firefox first 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.

References