6.12. Butterfly Toolchain

The GCC package contains the GNU compiler collection, which includes the C and C++ compilers. The Binutils package contains a linker, an assembler, and other tools for handling object files.

User Notes: http://wiki.linuxfromscratch.org/hlfs/wiki/toolchain

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]

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.

6.12.2. Contents of Binutils

Installed programs: addr2line, ar, as, c++filt, gprof, ld, nm, objcopy, objdump, ranlib, readelf, size, strings, and strip
Installed libraries: libiberty.a, libbfd.{a,so}, and libopcodes.{a,so}

Short Descriptions

addr2line

Translates program addresses to file names and line numbers; given an address and the name of an executable, it uses the debugging information in the executable to determine which source file and line number are associated with the address

ar

Creates, modifies, and extracts from archives

as

An assembler that assembles the output of gcc into object files

c++filt

Used by the linker to de-mangle C++ and Java symbols and to keep overloaded functions from clashing

gprof

Displays call graph profile data

ld

A linker that combines a number of object and archive files into a single file, relocating their data and tying up symbol references

nm

Lists the symbols occurring in a given object file

objcopy

Translates one type of object file into another

objdump

Displays information about the given object file, with options controlling the particular information to display; the information shown is useful to programmers who are working on the compilation tools

ranlib

Generates an index of the contents of an archive and stores it in the archive; the index lists all of the symbols defined by archive members that are relocatable object files

readelf

Displays information about ELF type binaries

size

Lists the section sizes and the total size for the given object files

strings

Outputs, for each given file, the sequences of printable characters that are of at least the specified length (defaulting to four); for object files, it prints, by default, only the strings from the initializing and loading sections while for other types of files, it scans the entire file

strip

Discards symbols from object files

libiberty

Contains routines used by various GNU programs, including getopt, obstack, strerror, strtol, and strtoul

libbfd

The Binary File Descriptor library

libopcodes

A library for dealing with opcodes—the “readable text” versions of instructions for the processor; it is used for building utilities like objdump.

6.12.3. Contents of GCC

Installed programs: c++, cc (link to gcc), cpp, g++, gcc, gccbug, and gcov
Installed libraries: libgcc.a, libgcc_eh.a, libgcc_s.so, libstdc++.{a,so}, and libsupc++.a

Short Descriptions

cc

The C compiler

cpp

The C preprocessor; it is used by the compiler to expand the #include, #define, and similar statements in the source files

c++

The C++ compiler

g++

The C++ compiler

gcc

The C compiler

gccbug

A shell script used to help create useful bug reports

gcov

A coverage testing tool; it is used to analyze programs to determine where optimizations will have the most effect

libgcc

Contains run-time support for gcc

libstdc++

The standard C++ library

libsupc++

Provides supporting routines for the C++ programming language