Defining launch environment and library constraints
Restrict your app’s components to their expected contexts.
Overview
You define launch environment and library constraints in constraint dictionaries that you either save in launchd property list files, or in separate property list files that you use in code signing. The constraint dictionaries you create contain facts and operations. Facts are assertions that properties of the executable the operating system is launching, or the library your process is loading, match conditions you specify. Operations allow for rich combinations of facts.
The top level of a constraint dictionary is implicitly an $and operation that includes all of the facts and operations in the dictionary. When one process tries to launch another process — by calling execve(_:_:_:) or posix_spawn(_:_:_:_:_:_:) — the operating system checks that the executable file satisfies its own self constraint. It also checks that the parent process’s executable satisfies the executable’s parent constraint, and that the responsible process’s executable satsifies the executable’s responsible process constraint. If any of these launch constraints aren’t satisfied, the operating system doesn’t run the program.
Your process can load a dynamic library if all of the facts and operations at the top level of the library constraint dictionary are true for the file that contains the library. If any part of the library constraint isn’t true, your process doesn’t load the library.
launchd tests constraints that you specify in launchd property list files when it needs to start your launch daemon or agent. If the executable specified in the launchd property list doesn’t satisfy the constraint in the property list, then launchd doesn’t start the process.
Constrain the executable’s launch environment
Construct the launch constraint by adding keys and values that represent constraint facts, and operators that combine facts using logical operations. Use facts from the list below in your launch constraint.
cdhashA binary data sequence that’s the hash of the code directory content of an executable, or an
$inoperator whose parameter is a list of data sequences. An executable satisfies this constraint if its code directory hash is the same as the value in the constraint. For more information about code directory hashes, see TN3126: Inside Code Signing: Hashes.
A single executable file can contain multiple code directory hashes, for different CPU architectures and hash algorithms. Identify an executable’s code directory hash using a collection of valid hashes and the $in operation.
entitlementsAn entitlement query that names an entitlement and gives its expected value. An executable satisfies this constraint if its code signature includes this entitlement with the specified value. For a list of entitlements, see Entitlements. For information on how to construct an entitlement query, see the
$queryoperator below.is-init-procA Boolean value that indicates whether the executable must be the operating system’s initialization process (
launchd).is-sip-protectedA Boolean value that indicates whether the executable must be a file protected by System Integrity Protection (SIP).
launch-typeAn integer value that describes the context in which the operating system is launching the executable. Launch type 0 is the default, meaning the operating system didn’t set a launch type. Starting in macOS 14.0, Launch Services sets launch type 3 when launching an executable to start an app; for example, when a person clicks an app icon in the Dock. Launch types 1 and 2 are reserved for use by the operating system.
on-authorized-authapfs-volumeA Boolean value that indicates whether the operating system loaded the executable from an authorized, authenticated APFS volume.
on-system-volumeA Boolean value that indicates whether the operating system loaded the executable from the currently-booted system volume.
signing-identifierA string that’s a code signing identifier, or an
$inoperator whose parameter is a list of strings. An executable satisfies this constraint if its signing identifier is the same as the value in the constraint. The code signing identifier for an executable file is usually the CFBundleIdentifier in the information property list of the bundle that contains the executable.team-identifierA string that identifies a registered developer, or an
$inoperator whose parameter is a list of strings. An executable satisfies this constraint if the team that signed the executable matches the value in the constraint.
Team identifiers are present in executables signed by code signing identities for development, TestFlight, App Store, or Developer ID.
validation-categoryAn integer that’s a code signature validation category, or a
$inoperator whose parameter is a list of integers. An executable satisfies this constraint if its signature is consistent with the validation category in the constraint. Use values for the validation category from the table below.
Use values from the table below with the validation-category fact.
Code signature validation category | Description |
|---|---|
| An operating system executable. |
| An executable distributed through TestFlight. |
| An executable signed by a development code signing identity. |
| An executable distributed through the App Store. |
| An executable distributed using an Enterprise Universal Provisioning Profile, or ad-hoc distribution. |
| An executable signed using Developer ID. |
| These values aren’t appropriate for |
| An executable signed with a code signing identity that doesn’t match any other category. |
This example of a launch constraint uses a team-identifier fact to require that an executable’s signed with the Team ID 8XCUU22SN2.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>team-identifier</key>
<string>8XCUU22SN2</string>
</dict>
</plist>Build complex checks with operators
Constraint dictionaries can include any of the following operators, to build complex checks. An operator can take the place of a value in a fact, in which case each of the values in the operator expression applies to the fact that contains the operator. An operator can also take the place of the fact key itself, in which case the values of the operator expression are themselves key-value pairs that name facts. As dictionaries only contain one instance of any particular key, use operators to compose multiple tests that use the same fact.
Operator | Value type | Description |
|---|---|---|
| A dictionary of facts or operators. | An |
| An array of subarrays. Each subarray contains a logical operator ( | An |
| A dictionary of facts or operators. | An |
| An array of subarrays. Each subarray contains a logical operator ( | An |
| A list of strings, data, or integers. | A fact using the |
| An integer. | A fact using the |
| An integer. | A fact using the |
| An integer. | A fact using the |
| An integer. | A fact using the |
| A dictionary that contains a single fact or operator. | The result of the |
| An array that contains subarrays for representing the entitlements query. | The kernel uses the query to test the executable’s entitlements. You can only use a |
The launch constraint in the example below uses the $or operator to require that an executable’s either signed with the Team ID 8XCUU22SN2, or is an operating system executable.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>$or</key>
<dict>
<key>team-identifier</key>
<string>8XCUU22SN2</string>
<key>validation-category</key>
<integer>1</integer>
</dict>
</dict>
</plist>Construct an entitlements query
An entitlements query is an array of query operations. Each operation is an array with two entries: an integer operation code, and a parameter that can be an integer, a string, or a Boolean value. The operations either select specific information about the entitlements, or match the currently-selected information against a value specified in the parameter.
The kernel executes your query in a virtual machine (VM) that has a context that includes an entitlements state and a validity flag. The initial value of the state is the executable’s entitlements dictionary, and the query execution is valid. The VM processes each operation in the query in sequence. A select operation updates the state by fetching specific information from the current state, or marks the execution as invalid if it can’t find the requested information. A match operation marks the execution as valid if the current state’s value matches the operation’s parameter, and invalid otherwise. If the execution remains valid until the VM executes all of the operations in the query, then the executable satisfies the query.
Use the following operation codes in entitlements queries:
Operation code | Operation | Value type | Description |
|---|---|---|---|
| Select key | A string that names a dictionary key | If the current state is a dictionary that contains this key, the operation updates the state to the value in the dictionary for the key. If the current state isn’t a dictionary or doesn’t contain the key, the operation marks the query execution as invalid. |
| Select index | An integer that represents an array index | If the current state is an array with enough elements, the operation updates the state to the value in the array at the given index. If the index isnʼt in the array or the current state isnʼt an array, the operation marks the query execution as invalid. |
| Match string | A string | Marks the execution as valid if the current state is a string equal to the parameter; otherwise, it’s invalid. |
| Match string prefix | A string | Marks the execution as valid if the current state is a string that starts with the parameter; otherwise, it’s invalid. |
| Match Boolean | A Boolean value | Marks the execution as valid if the current state is a Boolean value equal to the parameter; otherwise, it’s invalid. |
| String value allowed | A string | If the current state is a string, this operation is equivalent to match string (Operation code |
| Match integer | An integer | Marks the execution as valid if the current state is an integer equal to the parameter; otherwise, it’s invalid. |
| String prefix value allowed | A string | If the current state is a string, this operation is equivalent to match string prefix (Operation code |
| Select key with prefix | A string that names a dictionary key | If the current state is a dictionary that contains any key starting with the parameter, the operation updates the state to the value in the dictionary for the longest-matching key. If the current state isn’t a dictionary or doesn’t contain a key with the prefix, the operation marks the query execution as invalid. |
| Integer value allowed | An integer | If the current state is an integer, this operation is equivalent to match integer (Operation code |
| Match type | An integer, with values from the table below. | Marks the execution as valid if the type of the current state matches the type specified in the parameter; otherwise, it’s invalid. |
When you write an entitlements $query using the match type operation (Operation code 11 in the table above), use one of the values in this table as the parameter:
Value | The context’s expected type |
|---|---|
1 | A dictionary |
2 | An array |
3 | An integer |
4 | A string |
5 | A Boolean value |
The launch constraint in the example below uses an entitlements fact and the $query operator to require that an executable has the Camera entitlement (com.apple.security.device.camera) with the Boolean value true.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>entitlements</key>
<dict>
<key>$query</key>
<array>
<array>
<integer>1</integer>
<string>com.apple.security.device.camera</string>
</array>
<array>
<integer>5</integer>
<true/>
</array>
</array>
</dict>
</dict>
</plist>