DEV Community

Aomi Qaza
Aomi Qaza

Posted on • Originally published at zyekh.com

Systemd Service Sandboxing: Restricting Process Capability & System Calls

Systemd Service Sandboxing: Restricting Process Capability & System Calls

Production guide for sandboxing Linux daemons using systemd security directives like ProtectSystem, SystemCallFilter, and CapabilityBoundingSet.

Executive Summary & Key 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Frequently Asked Questions (FAQ)

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

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

Q: 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.


Originally published at https://zyekh.com/blog/systemd-service-sandboxing-and-security-hardening.html

Top comments (0)