procmgr_ability()

Updated: April 19, 2023

Control a process's ability to perform certain operations

Synopsis:

#include <sys/procmgr.h>

int procmgr_ability( pid_t pid,
                     unsigned ability, ... );

Arguments:

pid
The process ID of the process whose abilities you want to control, or 0 to control those of the calling process.
Note: In order to change a different process's abilities, your process needs the PROCMGR_AID_XPROCESS_ABLE ability enabled.
ability
A list of the abilities. Each ability in the list is composed of three separate components that are ORed together:
  • An identifier (PROCMGR_AID_*, or a custom ability found with procmgr_ability_lookup()) that tells procnto which particular ability you're modifying. See Abilities in the Security Policy Guide for the table detailing the abilities and their names.
  • One or more operations (PROCMGR_AOP_*) that identify the operation you're performing on the ability.
  • One or more domains (PROCMGR_ADN_*) that indicate whether you're modifying what you can do with the ability while running as root or non-root.
Note: Terminate the list with the special ability identifier PROCMGR_AID_EOL.

You can OR the domain flags and any of PROCMGR_AOP_DENY, PROCMGR_AOP_ALLOW, and PROCMGR_AOP_LOCK into the PROCMGR_AID_EOL macro that ends the list. If you do this, the operations are performed on all the unlocked abilities that you didn't specify in the list.

uint64_t lower, uint64_t upper
If the ability is for a subrange (see below), follow it by two uint64_t arguments that specify the lower and upper limits on the range.

Library:

libc

Use the -l c option to qcc to link against this library. This library is usually included automatically.

Description:

The procmgr_ability() function takes a list of ability operations to control what the identified process is allowed to do. This function lets a process start running as root, set the abilities it needs, and then change its group and user IDs. This can make your system more secure by reducing the number of potentially vulnerable processes running as root.

Note:
  • Using a security policy is more secure and less error-prone than calling procmgr_ability().
  • If you want to set more than one ability, you must specify a separate identifier-operation-domain argument (with any subranges) for each. The identifiers are an enumeration; don't try to OR them together.

You must OR in at least one of the following operations:

PROCMGR_AOP_DENY
Disallow the performance of the operation in the specified domain(s).
PROCMGR_AOP_ALLOW
Allow the performance of the operation in the specified domain(s). You must have the PROCMGR_AID_ABLE_PRIV ability enabled to do this for privileged abilities.
PROCMGR_AOP_SUBRANGE
Restrict the feature to set its parameter to a certain subrange in the specified domain(s). The meaning of the parameter depends on on the ability, as described above. Follow the ability entry in the function's parameter list with two uint64_t arguments that give the lower and upper bounds of the subrange. You must have the PROCMGR_AID_ABLE_PRIV ability enabled to do this for privileged abilities.

Note the following:

  • You must still have the PROCMGR_AOP_ALLOW flag set for the ability in the domain in order to successfully use the feature.
  • If you don't specify a subrange on an ability, and the ability is allowed, then it's allowed for the entire range.
  • If you specify a subrange on an ability, and the ability is allowed, it's allowed for just the subranges specified.
  • If you specify a subrange on an ability, and the ability is denied, the set subranges are ignored; the ability is denied regardless of the requested range.
  • If you specify the PROCMGR_AOP_SUBRANGE and PROCMGR_AOP_DENY flags together, the ability is denied, but the allowed subranges list (should the ability be enabled in the future) is modified to add the new range listed.
  • You can have multiple subrange entries in the list; they “OR” together to let you form a discontiguous set. To do this, specify the identifier-operation-domain argument again, followed by another pair of range arguments. For access checks that span a range, the entire range must be covered by a single subrange. For example, the PROCMGR_AID_MEM_PHYS ability with the enabled subranges 100–200 and 190–300 would not allow a request for the subrange 150–250.
  • Subranges can never be deleted once added to an ability. A PROCMGR_AOP_DENY doesn't delete any subranges associated with the ability being dropped. Any request to set a subrange adds to the list of allowed subranges.
