Desc: chrooting and other forms of paranoia
File: chroot.txt
Date: 19 August 2002
Auth: Russell Kroll <rkroll@exploits.org>

If paranoia is your thing, you've come to the right place.  It is
possible to run the drivers and upsd in a chrooted jail.  You just have
to create a miniature version of your system in a separate tree that has  
everything that they need.  This means things like your C library if
you dynamically linked the programs, configuration files, and so on.

This assumes you are already using the "security domains" setup as seen
in the FAQ with nutdev and nutsrv.  If you aren't, go read about that,
get it working, then come back to this document.  This is a lot easier
to do if you have the non-root startup already figured out.

Fair notice: this can be deep magic if you're not familiar with how
programs link to each other on your system.  If you've never run
ldconfig by hand or installed something from source before, this may not
be for you.

In this case I'm using /chroot/nut as the new root.

Design
------

Remember that the drivers and upsd talk to each other initially through
state files - typically in /var/state/ups.  Once they get hooked up
through that file, they use shared memory and SysV IPC to send things
around.  So, they do need to both run in the same jail filesystem.

Prepare the jail
----------------

On my Slackware based guinea pig system, here are the things that had
to be moved over to make everything happy:

	/bin/su		(but not suid root!)
	/bin/sh		(symlink to /bin/bash, as it is in the real /bin)
	/bin/bash

	/usr/local/ups			(obviously - copy what you need)

	/lib/ld-2.2.2.so		(change version numbers as needed)
	/lib/libc-2.2.2.so
	/lib/libcrypt-2.2.2.so
	/lib/libnss_compat-2.2.2.so
	/lib/libnsl-2.2.2.so
	/lib/libtermcap.so.2.0.8	(bash needs this)
	/lib/libdl-2.2.2.so

	/etc/ld.so.conf		(empty file, to make ldconfig be quiet)
	/etc/login.defs		(same as your normal one - keeps su happy)
	/etc/passwd		(just nutdev/nutsrv entries)
	/etc/group		(just the nut entry)

	/var/state/ups		(same permissions as the original one)

	/dev/console		(use cp -a for these to preserve details)
	/dev/null
	/dev/log
	/dev/ttyS1		(or whatever port you may be using)

Once all the libraries are in place, you need to run ldconfig to generate
all the symlinks for those so files.

	/sbin/ldconfig -r /chroot/nut

In the /etc/passwd and group files, just copy the entries you were using
for nutsrv and nutdev from the real system files.  Nothing else is needed.

You'll have to restart syslogd and add a switch that will make it pick
up the log entries from the programs.

	/usr/sbin/syslogd -a/chroot/nut/dev/log

Start the programs
------------------

Finally, you can start the driver:

	/usr/sbin/chroot /chroot/nut /bin/su nutdev -c \
		"/usr/local/ups/bin/newapc /dev/ttyS1"

Or, if you have switched to using the driver controller:

	/usr/sbin/chroot /chroot/nut /bin/su nutdev -c \
		"/usr/local/ups/bin/upsdrvctl start"

Then start the server:

	/usr/sbin/chroot /chroot/nut /bin/su nutsrv -c \
		"/usr/local/ups/sbin/upsd" 

If everything has been setup correctly, they should start up as before,
and the client programs like upsmon will see no difference.

Obviously this is expected to be quite a bit different on other systems,
but the principle is the same.  Clone what you need as far as libraries
and support files go, and leave the rest behind.  I recommend using tools
like strace where available to figure out other things that may be
needed.  su didn't work until all those glibc support files were copied
in, for example.  It would just say "Sorry.", which is not a great help.

Be sure you change your startup scripts to use the new chroot-based
init methods once you're satisfied with the operation of the programs
in this environment.

If everything has been done correctly, you'll have a clean environment
where the programs never have root.  So, if they happen to be compromised
somehow, the attacker is confined to the chroot jail.

upsmon
======

Note that upsmon must start with full root privileges since it has to
signal init to switch runlevels and shut down.  Recent developments have
minimized the use of root, however.  upsmon by default now drops root
powers in the main process shortly after reading the config file.

During normal operations, there are two upsmons running.  One is a
privileged parent which does nothing but block in read() reading for a
signal from the unprivileged child which does all the monitoring work.  If
the parent gets the proper result from the child, then it calls the
SHUTDOWNCMD.  Any other character results in it shutting down with an
error.

This design of a split parent/child with a limited communications channel
was inspired by the authentication techniques in Solar Designer's popa3d.

chrooting upsmon has not yet been attempted, but it should work if you can
tell your init to start the shutdown from inside the jail.
