Apple Silicon Software Foundations
A node runs a purpose-built operating system designed for protecting user data.
Overview
We designed the PCC node’s custom operating system using a minimized and hardened subset of iOS with the following goals:
The behavior of the system can be well understood by a security researcher through analysis of the software.
The entire set of software that can run on the system is measurable and described by the attestation.
Software is immutable at runtime and can change only during a reboot, which invalidates previously attested keys, and thus previous attestations.
We use hardware-based attestation to verify the boot firmware. But for a user’s device to verify the transparency guarantees, we also follow the hardware measurements with a chain of trust that covers all software within the High-security inference of a PCC node.
To allow comprehensive analysis of the software running on PCC nodes, we disable or remove mechanisms to execute code dynamically, including:
System shells such as
zshInterpreters such as
JavaScriptCoreDebuggers such as
debugserverJust-In-Time (JIT) compiler functionality
PCC strives for the smallest possible attack surface and Hermetic environment, while still enabling our desired workloads. PCC uses a small subset of the total code present on other iOS devices. The node’s operating system includes only a minimal set of boot firmware, SEP applications, and kernel extensions; where possible, it excludes drivers and firmware for unused hardware components.
The system includes the same GPU and Apple Neural Engine (ANE) functionality present in iOS, including the firmware and Metal stack. Large Language Model (LLM) functionality and application logic are packaged and loaded using Cryptexes: archives of artifacts that represent a fully signed and integrity-verified standalone software distribution package.
The nodes boot using our Secure Boot implementation, which loads the system to user space. Within user space, our initialization task, darwin-init, sets up the node based on the configuration it obtains from the BMC, such as the set of cryptexes to load. Once it loads all cryptexes, darwin-init initiates entry into Restricted Execution Mode, after which the node becomes available for serving external requests.
Secure Boot
Apple silicon’s Secure Boot process starts with the Secure and measured boot. These immutable components of the SoC start the boot process by validating the Image4 boot manifest, called the APTicket, then verifying the measurements of the iBoot and SEP firmware against this manifest. If the verification is successful, the digest of the manifest is locked into SEAL_DATA_A and the digest of the sepOS image into SEAL_DATA, before iBoot and sepOS begin execution.
After validating the APTicket and iBoot images, the Boot ROM continues the boot flow by handing off execution to iBoot. iBoot extends the boot chain and verifies the system’s firmware against the APTicket, including the Secure Page Table Monitor (SPTM), the Trusted Execution Monitor (TXM), and the kernel cache. Just like with iOS, iBoot then hands off execution to the SPTM, which bootstraps the system’s memory management unit, initializes TXM, and then hands off control flow to the kernel. The kernel initializes the rest of the system and boots to user space, where code-signing policies extend Secure Boot into user space.
The SEP has its own boot process rooted in the SEPROM. An early boot task in user-space on the Application Processor (AP) initiates the flow for issuing a boot command to the SEP. Once SEPROM receives this command, it copies the sepOS firmware into protected memory and independently verifies its signature. Upon success, the SEPROM begins executing sepOS, which in turn begins loading SEP applications.
Both the AP and the SEP use the Image4 format for Secure Boot. The Image4 manifest format contains constraints, such as a device’s hardware identifier, which cryptographically bind the Image4 manifest to an SoC, a technique known as personalization. This binding means that manifests are not transportable among devices. The binding also includes values that cannot be determined without the direct participation of the SoC, such as rotating anti-replay values. A list of Image4 tags and constraints is included in Appendix: Apple Silicon Secure Boot Tags.
Software Sealed Registers
To capture measurements that exist outside of SEAL_DATA and SEAL_DATA_A, the SEP provides a service to the AP called Software Sealed Registers (SSRs) that allows measurements to be ratcheted into the SEP. This service is similar to the function of a TPM’s Platform Configuration Register. Attestations generated by the SEP capture the contents of these SSRs. The APTicket captures the baseline software loaded on the AP, and the SSRs capture tunable configuration data and additional software packages that the PCC node loads after boot.
An SSR starts out empty, and the AP can update it to include data digests. Each update extends a running SHA-384 over the digests the register received, so after n updates the register holds the SHA-384 of those n digests concatenated in order. An update operation is a ratcheting step because it cannot be rolled back. When the system finishes initialization, the AP can ask the SEP to lock an SSR so it cannot be updated further, and this lock state is included in the attestation. In addition, the SEP binds the encryption keys that secure communication with PCC nodes to the SSR state, so the keys become inaccessible if the SSR’s contents change.
The following example illustrates the functioning of an SSR:
SSR: Empty
|
| Operation: Update(SHA-384('hello')) <-- ✅
| Value: d47d89ff...755cf5f2
|
| Operation: Update(SHA-384('world')) <-- ✅
| Value: f715f491...c96a1182
|
| Operation: Lock <-- ✅
| Value: f715f491...c96a1182
|
| Operation: Update(SHA-384('invalid')) <-- ❌
| Value: f715f491...c96a1182
Where:
SHA-384('hello'): 59e17487...e828684f
SHA-384('world'): a4d102bb...7d3ea185
SHA-384(SHA-384('hello')): d47d89ff...755cf5f2
SHA-384(SHA-384('hello') || SHA-384('world')): f715f491...c96a1182PCC’s attestation policy evaluates two Software Sealed Registers:
Cryptex Manifest Register: Contains the digests of all the Image4 manifests from Cryptexes activated on the AP.
Configuration Seal Register: Contains a digest of a subset of the configuration file that darwin-init uses to set up the node.
Code signing
Boot ROM and iBoot load only firmware and a kernel cache that they have verified against the APTicket and measured. Private Cloud Compute attestations must cover all software that might run on a node, so the complete set of user-space code is described by a set of trust caches, both as part of the APTicket and as components of cryptexes.
To enforce this behavior, the code-execution policy on a PCC node is managed by a separate monitor layer, the Trusted Execution Monitor (TXM), rather than the kernel. This separation helps ensure that a kernel compromise is not sufficient to execute arbitrary code on the node — an attacker would also need to bypass the TXM.
The TXM enforces several restrictive policies on PCC nodes to ensure that only known code can execute:
All code must be covered by a trust cache.
JIT mappings cannot be created.
Developer Mode cannot be enabled.
Debugging workflows are not supported.
PCC has an explicit goal that any code that runs on the node must be attested to. The base operating system contains services and daemons that set up the node. The digest of each binary on the base operating system is contained within the static trust cache, which is authorized by the APTicket and loaded by iBoot. Additional software outside the base operating system can be delivered to the system only in the form of Cryptexes; every cryptex includes its own Image4 manifest, and a cryptex that contains code also includes its own trust cache. This design enables the SEP’s attestation to capture all code contained within a cryptex before the code can run. For details on the trust cache format, see Appendix: Apple Silicon Trust Cache Format.
The Cryptex Manifest Register is a Software Sealed Register that contains ratcheted digests of the Image4 manifests for all cryptexes that the AP loads. Unlike other SSRs, the AP cannot directly update this register. Instead, its contents are controlled by the SEP and are managed as follows:
Before a cryptex is activated by
cryptexdon the AP,cryptexdpresents its Image4 manifest to the SEP.The SEP independently validates the manifest and, if successful, updates the Cryptex Manifest Register with the manifest’s digest.
The SEP also writes the digest to a special memory page that’s shared with TXM and not writable by any other component, including the AP kernel.
TXM then enforces that only trust caches included in this page may be used to load executable code, so every trust cache in use is measured for inclusion in the attestation.
TXM’s trust boundary doesn’t include the AP kernel, so the system has a special SEP-TXM page to facilitate direct communication between these components. We designed this direct channel to ensure that new code on the system cannot be loaded without first being recorded by the SEP for inclusion in attestations. Even with a kernel compromise, an attacker must also compromise either the SEP or TXM.
Restricted Execution Mode
The PCC node uses a new feature called Restricted Execution Mode (REM) to lock out functionality that’s required only during the system’s initial setup. Entering REM is enforced by TXM as a one-way transition, after which TXM refuses to load additional trust caches and imposes new constraints on code execution. The state of REM is communicated from TXM to the SEP using the SEP-TXM page, and is included by the SEP in all attestations it generates.
In REM-enabled trust caches, each trust cache entry includes an 8-bit flag field. Two of those bits represent REM permissions and indicate whether code is permitted to run if REM is supported, permitted before or after entering REM, or permitted regardless of REM. If the trust cache being evaluated by TXM doesn’t contain a REM policy (for example, because it’s a previous version of the format that doesn’t support REM policy), TXM assumes that both bits are zero.
Restricted Execution Mode Policy | High Bit | Low Bit |
|---|---|---|
None: Never permitted if REM is supported | 0 | 0 |
Before: Only permitted prior to REM | 0 | 1 |
After: Only permitted after REM | 1 | 0 |
Both: Permitted regardless of REM | 1 | 1 |
A PCC node cannot transition into REM if there is any before code resident in memory. If a daemon with the before policy has been launched by launchd, TXM enforces that it must be killed, even if it’s completely idle and not actively running code. This is designed to ensure that unnecessary code has been unloaded prior to processing any user data, thereby reducing the attack surface of the system.
Additionally, TXM denies entering REM if the Software Sealed Register is unlocked. While the contents of this register are controlled by the SEP, the AP still must ask the SEP to lock it. The lock state of this register is communicated from the SEP to TXM using the SEP-TXM page.
Ephemeral Data Mode
PCC nodes operate in a new Ephemeral Data Mode, which has two functions:
Per-boot data volume: Data written to the data volume does not persist to the next boot. Should PCC software inadvertently write user data to the volume, that data is unrecoverable after a reboot, so software with different security properties in a later boot session cannot read it.
Anti-persistence: Limits the impact of a compromised PCC node to a single boot session to prevent an attacker from remaining resident on the node, or re-exploiting the node for an extended period of time.
Per-boot data volume
Mutable data on a PCC node is intended to be stored on a dedicated data volume, separate from the immutable Signed System Volume that contains the operating system. The dedicated data volume is encrypted with a storage-key hierarchy managed by the SEP. iOS features, like Erase All Content & Settings, where user data can be quickly and reliably erased without modifying the system volume, use this same data-volume separation design.
With Ephemeral Data Mode enabled, the SEP randomizes this storage-key hierarchy at every boot. This cryptographically guarantees that no data-volume state written in a session can be read by any subsequent boot session.
On subsequent boot sessions, the mobile_obliterator boot task discards the previous encrypted data volume and reconstructs a clean volume from known-safe data, prior to loading other daemons.
Anti-persistence
Some storage regions are not covered by the SEP’s key-hierarchy randomization nor validated during the boot process by Secure Boot. This includes persistent data stores such as NVRAM and the Preboot volume. These data stores have existing protections, designed to limit which processes can read and write data, that prevent anyone from accidentally or maliciously storing user data in them.
The PCC threat model assumes full node compromise where those protections are defeated. Accordingly, each system boot scrubs these data stores, so an attacker cannot use crafted values to influence subsequent boot sessions. On the Preboot volume, MobileObliteration keeps only the boot objects that Secure Boot validates and the persistent asset caches that darwin-init revalidates before use. PCC implements these protections across several system components, including iBoot, MobileObliteration, and darwin-init.
Persistent asset caches
PCC caches certain large assets across reboots, rather than erasing them with the data volume, so a node doesn’t need to reacquire them on every boot. These caches hold only assets that Apple provides and that are common across nodes: the Cryptexes installed by a node’s configuration, and the large filters used by the Private Filter Service (PFS). PCC doesn’t use asset caches for data derived from a user’s request.
PCC caches such assets in two ways:
Cryptexes are stored on the Preboot volume and reused across boots when possible.
Other large assets are stored on cache volumes, which use a distinct APFS volume role that
mobile_obliteratorleaves in place across reboots.
Two properties keep both caches from becoming an Ephemeral Data Mode bypass:
- Restricted write access
The default sandbox rules do not allow write access to the Preboot volume or cache volumes. Only processes with the proper entitlements can access them, and PCC grants write access only to components that do not handle user data. Access to the Preboot volume requires the
com.apple.rootless.volume.Prebootentitlement, while a cache volume, mounted under/private/var/mnt/, requires acom.apple.security.exception.files.absolute-pathentitlement that names its mount path, with aread-onlyorread-writesuffix. Because the entitlement names the exact path it grants, a researcher can discover which processes can read or write a given cache volume by inspecting the published entitlements for that path.- Per-boot integrity validation
PCC treats cached bytes as untrusted and revalidates them before use. For cryptexes,
darwin-initchecks each cached cryptex against its expected measurements and discards any cached copy that doesn’t match. For cache volumes, each workload validates its cache volume’s contents against a trusted reference of its own.
The following workloads use cache volumes:
- PFS
Stores the fragment files of the large Bloom filters it serves, so it doesn’t download them again each boot. PFS splits access by role: a downloader fetches the fragment files at node startup and writes them to the volume, a root-privileged helper sets the volume’s ownership once at boot, and the controller that answers lookups has read-only access. None of the three handles user data. The downloader verifies each fragment file against its hash published in an attested cryptex, so even though the fragment data is delivered separately, it stays anchored to the node’s attestation.