C-Based Toolchain Hardening
Compiler writers provide a rich set of warnings from the analysis of code during compilation. Both GCC and Visual Studio have static analysis capabilities to help find mistakes early in the development process. The built in static analysis capabilities of GCC and Visual Studio are usually sufficient to ensure proper API usage and catch a number of mistakes such as using an uninitialized variable or comparing a negative signed int and a positive unsigned int.
As a concrete example, (and for those not familiar with C/C++ promotion rules), a warning will be issued if a signed integer is promoted to an unsigned integer and then compared because a side effect is -1 > 1 after promotion! GCC and Visual Studio will not currently catch, for example, SQL injections and other tainted data usage. For that, you will need a tool designed to perform data flow analysis or taint analysis.
Some in the development community resist static analysis or refute its results. For example, when static analysis warned the Linux kernel's sys_prctl was comparing an unsigned value against less than zero, Jesper Juhl offered a patch to clean up the code. Linus Torvalds howled “No, you don't do this… GCC is crap” (referring to compiling with warnings). For the full discussion, see [PATCH] Don't compare unsigned variable for <0 in sys_prctl() from the Linux Kernel mailing list.
The following sections will detail steps for two platforms. First is a typical GNU Linux based distribution offering GCC and Binutils, and second is modern Windows platforms. GCC (the compiler collection) and Binutils (the assemblers, linkers, and other tools) are separate projects that work together to produce a final executable. On Windows, you will use the tools available from Visual Studio and various SDKs. Other platforms should offer similar tools and capabilities.
The table below offers a set of compiler options to build your pro- gram. Static analysis warnings help catch mistakes early, while the linker options harden the executable at runtime. Refer to GCC Option Summary and Binutils (LD) Command Line Options for usage details.
In the table below, “GCC” should be loosely taken as “non-ancient distributions.” While the GCC team considers 4.2 ancient, you will still encounter it on Apple and BSD platforms due to changes in GPL licensing around 2007.
|Flag or Switch||Version||Discussion|
|-Wall -Wextra||GCC||Enables many warnings (despite their names, all and extra do not turn on all warnings).a|
|-Wconversion||GCC||Warn for implicit conversions that may alter a value.|
|-Wno-unused-parameter||GCC||Reduces warning noise when using -Wall due to C++ interface programming.|
|-Wformat=2 -Wformat-security||GCC||Increases warnings related to possible security de- fects, including incorrect format specifiers.|
|-fwrapv||GCC||Tames the optimizer so integer overflow checks based on wrap are not removed.b|
|-fstack-protector or -fstack-protector-all||GCC||Stack Smashing Protector (SSP). Improves stack layout and adds a guard to detect stack based buffer overflows.c|
|-Wstrict-overflow||GCC 4.2||Warn about optimizations taken due to [unde- fined] signed integer overflow assumptions.|
|-Wno-type-limits||GCC 4.3||Reduces C++ warning noise for t < 0 when template T is an unsigned signed type. Clang's equivalent is -Wno-tautological-compare.|
|Position Independent Executable, also known as Address Space Layout Randomization (ASLR). Both -fPIE and -pie are required.|
a Unlike Clang and -Weverything, GCC does not provide a switch to truly enable all warnings.
b -fwrapv requires twos-complement overflow, while -fno-strict-overflow does not. If your program only runs correctly with -fwrapv or -fno-strict-overflow, it is probably violating legal C/C++. See Ian Lance Taylor's blog on Signed Overflow.
c -fstack-protector guards functions with high risk objects such as C strings, while -fstack-protector-all guards all objects.
d -fPIE is a compiler option. It must be used in conjunction with the linker's -pie option.
The linker ….