Implementing security policies

QNX SDP8.0QNX OS System Security GuideAPIConfiguration
QNX OS security policies use a security policy file to define:
  • the rules that grant privileges to processes, and
  • the security policy types used to apply the rules to processes and other system elements.

For convenience and efficiency, QNX OS provides the secpolgenerate utility, which completes most of the work required to create a security policy for the current system, as well as other tools that manage and monitor behavior related to security policies. (There is no default security policy.)

In addition to the tutorial-like information in this section, you can use mkqnximage to create a system image that demonstrates how security policies work. See Secpol and policy options in the Using mkqnximage to Display Security Features chapter.

Prerequisites

To create a system that uses a security policy, you need to know how to build a bootable QNX OS image (for a detailed introduction, go to the OS Images chapter in the Building Embedded Systems guide). The examples here also follow the best security practice of running all services with their own unique user and group IDs after system startup, as discussed in User IDs for system services.

Security policy types

Security policy rules use security policy types to identify processes and the objects that they interact with. In the security policy, the types are represented by names.

For example, the following two rules grant privileges to a process that has the type random_t (most likely the random service). The second rule grants a privilege to a process of type random_t when it interacts with a channel with type devb_t:

allow_attach random_t /dev/random;
allow random_t devb_t : channel connect;

The type devb_t could also be used for a process and grant it privileges via rules. However, because objects such as channels don’t have privileges, those privileges would only apply to processes with that type.

When you start a process with a type, the system restricts it to the actions given to it by that type's rules (e.g., random started as random_t).

Note:
To avoid weakening security by giving a process permissions it does not need, make sure each resource manager has its own type (i.e., two or more resource managers should not share a type).

For further information about types, go to Using security policy types.

Starting processes with security policy types

To create a system that uses a security policy, you need to start every process that is still active when startup is complete with the name of a security policy type. This example starts a process with a type using on with the -T option, but you can just as easily use System Launch and Monitor (slm), which recognizes types, or your own code that spawns programs with types.

The following abbreviated startup script is for a QNX OS that runs on a VMWare virtual machine and is similar to one used by many BSPs. It is the first thing that runs in a system, executed directly by the OS kernel and process manager (procnto) acting as a rudimentary shell:

  [+script] startup-script = {

slogger2

# Some common servers
pipe
random

devb-eide blk cache=64M,auto=partition,vnode=2000,ncache=2000,noatime,commit=low
waitfor /dev/hd0

. . .

reopen /dev/con1

ksh /proc/boot/start-system
display_msg "---> Starting shell"
[+session] ksh -l &
}

The following startup script rewrites the example to include the basic content that you need to start a system that uses a security policy. You can't use it until the system has a security policy (if you try to boot you get errors), but it establishes the parameters that you need to generate the security policy later.

This script assigns a meaningful type name to each service. You can use any name you like, but policies are easier to work with if the name is based on the name of the associated service. Because each service has unique security requirements, you should have a different type for each service. The script also runs each service with a different user ID, using the -U and -u options:

[+script] startup-script = {

    # Push the security policy
    secpolpush

    on -T slogger2_t slogger2 -U 20:20

    # Some common servers
    on -u 21:21 -T pipe_t pipe
    on -u 22:21 -T random_t random

    on -T devb_t -u 23 devb-eide 
    blk cache=64M,auto=partition,vnode=2000,ncache=2000,noatime,commit=low
    waitfor /dev/hd0

    . . .

    ksh /proc/boot/start-system
    echo "---> Starting shell"
    on -d -t /dev/con1 -T console_t ksh -l

    reopen /dev/con1
}  

