![]() |
| October 2001 | Get BSD | New to BSD? | Search BSD | Submit News | FAQ | Contact Us | Join Us |
|
The Berkeley Internet Name Domain software, AKA "named," is one of the most important pieces in the mosaic that represents the structure of the Internet. Due to this importance, it is also a preferred target for hackers, who want to keep DNS from working, or worse, use security holes in the software to gain control over the machine. Such hacking of a DNS server can result in a break of confidentiality of the data returned from this server, and is, in general, a bad thing.
The "named" process usually runs as the root user on a system. There are two things that can be done to make things more safe against break-ins: The first is to not let the daemon run with full system (root) privileges; the other is to limit the possible damage by putting the named into a chroot environment where it can't access anything but a few files it needs to run. Running a program with a different root directory than /, which is done via the chroot command, is also called "sandboxing" or "jailing".
This article describes the steps that are necessary to run the BIND9 package on NetBSD in a chroot cage, using NetBSD's new rc.d-based startup system.
We will demonstrate the setup of named in a chroot cage using BIND version 9 as an example. It can be installed, e.g., via pkgsrc or as a binary package. When installing via pkgsrc, the following steps will do what we need:
# cd /usr/pkgsrc/net/bind9 # make install
As an alternative, a binary package can be installed. Look for bind-9.1.3.tgz on ftp.netbsd.org in the /pub/NetBSD/packages directory.
After installing the BIND package, we need to create an account under which the "named" daemon will run. We call the user "named", and it should not have system (root) privileges. We will later use the user's home directory as the root directory for our chroot cage. The easiest way to create such a user is using useradd(8):
# useradd -m named
When running the "named" daemon in a chroot cage, there are a few system files needed to run it, and they need to be present in the chroot directory. The following files are needed:
The "named" binary itself. It's located in /usr/pkg/sbin.
All the shared libraries that the "named" binary needs. We can use "ldd" to find which libs are needed on ELF platforms; on a.out, some guessing will be needed. Take the following list for a hint:
# ldd /usr/pkg/sbin/named | awk '/=>/ { gsub(".so.*", ".so*", $3); print $3 ; }'
/usr/pkg/lib/liblwres.so*
/usr/pkg/lib/libomapi.so*
/usr/pkg/lib/libdns.so*
/usr/lib/libcrypto.so*
/usr/pkg/lib/libisc.so*
/usr/lib/libc.so*
This example uses all versions (.so*) of the shared libs, to not catch only the numbered symlinks.
The shared library loader, either ld.so (a.out) or ld.elf_so (ELF). They are both located in /usr/libexec and are needed by any dynamically linked program to load its shared libraries.
The "named" daemon's config files. These are usually stored in the /etc/named directory plus in the /etc/named.conf config file (which is often only a symlink to /etc/named/named.conf).
All the files named above need to be copied in the chroot cage, ~named. Note we use the csh-syntax "~named" here, which should be accepted by all shells. If your shell does not support the ~-notion, you'll have to supply the full name of the user's home directory, usually /home/named.
Here's a command that copies the named files into their place:
tar plcf - \
/usr/pkg/sbin/named \
`ldd /usr/pkg/sbin/named | awk '/=>/ { gsub(".so.*", ".so*", $3); print $3 ; }'` \
/usr/libexec/ld*so \
/etc/named.conf \
/etc/namedb \
| ( cd ~named ; tar vxf - )
Besides the files described above, one more piece of information is needed. Password information is needed so the "named" binary can obtain information about the new user ID that it should switch to after starting up in the chroot cage. Besides /etc/passwd, the files master.passwd as well as their database backends, pwd.db and spwd.db, are needed. These files could be copied from the /etc dir, but for security reasons it is better to create only a minimal data set that contains only the "named" user.
The easiest way to set up a set of passwd data files is to set up the user in the "normal" system as we have done above, then extract the data from /etc/master.passwd and create the other files from that:
# grep named /etc/master.passwd > ~named/etc/master.passwd # pwd_mkdb -p -d ~named ~named/etc/master.passwd
Syslogd creates a socket /var/run/log that programs can log messages to. As our "named" will run in a chroot environment, it can't reach that file. In order to fix this, NetBSD's syslogd allows specifying several locations in which logging sockets can be created. We'll tell syslog to look in ~named/var/run/log.
To keep data in one place (and as we will need it later :), we use the variable $named_chroot in /etc/rc.conf to reference the chroot dir. So to change syslogd as described above, add the following to your /etc/rc.conf file:
syslogd_flags="-p $named_chroot/var/run/log -p /var/run/log"
"named" will not run with root privileges but with that of the "named" user. We have to make sure that user (and its "named" process :) can create the file in which the process' process ID (PID) will be stored. The easiest solution is to hand over the ~named/var/run directory to the "named" user:
# install -d -o named ~named/var/run
After these steps, the "syslogd" should be restarted to (re)create its routing sockets:
# sh /etc/rc.d/syslogd restart
Make sure that everything is set up properly after doing so:
# ls -l /var/run/log ~named/var/run/log srw-rw-rw- 1 root named 0 Aug 25 22:59 /home/named/var/run/log srw-rw-rw- 1 root wheel 0 Aug 25 22:59 /var/run/log
Of course, the startup system needs to be told about our plans, too. For that, the "named" version that comes with NetBSD should be disabled, and our "named" (version 9) be enabled in /etc/rc.conf. We also need to tell the system to start our "named" in a chroot dir, and to give the "named" daemon a command to change to the "named" user privileges after initial startup. The following lines in /etc/rc.conf will do the job:
named=no # disable NetBSD's named named9=yes # enable our named named_chroot=/home/named # chroot to /home/named (also used by syslog_flags) named_flags="-u named" # switch privileges to this user
Before we can fire up our new "named", we need to do two more things.
First, NetBSD 1.5.2 and older has a bug in /etc/rc.subr that prevents it from looking for the PID-file in the right place when chroot is used. We simply place a symlink to work around this bug:
ln -s ~named/var/run/named.pid /var/run/named.pid
Second, we want to make starting our new "named" permanent when the system starts up. The easiest way to do so is to make the "named9" startup script that comes with the BIND9 package available in /etc/rc.d:
ln -s /usr/pkg/etc/rc.d/named9 /etc/rc.d
This only works if /usr/pkg is on the root (/) filesystem though - else the /etc/rc.d/named9 symlink cannot be read at system startup. If your /usr/pkg is not on the root filesystem, you can put the following into /etc/rc.conf instead:
if [ -f /usr/pkg/etc/rc.d/named9 ] ; then
sh /usr/pkg/etc/rc.d/named9 start
fi
Now we are set up to run our "named" in a chroot cage! Using the new NetBSD startup system, the easiest way to do so is:
sh /etc/rc.d/named forcestop # just in case sh /etc/rc.d/named9 start
If you cannot have a /etc/rc.d/named9 script (link, see above), you can call the pkg's script manually via its real name:
# sh /usr/pkg/etc/rc.d/named9
To make sure everything is setup fine now, check with the following command:
# ps -aux | grep named named 19306 0.0 0.5 868 632 ?? Is 11:44PM 0:00.18 /usr/pkg/sbin/named -u named
See the "named" user ID here in the first column, telling that the "named" process is running under the designated non-root user-id. Checking the root dir can be done with the fstat(1) command:
# fstat -p 19306 USER CMD PID FD MOUNT INUM MODE SZ|DV R/W named named 19306 root /home 3745792 drwxr-xr-x 512 r ... # ls -ldi /home/named 3745792 drwxr-xr-x 5 named named 512 Aug 25 22:58 /home/named
We use fstat(1) to get the mountpoint and inode number of the process' root directory. We use ls(1) to verify that it is actually the right directory by comparing the inode numbers.
While trying to set the chroot cage for "named", I ran into a small problem with how to determine under which user the daemon should run. There are two possible ways to set this: by using su(1) before starting the daemon, or by telling the user to switch to our "named" user on its own. It turns out that the first option is not usable for our purpose, as the daemon needs the root privileges it first gets started with to bind to its listening socket, which is on a privileged port (53/UDP). As a result, the setup above uses the "name_flags" variable to hand the username to switch to to "named", instead or using "name_user", which would invoke su(1).
In general, the above procedure shows how to further tune the default NetBSD installation. While NetBSD is secure in the default installation, various aspects can be improved even more if the application demands it. Most people won't want to run their own DNS server, but there are good reasons to make things locked tight if you do so - and if your and your customers' business depends on it, more specific actions are needed.
There are many other areas where specific subsystems can be tuned, such as Samba, NFS, and web servers, but discussing them would be too much here and now. This article should give some hints on to tune any subsystem in general.