cryptex(5) File Formats Manual cryptex(5)

cryptex
Cryptex filesystem hierarchy specification

A cryptex is a cryptographically-sealed archive which encapsulates a well- defined filesystem hierarchy. The host operating system recognizes the hierarchy of the cryptex and extends itself with the content of that hierarchy. The name “cryptex” is a portmanteau for “CRYPTographically-sealed EXtension”.

Unlike other archive formats (e.g. tar(1), cpio(1), etc.), the content of a cryptex is not intended to be merged to a filesystem root. Conventionally, archives are merged to the root filesystem so that the operating system can discover new or updated content at a set of pre-determined paths that are relative to the filesystem root. For example, the user's chosen shell may discover executables in /usr/bin, and therefore new executables must be merged into that location in order for the shell to discover them.

However, as Darwin has more aggressively defended its operating system bits from tampering (e.g. via the Signed System Volume), it has become necessary to begin recognizing other content roots that are separate from the system but otherwise writeable by the user. For example, the shell may also discover executables in /usr/local/bin, which resides on the data volume rather than the signed and immutable system volume.

But these extra roots essentially force a single package of software to "break itself up" in order to be installed. Shell tools must be copied to one location, dynamic libraries to another, daemons to still another, etc. Once this is done, all provenance for the software is more or less lost unless the operating system employs complex monitoring and tracking of filesystem events.

Instead of extracting content and merging it to another filesystem, a cryptex is instead mounted at a randomly-chosen location when the system boots. Its content may then be examined by any subsystems which are interested in discovering content from cryptexes. In other words, subsystems must explicitly be taught about the possible existence of cryptex content, and the usefulness of cryptexes is directly proportional to the number of subsystems that agree to look for their contents.

This scheme maintains the structure of a software package as a single entity that is always handled as such. Prior to mounting the filesystem, the operating system can verify that the archive file itself has not been tampered with by taking a measurement of it and comparing to a known-good measurement before agreeing to mount it.

A cryptex houses a filesystem that very much appears as though it is intended to be merged to the root of a Darwin operating system. This is intentional. The distribution root produced by building a Darwin project should be able to be used as a cryptex assuming all relevant subsystems have been taught about cryptex content. Thus, cryptexes can be thought of as positionally-independent distribution roots.

Cryptexes formalize the conventions surrounding the Library directory locations and precedence into views. These conventions are documented in the “File System Programming Guide” available on Apple Developer Documentation Archive.

Views are distinguished by root directories in the filesystem, and each the view in which a piece of content resides has implications about the intended scope of that content. Defined views are

VIEW ROOT(S) PURPOSE
Application -tag -width -indent -compact Pa ./ Pa ./opt Pa ./usr/local Content which is private to the cryptex and should not be discovered by other subsystems
Platform -tag -width -indent -compact Pa ./System Pa ./usr Content which is published to the broader platform and should be discovered by other subsystems

Cryptexes impose the restriction that for a piece of content, there is only one directory within a view which may house that content, and two types of content may not share a directory. This is a generally agreed-upon convention in Darwin and other POSIX-comforming or Unix-like operating systems, but there are typically no technical barriers in place to enforce it.

The cryptex subsystem provides these barriers by requiring a priori knowledge of a type of content before it can be published for discovery to the broader operating system. Because the cryptex subsystem maintains complete control over where cryptexes are published and available in the filesystem, other subsystems cannot simply crawl the filesystem and reliably discover content they are interested in. These subsystems must ask the cryptex subsystem for a type of content of a specific name within a specific view. The path to a given piece of content is constructed from this (view, type, name) tuple. Put another way, rather than inferring information about content type and scope from a filesystem path, cryptexes construct the filesystem path from information about content type and scope.

Several types of content are already enumerated, though most are not discovered by other subsystems. Of the ones that are, only certain views are currently supported.

CONTENT TYPE DIRECTORY DESCRIPTION IMPLEMENTATION NOTES
Shell tool bin Binaries directly executed by the user in a shell Automatic discovery not implemented, though the CRYPTEX_PATH environment variable will provide a location which can be added by the user to his or her shell search path
Dynamically-linked library lib Shared libraries which may be mapped as executable into an already-executing process Libraries in the Application view are discovered and respected by the linker such that processes within a cryptex can use libraries within that same cryptex
System executable libexec A binary which is used by other programs and not meant to be directly executed by the user Not implemented
Daemon Library/LaunchDaemons A launchd.plist 5 which describes and defines a launchd 8 service Daemons in the Application view are discovered and bootstrapped automatically when the cryptex is mounted
Agent Library/LaunchAgents A launchd.plist 5 which describes and defines a user-specific launchd 8 service Not implemented
Manual page share/man A man 1 page which documented a component within the cryptex Not implemented
Application Applications A GUI application which is directly launched by the user Not implemented
Cocoa framework Library/Frameworks A specially-packaged dynamically-linked library which may include headers, resources, and versioning in a single directory structure Not implemented

VIEW CONTENT TYPE NAME PATH(S)
Platform Dynamically-linked library libfoo.dylib -tag -width -indent -compact Pa ./usr/lib/libfoo.dylib Pa ./System/lib/libfoo.dylib
Application System executable barbaz -tag -width -indent -compact Pa ./libexec/barbaz Pa ./opt/libexec/barbaz Pa ./usr/local/libexec/barbaz

All paths to a resource are considered exactly equivalent, and if the cryptex is built with different pieces of content at equivalent paths, the one returned by a query for that tuple is undefined.

The impact of a piece of content being located within a particular view is assigned by the subsystem which handles that content. For example, dyld(1) may impose linkage policy on a dynamic library based on the view in which it resides.

LIBRARY PATH VIEW EXAMPLE POLICY
./usr/lib/libfoo.dylib Platform Any process may link
./lib/libbar.dylib Application Only processes within the same cryptex may link

Discovery of cryptex resources is currently accomplished by an ad hoc collection of methods that are subsystem-specific. In a forthcoming release, a more uniform and extensible discovery interface and contract will be implemented.

Nothing about the current implementation's behavior should be considered stable, and implementation needs have been largely driven by the needs of the Security Research Device program. The details of these behaviors should be expected to change.

cryptexctl(1), hier(7), cryptexd(8),
4 September, 2020 Darwin