Wheezy

A complete Debian GNU/kFreeBSD system should work within a jail, on a GNU/kFreeBSD or regular FreeBSD host system, with a few limitations.

Jails work a lot like Linux OpenVZ. On the host you can see all processes running in all jails. Within a jail, you can only see the processes running in that jail.

Limitations

Be aware that some files in /proc or /sys, such as /proc/mounts, are not partitioned per jail, and this may leak some (read-only) information about the host, or other guests' mountpoints.

Some features such as sysvipc are not namespaced for individual jails, so for security reasons they are disabled by default. fakeroot requires this to be enabled. Running more than one postgresql-server instance in a shared sysvipc namespace would clash, and not normally work.

The raw_sockets feature is normally disabled, to prevent IP spoofing from inside the jail. The ping tool will not work properly as a result.

Creating a new jailed system

JID=101
MIRROR="http://http.debian.net/debian"

debootstrap \
 --exclude=devd,dmidecode,isc-dhcp-client,isc-dhcp-common,kldutils,pf,vidcontrol \
 wheezy /srv/jail/$JID "$MIRROR"

HOSTNAME=jail$JID.example.com
IP=10.1.0.$JID

echo "$HOSTNAME" > /srv/jail/$JID/etc/hostname
echo "$IP $HOSTNAME" >> /srv/jail/$JID/etc/hosts

The --exclude to debootrap lists some packages that are probably not useful in a jailed system. The devd package will typically not work in a jail.

Ensure the jailed system's /etc/resolv.conf is suitable. If a DNS resolver runs on the host system, you should reference it by unicast (public or private) IP address such as "nameserver 10.1.0.1", instead of e.g. "nameserver 127.0.0.1".

The jailed system will not have a loopback interface unless you create one.

Starting or stopping a jail

/!\ ATTENTION: Earlier versions of this Wiki page did not explain the necessary devfs setup to restrict the set of devices in /dev. See the advisory for a similar issue at http://security.freebsd.org/advisories/FreeBSD-SA-14:07.devfs.asc

TODO: upstream FreeBSD configures on boot a restricted ruleset 4, suitable for jailed systems. This is not packaged yet for Debian GNU/kFreeBSD but you can initialise it manually; you only need to do this once per boot of the host system (not for every jail creation).

while read RULE ; do devfs rule -s 4 add $RULE ; done <<EOF
hide
path log unhide
path null unhide
path zero unhide
path crypto unhide
path random unhide
path urandom unhide
path ptyp* unhide
path ptyq* unhide
path ptyr* unhide
path ptys* unhide
path ptyP* unhide
path ptyQ* unhide
path ptyR* unhide
path ptyS* unhide
path ptyl* unhide
path ptym* unhide
path ptyn* unhide
path ptyo* unhide
path ptyL* unhide
path ptyM* unhide
path ptyN* unhide
path ptyO* unhide
path ttyp* unhide
path ttyq* unhide
path ttyr* unhide
path ttys* unhide
path ttyP* unhide
path ttyQ* unhide
path ttyR* unhide
path ttyS* unhide
path ttyl* unhide
path ttym* unhide
path ttyn* unhide
path ttyo* unhide
path ttyL* unhide
path ttyM* unhide
path ttyN* unhide
path ttyO* unhide
path ptmx unhide
path pts unhide
path pts/* unhide
path fd unhide
path fd/* unhide
path stdin unhide
path stdout unhide
path stderr unhide
path ptyp* unhide user root group root
EOF

FIXME: this devfs ruleset breaks the method of PTY allocation used by wheezy chroots; ssh logins will warn of "PTY allocation request failed on channel 0", have no shell prompt, and likely have other issues. This additional rule seems to fix it (no idea why, and don't know if it's secure) :

path pt* unhide

sid/jessie chroots don't need that - they use a new method of pty allocation which unaffected.

Assuming a debootstrap'd installation already exists in /srv/jail/$JID/, here is an example of how to start it up inside a jail:

JID=101

# Linux-like /proc and /sys filesystems
mount -t linprocfs linprocfs /srv/jail/$JID/proc
mount -t linsysfs linsysfs /srv/jail/$JID/sys
  
# Ramdisk required for /run
mount -t tmpfs tmpfs /srv/jail/$JID/run
  
# A read-only /dev filesystem with restricted set of devices
mount -t devfs devfs /srv/jail/$JID/dev
# :XXX: ruleset 4 must be initialised as explained earlier in this Wiki page
devfs -m /srv/jail/$JID/dev rule -s 4 applyset
# Ensure the jail has some essential devices
for DEVICE in null random urandom zero
do if [ ! -e /srv/jail/$JID/dev/$DEVICE ]
    then
        echo "error: device '/dev/$DEVICE' MUST be available in the jail"
        exit 1
    fi
done
# Ensure the jail has only a limited set of devices
for DEVICE in mem kmem
do if [ -e /srv/jail/$JID/dev/$DEVICE ]
    then
        echo "error: device '/dev/$DEVICE' MUST NOT be available in the jail"
        exit 1
    fi
done

# Compatibility symlink from /dev/shm to /run/shm
ln -s /run/shm /srv/jail/$JID/dev/
  
# Optionally enable networking
HOSTNAME=jail$JID.example.com
# :XXX: this IP address *must* be assigned to one of the host's interfaces before the guest can use it
IP=10.1.0.$JID

mkdir -p /var/run/jail
jail -J /var/run/jail/$JID.jid -c jid=$JID \
  name=jail$JID \
  path=/srv/jail/$JID \
  host.hostname=$HOSTNAME \
  ip4.addr=$IP \
  command=/bin/sh -- -c "/etc/init.d/rc S && /etc/init.d/rc 2"

You may want to install and configure locales on the first boot:

apt-get install locales
dpkg-reconfigure locales

If openssh-server is installed within the jail, you should be able to SSH into it like a virtual private server.

jls (to list running jails) is not available yet. 709225

jexec is not available yet, but you can probably get by with:

# jail -m jid=$JID command=/bin/bash
# cd

A jail stops 'running' when all processes within it exit. (Within the jail, /etc/init.d/rc 0 ; exec kill -1 might be a way to force a shutdown?)

Squeeze

The libjail package was not distributed with Squeeze. The kernel functionality has existed since FreeBSD 4.x however, so it may work if you can build the necessary userland tools.