Creating a SE Linux Chroot environment

Why use a Chroot environment?

A large part of the use of chroot environments is for the purpose of security, it used to be the only way of isolating a user from a section of the files on a server. In many of the cases where a chroot used to be used for security it is now common practice to use a virtual server. Also another thing to note is that SE Linux provides greater access restrictions to most daemons than a chroot environment would so in many case using SE Linux with a sensible policy is a better option than using a chroot environment to restrict a daemon. So it seems to me that the security benefits that can be obtained by using a chroot environment have been dramatically decreased over the last 5+ years.

One significant benefit of a chroot environment is that of running multiple different versions of software on one system. If for example you have several daemons that won’t run correctly on the same distribution and if you don’t want to have separate virtual machines (either because you don’t run a virtualisation technology or because the resources/expense of having multiple virtual servers is unacceptable) then running multiple chroot environments is a reasonable option.

The Simplest Solution

The simplest case is when all the chroot environments are equally trusted, that means among many other things that they all have the latest security patches applied. Then you can run them all with the same labels, so every file in the chroot environment will have the same label as it’s counterpart in the real root – this will mean that for example a user from the real root could run /chroot/bin/passwd and possibly get results you don’t desire. But it’s generally regarded that the correct thing to do is to have a chroot environment on a filesystem that’s mounted nosuid which will deal with most instances of such problems. One thing to note however is that the nosuid mount option also prevents SE Linux domain transitions, so it’s not such a good option when you use SE Linux as domain transitions are often used to reduce the privileges assigned to the process.

There are two programs for labeling files in SE Linux, restorecon is the most commonly used one but there is also setfiles which although being the same executable (restorecon is a symlink to setfiles) has some different command-line options. The following command on a default configuration of a Debian/Lenny system will label a chroot environment under /chroot with the same labels as the main environment:

setfiles -r /chroot /etc/selinux/default/contexts/files/file_contexts /chroot

I am considering adding an option to support chroot environments to restorecon, if I do that then I will probably back-port it to Lenny, but that won’t happen for a while.

For a simple chroot once the filesystem is labelled it’s ready to go, then you can start daemons in the chroot environment in the usual way.

Less trusted Chroot environments

A reasonably common case is where the chroot environment is not as trusted. One example is when you run an image of an old server in a chroot environment. A good way of dealing with this is to selectively label parts of the filesystem as required. The following shell code instructs semanage to add file contexts entries for a chroot environment that is used for the purpose of running Apache. Note that I have given specific labels to device nodes null and urandom and the socket file log in the /dev directory of the chroot environment (these are the only things that are really required under /dev), and I have also put in a rule to specify that no other files or devices under /dev should be labelled. If /dev is bind mounted to /chroot/dev then it’s important to not relabel all the devices to avoid messing up the real root environment – and it’s impractical to put in a specific rule for every possible device node. Note that the following is for a RHEL4 chroot environment, other distributions will vary a little some of the file names.

semanage -i – << END
fcontext -a -t root_t -f -d /chroot
fcontext -a -t bin_t “/chroot/bin.*”
fcontext -a -t usr_t “/chroot/usr.*”
fcontext -a -t usr_t “/chroot/opt.*”
fcontext -a -f -d /chroot/dev
fcontext -a -f -s -t devlog_t /chroot/dev/log
fcontext -a -f -c -t null_device_t /chroot/dev/null
fcontext -a -f -c -t urandom_device_t /chroot/dev/urandom
fcontext -a -t "<<none>>" "/chroot/dev/.*"
fcontext -a -t "<<none>>" "/chroot/proc.*"
fcontext -a -t lib_t “/chroot/lib.*”
fcontext -a -t lib_t “/chroot/usr/lib.*”
fcontext -a -t bin_t “/chroot/usr/bin.*”
fcontext -a -t httpd_exec_t -d — /chroot/usr/bin/httpd
fcontext -a -t var_t “/chroot/var.*”
fcontext -a -t var_lib_t “/chroot/var/lib.*”
fcontext -a -t httpd_var_lib_t “/chroot/var/lib/php.*”
fcontext -a -t var_log_t “/chroot/var/log.*”
fcontext -a -t var_log_t -f — “/chroot/var/log/horde.log.*”
fcontext -a -t httpd_log_t “/chroot/var/log/httpd.*”
fcontext -a -t var_run_t “/chroot/var/run.*”
fcontext -a -t httpd_var_run_t -f — /chroot/var/run/
fcontext -a -t httpd_sys_content_t “/chroot/var/www.*”

You could create a shell script to run the above commands multiple times for multiple separate Apache chroot environments.

If there is a need to isolate the various Apache instances from each other (as opposed to just protecting the rest of the system from a rogue Apache process) then you could start each copy of Apache with a different MCS sensitivity label which will provide adequate isolation for most purposes as long as no sensitivity label dominates the low level of any of the others. If you do that then the semanage commands require the -r option to specify the range. You could have one chroot environment under /chroot-0 with the sensitivity label of s0:c0 for it’s files and another under /chroot-1 with the sensitivity label of s0:c1 for it’s files. To start one environment you would use a command such as the following:

runcon -l s0:c0 setsid chroot /chroot-0 /usr/sbin/httpd

1 comment to Creating a SE Linux Chroot environment