PROCMGR_AOP_LOCK
Lock the current ability so that no further changes to it can be made.
PROCMGR_AOP_INHERIT_YES
The changes to the ability are inherited across a spawn or exec.
PROCMGR_AOP_INHERIT_NO
The changes to the ability aren't inherited across a spawn or exec. This is the default.
Note: For a fork(), the parent's ability configuration is copied to the child verbatim, regardless of the INHERIT status of each of the abilities.

You must OR in at least one of the following for the domain portion:

PROCMGR_ADN_ROOT
Modify the ability of the process when it has an effective user ID of 0.
PROCMGR_ADN_NONROOT
Modify the ability of the process when it has an effective user ID other than 0.

Returns:

EOK
The abilities were successfully modified.
E2BIG
The list of abilities is too large. You might not have terminated the list with PROCMGR_AID_EOL.
EINVAL
There's something wrong with the parameters to the function.
ENXIO
(QNX Neutrino 7.0 or later) The process indicated by pid is no longer valid. It's going away, has core dumped, or become a zombie.
EPERM
One of the following:
  • A process that does not have PROCMGR_AID_ABLE_PRIV tried to give itself a privileged ability.
  • A process that does not have PROCMGR_AID_XPROCESS_ABLE tried to change the abilities of another process.
  • A process tried to change a locked ability and procnto was not run with the -bl option.
  • One of the specified abilities has a temporary ID (i.e., has PROCMGR_AID_UNCREATED ORed into it).

Examples:

Remove the ability for a root process to set the user ID when spawning a process:

procmgr_ability(0,
        PROCMGR_ADN_ROOT|PROCMGR_AOP_DENY|PROCMGR_AID_SPAWN_SETUID,
        PROCMGR_AID_EOL);

Regain the ability for a root process to set the user ID:

procmgr_ability(0,
        PROCMGR_ADN_ROOT|PROCMGR_AOP_ALLOW|PROCMGR_AID_SPAWN_SETUID,
        PROCMGR_AID_EOL);

Drop all abilities while running as root and lock out any further changes:

procmgr_ability(0,
        PROCMGR_ADN_ROOT|PROCMGR_AOP_DENY|PROCMGR_AOP_LOCK|PROCMGR_AID_EOL);

Allow a non-root process to set the user ID while spawning, but restrict the number to 10000 or higher and lock out any further changes. Remove all other abilities while running as root, and lock any further changes to them as well:

procmgr_ability(0,
        PROCMGR_ADN_NONROOT|PROCMGR_AOP_ALLOW|PROCMGR_AID_SPAWN_SETUID,
        PROCMGR_ADN_NONROOT|PROCMGR_AOP_SUBRANGE|PROCMGR_AOP_LOCK|PROCMGR_AID_SPAWN_SETUID,
        (uint64_t)10000, ~(uint64_t)0,
        PROCMGR_ADN_ROOT|PROCMGR_AOP_DENY|PROCMGR_AOP_LOCK|PROCMGR_AID_EOL);

Do the same as the above, but specify a discontiguous set of user IDs by using a second PROCMGR_AID_SPAWN_SETUID ability:

procmgr_ability(0,
        PROCMGR_ADN_NONROOT|PROCMGR_AOP_ALLOW|PROCMGR_AID_SPAWN_SETUID,
        PROCMGR_ADN_NONROOT|PROCMGR_AOP_SUBRANGE|PROCMGR_AID_SPAWN_SETUID,
        (uint64_t)1000, (uint64_t)1050,
        PROCMGR_ADN_NONROOT|PROCMGR_AOP_SUBRANGE|PROCMGR_AOP_LOCK|PROCMGR_AID_SPAWN_SETUID,
        (uint64_t)2000, (uint64_t)2013,
        PROCMGR_ADN_ROOT|PROCMGR_AOP_DENY|PROCMGR_AOP_LOCK|PROCMGR_AID_EOL);

Classification:

QNX Neutrino

Safety:  
Cancellation point No
Interrupt handler No
Signal handler No
Thread Yes