Posted by Steve on Mon 10 Jan 2005 at 14:22
I maintain a copy of GCC which has the ability to detect and prevent buffer overflow attacks from working. This simple guide explains how my GCC packages are built, if you write code which offers a service across a network you might be interested in using something similar yourself.
IntroductionWhat does it do?When it comes to buffer overflow protection there are a couple of different implementations which are available. One of the most tested and widely used is a patch from IBM which is known as SSP, (for "Stack Smashing Protection"). This patch was previously known as "ProPolice".
The IBM patch is available from its research homepage, although you won't need to fetch it from there if you're using Debian because the Debian GCC packages ship with the patch included in the source, although it's not enabled. This short recipe explains how you would enable it and rebuild your version of GCC.
Download GCC and PatchBefore you enable it you're probably wondering what does it do?
Well put simply it inserts extra code into your programs as you compile them, to warn against a buffer overflow exploit attempt.
Assuming that you have the following code:
void foo( char *user ) { char greeting[1024]; sprintf(greeting, "Hello %s", user ); printf( "%s", greeting ); }(This is a bogus example).
Here the function foo takes a string argument which is appended to the end of the string "Hello ", without any length testing. If this input is supplied by a user then it can be used to overflow the "greeting" buffer - and execute code.
The way that the SSP detects this is to add some extra code similar to this:
void foo( char *user ) { int canary = 33; char greeting[1024]; sprintf(greeting, "Hello %s", user ); printf( "%s", greeting ); if ( canary != 33 ) { printf( "Stack smashing attack thwarted\n" ); exit(-1); } }There is a new variable inserted on the local heap before the buffer - this has a random value assigned to it at runtime. Once the copy has occurred, but before the function has returned using a potentially overwritten return address this "canary" value is tested to make sure it contains what it should.
If the canary value has changed then we've detected a buffer overflow attempt, and this is logged before the program is terminated.
This will not catch all overflows, but it does raise the bar against most attackers.
Building GCCCreate a directory to contain the GCC source code, and download it with:
apt-get install dpkg-dev apt-get source gcc-3.4This will consume around 27Mb of space, and more will be required to actually build the source.
Once you've downloaded the source you'll be left with some files such as these:
drwxr-xr-x 7 root root 4096 Jan 10 13:18 gcc-3.4-3.4.3 -rw-r--r-- 1 root root 5377788 Jan 10 13:17 gcc-3.4_3.4.3-7.diff.gz -rw-r--r-- 1 root root 2643 Jan 10 13:17 gcc-3.4_3.4.3-7.dsc -rw-r--r-- 1 root root 30513800 Nov 20 23:17 gcc-3.4_3.4.3.orig.tar.gzThe source to the package has been unpacked here into the directory gcc-3.4-3.4.3, so change into that directory and look around.
You'll soon discover that the source to GCC is still in a collection of compressed files, and the only real content is the debian/ subdirectory.
This debian directory contains all the files which we must modify, there are three things we need to change:
- The build options to make sure that the patch is applied.
- The version of the package to prevent it from being upgraded.
- The version number of the compiler so we know we have it working.
The first is simple, open the file debian/rules.patch with your favourite editor and find the following lines:
# not applied by default #debian_patches += protectorUncomment the second leaving you with:
# not applied by default debian_patches += protectorNow we need to change the version number of the package, do that by editing the file debian/changelog. Copy the top of the file and paste it in again - (the format of this file is well defined and it's not very forgiving of extra linebreaks, whitespace etc) - then modify the version number to add the letters ssp after the number:
gcc-3.4 (3.4.3-7ssp) unstable; urgency=low * Added SSP patch. -- Steve Kemp Sat, 8 Jan 2005 10:57:39 +0100The format of the changelog files is pretty strict, so you should copy the previous entry and just change the date + version number (the bit in brackets). Add in a suffix to whatever version you have ssp is what I use here.
The final thing is to update the version string which is output when you run "gcc --version", edit the file debian/patches/gcc-version", and look for the following line:
sed -e '/version_string/s/"\([^"]*\)"/"\1 (Debian'"$pkgversion"')"/' \ $dir/version.c > $dir/version.c.new \I change it to read:
sed -e '/version_string/s/"\([^"]*\)"/"\1 (Debian'"$pkgversion" SSP by Steve Kemp')"/' \ $dir/version.c > $dir/version.c.new \Now we've made all the changes we need.
Testing ItEven on a powerful machine rebuilding GCC and all its components is going to take a long time, and use a lot of disk space.
Make sure you have all the packages which are required to rebuild gcc-3.4 installed by running:
apt-get build-dep gcc-3.4Once that's done you are almost ready - you just need some utility scripts installed to handle the build, to get those run:
apt-get install devscripts build-essentialNow we can go! Whilst remaining inside the "debian/" directory run:
debuildThe build process will start, and you will see lots of progress and diagnostic output.
After a few hours hopefully all will be done and you'll have a lot of .deb files produced which you can install.
Here's one I made earlierOnce you've built and installed the new version of gcc you should find that two new command line arguments are available:
-fstack-protector * Enables SSP protection. -fno-stack-protector * Disables SSP protection.The best way to see this working is to use it to compile something with and without the protection, and see how they compare.
Download test-ssp.c, which is a simple program based around the vulnerable example code we used above.
Compile this code twice, once with the protection and once without it:
cd /tmp wget http://www.debian-administration.org/articles/75/test-ssp.c gcc-3.4 -fno-stack-protector -o test-ssp1 test-ssp.c gcc-3.4 -fstack-protector -o test-ssp2 test-ssp.cThis will give you two binaries test-ssp1 and test-ssp2. Notice how they are almost identical in size?
root@undecided:/tmp# ls -l test-ssp* -rw-r--r-- 1 skx users 839 Jan 10 14:25 test-ssp.c -rwxr-xr-x 1 root root 12289 Jan 10 17:58 test-ssp1 -rwxr-xr-x 1 root root 15083 Jan 10 17:58 test-ssp2Now try giving them both long arguments - say a 1234 character long argument, produced by running `perl -e 'print "x"x1234'`:
./test-ssp1 `perl -e 'print "x"x1234'` Hello XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Segmentation faultThe program crashes after printing its greeting because the return address to the function was overwritten, and pointed to an invalid address
Now run the protected program identically:
./test-ssp2 `perl -e 'print "X"x1234'` Hello xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx test-ssp: stack smashing attack in function fooAborted
On the other hand if you just want to use the compiler, not rebuild it yourself then you can use the package I rebuilt for unstable.
It usually lags around a week after GCC upgrades and can be installed by adding the following to your /etc/apt/sources.list file:
# # SSP / ProPolice GCC and supporting packages. # # deb http://people.debian.org/~skx/apt/sarge ./ deb-src http://people.debian.org/~skx/apt/sarge ./
This article can be found online at the Debian Administration website at the following bookmarkable URL:
This article is copyright 2005 Steve - please ask for permission to republish or translate.