← Back to Articles
System Hardening • Systemd Security

Systemd Service Sandboxing: Restricting Process Capability & System Calls

Systemd Service Sandboxing: Restricting Process Capability & System Calls
Systemd Service Process Isolation & System Call Filtering
Executive Summary & Key Security Takeaways
  • FileSystem Protection: Set ProtectSystem=strict and ProtectHome=yes to enforce read-only mount namespaces.
  • Privilege Restriction: Mandate NoNewPrivileges=yes to block suid escalation.
  • Capability Bounding: Restrict Linux capabilities using CapabilityBoundingSet=.
  • System Call Filtering: Block dangerous syscalls via SystemCallFilter=@system-service.

1. The Danger of Unrestricted System Daemons

Traditional Linux daemons running as system services often possess full access to the entire root file system, user home directories, and kernel syscall interfaces.

If an application vulnerability (such as a remote code execution in web application gateways) is exploited, the attacker inherits the full permissions of the daemon, allowing them to read sensitive files in /etc/ or modify system binaries.

Systemd provides built-in process isolation directives using Linux kernel namespaces, cgroups, and seccomp filters without needing Docker or heavy container runtimes.

Sandboxing services at the systemd layer creates isolated execution environments, preventing lateral movement during security incidents.

Operating systems hardening requires continuous verification of process behavior, ensuring that isolated daemons remain tightly bounded within their security domains without degrading performance.

# Inspect security score of an active service unit
systemd-analyze security nginx.service

2. Enforcing Read-Only File System Mount Namespaces

The ProtectSystem directive creates a private mount namespace for the service, mounting system directories as read-only.

Setting ProtectSystem=strict mounts the entire file system hierarchy as read-only for the process, except for explicit paths specified in ReadWritePaths=.

Setting ProtectHome=yes makes /home, /root, and /run/user inaccessible and invisible to the daemon.

PrivateTmp=yes allocates isolated /tmp and /var/tmp directories, preventing symlink attacks and inter-process temporary file snooping.

Operating systems hardening requires continuous verification of process behavior, ensuring that isolated daemons remain tightly bounded within their security domains without degrading performance.

# /etc/systemd/system/myapp.service.d/override.conf
[Service]
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/log/myapp /var/lib/myapp
PrivateTmp=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes

3. Privilege Escalation Prevention via NoNewPrivileges

Attacker payloads often attempt privilege escalation by executing SUID binaries (like sudo or pkexec) from within compromised service processes.

Setting NoNewPrivileges=yes ensures that the process and any child processes it spawns can never gain new privileges through setuid/setgid bits or file capabilities.

This single directive neutralizes an entire class of SUID exploit primitives across all Linux service processes.

Combine with ProtectControlGroups=yes to prevent daemons from altering cgroup resource constraints.

Operating systems hardening requires continuous verification of process behavior, ensuring that isolated daemons remain tightly bounded within their security domains without degrading performance.

# Block SUID privilege escalation
[Service]
NoNewPrivileges=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
MemoryDenyWriteExecute=yes

4. Restricting Linux Capabilities

Linux divides root privileges into distinct capabilities (e.g., CAP_NET_ADMIN, CAP_SYS_ADMIN, CAP_NET_BIND_SERVICE). Unrestricted daemons retain all capabilities.

The CapabilityBoundingSet directive defines an explicit whitelist of capabilities allowed for the service process. All other capabilities are dropped permanently during process startup.

Dropping unnecessary root capabilities ensures that compromised daemons cannot load kernel modules, manipulate network routing tables, or mount raw file systems.

Operating systems hardening requires continuous verification of process behavior, ensuring that isolated daemons remain tightly bounded within their security domains without degrading performance.

# Allow binding low ports (<1024) but drop all other root capabilities
[Service]
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE

5. Filtering Dangerous Kernel System Calls (Seccomp)

Linux exposes over 300 kernel system calls. Most web applications and background services require fewer than 40 syscalls.

The SystemCallFilter directive uses seccomp to block dangerous syscalls like ptrace, reboot, or kexec_load. Systemd provides predefined syscall groups like @system-service and @sandbox.

Restricting available system calls reduces kernel attack surface against zero-day kernel privilege escalation exploits.

Operating systems hardening requires continuous verification of process behavior, ensuring that isolated daemons remain tightly bounded within their security domains without degrading performance.

# Enforce Seccomp System Call Filtering
[Service]
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources
SystemCallErrorNumber=EPERM

6. Automated Security Audit Scores with systemd-analyze

Systemd includes an automated security analyzer that evaluates unit file directives against security best practices and outputs an audit score.

Run systemd-analyze security to inspect all active services on the system and identify unhardened daemons needing isolation overrides.

Apply unit overrides safely using systemctl edit without modifying vendor service files.

Operating systems hardening requires continuous verification of process behavior, ensuring that isolated daemons remain tightly bounded within their security domains without degrading performance.

# Audit all active services
systemd-analyze security

# Reload systemd daemon to apply unit overrides
systemctl daemon-reload
systemctl restart myapp.service

Frequently Asked Questions (FAQ)

How do I inspect the security score of a systemd unit?

Run systemd-analyze security to view an automated 1-10 security audit score.

What happens if a process calls a blocked SystemCallFilter syscall?

By default, seccomp terminates the process with SIGSYS. Setting SystemCallErrorNumber=EPERM returns an Operation Not Permitted error code instead.

Zyekh Abdul Qadir Jailani

Written by Zyekh Abdul Qadir Jailani

Digital Forensics & Incident Response (DFIR) Specialist & Security Researcher specializing in Linux kernel hardening, threat hunting, and system security research.

Utility Security Tools Related to this Article:

Gunakan Environment Variables Formatter dan Cron Expression Generator untuk membantu alur kerja konfigurasi keamanan Anda secara privasi di browser.