			SuSE secure compartment
				v1.1

		(c) 2000 by Marc Heuse <marc@suse.de>





INTRODUCTION
------------

This tool was written to securely run untrusted services and programs.
It has all options needed to make the impact of an successful hacker
attempt on a service as small as possible.


INSTALLING
----------

Type "make install" (this will also compile the program)
The binary "compartment" will be installed in /usr/sbin, the textfiles
README, CHANGES and TODO to /usr/doc/packages/compartment and the man page
compartment.1 to /usr/share/man/man1


IMPORTANT TIPS
--------------

This section should be below "how to run" however I fear that *you* might
stop reading before getting to this section.
So listen up and take notice of these important tips:

	* always try to use the --chroot option. This might take some work and
	  pain, however it is the best way to secure a service.
	* always try to use the --user AND --group option if no root
	  priviliges are needed.
	* if root privs are needed, use capabilities
	* if you use capabilities:
		-> always chroot !
		-> chown all files/dirs to another user than root if thats
		   possible - otherwise just those which really need to be
		   writable by the program
	* there are several capsets which should not be used, because then
	  it might be easy to become the real superuser of the machine:
		CAP_NET_ADMIN, CAP_NET_RAW, CAP_FOWNER, CAP_SYS_MODULE,
		CAP_SYS_CHROOT,	CAP_SYS_PTRACE, CAP_SYS_ADMIN
	  And several others can be used to denial-of-service the machine!
	  Once again: always chroot when using capabilities!

Remember these tips!


If you have got problems getting a program running chrooted or with capsets,
try to "strace -v -s 250 -ff -F -qix -o problem /usr/sbin/compartment ...."
the problem - check for system calls which failed and try to figure out how
to get it working.

And please: if you get a program/daemon running with chrooting and/or
capsets, please send me an email (marc@suse.de) with all information. Far
below is a section called "how to get the service xxx running" which needs
*your* input.


HOW TO RUN
----------

Run "compartment" without any argument to see the options:


SuSE secure compartment v1.0 Marc Heuse <marc@suse.de> http://www.suse.de/~marc

Syntax: compartment [options] /full/path/to/program

Options:
	 --chroot path	 chroot to path
	 --user user	 change uid to this user
	 --group group	 change gid to this group
	 --init program	 execute this program/script before doing anything
	 --cap capset	 set capset name. This option can be used several times.
	 --verbose	 be verbose
	 --quiet	 do no logging (to syslog)
         --fork          fork (if everything is fine)

Hints: always try to chroot; use --user&group if possible; chroot and chown all
files to another user than root if you use capabilties. Read the README file!

Known capset names: none CAP_CHOWN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH
CAP_FOWNER CAP_FSETID CAP_FS_MASK CAP_KILL CAP_SETGID CAP_SETUID CAP_SETPCAP
CAP_LINUX_IMMUTABLE CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_ADMIN
CAP_NET_RAW CAP_IPC_LOCK CAP_IPC_OWNER CAP_SYS_MODULE CAP_SYS_RAWIO
CAP_SYS_CHROOT CAP_SYS_PTRACE CAP_SYS_PACCT CAP_SYS_ADMIN CAP_SYS_BOOT
CAP_SYS_NICE CAP_SYS_RESOURCE CAP_SYS_TIME CAP_SYS_TTY_CONFIG
(see linux/capability.h for more information)


THE OPTIONS
-----------

--chroot is the path to chroot to. Notice that you need all needed libraries
in (chroot_path)/lib! (run "ldd program_to_run" to see which libraries are
needed.) After you created (chroot_path)/lib and copied the libraries there,
create (chroot_path)/etc as well and run "ldconfig -X -r chroot_path".
Finally copy all needed program files and create /dev devices if necessary.

--user sets the userid which will run the program

--group sets the groupid which will run the program

if either --user or --group is used, setgroups(0, NULL) will be called, to
drop all suplementary groups.

--init is a program which will be initially run. You can use this e.g. to create
a fresh chroot environment before launching the real programs chrooted.

--verbose tells you everything "compartment" does

--quiet tells you nothing (doesn't log anything to syslog)

--fork forks before executing the program, however checks that everything is
right beforehand. That means that you have to specify the full pathname of
the program to execute!

--cap let's you define one or more capsets. e.g. if you set
--cap CAP_NET_BIND_SERVICE the process will be able to bind to ports < 1024,
but not any other thing, root can normally do!
NOTE: You can't use --cap and --user together (the 2.2 and most 2.3 kernels
do not support this. This is fixed in the late 2.3 series. SuSE compartment
will support this when 2.4 gets outs)
If you want to know what capsets are available and what they do, check out
(/usr/include/)linux/capability.h


