secpollaunch

Updated: April 19, 2023

Launch a process with different privileges

Runs on:

QNX Neutrino

Description:

The secpollaunch utility provides a secure way to allow a process to launch processes with privileges that are different than its own. Like setting the setuid or setgid permission bits for an executable, secpollaunch allows a process to spawn a process with additional privileges but can control more than just the user ID (UID) or group ID (GID) of the spawned process.

Without secpollaunch, if a process needs to spawn another process with different security requirements, it needs both its own privileges and those of the process it spawns. But if the new process is spawned via secpollaunch (either directly or indirectly using a symbolic link), secpollaunch determines which process is spawned as well as its arguments, environment variables, and other properties.

The secpollaunch utility relies on a process having one set of abilities when it runs as root and a different set when it runs as non-root. Having extra abilities in the root set is not an issue because the process can't take advantage of them when it runs as non-root (unless it has the abilities PROCMGR_AID_SETUID or PROCMGR_AID_SPAWN_SETUID that include the range 0). When a process launches a process via secpollaunch, secpollaunch can access these extra abilities and run them in a way that the calling process can't because it is setuid root. Because secpollaunch only runs what it is configured to run, it provides a safe way of allowing a process to run things that require different privileges without allowing the process to make use of those privileges in any other way. It is similar to just using setuid root programs but is more flexible and more secure.

To use secpollauch:

  • The system must use security policies.
  • Any process that invokes secpollauch must be running with a non-root user ID and not have the ability to switch to root.
  • The secpollaunch binary must be setuid root.

Setting up a system to use secpollaunch

For a process to invoke secpollaunch, a secpollaunch configuration file that corresponds to its security type is required. For security reasons, the invoking process cannot provide secpollaunch with the configuration file's location. Instead, secpollaunch determines the path based on the security type of the process. The path is always in the following format:

/proc/boot/secpollaunch-type_name.cfg

For example, the following configuration file applies to a process with a security type proctype_t:

/proc/boot/secpollaunch-proctype_t.cfg

To make sure this file is protected appropriately, keep it in the IFS (which ideally is protected by secure boot). However, if it cannot be in the IFS, the path can be a symbolic link (including a process manager symlink) that points elsewhere.

To keep secpollaunch secure, processes cannot be able to affect the configuration files. For example, they are not secure if you mount a writable file system at / or allow processes to attach their channels to anything that includes /proc/boot.

Invoking secpollaunch

When you invoke secpollaunch, you specify the name of the command to run and any arguments that are needed. The command name determines which section in the configuration file contains any alternative arguments and any other configuration such as environment variables.

Use one of the following methods to invoke a program via secpollaunch:

In either case, secpollaunch determines the name of the configuration file based on the type of the invoker and then searches the configuration file using ping.

Configuration file format

