Ability inheritance

Updated: April 19, 2023

By default, procmgr abilities aren't inherited when you create a new process by using exec*(), posix_spawn*(), or spawn*().

You can modify this setting by specifying the PROCMGR_AOP_INHERIT_YES flag for an ability that a child needs, or PROCMGR_AOP_INHERIT_NO for abilities that a child doesn't need. When children inherit abilities from their parent, make sure that they change the inheritability of any abilities that their children shouldn't receive. For example:

procmgr_ability(0,
                PROCMGR_ADN_NONROOT // Non-root domain
                  | PROCMGR_AOP_ALLOW // Allow the ability
                  | PROCMGR_AOP_INHERIT_NO // Prevent inheritance
                  | PROCMGR_AID_SPAWN_SETUID, // Specified ability
                PROCMGR_AID_EOL // End of ability list.
);

We recommend against making allowed abilities inheritable unless absolutely necessary. Not marking an allowed ability as inheritable allows the system to set it back to a safe default when executing a new process. Any abilities that have been explicitly locked, denied, or both that shouldn't be accessible to child processes should be marked as inheritable, to make sure that the locks and deny states persist.

Note: Forking and spawning handle ability inheritance in different ways:

Here's a simple example of potentially insecure inheritance, due to the combination of PROCMGR_AOP_ALLOW and PROCMGR_AOP_INHERIT_YES. If you're required to do this in your program, make sure the child doesn't inherit any abilities that it doesn't really need.

procmgr_ability(0,
                PROCMGR_ADN_NONROOT // Non-root domain
                  | PROCMGR_AOP_ALLOW // Allow the ability
                  | PROCMGR_AOP_INHERIT_YES // Inheritance
                  | PROCMGR_AID_SPAWN_SETUID, // Specified ability
                PROCMGR_AID_EOL // End of ability list.
);

The following code is more secure because the child will inherit the denied setting for the ability, due to the combination of PROCMGR_AOP_DENY and PROCMGR_AOP_INHERIT_YES:

procmgr_ability(0,
                PROCMGR_ADN_NONROOT // Non-root domain
                  | PROCMGR_AOP_DENY // Deny the ability
                  | PROCMGR_AOP_INHERIT_YES // Inheritance
                  | PROCMGR_AID_SPAWN_SETUID, // Specified ability
                PROCMGR_AID_EOL // End of ability list.
);

Inheritance of a locked and allowed procmgr ability is almost always a vulnerability, unless that ability has been allowed in a more restricted fashion than it would normally be allowed on the system. The following code is an insecure example of locking and inheriting an allowed procmgr ability, due to the combination of PROCMGR_AOP_ALLOW, PROCMGR_AOP_LOCK, and PROCMGR_AOP_INHERIT_YES:

procmgr_ability(0,
                PROCMGR_ADN_NONROOT // Non-root domain
                  | PROCMGR_AOP_ALLOW // Allow the ability
                  | PROCMGR_AOP_LOCK // Lock the ability
                  | PROCMGR_AOP_INHERIT_YES // Inheritance
                  | PROCMGR_AID_SPAWN_SETUID, // Specified ability
                PROCMGR_AID_EOL // End of ability list.
);

The following code is secure and encouraged because the child will inherit the denied setting for the ability and never be able to unlock it, due to the combination of PROCMGR_AOP_DENY, PROCMGR_AOP_LOCK, and PROCMGR_AOP_INHERIT_YES:

procmgr_ability(0,
                PROCMGR_ADN_NONROOT // Non-root domain
                  | PROCMGR_AOP_DENY // Deny the ability
                  | PROCMGR_AOP_LOCK // Lock the ability
                  | PROCMGR_AOP_INHERIT_YES // Inheritance
                  | PROCMGR_AID_SPAWN_SETUID, // Specified ability
                PROCMGR_AID_EOL // End of ability list.
);

You can use code like this to limit procmgr abilities that are normally allowed in the PROCMGR_ADN_NONROOT domain.