How to 'chroot' an Apache tree with Solaris (2.6)

Table of Contents


Chroot-ing a tree under Solaris is relatively simple, much like the Linux case (indeed, you should check out this link first for some background info).. This example uses Solaris 2.6, gcc 2.95.2 and Apache 1.3.12. It assumes that you have a few additional useful GNU tools on your system; that is, GNU tar and zip. This example also includes PHP 4b4 (as an apache module), and an installation of Perl perl 5.005_03 in the chrooted tree.

MySQL 3.22.27 is not installed in the chroot-ed tree, but an example install on the system is added here for completeness.

Some information for producing a solaris chroot-ed tree was gleaned from this page at CERT.

Additional Notes

Detailed Steps

* Prepare a Chroot-ed File System

  1. Set up the tree anywhere (preferably another disk or a non-system partition to discourage others from making hard links to files outside your web tree), but use a symlink (eg /www) to reference it.
    ROOT> mkdir /export/misc/www
    ROOT> chmod 555 /export/misc/www
    ROOT> ln -s /export/misc/www /www

  2. Create the basic directories; bin will be a link to usr/bin, and lib will be a link to usr/lib
    !! NOTE the lack of leading slashes in this example, except where I copy files from the regular file system. Do NOT mix up your chroot-ed tree with your real '/'!
    You have been warned!
    I have indicated the chroot-ed files in magenta
    ROOT> cd /www
    ROOT> mkdir -p usr/bin usr/lib etc tmp dev webhome
    ROOT> ln -s usr/bin bin
    ROOT> ln -s usr/lib lib

  3. /tmp is given special perms.
    ROOT> chmod 777 tmp
    ROOT> chmod +t tmp

  4. Make the special device files for Solaris:
    ROOT> mknod dev/null c 13 2
    ROOT> mknod dev/zero c 13 12
    ROOT> mknod dev/tcp c 11 42

  5. set the permissions and ownership for the dev files:
    ROOT> chmod 666 dev/*
    ROOT> chgrp -R sys . # recursively set group ownership for the web-tree

  6. Set up the timezone info for YOUR timezone (this example uses MET):
    ROOT> mkdir -p usr/share/lib/zoneinfo
    ROOT> cp -pi /usr/share/lib/zoneinfo/MET usr/share/lib/zoneinfo/

  7. Now copy in the shared libraries that provide a very basic chroot-ed file system
    ROOT> cp -pi /usr/lib/ /usr/lib/ \
      /usr/lib/ usr/lib/

  8. Test your tree ('cat' will be needed by 'apachectl' later, but is not strictly necessary if you change 'apachectl' ):
    ROOT> cp -pi /usr/bin/ls /usr/bin/cat /usr/bin/sh bin/
    ROOT> chroot /www /bin/ls -l /
    lrwxrwxrwx   1 0        1              7 Apr 11 21:37 bin -> usr/bin
    drwxr-xr-x   2 0        3            512 Apr 11 21:40 dev
    drwxr-xr-x   2 0        3            512 Apr 11 21:37 etc
    lrwxrwxrwx   1 0        1              7 Apr 11 21:37 lib -> usr/lib
    drwxrwxrwt   2 0        3            512 Apr 11 21:37 tmp
    drwxr-xr-x   4 0        3            512 Apr 11 21:37 usr
    drwxr-xr-x   2 0        3            512 Apr 11 21:37 webhome
  9. You can remove 'ls'; it was only used for testing:
    ROOT> rm bin/ls

* Prepare a User and the Naming Service

Here we create the user whom apache will run as, and the necessary naming services for this configuration.
  1. Create a new user that doesn't exist on the system, and give the user a unique name (eg: www) and user id (eg:888). It isn't actually necessary for the user:group to exist in the real authentication files.
    ROOT> cd /www
    ROOT> touch etc/passwd etc/group etc/shadow
    ROOT> chmod 400 etc/shadow

  2. Edit these three files. For the sake of this example I am just echoing the data into the files:
    ROOT> echo 'www:x:888:888:Web Account:/webhome:/usr/bin/False' > etc/passwd
    ROOT> echo 'www:x:888:' > etc/group
    ROOT> echo 'www:*:10882::::::' > etc/shadow

  3. I have given this user no login, and no shell. Just to be complete, compile a 'no-go' shell called False:
    ROOT> echo 'int main(int argc, char *argv[]) { return(1); }' > /tmp/False.c
    ROOT> gcc -o /www/usr/bin/False /tmp/False.c

  4. While we are at it, lets mark the binaries as execute-only:
    ROOT> chmod 111 usr/bin/*

  5. Some naming services will be required.
    I chose to rely on files and DNS, even though I also run NIS on my home machines.

    Note: The libresolv library will be needed as well (This will become evident when PHP is installed).
    ROOT> cp -pi /usr/lib/ usr/lib/
    ROOT> cp -pi /usr/lib/ usr/lib/

  6. We will need 4 files to complete the configuration for Naming Service. The contents of these files will depend on your IP and DNS setup. Here we assume that the web server is named sun.mynet.home with IP address
    # ---- Contents of    etc/nsswitch.conf ----#
    passwd: files
    shadow: files
    group: files
    hosts: files dns

    # ---- Contents of    etc/resolv.conf ----#
    domain mynet.home
    ## use the IP address of your naming server
    ## eg: if bind is not installed on your web server:
    ## use this if your web server is a (caching) name server:

    # ---- Contents of    etc/hosts ----# localhost sun.mynet.home sun loghost

    # ---- Contents of    etc/netconfig ----#
    tcp tpi_cots_ord v inet tcp /dev/tcp -

  7. If necessary correct the group permissions:
    ROOT> chgrp -R sys etc/

* Compile and Install Apache

  1. Make the top-level directory for the apache install (in this example: /apache); and create a symlink to it in the real tree:
    ROOT> mkdir /www/apache
    ROOT> ln -s /www/apache /apache

  2. I normally compile and install as an ordinary user (in this example: softs), rather than as 'root'. Note, however, that the installation of apache should be done as root. (See the 'security tips' in the online apache documentation)
    In this case I compile sources in /usr/local/src/chr, which is owned by softs:softs
    $> cd /usr/local/src/chr
    $> gtar zxf /path/to/apache_1.3.12.tar.gz
    $> cd apache_1.3.12

  3. Edit config.layout so that it includes a special layout called chroot:
    #   chroot layout.
    <Layout chroot>
      prefix:        /apache
      exec_prefix:   $prefix
      bindir:        $exec_prefix/bin
      sbindir:       $exec_prefix/bin
      libexecdir:    $exec_prefix/libexec
      mandir:        $prefix/man
      sysconfdir:    $prefix/conf
      datadir:       $prefix
      iconsdir:      $datadir/icons
      htdocsdir:     $datadir/htdocs
      cgidir:        $datadir/cgi-bin
      includedir:    $prefix/include
      localstatedir: $prefix/var
      runtimedir:    $localstatedir/logs
      logfiledir:    $localstatedir/logs
      proxycachedir: $localstatedir/proxy
  4. Now configure and make:
    $> ./configure "--with-layout=chroot" "--enable-module=most"
    $> make
    ROOT> make install ## I am root!

  5. Copy the other shared libraries that will be needed by Apache as configured in this example.
    Note that other configurations may require other libraries (use ldd to find out)
    ROOT> cp -pi /usr/lib/ /usr/lib/ \
      /usr/lib/ usr/lib/

  6. Do a quick test to see that it worked. The main fields to edit in the configuration file /apache/conf/httpd.conf for a quick test are:
    User www
    Group www
    Here is a sample httpd.conf file .

  7. Start the daemon (you need to be root):
    ROOT> chroot /www /apache/bin/apachectl start

  8. Test the URL (if you don't have lynx installed then use another browser):
    $> lynx -dump http://yourserver/

* Compile and Install MySQL

If you don't have some kind of useful curses library, then you will have to compile and install one. I previously installed ncurses 1.9.9 on this sun box, and was therefore able to install MySQL without problems.
  1. If you are only installing a client setup, then the path to the database ('--localstatedir=/home/mysql/db') is not important, and should be omitted (the default is $prefix/var). For a more complete example of installing a database as well, see the Linux example.
    $> cd /usr/local/src/chr ## I am NOT root!
    $> gtar zxf /path/to/mysql-3.22.27.tar.gz
    $> cd mysql-3.22.27
    $> ./configure --localstatedir=/home/mysql/db --prefix=/usr/local/mysql
    $> make
    $> make install

  2. To test the installation make sure that the path to the MySQL binaries and shared libraries are in your paths, for example:
    $> echo $LD_LIBRARY_PATH
    $> echo $PATH

  3. Test by connecting to a MySQL server ('ns' in this case):
    $> mysql -h ns -u web -p
    Enter password: 
    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 90 to server version: 3.22.27
    Type 'help' for help.
    mysql> quit

* Compile and Install PHP

  1. Stop the apache daemon, if it is running:
    ROOT> chroot /www /apache/bin/apachectl stop

  2. You must first compile PHP, then recompile Apache. You will need to do this each time you upgrade either software package.
    $> cd /usr/local/src/chr ## I am NOT root!
    $> gtar zxf /path/to/php-4.0b4.tar.gz
    $> cd php-4.0b4
    $> ./configure --with-mysql --with-apache=../apache_1.3.12 \
       --enable-track-vars --sharedstatedir=/tmp

    $> make
    $> make install

  3. Now recompile Apache, activating the PHP module:
    $> cd ../apache_1.3.12/
    $> ./configure "--with-layout=chroot" "--enable-module=most" \

    $> make
    ROOT> make install ## I am root!

  4. More shared libraries (for PHP) are needed in the chrooted tree:
    ROOT> cp -pi /usr/lib/ /usr/lib/ \
      /usr/lib/ /www/usr/lib/

  5. If you will be needing mysql, you must install that library as well from the place it was compiled into:
    ROOT> cp -pi /usr/local/mysql/lib/mysql/ /www/usr/lib/

  6. You will probably want to clean up config files, and edit httpd.conf so that it recognizes .php files, if you have not already done so:
    ROOT> cd /apache/conf
    ROOT> rm srm.conf access.conf
    ROOT> cd /apache
    ROOT> rm -rf man include
    ROOT> edit /apache/conf/httpd.conf :
      AddType application/x-httpd-php .php
      AddType application/x-httpd-php-source .phps

  7. This would be a good time to give ownership of the htdocs tree to the web tree 'owner':
    ROOT> chown -R 888:888 /www/apache/htdocs

  8. Restart the daemon:
    ROOT> chroot /www /apache/bin/apachectl start

  9. Check for PHP:
    ROOT> chroot /www /apache/bin/httpd -l | grep php

  10. Here is a 'hello world' script to test PHP. It should be installed as 'hello.php', with a copy or a symlink as 'hello.phps' for source-code viewing if you wish. Do not leave it lying around for the public after you have finished testing!

* Compile and Install Perl

You can probably get away with simply copying your current installation of perl (eg: /usr/lib/perl5 ) into /www/usr/lib/; and copying your perl executable (eg: /usr/bin/perl5.00503 ) into /www/usr/bin/. You would need to check for, and install any missing shared libraries. Also, you should make a hard link from usr/bin/perl5.00503 to usr/bin/perl in /www as well.

Nonetheless, I show how to compile and install perl.

  1. Make the nessary links to install into the chroot-ed tree. This example uses /perl inside the tree. Ever fearful :-O, I installed as 'softs':
    ROOT> mkdir /www/perl
    ROOT> ln -s /www/perl /perl
    ROOT> chown softs:softs /www/perl ## change back to root once installed

  2. As the owner (softs) of the source tree, unpack perl.
    $> cd /usr/local/src/chr
    $> gtar zxf /path/to/perl5.005_03.tar.gz

  3. You need to run Configure, accepting most of the defaults from the script. You will also probably want to specify 'none' for the man pages. The 2 main defaults to change in my example are listed below:
    $> ./Configure

  4. Compile and install it.
    $> make
    $> make test
    $> make install

  5. Change ownership of the perl tree to root, and create a symlink to perl in the usr/bin tree:
    ROOT> chown -R root:sys /www/perl ## changed back to root
    ROOT> cd /www/usr/bin
    ROOT> ln -s ../../perl/bin/perl perl

  6. Test your installation:
    ROOT> chroot /www /usr/bin/perl -v
    This is perl, version 5.005_03 built for sun4-solaris
  7. Set up the example perl cgi bin script installed with the apache server:
    ROOT> cd /www/apache/cgi-bin
    ROOT> chmod ugo+x *

  8. Start your apache server, and test the example perl cgi bin script installed with the server:
    ROOT> chroot /www /apache/bin/apachectl start
    $> lynx -dump http://yourserver/cgi-bin/printenv
    While you are at it, check test-cgi as well:
    $> lynx -dump http://yourserver/cgi-bin/test-cgi

  9. Finally REMOVE the execute bit from the example cgi-scripts, or remove them entirely:
    ROOT> chmod ugo-x /www/apache/cgi-bin/*

* Some Security Considerations

  1. See the 'security tips' in the online apache documentation for some help in this area. One extra precaution to take is to remove read-write permissions on the httpd scripts and binaries:
    ROOT> chmod ugo-rw /www/ apache/bin/*

* Cleanup, etc. After Installation

  1. Remove temporary links needed for installation of apache and perl:
    ROOT> rm /apache /perl
  2. (To be done: show example startup script for automatic startup of apache on boot, and on runlevel changes)
  3. (To be done: provide a mechanism for automatically cleaning up the apache log files.)
  4. (To be done: provide examples of escaping the chroot-ed tree..)

Denice Deatrich
Last modified: Thu May 11 11:24:58 DST 2000