Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Sandboxing & Mandatory Access Control

InterGenOS confines what software can do, not just who is allowed to run it. Two layers work together: a mandatory access control (MAC) policy that constrains every system daemon regardless of its user, and per-service sandboxing that removes the kernel interfaces, file paths, and system calls a service has no legitimate need to touch.

Where a confinement directive conflicts with convenience, confinement wins. The goal is a machine you understand, can modify, and can trust: nothing here is hidden behind a vendor toggle or applied silently after the fact.

This page describes the behavior that ships today in InterGenOS 1.0-dev (build id v1.0-dev1). It is a companion to the Hardening Baseline, which covers the full default posture.

Hardened from boot, not after

InterGenOS does not rely on post-installation hardening scripts. The environment is confined from the moment the system boots. The controls described below are defaults baked into the system services and policies that ship in the image, not options you enable later.

Mandatory Access Control: AppArmor in enforce mode

InterGenOS uses AppArmor as its mandatory access control layer. An AppArmor profile describes, per program, which files a process may read or write, which capabilities it may use, and which network operations it may perform. The kernel enforces those rules even against root, so a compromised daemon is held to the boundaries its profile defines.

Many distributions leave MAC in complain mode (where violations are logged but allowed) or disable it for third-party packages. InterGenOS ships AppArmor profiles for system daemons in enforce mode by default. Violations are blocked, not merely recorded.

If you are authoring or adjusting a profile for your own software, enforce mode is the design point to target. AppArmor’s complain mode remains available as a development aid while you write a profile, but the shipped system daemons do not depend on it.

Per-service sandboxing with systemd

On top of the MAC layer, every system service is sandboxed using systemd’s isolation directives. These shrink the blast radius of a compromise: even if an attacker takes over a service, the service can no longer see most of the filesystem, gain new privileges, reach the kernel’s tunable interfaces, or issue system calls outside a tight allowlist.

The baseline directives applied across system daemons include:

DirectiveEffect
NoNewPrivileges=trueThe service and its children can never gain new privileges (blocks setuid escalation).
ProtectSystem=strictThe entire filesystem is read-only to the service except explicitly allowed paths.
ProtectHome=trueUser home directories are inaccessible.
PrivateTmp=trueThe service gets a private, isolated /tmp.
PrivateDevices=trueOnly a minimal, virtualized set of devices is visible.
ProtectKernelTunables=trueKernel tunables (/proc/sys, /sys) are read-only.
ProtectKernelModules=trueLoading and unloading kernel modules is denied.
ProtectKernelLogs=trueThe kernel log ring buffer is inaccessible.
ProtectControlGroups=trueThe cgroup hierarchy is read-only.
ProtectHostname=trueThe service cannot change the system hostname.
ProtectClock=trueThe service cannot change the system clock.
ProtectProc=invisibleOther processes are hidden in the service’s /proc.
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6Only these socket address families are permitted.
RestrictNamespaces=trueCreating new namespaces is denied.
RestrictRealtime=trueReal-time scheduling is denied.
RestrictSUIDSGID=trueCreating setuid/setgid files is denied.
LockPersonality=trueThe execution domain (personality) is locked.
MemoryDenyWriteExecute=trueMemory pages cannot be both writable and executable.
RemoveIPC=trueIPC objects owned by the service are cleaned up on exit.
SystemCallArchitectures=nativeOnly native-architecture system calls are allowed.
SystemCallFilter=@system-serviceThe system-call surface is reduced to the service allowlist.
SystemCallFilter=~@privileged @resources @mount @swap @rebootPrivileged, resource-control, mount, swap, and reboot syscall groups are explicitly denied.

MemoryDenyWriteExecute=true carries the one documented exception: packages that genuinely require a just-in-time (JIT) compiler are exempted, because W^X memory would otherwise break them. The shipped example is PostgreSQL, whose service unit sets MemoryDenyWriteExecute=false so the LLVM JIT compiler keeps working; operators who want the strict W^X posture can disable the JIT in the database configuration instead. The exemption is per-package and deliberate, not a blanket relaxation.

Network exposure is closed by default

Sandboxing the runtime is only half the story; the other half is not exposing the service in the first place. Any server package shipped by InterGenOS binds exclusively to localhost (127.0.0.1) by default. Services do not listen on public interfaces unless you deliberately edit their configuration to allow it.

There are also no default or blank credentials. InterGenOS does not ship databases or services with empty or stock “admin” passwords; initial credentials are randomly generated or require manual setup.

How this fits the rest of the trust chain

Sandboxing and MAC are the runtime confinement layer. They sit on top of an integrity-verified boot and software supply chain:

  • A signed Secure Boot chain validates the bootloader, kernel, and Unified Kernel Images, and dm-verity protects the read-only system image. Installed systems re-sign each kernel’s UKI with a local Machine Owner Key (MOK) on every kernel install or upgrade. Forge, the installer, walks you through enrolling that MOK on first boot.
  • The package manager (pkm) verifies a signed index and per-package SHA-256 hashes before anything is installed.

Together these mean a service is launched from verified bytes, then held inside an enforced policy and a stripped-down sandbox for its entire lifetime.

For the boot and signing side of this chain, see Verified Boot & Secure Boot.

Auditing it yourself

These are conventional, well-documented Linux mechanisms, which is the point: you can inspect them with standard tools rather than trusting a claim.

  • aa-status reports which AppArmor profiles are loaded and which are in enforce versus complain mode.
  • systemctl show <service> prints the effective sandboxing directives for any unit, so you can confirm a service runs with the hardening described above.
  • systemd-analyze security <service> produces a per-service exposure report.

Confirm the defaults, change what you need to, and trust the result because you checked it.

See also