---
title: Apple Silicon Software Layering
framework: Private Cloud Compute Security Guide
role: article
role_heading: Article
path: private-cloud-compute/softwarelayering
---

# Apple Silicon Software Layering

A node builds its software stack from a hardened operating system and a set of signed, measured cryptexes.

## Overview

Overview Cryptexes PCC nodes extend their base functionality through cryptexes, the same technology behind the Security Research Device Program and Rapid Security Response. A cryptex is an assemblage of artifacts that represents a fully signed and integrity-verified, standalone software distribution package. Cryptexes enclose an independent Image4 manifest that authorizes each artifact bundled within the cryptex. For a list of the artifacts and the set of Image4 tags in a cryptex, see Appendix: Apple Silicon Secure Boot Tags. The cryptexctl tool is used to personalize a cryptex on a specific PCC node prior to activation by the cryptexd daemon. cryptexd sends the Image4 manifest of cryptexes that it activates to the SEP, which performs a trust evaluation of the manifest, then ratchets its digest into the Software Sealed Registers. Node validation replays these ratcheting operations and compares the result against the Cryptex Manifest Register the bundle reports. A match confirms that the bundle lists every manifest the SEP evaluated, and no others. Both cryptexd and cryptexctl have the before Restricted Execution Mode policy and are therefore prevented from launching once the system enters REM. The system personalizes cryptexes with an anti-replay value, which is rotated each boot. If the manifest survives a reboot, that value is not re-usable. This guarantees that if Apple revokes the signing window of a cryptex, any nodes actively using that cryptex will reject it at the next boot cycle. When the cryptexd daemon activates a cryptex, each bundled artifact within the cryptex must be loaded by the appropriate subsystem. For example, the disk image artifact is loaded by the APFS kernel extension, while the trust cache artifact is loaded by the Code signing. Each system component that manages a given artifact performs its own independent trust evaluation of the Image4 manifest before it accepts the artifact. Codeless cryptexes Private Cloud Compute uses certain cryptexes, such as those containing model weights, only for the delivery of non-executable content. These cryptexes don’t include a trust cache. The codeless nature of such a cryptex is designated by the presence of a data constraint, which declares the cryptex to be data only. We designed PCC to ensure that codeless cryptexes cannot change system behavior in a way that violates the system’s Stateless Computation guarantees. This enables them to be used for data that sits outside of PCC’s Verifiable Transparency guarantees, such as the server-side foundation model. When cryptexd encounters a codeless cryptex, it doesn’t examine it for launchd jobs, jetsam properties, or logging profiles, and it doesn’t attempt to load any trust caches from it. For defense-in-depth, TXM also rejects any Image4 manifests that contain the data constraint. Because TXM is the authority for managing trust caches, this additional constraint enforces that the system cannot use codeless cryptexes to authorize executable content. Codeless cryptexes are ratcheted into the Cryptex Manifest Register in the same way as any other cryptex, so they are represented in attestation bundles obtained from a PCC node. Whether the content of a codeless cryptex falls inside or outside PCC’s verifiable transparency guarantees is a per-cryptex decision. The server-side server-side foundation model deliver the models in formats designed for PCC and its threat model. As a result, these cryptexes can safely sit outside those guarantees. Other codeless cryptexes carry model assets, for example, the Embedding Generation model and the voice and pronunciation assets used for Speech Synthesis, in existing formats such as Core ML and BNNS-IR. The complexity of these formats means that, under PCC’s threat model, we choose not to assume the assets can be parsed safely. Rather than admit these files as trusted data, we hold them to the same transparency bar as PCC’s executable code and publish them for independent inspection using the Virtual Research Environment tools. darwin-init The darwin-init daemon serves a role similar to cloud-init in Linux-based cloud systems. With Ephemeral Data Mode, each boot of a PCC node starts from a clean state with no configuration and only the base operating system. darwin-init then loads the additional required code, sets the node’s configuration, and then enters Restricted Execution Mode. darwin-init uses a configuration that it loads from the BMC over a chassis-internal network. The configuration uses a custom JSON-based format and includes: Metadata and locations of cryptexes to load Node’s desired hostname Initial firewall rules to use at boot System logging policy Key-value-based configuration for other software components The config-security-policy key in the configuration indicates the security posture of the current environment. darwin-init uses this key to limit the configuration options it allows to be set (or not set) based on the deployment environment. This allows the system to support development options while preventing these options from being enabled in production environments. Production PCC systems use one of two customer policies: customer for inferencing nodes and customerProxy for proxy nodes that coordinate inferencing requests across one or more inferencing Distributed inference. The two policies impose the same restrictions and differ only in the role they allow: customerProxy accepts a configuration only if it declares the node a proxy, and customer rejects one that does. A node’s policy therefore fixes whether it can act as a proxy and forward requests to other attested PCC nodes. This configuration policy state is ratcheted into the Software Sealed Registers and therefore available in attestations to be verified by a user’s device, as discussed in Node validation. To simplify verification, and ensure forward- and backward-compatibility between a user’s device and a node, only the policy state and specifically selected keys are included in the Configuration Seal Register, rather than the entire darwin-init configuration. PCC’s threat model treats this configuration data as attacker-controlled, and darwin-init allows only the application of configuration options that cannot negatively impact the security or privacy properties of the system. Additionally, consumers of configuration data allowed by the darwin-init policy are expected to treat the data as hostile and validate it appropriately. The list of parameters allowed in this configuration is included in Appendix: Apple Silicon System Configuration. A key responsibility of darwin-init is to download, personalize, and then install the set of cryptexes required by the PCC node. To save time on downloading large models every boot, darwin-init supports a local cache of the cryptexes that it loaded in the previous boot, and stores this cache on the Preboot volume. darwin-init cryptographically revalidates the cache’s contents during each boot to prevent the cache storage from being used as an Ephemeral Data Mode bypass. darwin-init deletes any file contents that fail validation before it installs the cryptexes, to prevent data leaking from one workload to another. Once darwin-init has installed all cryptexes and other configuration data is in place, darwin-init asks the SEP to lock the cryptex SSRs, so no further cryptex manifests can be ratcheted and no additional code can be loaded. There are two mechanisms that darwin-init supports for setting configuration data for other software components: The preferences array indicates data which darwin-init needs to write to CFPreferences. To limit the attack surface on the system, our customer and customerProxy policies allow darwin-init to set only a carefully chosen set of preference domains. The secure-config dictionary indicates data that needs to be registered by darwin-init with secureconfigd, which exposes it to clients through the SecureConfigParameters APIs. secure-config is a new interface designed for PCC to separate critical configuration into a dedicated, type-constrained, and easily auditable interface. Code that uses this interface reads the configuration through the SecureConfigParameters APIs, rather than reading directly from disk. Only secureconfigd is able to write to the on-disk storage for the secure-config configuration; this interface prevents an attack from being able to use the data for lateral movement within the system. Once darwin-init has completed configuring the system, it performs a user-space reboot (USR) so the system can enter REM. A USR is a special operation that terminates all processes and reinitializes launchd. This operation enforces that there are no processes with the before Restricted Execution Mode policy that are running. After launchd has reinitialized, it uses a system call to ask TXM to enter REM before loading any services. launchd has support for marking services as ineligible for REM in their launchd.plist, such that they are not reloaded after the user-space reboot. The binaries for services such as darwin-init or sysdiagnose have the before policy, so marking them as ineligible in their launchd.plist ensures that launchd doesn’t attempt to run them once REM has been enabled. note: darwin-init: daemon, framework libsecureconfig: secureconfigd, SecureConfigDB framework PCC node cryptexes Using cryptexes to extend iOS Secure Boot to cover all loaded code lets us build the PCC node software from multiple layers: the private cloud extensions, the ML stack, and the models themselves. This enables operational flexibility, while also ensuring that all components of the system are covered by the attestation.

