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 | ./ ./opt ./usr/local | Content which is private to the cryptex and should not be discovered by other subsystems |
Platform | ./System ./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 which describes and defines a launchd service | Daemons in the Application view are discovered and bootstrapped automatically when the cryptex is mounted |
Agent | Library/LaunchAgents | A launchd.plist which describes and defines a user-specific launchd service | Not implemented |
Manual page | share/man | A man 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 | ./usr/lib/libfoo.dylib ./System/lib/libfoo.dylib |
Application | System executable | barbaz | ./libexec/barbaz ./opt/libexec/barbaz ./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.
September 4, 2020 | Darwin |