Secpol and policy options

Updated: April 19, 2023

The --secpol option and the related --policy option are used to make use of security policies on an image generated by mkqnximage.

The --secpol option provides three options:

no
Security policies are not used. This is the default.
secure
The system is being run securely using the policy specified by the --policy option.
open
The system is being run with policy generation. In this mode, by default, all processes are unconstrained.

The --policy option can either be none (no policy file is put on the system) or it can be set to the path to a textual security policy. In the latter case, the policy file is compiled and put on the image in one of two places. If you use the secure option, you have to specify a policy; otherwise, the system won’t boot. With the open option, you have the choice of using a policy or not, depending on whether you want to generate a policy from scratch or from an existing one.

If a policy is used, you can edit the text file that describes the policy, in which case if the image is rebuilt, the changed policy is re-compiled. This mechanism provides a good way of experimenting with policy changes.

The --secpol option makes many changes to the configuration of the system. Most of the changes are the same whichever --secpol option is used. However, the open option adds a few extras.

In the IFS startup script (in ifs.build), prior to anything being started, the secpolpush utility is run to push the security policy to procnto.

The biggest changes are in the startup script, startup.sh. While the changes are extensive, they are simple in nature. For every service that is started, everything that will leave a process running after startup completes is started with a security type using the on utility. It is done in two ways, depending on the details of the service. If the service either supports security policy type transitions or doesn’t support any form of privilege dropping, the on command is used to give the service both a type and a user and group ID. For example:

slogger2 -U 21:21 -P /pps/slogger2 

pci-server --config=/proc/boot/pci_server.cfg 

is changed to:

on -T slogger_t -u 21:21 slogger2  -P /pps/slogger2 

on -T pci_server_t -u 34:34 pci-server --config=/proc/boot/pci_server.cfg 

If the service doesn’t support type transitions but does support dropping root (typically a -U option), then on is used only to set the type, for example:

devc-pty -U 37:37 

is changed to:

on -T devc_pty_t devc-pty -U 37:37 

It’s not necessary to get it right first time. By inspecting a running system you can tell how processes behave and make changes accordingly. Commands such as:

waitfor /dev/socket 

are left alone. It doesn’t matter that they run as root with no type as they don’t persist.

The last change used whenever security policies are used is a change to PAM configuration. Each PAM configuration file now includes the pam_secpol.so module to force a type transition when, for example a user logs in over ssh.

When the --secpol option is set to open, an extra set of changes are made. The changes depend slightly on another option, --ablelock. The following assumes this is set to yes (the preferred setting).

The biggest change is starting secpolgenerate prior to invoking secpolpush. While this could be much simpler, the way it is done here allows the base security policy and secpolgenerate’s configuration file to be located on a read/write file system. It is strongly recommended that this practice be followed as it greatly simplifies development. To do this, a minimal set of services is started to provide access to a filesystem (in this case, pci-server and devb-eide). Once running, secpolgenerate is started and then the services that were started are killed off. The aim is to return the system to the state it was in, though now with secpolgenerate running.

When secpolgenerate is used, the library libsecpol-gen.so.1 is used in place of libsecpol.so.1. The mkqnximage utility does this by creating a process manager symlink from libsecpol-gen.so.1 to libsecpol.so.1, though it could just as easily be done by putting libsecpol-gen.so.1 in the image with the name libsecpol.so.1.

The other change for using secpolgenerate is the addition of a number of files in the data partition that will appear in /data/var/secpol. These files include the secpolgenerate configuration file and, if the --policy option was used to provide a policy, the binary policy file. By putting these files here, it is possible to replace them at run time and reboot to make them take effect. When you use --secpol=secure, the binary policy file is instead put in its standard location, /proc/boot/secpol.bin.

The best way to gain experience with security policies is to start with --secpol=open. An image built this way should boot normally.

If you run the command pidin -f an_, you’ll get output similar to:

   49155 proc/boot/slogger2  slogger_t__run    

   65541 proc/boot/pci-server  pci_server_t      

   90118 proc/boot/devb-eide  devb_t__run       

  983067 system/xbin/pidin  user_root_t 