The software components of the system are distributed between the operating system and cryptex extensions. The operating system image has support for bootstrapping the system, integrating with the hardware, and handling attestations; the cryptexes contain application software. Private Cloud Extensions The PrivateCloudSupport cryptex contains platform-level support components required on each PCC node that enable the PCC node to integrate with data-center infrastructure:  |  |   |  |   |  |   |  |   |  |   |  |   |  |  PCC cloud applications The PCC application layer sits above the cloud extensions, consisting of a set of cloud applications that are CloudBoard. Appendix: PCC Application Identifiers records which cryptex distributes each application’s components. Worker nodes run the following cloud applications:  |  |   |  |   |  |   |  |  These cloud applications use the following supporting components:  |  |   |  |   |  |  A proxy app is a cloud application that runs on a proxy node and distributes a request to other PCC nodes using Transitive Trust. A proxy node running PCC Agent is an PCC Agent; current inference and agentic flows use the agent. Proxy nodes run:  |  |   |  |   |  |  For each cloud application’s cloud-app name, ServiceDiscovery registration, cryptex, and transparency-log names, see Appendix: PCC Application Identifiers. Foundation model and adapter cryptexes Apple models are deployed to nodes using codeless cryptexes, which contain only weights, parameters, and configuration metadata. Adapters are collections of model weights that are overlaid onto the common base foundation model. PCC includes a broad set of adapters, each fine-tuned for a specific feature. It’s an efficient way to scale the capabilities of our foundation model. Although the model and adapter cryptexes are measured and attested to like standard cryptexes, they are considered proprietary and not published as part of our transparency commitment. PCC’s threat model therefore considers any data that is in these cryptexes to be attacker-controlled. To prevent these cryptexes from undermining PCC’s security architecture and privacy properties, PCC represents the model and adapters in a custom format for the MetalLM library. We designed this format to encode weights and a fixed set of configuration values without programmable control flow; every architecture it can select is implemented in the MetalLM library.