A WORD ABOUT /CHROOT
--------------------

If you are chrooting a service, you have to create a secure chroot
compartment.
Most important: /chroot should be on a partition of it's own, to prevent
local hardlink attacks.
Furthermore, you can use ext2 mount security options:
	nosuid  - to prevent suid file creation from a compromised service
	noatime - for performance reasons
About other mount options: 
	ro (readonly) - is great but usually won't work with your services
			because most would need to write to a file somewhere.
	nodev	- also great and important, but then you can't log to syslog
		  via the log device (e.g. /chroot/dev/log)
	noexec	- can't be used because compartment has to execute the service

After you have setup this, create the following directories within /chroot:
bin and dev. Both should have 0755 permissions.
Ensure that syslog creates a second log device in /chroot/dev. This is done
by starting syslogd with the option "-a /chroot/dev/log".
If you have SuSE Linux, this can easily be done by setting the
SYSLOGD_PARAMS variable in /etc/rc.config with this parameter.

If you use the example scripts init_bind8 and/or init_squid2, then put the
init_* file(s) into the /chroot/bin directory with 0700 permissions.


HOW TO GET THE SERVICE/PROGRAM XXX RUNNING
------------------------------------------

This section needs input. Have you successfully used chrooting etc. on
apache, wu-ftpd, named etc. etc.? Send the information to marc@suse.de and
I will put it here so everyone can enhance the security on his system.

BIND8 - named:
See the file init_bind8 which is appended to this README on how this could
be implemented with bind8.
You have to create /chroot and put init_bind8 into /chroot/bin/ and
afterwards exchange the named execution in the rc startup scripts (it's
/etc/rc.d/named on SuSE Linux, where the line is
	startproc /usr/sbin/named -u named -g named
) with:
 /usr/sbin/compartment --chroot /chroot/bind8 --init /chroot/bin/init_bind8 \
   --cap CAP_NET_BIND_SERVICE --fork --group root /usr/sbin/named
Please note that if you want to change the zones or config files, that you
have to change the normal files within /etc and /var/named and NOT the ones
in /chroot! You have to restart the service for the changes to take effect.
You also have to change the syslogd startup: add the following commandline
option: "-a /chroot/dev/log" which adds another unix domain socket for logging.

SQUID2:
See the file init_squid2 which is appended to this README (after init_bind8)
on how this couldbe implemented with squid2.
You have to create /chroot and put init_squid2 into /chroot/bin/ and
afterwards exchange the squid execution in the rc startup scripts (it's
/etc/rc.d/squid on SuSE Linux, where the lines are:
	/usr/sbin/squid -z
and
	startproc -l /var/squid/squid.out /usr/sbin/squid -sYD
) with:
 /usr/sbin/compartment --chroot /chroot/squid2 --init /chroot/bin/init_squid2 \
   --user squid --fork /usr/sbin/squid -sYD
You also have to change the syslogd startup: add the following commandline
option: "-a /chroot/dev/log" which adds another unix domain socket for logging.
The logfiles of squid2 will be placed in /chroot/log !


LOGGING
-------

Everything is logged to stderr and syslog (unless --quiet is used).
Also the whole argument list is printed to syslog.
Everything is logged with DAEMON.NOTICE


QUESTIONS / BUGS
----------------

Send an email to marc@suse.de.
A beta of the package can always be found at http://www.suse.de/~marc


----- EXAMPLE SCRIPT : init_bind8 -----
#!/bin/sh
#
# auto_chroot_script for named from the bind8 package and SuSEcompartment v0.8
# (c) 2000 by Marc Heuse <marc@suse.de>
#
#
# compartment call (where this script is /chroot/bin/init_bind8):
#  /usr/sbin/compartment --chroot /chroot/bind8 --init /chroot/bin/init_bind8 \
#      --cap CAP_NET_BIND_SERVICE --fork --group root /usr/sbin/named
#
CHROOT_DIR="/chroot/bind8"	# chroot directory
OWNER="bin.bin"			# user.group owner of all chrooted files
DEV_LOG="/chroot/dev/log"	# add "-a /chroot/dev/log" to the syslogd start

DIR_LIST_755="/var /etc /lib /bin /dev"
DIR_LIST_1775="/tmp /var/run /var/named/slave"
FILE_LIST="/usr/sbin/named /etc/localtime /etc/named.conf /etc/protocols \
 /etc/resolv.conf /etc/services /var/named/* /dev/null"
CHOWN_ROOT=""
CHGRP_ROOT="$DIR_LIST_1775"

