5.2 Linux Layered Isolation: MAC, seccomp, and Host Hardening
In Discretionary Access Control, the resource owner can modify permissions; once a process acquires that account, it often gains read access to all data associated with that account. Mandatory Access Control, seccomp, and namespaces introduce independent constraints from different perspectives. However, no single mechanism can transform untrusted code into absolute security.
SELinux and AppArmor Limit Object Access
SELinux typically enforces policies based on labels assigned to processes and objects:
atlas_api_t process
can read atlas_config_t
can write atlas_data_t
cannot read shadow_tAppArmor profiles describe file, network, and capability permissions, with file access generally centered on paths. Profiles can attach through executable-path matching or use named profiles and explicit transitions; they are more than executable-path allowlists. The choice between SELinux and AppArmor often depends on the distribution ecosystem, tooling availability, and team expertise, rather than a simple comparison of "which is more secure."
Policies should be derived from actual application data flows. Simply setting SELinux to permissive mode or applying an AppArmor unconfined rule to a process is merely disabling enforcement; blindly generating allow rules in response to denials turns attack patterns into legitimate access patterns.
A sound approach involves first collecting minimal normal behavior in a test environment, crafting narrow policies, and conducting both positive and negative testing before deploying to production enforcement. Production denials must be correlated with version and request context for investigation, rather than automatically dismissed as false positives.
Narrowing the syscall Attack Surface with seccomp
seccomp-BPF executes actions such as allow, errno, kill, or trap based on syscall numbers and limited parameter data. Ordinary seccomp-BPF filters cannot dereference pointer arguments, so they cannot directly enforce "only open /srv/data." This also avoids a class of races in which path memory changes between filtering and execution. File path constraints should instead be enforced jointly by DAC/MAC, namespaces, and secure APIs.
A default-deny allowlist narrows exposure, but is more likely to break compatibility when behavior changes in libc, language runtimes, JIT compilers, or other upgraded components. Profiles must be generated and tested on the target architecture, kernel version, and actual workloads, including edge cases and upgrade scenarios.
Returning EPERM can allow applications to fail gracefully, but it may also conceal attack detection; directly killing the process is more explicit, though it could be exploited by malicious requests for denial-of-service. The choice of action must be balanced against service recovery and monitoring capabilities.
Namespace Changes the View, Not the Kernel
Mount, PID, network, IPC, UTS, and user namespace mechanisms isolate the resources that processes perceive. Containers combine these isolation techniques with cgroup, capability, and LSM (Linux Security Modules) controls.
Containers running on the same host still share the same kernel. Vulnerabilities in the kernel, overly permissive capabilities, exposed host sockets, privileged containers, and unsafe device mappings can all lead to breaches. High-risk, untrusted tenants should use lightweight VMs, microVMs, or isolated nodes to achieve stronger kernel boundaries.
Particularly avoid mounting the container runtime socket into regular applications; this typically grants equivalent management privileges over containers on the host, and often a route to host control. Mounts involving hostPID, hostNetwork, mounting the host root filesystem, and running in privileged mode all require separate, explicit exception approvals.
Cgroups and rlimits Bound Resource Exhaustion
Isolation must also control resource consumption. Attackers could exhaust process counts, memory, CPU, file descriptors, or disk space. cgroup limits resource shares and caps, while rlimit constrains per-process or per-user boundaries; both must work in tandem:
- Request-level limits on body size, decompression, and execution time;
- Separate disk partitions and log rate constraints;
- OOM (Out-of-Memory) policies and service restart backoff;
- Global capacity reservations to prevent all sandboxes from reaching their limits simultaneously.
Setting limits too low turns legitimate peak usage into self-denied service. These thresholds must be determined through stress and degradation testing.
The Kernel and Boot Chain Determine Underlying Trustworthiness
The host baseline includes:
- Using supported kernels and distributions, and tracking security patches and required reboots;
- Minimal installation, disabling unused daemons, protocols, and kernel modules;
- Enforcing Secure Boot or verified boot based on device threat modeling to validate boot components;
- Restricting access to module loading, BPF, perf, debugfs, ptrace, and kernel logging;
- Auditing changes to critical configurations, accounts, services, and packages;
- Time synchronization, remote log forwarding, and integrity protection to prevent attackers from erasing local evidence.
Live patching can reduce some reboot windows, but it does not eliminate the need for restarts in all kernel or user-space updates. The asset inventory must clearly distinguish between "installed version" and "currently running version."
Test the Boundaries Around the Sandbox
A defense composition can be represented as:
Low-privilege UID
+ Minimal capability
+ Read-only or minimal file view
+ MAC policy
+ seccomp syscall allowlist
+ cgroup/rlimit
+ Isolated network and temporary identity
+ Updates, detection, and recoveryTest normal behavior and denials in a disposable isolated environment. Use fake secrets, a test metadata service, and neighboring test processes to check file access, networking, ptrace, mount, and syscall restrictions. Resource-exhaustion tests need small process/disk quotas, an external timeout, and cleanup. Observe behavior at the limit rather than running an unbounded fork bomb or filling a shared host disk. Check both the blocked action and actionable telemetry.
For example, give a transcoding sandbox a read-only input directory and a separate output directory. A normal job should succeed, overwriting input should fail, and reaching the output quota should stop the job while the main service remains responsive. If negative operations also succeed, inspect mount views, MAC enforcement mode, and the process that actually handled the request.
The next chapter examines segmentation, identity-aware access, egress controls, and network detection between hosts.
References
- Linux Kernel, Threat Model
- Linux Kernel, Seccomp BPF
- SELinux Project, SELinux Notebook
- AppArmor, Documentation