As this is my first official blog post, I thought it would be fitting that I explained just how I got here…as in, how you’re actually able to read this post.  I’ll use this and the next few posts to explain how I got various web applications to run on a (more-or-less) default installation of OpenBSD 4.3, without un-jailing httpd.  I can’t say that my methods are necessarily the best methods–heck, I’m not even sure they’re good methods, but they do work.  So with that being said, if someone knows of a better way to do anything I describe, please let me know!

From the OpenBSD FAQ 10.16:

A chroot(2)ed application is locked into a particular directory and unable to wander around the rest of the directory tree, and sees that directory as its / (root) directory. In the case of httpd(8), the program starts, opens its log files, binds to its TCP ports (though, it doesn’t accept data yet), and reads its configuration. Next, it locks itself into /var/www and drops privileges, then starts to accept requests. This means all files served and used by Apache must be in the /var/www directory. In the default configuration of OpenBSD, all the files in the /var/www directory are read-only by the user Apache runs as, www. This helps security tremendously – should there be a security issue with Apache, the damage will be confined to a single directory with only “read only” permissions and no resources to cause mischief with.

This means that httpd can’t utilize anything outside of its jail, meaning that pretty much any file, script, executable, or shared library you may need to run a web application needs to exist within the chroot jail.  It also means that getting applications like Gallery or Trac to run is somewhat of an interesting experience; I’ll explain how I got those to work in later posts.

Now, one of the possible problems with running Apache in a chroot is that you need to keep the binaries in sync with the base OS, and if that process is difficult or time-consuming you run the risk of letting them get “out of sync” with the (hopefully updated and patched) base OS, and as a result begin to lose some of the advantage of the httpd jail.  To this end, I wrote the following script.  It will search the following paths for files:

  • /var/www/bin
  • /var/www/lib
  • /var/www/sbin
  • /var/www/usr/X11R6/bin
  • /var/www/usr/X11R6/lib
  • /var/www/usr/X11R6/sbin
  • /var/www/usr/bin
  • /var/www/usr/lib
  • /var/www/usr/local/bin
  • /var/www/usr/local/lib
  • /var/www/usr/local/sbin
  • /var/www/usr/sbin

The script checks the chrooted version of the file against the “base-OS” version, and if the base version is newer it gets copied into the jail. Once this process is complete it runs ldd(1) on each dynamically-linked ELF executable and shared object library, compiling a list of all the needed shared libraries.  If any of these libraries is missing the script will copy it into the chroot jail. 

# For each binary in the chroot jail, recopy it from the base OS.


echo `date` >> $LOG
echo -------------------------- >> $LOG

echo syncing jail with base OS
for i in `find ${PREFIX}/{,usr/{,X11R6/,local/}}{{,s}bin,lib} 2> /dev/null`; do
  if [ -f $i ]; then
    BASEFILE=$(echo $i | sed -e "s|$PREFIX||")

    # Copy the file from the base OS
    if [ $BASEFILE -nt $i ]; then
      echo -n !
      cp -p $BASEFILE $i
      echo $BASEFILE --> $i >> $LOG
      echo -n .

    FTYPE=$(file -b $i | awk '/dynamic|shared/ { print $1 }')
    if [ "$FTYPE" == "ELF" ]; then
      ldd $BASEFILE 2> /dev/null | awk '/rlib/ { print $7 }' >> $LDDFILE

echo done.
echo checking that all support libraries are present
for i in $SUPPORTLIBS; do
  if [ -e "${PREFIX}/$i" ]; then
    echo -n .
    echo -n !
    echo $i --> ${PREFIX}/$i >> $LOG
    mkdir -p /var/www`dirname $i`
    cp -p {,$PREFIX}$i
echo done.

rm -f $LDDFILE

This should keep your chroot in sync with your base system, and also serves as a way to ensure that all needed libraries exist in the chrooted environment as well.