Initialization

Updated: April 19, 2023

To help avoid vulnerabilities, make sure that after startup a resource manager runs with minimum privilege and does not run as root.

Reducing privileges after startup

In almost all cases, a resource manager needs more abilities during startup than it does during its subsequent operation. Usually, many of the abilities it needs at startup are given only to root by default.

The method for removing abilities for post-startup operation depends on whether the system is using security policies.

If security policies are used, you can call secpol_transition_type() after initialization to drop privileges (see secpol_transition_type()). A resource manager can try this action and fall back to the second option if it fails. This behavior allows a resource manager to run successfully both in systems with security policies and systems without them.

If you're not using security policies, start the resource manager as root and then, after initialization, configure abilities and change to a non-root user ID. By convention, resource managers use a command line parameter to specify the user ID, group ID, and additional groups to run as.

For example, for devi-hid, the -U option uses one of the following formats:
-U user_name
-U uid[:gid[,sup_gid]*]]
In the first form, the service sets itself to the named user and uses that user's groups. It depends on the /etc/passwd and /etc/group files. In the second form, the service sets its user ID (and, optionally, its group ID and supplementary groups) to the specified values.
For example, the following startup script entry sets the user ID for pipe to 21 and its group ID to 22:
pipe -U 21:22

In addition, you can use the set_ids_from_arg() function in the liblogin library to change the resource manager's user ID, group ID, and additional groups.

Channel accessibility

If a channel doesn't need to be accessed by other processes, make it private (using the _NTO_CHF_PRIVATE flag) to reduce the attack surface exposed by the resource manager.

Setting permissions

Before you call resmgr_attach(), make sure that you assign the correct permissions to the resource manager, which is typically done using iofunc_attr_init(). Although setting the user ID, group ID, and POSIX permissions of the resource does not prevent clients from contacting the resource manager, many of the internal resource manager library functions rely on correctly set user ID, group ID, and POSIX permissions to implement proper permission checking.

For example, the following code configures the device exposed by the resource manager as a regular file with permissions of 0600 (a secure, default permission value):

iofunc_attr_t io_attr;
iofunc_attr_init( &io_attr, S_IFREG | 0600, 0 , 0 );
By default, iofunc_attr_init() uses the current user and group ID of the resource manager process when it assigns IDs to the resource. QNX recommends using the resource manager's current user or group ID when you assign the user or group ID to the resource. This is the default behavior of iofunc_attr_init() when the info parameter is NULL.

Restricting chown

By default, the resource manager library allows a client with the same user ID as the resource to change the user and group ID on the resource to any other user on the system. To prevent a client from changing the user ID on a file exposed by a resource manager mountpoint, set the IOFUNC_PC_CHOWN_RESTRICTED flag in the mount attributes (see iofunc_mount_t in the C Library Reference). All the filesystem resource managers that QNX Neutrino provides set this flag.

For example, the following code sets IOFUNC_PC_CHOWN_RESTRICTED:

iofunc_mount_t mattr;
iofunc_mount_init(&mattr, sizeof(mattr));
mattr.conf |= IOFUNC_PC_CHOWN_RESTRICTED;
io_attr.mount = &mattr;