How Apple Container Handles Linux Capabilities and Security Isolation

Apple's container runs each workload inside a lightweight Linux VM, enforcing security isolation through a three-layer mechanism that combines OCI default capabilities, user-provided --cap-add and --cap-drop flags, and kernel-level Linux Security Module (LSM) hardening with a strict lsm=lockdown,capability,landlock,yama,apparmor profile.

The apple/container repository implements a declarative and defensive security model where fine-grained Linux capabilities replace full root privileges. Instead of relying solely on traditional user permissions, the runtime constructs a meticulously curated capability bitmap that the kernel enforces at the system call level, dramatically reducing the attack surface for containerized workloads.

Architecture Overview: VM-Based Isolation

Every container spawned by the Apple container runtime executes within its own lightweight Linux VM. This virtualization boundary provides the foundation for security isolation, ensuring that privileged operations inside the container are strictly controlled by the host kernel.

The isolation strategy combines virtual machine boundaries with Linux kernel security features. When the VM boots, the kernel receives a hardened command-line argument string that activates multiple Linux Security Modules (LSMs) simultaneously. According to the source code in Sources/Services/RuntimeLinux/Server/RuntimeService.swift at line 164, the kernel launches with:


lsm=lockdown,capability,landlock,yama,apparmor

This LSM stack ensures that capability boundaries are enforced while blocking accidental privilege escalation through disabled non-required interfaces.

The Three-Layer Capability Security Model

Security isolation is implemented through three distinct layers that operate sequentially during container creation.

Layer 1: OCI Default Capabilities

The runtime initializes each container with the minimal OCI default capability set defined by the Open Container Initiative specification. In Sources/Services/RuntimeLinux/Server/RuntimeService.swift at line 1170, the effectiveCapabilities function seeds the initial capability bitmap using Containerization.LinuxCapabilities.defaultOCICapabilities.

The default set includes:

  • CAP_AUDIT_WRITE
  • CAP_CHOWN
  • CAP_DAC_OVERRIDE
  • CAP_FOWNER
  • CAP_FSETID
  • CAP_KILL
  • CAP_MKNOD
  • CAP_NET_BIND_SERVICE
  • CAP_NET_RAW
  • CAP_SETFCAP
  • CAP_SETGID
  • CAP_SETPCAP
  • CAP_SETUID
  • CAP_SYS_CHROOT

This minimal baseline ensures containers can perform basic operations without unnecessary privileges.

Layer 2: User-Provided Flags

Users modify the default set through --cap-add and --cap-drop CLI flags. These arguments undergo strict validation and normalization in Sources/Services/ContainerAPIService/Client/Parser.swift at line 1025.

The capabilities(capAdd:capDrop:) function:

  1. Converts all input to uppercase
  2. Adds the CAP_ prefix if missing
  3. Validates each name against the CapabilityName enum
  4. Raises ContainerizationError for invalid capability names

This validation occurs before the configuration reaches the VM, ensuring only legitimate Linux capabilities can be requested.

Layer 3: Kernel LSM Hardening

The final layer occurs at VM boot time. As implemented in RuntimeService.swift, the kernel command line includes the strict LSM profile that enables lockdown, capability, landlock, yama, and apparmor modules simultaneously. This hardening ensures that even if a process somehow escapes its capability constraints, additional security policies prevent privilege escalation.

How Effective Capabilities Are Computed

The RuntimeService.swift file at line 1170 implements a three-step algorithm in the effectiveCapabilities function to determine the final capability set:

  1. Initialize: Start with the OCI default capabilities, or an empty set if ALL is dropped
  2. Apply additions: Process --cap-add entries, with ALL replacing the entire set
  3. Apply removals: Remove individual capabilities specified in --cap-drop

The ALL sentinel acts as a wildcard. Using --cap-add ALL grants every capability, while --cap-drop ALL removes everything. The algorithm processes drops after adds, meaning --cap-drop ALL --cap-add ALL results in a full capability set.

This computed bitmap is then stored in the container's ContainerConfiguration (defined in Sources/ContainerResource/Container/ContainerConfiguration.swift at line 57) and passed to the VM kernel as the effective capability mask for PID 1.

Practical Examples

Modifying Capabilities via CLI

Grant network administration privileges while removing the ability to change file ownership:

container run --cap-add NET_ADMIN --cap-drop CHOWN alpine ip link set eth0 up

Start with zero privileges and add only specific capabilities:

container run --cap-drop ALL --cap-add SETUID --cap-add SETGID alpine id

Drop a specific default capability:

container run --cap-drop CHOWN alpine chown 100 /tmp

Swift Implementation: Computing Capabilities

The following Swift code demonstrates how the runtime computes the effective capability set:

import Containerization

// User input from CLI flags
let capAdd = ["NET_ADMIN", "ALL"]
let capDrop = ["CHOWN"]

// Parser normalizes and validates
let (normAdd, normDrop) = try Parser.capabilities(capAdd: capAdd, capDrop: capDrop)

// RuntimeService calculates final bitmap
let finalCaps = try RuntimeService.effectiveCapabilities(
    capAdd: normAdd,
    capDrop: normDrop)

// Result contains only permitted capabilities
print(finalCaps.capabilities)

Configuring Process Security

When constructing a container configuration programmatically:

var containerConfig = ContainerConfiguration()
containerConfig.capAdd = ["ALL"]
containerConfig.capDrop = ["CAP_SYS_ADMIN"]

// Configuration propagates to the VM runtime
let proc = try RuntimeService.configureProcess(
    from: containerConfig,
    using: ociConfig)

Key Implementation Files

Summary

  • Apple container isolates workloads using lightweight Linux VMs with strict LSM profiles (lsm=lockdown,capability,landlock,yama,apparmor)
  • Default capabilities follow the OCI specification, providing a minimal privileged baseline in RuntimeService.swift
  • User customization occurs through validated --cap-add and --cap-drop flags processed by Parser.swift
  • Effective capability computation follows a three-step algorithm: initialize with defaults, apply additions, then apply removals
  • The kernel enforces the final capability bitmap at the syscall level, returning EPERM for unauthorized privileged operations

Frequently Asked Questions

What is the default capability set in Apple container?

The default set includes 14 capabilities defined by the OCI specification: CAP_AUDIT_WRITE, CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_FOWNER, CAP_FSETID, CAP_KILL, CAP_MKNOD, CAP_NET_BIND_SERVICE, CAP_NET_RAW, CAP_SETFCAP, CAP_SETGID, CAP_SETPCAP, CAP_SETUID, and CAP_SYS_CHROOT. These are seeded from Containerization.LinuxCapabilities.defaultOCICapabilities in RuntimeService.swift.

How does the ALL sentinel work with capability flags?

Using --cap-add ALL grants every Linux capability, replacing the current set entirely. Conversely, --cap-drop ALL removes all capabilities. Because the algorithm processes drops after adds, the sequence --cap-drop ALL --cap-add ALL results in a container with full privileges, while --cap-add ALL --cap-drop ALL results in no privileges.

What LSM modules does the container runtime use for isolation?

The VM kernel boots with lsm=lockdown,capability,landlock,yama,apparmor. This combination provides defense-in-depth: the capability module enforces traditional Linux capabilities, while lockdown, landlock, yama, and apparmor provide additional restrictions on privileged operations, ptrace, and filesystem access.

Can I add virtualization capabilities to a container?

Yes, the --virtualization flag exposes nested virtualization (KVM) to the container, but this requires supported Apple Silicon hardware and a kernel compiled with the necessary configuration options. This is an exception to the minimal-default policy and must be explicitly requested.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →