SELinux and the Installer

 

Copyright 2013 by Citrix Systems, Inc. This work is licensed under the Creative Commons Attribution 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/.



This page covers the places where the installer and SELinux collide. When this happens things can get pretty ugly as debugging failures related to SELinux can be difficult. This documentation needs to be kept up to date when changes to our design and implementation are made. This documentation is related to the last two versions of OpenXT's predecessor.

The Old

The method used to deal with SELinux specific stuff in the installer up through the older releases was a bit of a hack. This all stemmed from the belief that labeling the file systems in the installer was "the right thing to do". This mostly stemmed from the desire to make booting even on the first boot as fast as possible.

Labeling

This approach was a bit misguided. Our firstboot script moved a bunch of files around and this required relabeling a bunch of files anyways. Further, doing the relabeling in the installer for media installs was trivial as there's no SELinux policy enforced in the installer. The same installer code is how we do the OTA update though and in that environment the dom0 policy is in play. If the necessary labels aren't available in this policy then the relabeling will fail.

Dom0 Policy

We worked around the issue with file labels by loading the poilcy from the rootfs for the new release into the kernel of the system being upgraded. This wasn't an issue for releases that all had the same kernel version. Unfortunately different kernels often have new / different object classes and the a policy for a new kernel will often refuse to load into an older kernel. This is the current state of OTA upgrade in the new version w/r to SELinux: we fail attempting to load the policy from the new version release in the kernel from the old version system we're upgrading.

The New

Given the above, we obviously can't count on the installer to do any file labeling operations. Really the current implementation is just lazy (yes I just called myself lazy).

File Labeling

The same effect can be achieved by doing the file labeling in the first boot path. The benefit to this approach is that we don't have to worry about the old policy vs the new policy. Obviously we want these files to have the labels from the new policy so relabeling them when the new policy is in effect is "the right thing to do".

This approach is a bit of a pain as it requires labeling to happen immediately upon mounting specific r/w file systems. This isn't insurmountable though it does make our boot process less general. The relevant mount points and where they're labeled are:

/boot/system This is mounted extremely early in the boot process by the initramfs. Relabeling here isn't impossible but it's a pain. The good news is that the SELinux policy isn't loaded yet in the initramfs so we can just include the 'setfiles' utility in the initramfs to relabel /boot/system immediately after it's mounted on firstboot.

/config The config partition is mounted next. It could be mounted in two different places. If measured launch hasn't been activated then the xenclient-config-access init script will do the mounting. If measured launch has been configured then the init.root-ro script does the mounting after we get the crypto key from the TPM. In both of these situations the SELinux policy is already in effect so we use the restorecon utility.

/var/log /var/cores /storage Both /var/log and /var/cores are mounted by the cryptdisks init script. They're not accessed till after the mountall init script is run though, so we do all remaining labeling in there. This is much like the relabeling of /config as we just use the restorecon utility on firstboot.

Policy

After moving all labeling operations out of the installer and into the firstboot path we still have issues to sort out with the policy. Moving the relabel operations removes the problem of unknown types on files but we still have the possibility of the installer requiring permissions that weren't allowed in the dom0 being updated.

Predicting the necessary permissions is like predicting the future unfortunately. We're already seeing this with the bits of the installer that run the install-bootloader script in the new dom0 via a chroot. The new dom0 in this case has a newer version of lvm / dmsetup and this needs additional permissions. This is literally one line of policy but it's enough to cause the OTA upgrade to fail.

What we need is a targeted method for installing some set of new policy modules into the running kernel before we attempt to do an OTA upgrade. This actually fits quite well into the model of the installer. The installer itself is broken into two parts with the second part being the installer code that's directly run by the OTA upgrade mechanism. This 'control' package contains the installer logic and is extracted alongside the file system images that it installs. Adding a set of SELinux policies to this control package and adding the logic to load them is pretty straight forward.

Peculier

The old version unfortunately wasn't built to support loading arbitrary SELinux modules at runtime. The ability to run commands like:

semodule -i somemodule.pp.bz2

requires that the /etc/selinux/xc_policy directory be writable. In the old version (and new for that matter) this is read only like the rest of the rootfs. The easiest way to work around this is to push the policy necessary to upgrade OTA into a new old version release. This is horrid but it's easy for us. It's hard on customers though as it will require them to upgrade to the latest old version before they can upgrade to the new version.