A secpollaunch configuration file uses a simple, line-based format. Lines that contain only whitespace or whose first non-whitespace character is a pound sign (#) are ignored.

The following lines are an example of a configuration file:

# Settings that are used for all commands
[global]
    keep_env = TERM HOME    
[ping]
    cmd = /system/other_bin/ping -c 1 %1
    type  = ping_t
[make_logs]
    cmd = /system/other_bin/generate_logs -c %1 -w %2
    creds = 10:20:keep
    type  = log_gen_t
    set_env = PATH=/proc/boot:/system/other_bin:/system/xbin
    keep_env = LOGNAME
    umask = 0
    launch_if = path /dev/socket
            

Section headings are in square brackets. Settings in a [global] section apply to any command, but can be overridden by values later in the file. All other sections apply when secpollaunch invokes the corresponding command (i.e., the section name was the first command line argument when secpollaunch was invoked or the name in the link that invoked secpollaunch indirectly).

Sections can specify the following options:

cmd
A string that contains the command to execute. The first element of the string must be the absolute path of the program to execute. The remainder of the line is a space-separated list of arguments to pass to the program. These arguments can be wrapped in single or double quotes to allow for whitespace.
You can also use arguments specified by the invoking program instead of some or all of the arguments specified by cmd. Use the following arguments (all begin with a percentage sign (%)) to perform this substitution:
  • %n — substitute the argument at the specified position (e.g., %4 to substitute the fourth argument).
  • %n1-n2 — substitute arguments n1 through n2 (e.g., %1-3 to substitute arguments one through three).
  • %n- — substitute all arguments starting at n.
  • %* — substitute all arguments.
There is no default for this parameter.
type
The security type for the new process. By default, the type is unchanged.
creds
A string that sets the UID, GID, and supplementary GIDs. The string uses one of the following formats:
  • uid:gid
  • uid:gid:gid1[,gid2...]

where uid and gid* are user and group IDs, names from /etc/passwd and /etc/group, or the string keep.

When uid or gid are keep, the UID or GID is unchanged from the parent. However, if gid is keep and uid is a name, the GID of the entry in /etc/passwd is used. If gid1 is keep, the supplementary groups of the parent are used and can be added to.

Omitting creds is the same as specifying keep:keep:keep.

keep_env
A space-delimited list of environment variables to preserve. By default, all environment variables are discarded. If you use this option multiple times, each instance adds to the set of environment variables.
set_env
A space-delimited list of name-value pairs (format is name=value) that define environment variables to set. Overrides any existing environment variable setting, including any set by a previous instance of set_env.
umask
An octal string that defines the file mode creation mask to use. Default is 022.
options
A space-separated list of one or more of the following options:
  • noaslr — Disable address space layout randomization (ASLR) for the spawned process. By default, it is always enabled.
  • preswitch — Indicates that secpollaunch should switch its own type, UID, and GID prior to spawning instead of having posix_spawn() perform the changes. This option is only needed to honor the setuid/setgid behavior when you invoke a setuid or setgid program.
  • debug — Output information that can be helpful for diagnosing problems.
launch_if

When you specify this option, the main command is executed only when one or more criteria are satisfied. If you have more than one condition, they must all be met for the main command to be executed. There are two variants for this option: path, and cmd or qcmd.

Below is the syntax for each option:

path option:
launch_if = [!] path pathname
cmd or qcmd option:
launch_if = [!] cmd|qcmd command (args)

The difference between using cmd and qcmd: qcmd will redirect stdout and stderr to /dev/null.

Details for each of the options:
  • path — Checks the existence of pathname. If pathname doesn't exist, the main command is not executed.
  • cmd or qcmd — Checks the return value of executing command with the given args. The rules for this command and its arguments are the same as the rules for the main command. The specified command is run as root. If the return status is non-zero, the main command is not executed. To reduce potential security issues, PATH and LD_LIBRARY_PATH variables are set to the configuration values of _CS_PATH and _CS_LIBPATH.
    Alert: Since the cmd and qcmd commands are executed as root, arguments passed to secpollaunch for a launch_if command must be used carefully to avoid potential security issues.
To invert the condition the main function depends on, add ! before the chosen test type. For example, if you wanted to ensure the main command didn't execute when /dev/socket exists:
 launch_if = ! path /dev/socket
An example of inverting a qcmd command to have the main command run if io-audio is running:
 launch_if = ! qcmd slay -p io-audio
Note: When you allow arguments to be substituted (especially when you use %*), the caller is free to specify any argument, not just the ones that you want to allow. To prevent the caller from performing unintended, potentially harmful operations, you can configure secpollaunch to use a shell script (from a trusted partition) that performs additional argument validation when it executes the command, instead of executing the command directly.

Examples:

The following configuration file section specifies the configuration for pidin when it is invoked via secpollaunch:

[pidin]  
        cmd = /system/other_bin/pidin %*
        type = pidin_t

It allows any arguments that the invoking process specifies, without the invoking process needing the privileges required to execute the commands. The privileges are given to the spawned process by secpollaunch. For example, to show the environment of random:

secpollaunch pidin -p random env

However, using %* allows unrestricted access to pidin (other than restrictions applied by using the pidin_t type). The following example sections also configure pidin, but restrict the permitted arguments:

[pidin_state]
   cmd = /system/other_bin/pidin -p %1
   type = pidin_t
[pidin_type]
   cmd = /system/other_bin/pidin -p %1 -f _
   type = pidin_t

With this configuration, when a process uses the following command to run pidin_state, only the single argument—which has to be a process ID or process name that -p takes—is substituted:

secpollaunch pidin_state random

Similarly, when a process uses the following command to run pidin_type, secpollaunch gets the process name from the invoking process and the value that -f takes from the configuration file.

secpollaunch pidin_type random