This revised script includes the following changes:

  • It switches the system from one operating according to pre-QNX Neutrino 7.0 rules to one that supports and enforces security policies using the following command:
    secpolpush
  • It runs services with a non-root user ID in two different ways. For pipe, random, and devb, it starts the service with its intended user. For slogger2, it starts the service as root and then specifies a user for the process to switch to later.

    You can use user names instead of numeric user IDs, but make sure that the user names are present in /etc/password.

    Note:
    Some processes drop privileges by calling secpol_transition_type(). Start these processes with their user ID (using on with -u), instead of starting them as root and passing them the -U option to have them switch later. (When you generate a policy, this behavior is indicated by the creation of a type__run type.)

    If a process does not transition type, but accepts an option to change user ID, start it as root but specify options that switch the ID later.

    For a process that does not transition type and can’t change its user ID, start it as non-root.

    To identify processes that switch types using secpol_transition_type(), run the following command after you start your system:
    pidin -f a_n

    Processes that switch types using secpol_transition_type() appear in the output with the suffix __run.

  • It changes how it provides a shell on the console. In most cases, BSPs use the following command to provide a shell:

    [+session] ksh -l &

    The revised script uses the following command, which has a similar effect but runs the shell as its own type, console_t (starting a console this way is not secure—don't use it on production systems):

    on -d -t /dev/con1 -T console_t ksh -l

Generate and apply a security policy

Using secpolgenerate is a fast and accurate way to create an initial security policy and update it throughout the development process. It simplifies iterative development by capturing the differences from an existing policy.

In the following example, the startup script adds the lines required to start and configure secpolgenerate, which creates a policy, then invokes secpolpush to push the policy. It assumes the binaries secpolgenerate and libsecpol-gen.so.1 are included in the IFS:

secpolgenerate -u -t 100
LD_PRELOAD=secpol-preload.so
procmgr_symlink /proc/boot/libsecpol-gen.so.1 /proc/boot/libsecpol.so.1
                
secpolpush

It also preloads secpol-preload.so to help discover any paths that might generate too-permissive abilities.

This code should boot your system unless there are errors in the startup script or missing files.

In this example, the system is completely insecure. The -u option tells secpolgenerate that the system should be allowed to run in unrestricted mode, which means, generally speaking, the processes' behavior is not limited in any way.

The -t 100 option allows up to 100 security types. However, in some cases, such as when you are starting a lot of services or the ones you're starting use many security types, a larger number of types is required. A useful starting point is twice the number of services you are starting plus 20 more.

The first time you run secpolgenerate, simply performing a system boot may be sufficient to generate a policy that you can use to familiarize yourself with the related security features. In most cases, you continue to exercise your system at intervals specific to your development process so that secpolgenerate can more thoroughly track all the possible activity that processes can generate. For more information, go to Developing systems with a security policy.

Compiling the generated policy

The security policy is a text file that contains rules in the security policy language and is located in /dev/secpolgenerate/policy. For description of the language, go to Security policy language.

You compile the security policy text file on your host machine using secpolcompile. Use one of the following methods to copy the file to your host:
  • The QNX Momentics IDE Target File System Navigator.
  • If you're running ssh, the cat command using the following format:

    ssh root@<ip-address> cat /dev/secpolgenerate/policy

You can use sftp to copy the policy, but not scp because it copies only the length that stat() returns. Because secpolgenerate generates policy content as the file is being read, it does not provide a meaningful file size.

On your development host machine, use the following command to compile the policy:

secpolcompile -o secpol.bin policy

For more information, go to the secpolcompile entry in the Utilities Reference.

Booting securely

Add the compiled security file to the IFS. To make sure the file is in a predictable location, QNX recommends that you use the default policy filepath /proc/boot/secpol.bin.

If the startup script runs secpolgenerate, as shown in the earlier examples, remove the lines that run it. In the following example, the lines are commented out:

# secpolgenerate -u -t 100
# LD_PRELOAD=secpol-preload.so
# procmgr_symlink /proc/boot/libsecpol-gen.so.1 /proc/boot/libsecpol.so.1
                
secpolpush

After you rebuild your OS image with these changes, you reboot the system. After the reboot, system activity is restricted to what's in the policy—behavior that secpolgenerate observed when you exercised the system.

Page updated: