Securing Slackware
Using the exec-shield Kernel Patch on Slackware 10.1
Kurt Fitzner <kfitznerATexcelcia.org>
The Holy Grail of most any hacker trying to get access
to a system is the remote buffer overflow attack. Well, actually,
it's finding a Windows PC not protected by a firewall, but the remote
buffer overflow attack is a (somewhat) close second. This article
will discus one way to help protect against this type of attack on a
Slackware Linux system with the installation of a special system called
exec-shield. This installation will occur in two phases. The first
phase is installing the exec-shield kernel patch, the second is
replacing some of Slackware's packages with ones that are compiled to
work together with exec-shield.
What is a Buffer Overflow Attack?
Before
we explain how to protect against a buffer overflow attack, it is
useful to examine what exactly this attack is and what the
ramifications are for an unprotected system.

Illustration
1 – A Normal Stack
When writing software, it's often the case that a programmer
needs to set aside memory to hold information coming into the
program. This temporary memory, called a buffer, is used to hold data
while the program figures out what to do with it. For example, it
might be used by a web server to hold the URL of the web page a
browser is requesting. The browser sends the URL to the web
server, the web server stores it temporarily in a buffer, then it
processes the URL to find out exactly what the browser is asking.
Programmers
often use an area called the stack to create these temporary
buffers. A program's stack is a fixed size temporary “scratchpad”
area used by programs to store variables. The reason it's called the
stack is that it's oriented upside-down from how memory is usually
accessed. Memory is usually used from first to last, top to bottom.
The stack is used from bottom to top – putting data on the
stack is putting another plate on a stack of plates – the last
plate you put on is the first one you take off (this is sometimes
referred to as “LIFO” – last-in, first-out). In
addition to holding variables, the stack is also used to
store the return address when a program jumps to a subroutine. That is, when
a program jumps to (or “calls”) a subroutine, the address
of the location in memory to jump back (return) to when the subroutine is done
is stored on the stack.
Because
the stack is of a limited size, programmers don't like wasting space
in it. So when a buffer is needed, programmers make that buffer big
enough to hold the largest piece of data going in it, but no larger.
In the case of our web server, a long URL is generally going to be
somewhere on the order of a few hundred bytes. Some URLs store
information for CGI forms, so the programmer might make the buffer as
large as two or four kilobytes. Many browsers won't process a URL
longer than that. The web server's stack when it is executing the
subroutine to process a URL might look something like Illustration 1.
The stack grows upward, like a stack of plates, so the return address
which was placed on the stack first, is actually located “under”
the buffer and other variables that the subroutine uses.

Illustration
2 – Stack After a Successful Attack
A buffer overflow attack works by trying to fill a buffer with
more information than a programmer has reserved for it in the code.
If the program is vulnerable to the attack – if it doesn't
check the size of the incoming data before it copies it to its
buffer, then a specially crafted URL could overwrite the return
address with its own address, and even malicious code to “take
over” the program. A program that is taken over in such a way
can be used by the attacker to do anything that the user that owns
the program can do. If the program is run as root, as quite a few
processes are, then a successful attack can give complete control over
your system to the attacker.
In the past, programs that were vulnerable to such an
attack were vulnerable because the programmers who wrote them –
honest programmers – never used to think in terms of what
a dishonest person might do to break their program. If the
specification the programmer was following says the maximum size of a
piece of data is so many bytes, then that's how many bytes the
programmer allocates for it. There can't be more than that,
because the specification says there can't be, so there is no reason
to waste memory for a larger buffer, or waste CPU time by performing
special checks on the size of the incoming data. Even today with the
focus on writing programs that are secure, vulnerabilities crop in.
Sometimes they are in parts of the code that are inherited from earlier
times when people weren't thinking in such terms. Sometimes it's
simply a programmer who made a small mistake, or forgot to think in
terms of security. It only takes one such instance to make a program
vulnerable to this sort of attack. One
report suggests that a vulnerable PC connected to the Internet
will be compromised in an average of 20 minutes. Another
report suggests that it is as little as four minutes. That's not
to suggest that all vulnerabilities are buffer overflow
vulnerabilities. That is just one type. However, this author's
Slackware firewall PC registers several buffer overflow probes each
day in its web
server log.
If You Don't Need It, Don't Use It
The
best way to secure against a buffer overflow attack is to run
software that isn't vulnerable to such attacks. Performing a full
security code audit on every piece of software running on a firewall
is generally not within the capacity of most users. However, it is
within any user's ability to shut down any services that aren't
needed. The first rule of thumb regarding services running on any PC
connected to the Internet should be “if you don't need it don't
use it”. Slackware is pretty good about not enabling Internet
services by default. If your Linux PC is connected to the Internet,
take a look at your /etc/inetd.conf file. This file controls what
Internet services are supported by the inetd super-server. Go over
your configuration file and look for services that you aren't using.
If you don't know that you need it, turn it off. An attacker can't
attack nothing.
The exec-shield
Kernel Patch
Ingo
Molnar, a kernel hacker (the good kind of hacker) working for Red
Hat, has written a patch for the Linux kernel that is designed to
protect you against most buffer overflow attacks. It has been made in
such a way that it can protect you against such attacks even if you
are running software that would otherwise be vulnerable to it. If you
look at Illustration 2 above, you notice that the malicious code was
stored as data on the stack. The exec-shield system works, in part,
by making the stack (and other areas of memory where data is stored)
unable to execute code. When a program is loaded into memory for
execution, the code and the data are loaded into different areas in
memory. There is usually no reason why the data areas need to run
code, so the exec-shield patch prevents this. It won't prevent a
buffer overflow from occurring in a program that is vulnerable to it,
but it will block a hacker from being able to exploit a
vulnerability by running malicious code stored on the stack or in
data buffers.
Installing the patch is not difficult. We will go
through the process step-by-step:
Since this is a kernel patch, you will (of course)
need to ensure that you have installed the kernel sources first. If
you are using the default kernel with Slackware 10.1 then you have
kernel version 2.4.29 and you can install the kernel sources from
your Slackware CD or from any Slackware
mirror site. If you are running the 2.6.10 kernel from the
testing directory, then the kernel source package is
testing/packages/linux-2.6.10/kernel-source-2.6.10-noarch-1.tgz –
again, available from your Slackware CD or any mirror site.
To obtain the exec-shield patch, go to
http://people.redhat.com/mingo/exec-shield/.
The patch is (as of the time of this writing) available for the
2.4.29, 2.6.10, and 2.6.11 kernels. Download the patch for your
kernel.
To apply the patch, change to the top directory
inside your kernel tree (/usr/src/linux) and as root run the
command:
$ patch -p1 < ~/exec-shield-2.4.29-A2
Of course, substitute the path to and filename for the patch you
are actually using.
There aren't any configuration options for the exec-shield
patch, so you can go ahead and build your kernel. If this is the
first time you're compiling your own kernel, you will need to
configure it first – “make menuconfig” is the
easiest way. A full tutorial on how to configure and build a kernel
is not within the scope of this article, however there are many
resources with information on this. The new “Kernel
Rebuild Guide” is probably the best.
Once the kernel is built, you will need to install it.
Slackware configures lilo to expect the kernel in the /boot
directory. A fairly easy way to make sure this happens is to edit
the top level Makefile in the Linux kernel tree. In the 2.4 series
of kernels, line 77 sets the install path, though this is commented
out by default. Uncomment this and set it so the line reads:
export INSTALL_PATH=/boot
This way, any time a “make install” is run in the
Kernel tree, the new kernel will get put in /boot and lilo will be
run automatically to install it. Since lilo is the default loader
for Slackware, this makes it very convenient to install new kernels.
Once the kernel is installed, you are ready to reboot your PC to
load it up, or alternatively you can continue on to replace some of
your packages with ones that work with exec-shield.
Special exec-shield
Packages
Some of the protections offered by the exec-shield kernel patch don't
require you to do anything more than install the patch and recompile
your kernel. However, to get the full benefit from exec-shield, you
will need to run binaries that have been compiled for it.
The reason for this is a ramification of what was explained earlier.
The exec-shield kernel patch will prevent a hacker from being able to
use a buffer overflow attack to execute malicious code inserted
during the attack. It does this by preventing memory that is used
for data from being able to execute code. However, it can't stop the
buffer overflow from happening in the first place if you have any
software that has a vulnerability. If you refer back to Illustration
1, you will see that the return address for any subroutine is located
on the stack. An attacker could conceivably use a buffer overflow
attack to replace that return address with one that goes somewhere
else – for example, the system function in glibc. If
you have the man pages installed on your Slackware PC, type “man
system” and you will see that this function could be used by an
attacker to run any shell command on your PC. Don't fret, the
exec-shield patch protects against this too, but in a slightly
different way.
In order for a malicious attacker to get your system to do what the
attacker wants it to do by using a buffer overflow to rewrite a
return address, the attacker has to know the exact address in memory
on your system of a useful function. Without exec-shield
installed, the address of the system() function on my system might be
the same as it is on hundreds of other Slackware PCs, simply because
what Slackware installs on different systems may be virtually
identical. With exec-shield, however, the kernel randomizes where in
memory any shared library is loaded. It also randomizes where the
stack and any extra data for any particular program is. What it
can't randomize is where in memory a particular program is loaded.
This is because the load address for a program is determined when it
is compiled.
In order to randomize the location in memory where a program is
loaded, the program has to be compiled in a new way – it has to
be compiled as a “position-independent executable”, or
PIE. If you are familiar with shared libraries, this will sound very
much like the “position-independent code” (or PIC) that a
shared library uses. This is because they are almost identical
concepts. A position-independent executable is loaded by the kernel
in the same way a shared library would be loaded.
You don't need to replace every single binary on your system with a
PIE executable. Remember, the purpose here is to protect from remote
buffer overflow attacks. Programs that don't communicate over the
Internet aren't vulnerable to a remote attack and don't need this
extra protection. This author has prepared a set of Slackware 10.1
packages for the server software that is generally most often probed
and attacked. These packages, all available from linuxpackages.net,
are: apache
1.3.33, sendmail
8.13.3, bind
9.3.0, imapd
4.62, popa3d
0.6.4, portmap
5.0, and proftpd
1.2.10. To use, simply download the packages and use upgradepkg
as root to upgrade your current package with the new one:
$ upgradepkg apache-1.3.33-i486-2Hkf.tgz
etc...
In the case of packages for software that is currently running, it is
suggested that you first shut down such software using its startup
script in /etc/rc.d:
$ /etc/rc.d/rc.bind stop
$ /etc/rc.d/rc.httpd stop
$ /etc/rc.d/rc.portmap stop
$ /etc/rc.d/rc.sendmail stop
Checking on exec-shield
Ok, there is
one slight correction we'll talk about here. When earlier it was
said that exec-shield would make the stack and data areas of programs
non-executable, this was only partly right. It will do this, but
there are certain very rare ways to write a program that requires
that the stack and data areas not have this restriction. Whenever
gcc detects a program written this way, it will put a flag in the end
program telling the system that it must have an executable stack. If
gcc doesn't detect a program written this way, it will put in a flag
saying it's all right for the program to have a non-executable stack.
The exec-shield patch is smart, and will look for these flags and
honor them. If the stack flag isn't present at all – say, for
a program compiled on a version of gcc prior to this flag being
supported, then exec-shield plays it safe and treats the program as
if it needs an executable stack and disables exec-shield protection
for that program.
All the
packages included in Slackware 10.1 are compiled with a version of
gcc that is recent enough to support the flag and there are not to
this author's knowledge any programs included in Slackware 10.1 that
require an executable stack. However, it is possible you may run
into programs that do require an executable stack or old binaries
that don't have any stack flag in them. You will want a way to check
programs running on your system to see if exec-shield is enabled for
them or not. In addition, you will want to be able to check to see
what programs on your system are position-independent executables. A
script, called lsexec
will allow you to check one or all the processes running on your
system. The script will give you information on all running
processes or a single process by name or by PID. For example, to get
information on all running processes, download the script and, as
root, type:
$ lsexec –all
For each running process, you will be told whether the executable is
a PIE, and whether or not exec-shield is enabled for it. Remember,
exec-shield is enabled if the process doesn't need an executable
stack, disabled if it does need one or if it's been produced with an
old version of gcc that doesn't support the executable/non-executable
stack flag.
You will also be given information regarding whether the process is
full relro, partial relro, or no relro. That's something that isn't
covered here. For the purposes of this article, it suffices to say
that making a binary relro goes hand-in-hand with making it a PIE and
helps make it more secure. There is further reading at the end of
this article for those that want to get more information on the
technical details.
Summary and Caveats
There are a few things to remember about exec-shield. It can
dramatically increase the security on your system, but it isn't the
be-all end-all protection. For one, it cannot make a program
invulnerable to a buffer-overflow attack – not if that program
has such a weakness in it. What it can do is mitigate the
consequences of any such weakness. It makes it orders of magnitude
harder for an attacker to take advantage of such a weakness to get
control over your system. If a buffer-overflow weakness is found in
a version of software you are using, an attacker can probably use
that weakness in a denial-of-service attack of some sort. An
attacker can probably cause the program to crash – but it's
unlikely that the attacker can use the weakness to gain any control
over your server.
Also to remember, that buffer overflow attacks are only one type of
attack. Running exec-shield won't protect you against other types of
attacks. It is still just as important to keep up with security
advisories and update any programs that have been shown to have any
weakness (including buffer overflow weaknesses).
That all being said, exec-shield can help make your Slackware system
a much more secure server or firewall.
Further Reading
van de Ven, Arjan (2004). New Security Enhancements in Red Hat
Enterprise Linux v.3, update 3 [On-line]. Retrieved 4 March 2005
from the World Wide Web:
http://people.redhat.com/mingo/exec-shield/docs/WHP0006US_Execshield.pdf
Drepper, Ulrich (2004). Security Enhancements in Red Hat Enterprise
Linux (beside SELinux) [On-line]. Retrieved 4 March 2005 from the
World Wide Web: http://people.redhat.com/drepper/nonselsec.pdf
Molnar,
Ingo (2003). [Announcement] “Exec Shield”, new Linux
security feature [On-line]. Retrieved 5 March 2005 from the World
Wide Web:
http://groups.google.ca/groups?q=exec-shield&hl=en&lr=&selm=20030502164023%240fbc%40gated-at.bofh.it&rnum=2
(ed.
archive of original exec-shield announcement – contains
information that is now inaccurate with respect to the current
version of exec-shield)