Introduced in iOS 16 / macOS Ventura (13.0), Launch Constraints are a security mitigation used to constrain how binaries can be launched.
There are three types of constraints:
- Self Constraints, which the launched binary itself must meet
- Parent Constraints, which the parent process must meet
- Responsible Constraints, which the “responsible process” must meet (presumably the process that asked launchd to launch it)
Note that Self, Parent and Responsible Constraints can also be set by the process performing the launch and they can be included in the code signature, in the new blob type 0xFADE8181.
In both cases, the constraints are DER encoded (just like the DER entitlements).
Constraint Categories
Each binary is assigned a constraint category. These define a set of launch constraints that apply to it.
In iOS 16, there are 7 documented categories (from Linus Henze), while in iOS 17 there are 18 documented categories (from Csaba Fitzl).
iOS 16
Category | Self Constraint | Parent Constraint | Responsible Constraint |
---|---|---|---|
0 | No Constraints | N/A | N/A |
1 | (on-authorized-authapfs-volume || on-system-volume) && launch-type == 1 && validation-category == 1 | is-init-proc | |
2 | on-authorized-authapfs-volume || on-system-volume | ||
3 | (on-authorized-authapfs-volume || on-system-volume) && (launch-type == 0 || launch-type == 1) && validation-category == 1 | ||
4 | (on-authorized-authapfs-volume || on-system-volume) && (launch-type == 0 || launch-type == 1) && validation-category == 1 | (on-system-volume && signing-identifier == “com.apple.mbfloagent” && validation-category == 1) || is-init-proc | |
5 | validation-category == 1 | (on-system-volume && signing-identifier == “com.apple.mbfloagent” && validation-category == 1) || is-init-proc | |
6 | (!in-tc-with-constraint-category || is-sip-protected || on-authorized-authapfs-volume || on-system-volume) && launch-type == 1 && validation-category == 1 | (apple-internal && entitlements[“com.apple.private.set-launch-type.internal”] == 1) || is-init-proc | |
7 | validation-category == 1 |
iOS 17
Category | Self Constraint | Parent Constraint |
---|---|---|
0 | N/A | N/A |
1 | (on-authorized-authapfs-volume || on-system-volume) && launch-type == 1 && validation-category == 1 | is-init-proc |
2 | on-authorized-authapfs-volume || on-system-volume | |
3 | (on-authorized-authapfs-volume || on-system-volume) && (launch-type == 0 || launch-type == 1) && validation-category == 1 | |
4 | (on-authorized-authapfs-volume || on-system-volume) && (launch-type == 0 || launch-type == 1) && validation-category == 1 | (on-system-volume && signing-identifier == “com.apple.mbfloagent” && validation-category == 1) || is-init-proc |
5 | validation-category == 1 | (on-system-volume && signing-identifier == “com.apple.mbfloagent” && validation-category == 1) || is-init-proc |
6 | (!in-tc-with-constraint-category || is-sip-protected || on-authorized-authapfs-volume || on-system-volume) && launch-type == 1 && validation-category == 1 | (apple-internal && entitlements[“com.apple.private.set-launch-type.internal”] == 1) || is-init-proc |
7 | validation-category == 1 | |
8 | (on-authorized-authapfs-volume || on-system-volume) && launch-type == 2 && validation-category == 1 | (on-authorized-authapfs-volume || on-system-volume) && (signing-identifier == “com.apple.sysdiagnose” || signing-identifier == “com.apple.sysdiagnose”) && validation-category == 1 |
9 | (on-authorized-authapfs-volume || on-system-volume) && apple-internal == 1 && (launch-type == 0 || launch-type == 2) && validation-category == 1 | |
10 | (on-authorized-authapfs-volume || on-system-volume) && (launch-type == 0 || launch-type == 2) && validation-category == 1 | |
11 | Same as 10? | Same as 10? |
12 | (on-authorized-authapfs-volume || on-system-volume) && (launch-type == 0 || launch-type == 1 || launch-type == 2) && validation-category == 1 | |
13 | (launch-type == 0 || launch-type == 2) && validation-category == 1 | |
14 | (on-authorized-authapfs-volume || on-system-volume) && launch-type == 3 && validation-category == 1 | is-init-proc |
15 | (on-authorized-authapfs-volume || on-system-volume) && (launch-type == 0 || launch-type == 3) && validation-category == 1 | is-init-proc |
16 | launch-type == 3 && validation-category == 1 | is-init-proc |
17 | (((is-sip-protected || on-authorized-authapfs-volume || on-system-volume) && validation-category == 1) || apple-internal == 1) && launch-type == 2 | |
18 | (on-authorized-authapfs-volume || on-system-volume) && developer-mode && validation-category == 1 | ((is-init-proc || signing-identifier == “com.apple.CoreDevice.dtdebugproxyd”) && validation-category == 1) || apple-internal |
19 | Same as 2? | Same as 2? |
20 | (on-authorized-authapfs-volume || on-system-volume) && (launch-type == 0 || launch-type == 1 || launch-type == 3) && validation-category == 1 |
Launch Type
Launch types are a type of launch constraint that are checked by AMFI on launch. They can be set via posix_spawn by calling the posix_spawnattr_set_launch_type_np function.[permanent dead link]
CS_LAUNCH_TYPE_NONE = 0
CS_LAUNCH_TYPE_SYSTEM_SERVICE = 1
CS_LAUNCH_TYPE_SYSDIAGNOSE = 2
CS_LAUNCH_TYPE_APPLICATION = 3
Validation Categories
Validation categories are a type of launch constraint that are set by AMFI during code signature validation.
There are 10 categories:
- Binary from TrustCache
- TestFlight Development or Production signed – Requires amfid validation
- Signed by an Apple Developer (Production) – Requires amfid validation
- AppStore fast path
- Signed with an iPhone Distribution Certificate – Requires amfid validation
- Signed with a trusted Certificate and not 2, 3, 5 or 10 – Requires amfid validation
- Locally-signed fast path (Rosetta)
- ??? (apparently unused)
- OOP-JIT fast path
- From compilation service, untrusted or iPhone VPN App Production signed
< Todo: Show how TC format changed, how to reverse constraint categories from TCv2 >