Security

A resource manager is usually a privileged process, so you should be careful not to let a client coerce it into exhausting resources or compromising the system.

When you're designing your resource manager, you should consider the following:

The permissions on the resource manager's entry in the pathname space
You specify these permissions as an argument to iofunc_attr_init(). In general, there isn't a “correct” set of permissions to use; you should restrict them according to what you want other processes and users to be able to do with your resource manager.
Running as root
A resource manager typically needs to be started by root in order to attach to the pathname space, but it's a good idea to use procmgr_ability() to retain the abilities that the resource manager needs, and then run as a non-root user. For more information, see Process privileges in the QNX Neutrino Programmer's Guide.
Requests to allocate resources on behalf of a client
If the resource manager isn't a critical process that needs to be free of any resource constraint thresholds, it can simply run in constrained mode (see Resource constraint thresholds in the QNX Neutrino Programmer's Guide).

If the resource manager is a critical process, it should keep the PROCMGR_AID_RCONSTRAINT ability (see procmgr_ability()), but it then needs to ensure that constrained clients don't use it to allocate a resource in excess of the currently defined threshold. Unless the resource manager is managing the resource itself, compliance generally means adopting the client's constraint mode when handling a request, in one of the following ways:

  • Automatically, by setting RESMGR_FLAG_RCM in the resmgr_attr_t structure (see the entry for resmgr_attach() in the QNX Neutrino C Library Reference):
    resmgr_attr.flags |= RESMGR_FLAG_RCM;
    resmgr_attach(dpp, &resmgr_attr, name, _FTYPE_ANY, 0, &connect_funcs,
                  &io_funcs, &io_attr))
        
  • Manually, by checking for _NTO_MI_CONSTRAINED in the flags member of the _msg_info structure, available from a call to MsgReceive() or MsgInfo(). If this bit is set, the message was received from a constrained client; when the resource manager allocates resources on behalf of such a client, it should constrain itself using ThreadCtl() with the _NTO_TCTL_RCM_GET_AND_SET command:
    int value = 1; // 1 to constrain, 0 to remove constraint
    ThreadCtl(_NTO_TCTL_RCM_GET_AND_SET, &value); /* swaps current state with value */
    
    /* Handle the request... */
    
    ThreadCtl(_NTO_TCTL_RCM_GET_AND_SET, &value); /* restores original state */
        

When a resource manager runs as a constrained process or constrains one of its threads, resource allocation requests fail when there are still resources available. It should handle these failures in the same way it would handle a failure caused by complete exhaustion of resources, generally by returning an error to the client. If the resource manager can continue to process messages, it should do so, for the sake of overall system stability.

Checking a client's abilities
You can make sure that a client has the appropriate abilities by calling ConnectClientInfoAble() or iofunc_client_info_able(). Both of these take as an argument a list of abilities; if the client doesn't have all the required abilities, these functions set _NTO_CI_UNABLE in the flags member of the _client_info structure.
Note: If you've called one of these functions, iofunc_check_access() returns EACCES if _NTO_CI_UNABLE is set.

Your resource manager can create custom abilities by calling procmgr_ability_create(); a client can get identifiers for them by calling procmgr_ability_lookup(), and then call procmgr_ability() to retain them before it switches to a non-root user ID. For more information, see Creating abilities in the QNX Neutrino Programmer's Guide. When you check a client's abilities, you can include a combination of PROCMGR_AID_* abilities and custom ones.

The resource manager library creates the following custom abilities:

Ability ID Ability name Description
IOFUNC_ABILITYID_CHOWN iofunc/chown (IOFUNC_ABILITY_CHOWN) Allow the client to set the ownership of files, even if not root
IOFUNC_ABILITYID_DUP iofunc/dup (IOFUNC_ABILITY_DUP) Allow the client to duplicate another process's handle
IOFUNC_ABILITYID_EXEC iofunc/exec (IOFUNC_ABILITY_EXEC) Grant execute access to files and directories that the client wouldn't normally have access to
IOFUNC_ABILITYID_READ iofunc/read (IOFUNC_ABILITY_READ) Allow the client to access files for reading, even if it doesn't have the required permissions