# start
umask 022
export PATH="/usr/sbin:/sbin:/usr/bin:/bin"
rm -rf "$CHROOT_DIR"
mkdir -p -m 755 "$CHROOT_DIR" || exit 1
cd "$CHROOT_DIR"
for i in $DIR_LIST_755; do
   mkdir -p -m 755 "$CHROOT_DIR/$i"
done
for i in $DIR_LIST_1775; do
   mkdir -p -m 1775 "$CHROOT_DIR/$i"
done
ln -s . usr
ln -s bin sbin
ln -s tmp var/tmp
for i in $FILE_LIST; do
   LIB=`ldd $i 2> /dev/null |grep -v "not a "| awk '{print$ 3}'`
   cp -a $i "$CHROOT_DIR/$i"
   for j in $LIB; do
      test -e "$CHROOT_DIR/$j" || cp -p "$j" "$CHROOT_DIR/lib"
   done   
done
ldconfig -r "$CHROOT_DIR" 2> /dev/null
chown -R $OWNER "$CHROOT_DIR"
for i in $CHOWN_ROOT; do
   chown root "$CHROOT_DIR/$i"
done
for i in $CHGRP_ROOT; do
   chgrp root "$CHROOT_DIR/$i"
done
test -e "$DEV_LOG" || {
   echo "Warning: $DEV_LOG not found. Add \"-a $DEV_LOG\" to the syslogd startup."
   exit 1
}
ln "$DEV_LOG" dev/log

# end

----- EXAMPLE SCRIPT : init_squid2 -----
#!/bin/sh
#
# auto_chroot_script for squid from the squid2 package and SuSEcompartment v0.8
# (c) 2000 by Marc Heuse <marc@suse.de>
#
#
# compartment call (where this script is /chroot/bin/init_squid2):
#  /usr/sbin/compartment --chroot /chroot/squid2 --init /chroot/bin/init_squid2 \
#      --user squid --fork /usr/sbin/squid -sYD
#
CHROOT_DIR="/chroot/squid2"	# chroot directory
OWNER="bin.bin"			# user.group owner of all chrooted files
DEV_LOG="/chroot/dev/log"	# add "-a /chroot/dev/log" to the syslogd start

DIR_LIST_755="/var/squid/logs /var/squid/cache /usr/share/squid /etc /lib \
 /bin /dev"
DIR_LIST_1775="/tmp"
FILE_LIST="/etc/squid.conf /etc/resolv.conf /etc/nsswitch.conf /etc/hosts \
 /etc/host.conf /lib/libnss_*.so.2 /etc/localtime /etc/services \
 /usr/sbin/squid /usr/sbin/dnsserver /usr/sbin/unlinkd \
 /dev/null"
CHOWN_SQUID="/var/squid/*"
LOGS="access.log cache.log store.log" # in /var/squid/logs

# start
umask 022
export PATH="/usr/sbin:/sbin:/usr/bin:/bin"
test -d /chroot/log || mkdir -m 0755 /chroot/log
rm -rf "$CHROOT_DIR"
mkdir -p -m 755 "$CHROOT_DIR" || exit 1
cd "$CHROOT_DIR"
mkdir -m 755 var
ln -s . usr
ln -s bin sbin
ln -s tmp var/tmp
for i in $DIR_LIST_755; do
   mkdir -p -m 755 "$CHROOT_DIR/$i"
done
for i in $DIR_LIST_1775; do
   mkdir -p -m 1775 "$CHROOT_DIR/$i"
done
for i in $FILE_LIST; do
   LIB=`ldd $i 2> /dev/null |grep -v "not a "| awk '{print$ 3}'`
   cp -a $i "$CHROOT_DIR/$i"
   for j in $LIB; do
      test -e "$CHROOT_DIR/$j" || cp -p "$j" "$CHROOT_DIR/lib"
   done   
done
ldconfig -r "$CHROOT_DIR" 2> /dev/null
cp -a /usr/share/squid "$CHROOT_DIR"/usr/share
chown -R $OWNER "$CHROOT_DIR"
for i in $CHOWN_SQUID; do
   chown squid "$CHROOT_DIR/$i" 2> /dev/null
done
test -e "$DEV_LOG" || {
   echo "Warning: $DEV_LOG not found. Add \"-a $DEV_LOG\" to the syslogd startup."
   exit 1
}

ln "$DEV_LOG" dev/log
set -o noclobber
for i in $LOGS; do
   test -e /chroot/log/"$i" || {
	> /chroot/log/$i || exit 1
   }
   chown squid.root /chroot/log/"$i"
   chmod 640 /chroot/log/"$i"
   ln /chroot/log/$i var/squid/logs/$i
done
set +o noclobber

/usr/sbin/compartment --chroot "$CHROOT_DIR" --user squid /usr/sbin/squid -z

# end
