6.12.1. Installation of GCC
This package is known to have issues when its default optimization
flags (including the -march
and -mtune options) are
changed. If any environment variables that override default
optimizations have been defined, such as CFLAGS and CXXFLAGS,
unset them when building GCC.
Unpack the binutils-2.17, gcc-core-4.1.2, gcc-g++-4.1.2, and
gcc-testsuite-4.1.2 source packages but do not change directory.
Then combine the two packages to the same directory with the
following commands:
mv -v gcc-4.1.2/ butterfly-toolchain
mv -v binutils-2.17 butterfly-toolchain/
cd butterfly-toolchain/
ln -vs binutils-2.17/{bfd,binutils,gas,gprof,ld,opcodes} .
This patch is from the “binutils-2_17-branch” CVS branch. This branch
is open for bug fixes only, and does not add any new features.
Apply this patch with the following command:
patch -Np1 -i ../binutils-2.17-branch_update-2.patch
This is from Binutils CVS: http://sourceware.org/ml/binutils-cvs/2006-10/msg00044.html,
and adds support for the mkstemp(3) C library function for safer
temporary file creation. Apply this patch with the following
command:
patch -Np1 -i ../binutils-2.17-hardened_tmp-3.patch
Patch to add -z lazy:
patch -Np1 -i ../binutils-2.17-lazy-1.patch
The -z lazy patch adds a new option to
the manual and info pages for ld. Binutils won't regenerate
these files by default, so we remove them to convince Binutils to
rebuild them with the new option:
rm -v ld/ld.{1,info}
This patch is from various Binutils-cvs differences, and fixes
warnings caused by -D_FORTIFY_SOURCE:
patch -Np1 -i ../binutils-2.17-fortify_warnings-1.patch
This next patch is from Binutils CVS: http://sourceware.org/ml/binutils-cvs/2007-04/msg00021.html,
and fixes --warn-shared-textrel
--fatal-warnings so that the warning is indeed fatal:
patch -Np1 -i ../binutils-2.17-PR4304-1.patch
The configure script in this version
of Binutils does not handle double digit version numbers from
Texinfo. The following patch is from Binutils-cvs:
http://sourceware.org/cgi-bin/cvsweb.cgi/src/configure.diff?r1=1.268&r2=1.268.2.1&cvsroot=src.
Apply the patch with the following command:
cd binutils-2.17/
patch -Np1 -i ../../binutils-2.17-texinfo_fix-1.patch
cd ../
Patch Binutils for PT_PAX_FLAGS:
cd binutils-2.17/
patch -Np1 -i ../../binutils-2.17-pt_pax-1.patch
cd ..
This next patch is from GCC CVS: http://gcc.gnu.org/viewcvs?view=rev&revision=113179,
and fixes a bug when libmudflap is
linked to a multithreaded program. The bug report is here:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26864.
Apply this patch with the following command:
patch -Np1 -i ../gcc-4.1.2-PR26864-1.patch
This version of GCC has the same Texinfo bug as Binutils, and has
been fixed in GCC-cvs:
http://gcc.gnu.org/viewcvs/trunk/configure?r1=128495&r2=128497&diff_format=h.
Apply this patch with the following command:
patch -Np1 -i ../gcc-4.1.2-texinfo_fix-1.patch
Apply the DWARF3 patch:
patch -Np1 -i ../gcc-4.1.2-DW_CFA_val-1.patch
Apply the -Wno-overlength-strings patch:
patch -Np1 -i ../gcc-4.1.2-Wno_overlength_strings-1.patch
Add the patch for __strncat_chk
compile time checking:
patch -Np1 -i ../gcc-4.1.2-strncat_chk-1.patch
Apply the -D_FORTIFY_SOURCE=2 GCC specs patch:
patch -Np1 -i ../gcc-4.1.2-fortify_source-2.patch
Apply the -fstack-protector-all GCC specs
patch:
patch -Np1 -i ../gcc-4.1.2-fstack_protector-1.patch
Apply the -fPIE patch:
patch -Np1 -i ../gcc-4.1.2-fpie-2.patch
Fix the RPATH_ENVVAR for bfd and opcode:
sed -e 's@/.:$$r@/.libs:$$r@' -e 's@/.:@/.libs:@' -i.orig Makefile.in
The mudflap debugging feature included with GCC will normally allow
a program to continue running during violations to give the user
more information. The following command will change this default
behaviour so libmudflap will send an
ABRT signal to abort the program. This can be reset with the
MUDFLAP_OPTIONS environment variable.
Please keep in mind that mudflap is a debugging feature, and was
not intended as a security feature, and is being implemented like
this here because this is better than not using it at all. This
modification can be circumvented by a user setting the LD_PRELOAD environment variable to load an alternate
libmudflap library:
sed 's/violation_mode = viol_nop/violation_mode = viol_abort/' \
-i.orig libmudflap/mf-runtime.c
Create a separate build directory again:
mkdir -v ../butterfly-build
cd ../butterfly-build
Prepare for compilation:
../butterfly-toolchain/configure --prefix=/usr \
--libexecdir=/usr/lib --enable-shared \
--enable-threads=posix --enable-__cxa_atexit \
--enable-clocale=gnu --enable-languages=c,c++ \
--enable-checking --disable-werror
Compile the package:
make tooldir=/usr
The meaning of the make parameter:
-
tooldir=/usr
-
Normally, the tooldir (the directory where the executables
will ultimately be located) is set to $(exec_prefix)/$(target_alias). For
example, i686 machines would expand that to /usr/i686-pc-linux-gnu. Because this is a
custom system, this target-specific directory in /usr is not required. $(exec_prefix)/$(target_alias) would be
used if the system was used to cross-compile (for example,
compiling a package on an Intel machine that generates code
that can be executed on PowerPC machines).
To test the results:
make -k check
There is an SSP test in gcc.misc-tests/. The testsuite will be very bad.
SSP and PIC need to be disabled in CFLAGS_FOR_TARGET, and
-L/usr/lib/static probably needs to be added so static libraries
can be used.
Install the package:
make tooldir=/usr install
If you plan to link suid packages to libmudflap then you need to move the mudflap
libraries to /lib with the following
command:
mv -v /usr/lib/libmudflap{,th}.so* /lib
ln -vsf ../../lib/libmudflap.so.0 /usr/lib/libmudflap.so
ln -vsf ../../lib/libmudflapth.so.0 /usr/lib/libmudflapth.so
Move the static libraries installed by GCC:
mv -v /usr/lib/{libsupc++,libstdc++}.a /usr/lib/static/
mv -v /usr/lib/{libbfd,libiberty,libmudflap,libmudflapth}.a /usr/lib/static
mv -v /usr/lib/{libopcodes,libssp,libssp_nonshared}.a /usr/lib/static
mv -v /usr/lib/gcc/$(gcc -dumpmachine)/4.1.2/libgcov.a /usr/lib/static/
Move libc.a and libdl.a from the C library package:
mv -v /usr/lib/{libc,libdl}.a /usr/lib/static
Some packages expect the C PreProcessor to be installed in the
/lib directory. To support those
packages, create this symlink:
ln -vs ../usr/bin/cpp /lib
Many packages use the name cc to call the C compiler. To
satisfy those packages, create a symlink:
ln -vs gcc /usr/bin/cc
Install the libiberty header file
that is needed by some packages:
install -v -m0644 ../butterfly-toolchain/include/libiberty.h \
/usr/include
Important
With Glibc the _FORTIFY_SOURCE checking will respond to buffer
overflows before SSP will.
All these test programs are from the NetBSD progect.
If there is a “Segmentation
Fault” anywhere, then something is not right.
This first program will defeat _FORTIFY_SOURCE checking, but
should be caught by SSP. This program accepts a number command
line argument, and displays that many 0's, until the buffer
overflows. The actual number needed seems to vary between libc
versions...:
cat > ssp-overflow.c << "EOF"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void raw(char *, size_t);
static void
raw(char *b, size_t len) {
b[len] = '\0';
}
int
main(int argc, char *argv[])
{
char b[10];
size_t len = atoi(argv[1]);
(void)strncpy(b, "0000000000", sizeof(b));
raw(b, len);
(void)printf("%s\n", b);
return 0;
}
EOF
gcc -o ssp-overflow ssp-overflow.c
./ssp-overflow 9
./ssp-overflow 12
This should display:
0000000000
*** stack smashing detected ***: ./ssp-overflow terminated
Aborted
Also check that this program is compiled with other hardening
options:
readelf -ld ssp-overflow | \
grep -E 'Shared object|TEXTREL|PAX|BIND_NOW|GNU'
This should not display “TEXTREL”. This should only display:
Elf file type is DYN (Shared object file)
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
GNU_RELRO 0x000ee0 0x00001ee0 0x00001ee0 0x00120 0x00120 R 0x1
PAX_FLAGS 0x000000 0x00000000 0x00000000 0x00000 0x00000 0x4
0x00000018 (BIND_NOW)
This says we have a shared object without text relocation, which
is ideal to take the greatest advantage of PaX. Next we have GNU
Stack header marking, needed by PaX. The GNU Relro header is from
the -z relro linker option. The PaX
header is used by PaX, and is from the Binutils PaX patch. The
Bind Now section is from the -z now
linker option.
This next program will test the _FORTIFY_SOURCE checking. At the
same time we can test the negative compiler options to verify
that they also work. This is an example where static code
checking will not detect a problem. The only issue that is
reported by static code analysis programs, like Splint or the -Wextra option, is that the
int argc paramter is unused:
cat > fgets-overflow.c << "EOF"
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
char b[10];
int len = atoi(argv[1]);
if ((fgets(b, len, stdin)) != b)
return 1;
(void)printf("%s\n", b);
return 0;
}
EOF
gcc -o fgets-overflow fgets-overflow.c -fno-stack-protector \
-nopie -fno-pie -nonow -norelro
echo abcdefghijklm | ./fgets-overflow 10
echo abcdefghijklm | ./fgets-overflow 14
This should display:
abcdefghi
*** buffer overflow detected ***: ./fgets-overflow terminated
Aborted
Glibc may also display a backtrace.
And check that the negative options worked, and this is a normal
dynamically linked object:
readelf -ld ./fgets-overflow | \
grep -E 'Executable file|PAX|BIND_NOW|GNU'
This should display:
Elf file type is EXEC (Executable file)
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
PAX_FLAGS 0x000000 0x00000000 0x00000000 0x00000 0x00000 0x4
Both _FORTIFY_SOURCE and SSP will abort this program if the
program's argument (14 in the above example) is more than 10.
The next program is a simple strcpy(3) overflow, and is an
example where static code analysis will catch the problem. At the
same time we can check that static linking works:
cat > strcpy-overflow.c << "EOF"
#include <string.h>
int main()
{
char buf[2];
strcpy(buf,"12345");
return 0;
}
EOF
gcc -o strcpy-overflow strcpy-overflow.c -static -L/usr/lib/static
This should display:
strcpy-overflow.c: In function 'main':
strcpy-overflow.c:5: warning: call to __builtin___strcpy_chk will
always overflow destination buffer
Here the _FORTIFY_SOURCE feature is warning that the compiler
knows in advance that strcpy(3) will overflow. Try to run the
program:
./strcpy-overflow
This should display:
*** buffer overflow detected ***: ./strcpy-overflow terminated
Aborted
In this fortify-test program the strcpy() function was replaced
with the __strcpy_chk() function at compile time, when the
warning was generated. The __strcpy_chk() function then aborted
the program at run time when a buffer overflow was detected.
Also check that the static linking worked:
readelf -d ./strcpy-overflow
This should display:
There is no dynamic section in this file.
This particular program can also be used to test the Stack
Smashing Protector. Recompile this program with optimizations
disabled and FORTIFY_SOURCE enabled, which will override the GCC
specs, simply to show that FORTIFY_SOURCE only works with
optimizations:
gcc -o strcpy-overflow strcpy-overflow.c -O0
Then run it:
./strcpy-overflow
This should return:
*** stack smashing detected ***: ./ssp-test terminated
Aborted
If your libc has arc4random(), the
following program will test it:
cat > arc4rnd-tst.c << "EOF"
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int random_number;
random_number = arc4random() % 65536;
printf("%d\n", random_number);
return 0;
}
EOF
gcc -o arc4rnd-tst arc4rnd-tst.c -Wall
./arc4rnd-tst && ./arc4rnd-tst && ./arc4rnd-tst
This should display three lines of completely different numbers.
FIXME: Test where the entropy is coming from. Maybe have a
program which will run arc4random()
over and over until numbers repeat, and then report the averages.
The arc4_prng patch also modifies the strfry. The next program will test it is
working:
cat > strfry-tst.c << "EOF"
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
char *string;
string = malloc(sizeof(char) * 26);
(void) strncpy(string, "abcdefghijklmnopqrstuvwxyz", sizeof(char) * 26);
(void) strfry(string);
(void) printf("%s\n", string);
free(string);
return 0;
}
EOF
gcc -o strfry-tst strfry-tst.c -Wall
./strfry-tst && ./strfry-tst && ./strfry-tst
This should display three lines of equal length, in a random
sequence.
If your libc has issetugid(), the
following program will test it:
cat > issetugid-tst.c << "EOF"
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int GETUID=getuid(), GETGID=getgid();
int GETEUID=geteuid(), GETEGID=getegid();
int ISSETUGID=issetugid();
printf("Your real user ID is %d\n", GETUID);
printf("Your real group ID is %d\n", GETGID);
printf("Your effective user ID is %d\n", GETEUID);
printf("Your effective group ID is %d\n", GETEGID);
if (ISSETUGID == 1)
{
printf("issetugid() says this program is SUID\n");
}
else
{
printf("issetugid() says this program is not SUID\n");
}
return 0;
}
EOF
gcc -o issetugid-tst issetugid-tst.c -Wall
chmod +s ./issetugid-tst
echo "dummy:x:101:99:Dummy User:/nonexistent:/bin/sh" >> /etc/passwd
su-tools dummy -c $(pwd)/issetugid-tst
chmod -s ./issetugid-tst
su-tools dummy -c $(pwd)/issetugid-tst
sed '/dummy/d' -i /etc/passwd
This should display:
Your real user ID is 101
Your real group ID is 99
Your effective user ID is 0
Your effective group ID is 0
issetugid() says this program is SUID
...
Your real user ID is 101
Your real group ID is 99
Your effective user ID is 101
Your effective group ID is 99
issetugid() says this program is not SUID
Please note that this issetugid()
test will not work correctly on a “nosuid” mounted partition.