This shows the security types each process is running as. In the case of pci-server, the type is the same as the one it was started as. This is an indication that it doesn’t support type transitions. The other two, both end in __run, which shows that they have performed a transition. None of these types are preconfigured—they are generated on the fly based on what processes do.

You should find that every process has a type with the sole exceptions of procnto-smp-instr and secpolgenerate.

A system running secpolgenerate is usually not secure, in fact it is very insecure. To see this, you can try doing normally prohibited things as a non-root user. For example:

# su user1 

$ ln -sPf /proc/boot/echo /data/another_echo 

$ /data/another_echo hello 

hello 

If you try this on a system not built in this way, the ln command fails because creating process manager symlinks is a privileged operation.

One of the primary reasons for using secpolgenerate is to have it generate a security policy. If you look in the directory /dev/secpolgenerate, you’ll see three files (as well as several non-files). If you look in policy, this includes such content as:

# === Rules for type user_user1_t ============ 

allow_link user_user1_t { 

    /data/another_echo 

}; 

allow user_user1_t self:ability { 

    setuid:101 

    setgid:1 

    channel_connect:devb_t,pipe_t 

}; 

These are all security policy rules needed for the system to do what it has done. In this case, you can see the effect of creating the process manager symlink in the last example. If you create another one with a different name, you’ll see that reflected in the policy file too.

The unused and errors files will be empty apart from a comment. If you had used the --policy option to specify an initial policy, the unused file would indicate any rules that were in that policy that have not been required so far. This might be a hint that those rules are no longer required. If the --policy option was used to configure an initial policy, the policy file would also change, showing only new rules that are needed that weren’t in the initial policy instead of a complete policy.

It should be possible to take the policy that secpolgenerate has created and re-build the system to use it. Two ways to obtain the policy are to either use the target file system navigator in QNX Momentics IDE, or use sftp. To get it with sftp, you run something such as the following on the host side:

$ sftp root@172.16.40.144 

Connected to root@172.16.40.144. 

sftp> get /dev/secpolgenerate/policy policy.txt 

Fetching /dev/secpolgenerate/policy to policy.txt 

sftp> quit 

The image can then be rebuilt and re-started using the policy:

mkqnximage --policy=policy.txt --run 

Because this image is still using policy generation, it behaves much as before and is equally insecure. If you repeat the earlier example of creating a process manager symlink, though with a different name, as a non-root user and look at /dev/secpolgenerate/policy, you should see the file is much smaller and only has, possibly, a single new rule. If you look in unused, you will find the rule used to create the previous process manager symlink to be there reflecting the fact that the rule no longer appears to be needed. This demonstrates how one uses the output of secpolgenerate to guide policy maintenance. It is important to note that you shouldn’t apply changes indicated by secpolgenerate blindly. It is possible that you’ve done things that wouldn’t normally be done and you wouldn’t want the final policy to reflect this. The unused rules might also simply be the result of not having fully exercised the system.

You can also run the system in a secure fashion. There are two ways to do this. One way is to change the --secpol option to secure. This represents how you would release a system that uses security policies. The second way is how you might do it during development. Rather than rebuilding the system, you can use the system built to use secpolgenerate and flip it to be secure. To do this, you edit the file /data/var/secpol/config and add the line:

option restricted

This will take effect when you reboot. However, before you reboot, it is important that you verify that there are no errors in the file since if there are you might find the system doesn’t boot and you have no means to correct them. The simplest way to check for errors is to run secpolgenerate. If you run:

# secpolgenerate -c /data/var/secpol/config -N 

You should just see the messages:

secpolgenerate: tracelog_monitor likely failed … 

secpolgenerate: failed to run trace_monitor 

This shows secpolgenerate accepted the configuration file but failed because another instance of secpolgenerate was already running. If there had been configuration errors, it would instead have reported them.

Having changed the configuration file, if you then reboot, you should be able to repeat the creation of process manager symlinks as a non-root user as was done earlier. If, however, you try something new, for example:

$ ln -sPf /proc/boot/echo /data/another_echo3  

ln: unable to link. (/proc/boot/echo or /data/another_echo3): Permission denied 

This request is denied because while a process manager symlink of the original name can be created, one with a new name cannot. If you now look in the file /dev/secpolgenerate/errors, you see an indication of this failure.