This site is the archived OWASP Foundation Wiki and is no longer accepting Account Requests.
To view the new OWASP Foundation website, please visit https://owasp.org

Difference between revisions of "C-Based Toolchain Hardening"

From OWASP
Jump to: navigation, search
Line 1: Line 1:
[[C-Based Toolchain Hardening]] is a treatment of project settings that will help you deliver reliable and secure code when using C, C++ and Objective C languages in a number of development environments. This article will examine Microsoft and GCC toolchains for the C, C++ and Objective C languages. It will guide you through the steps you should take to create executables with firmer defensive postures and increased integration with the available platform security. Effectively configuring the toolchain also means your project will enjoy a number of benefits during development, including enhanced warnings and static analysis, and self-debugging code.
 
 
There are four areas to be examined when hardening the toolchain: configuration, preprocessor, compiler, and linker. Nearly all areas are overlooked or neglected when setting up a project. The neglect appears to be pandemic, and it applies to nearly all projects including Auto-configured projects, Makefile-based, Eclipse-based, Visual Studio-based, and Xcode-based. Its important to address the gaps at compile/link time because its [difficult to impossible to [http://sourceware.org/ml/binutils/2012-03/msg00309.html add hardening on a distributed executable after the fact] on some platforms.
 
 
The article will also detail steps which quality assurance personnel can perform to ensure third party code meets organizational standards. Many organizations have Security Testing and Evaluation (ST&E) programs or operate in the US Federal arena where supply chain audits are necessary. If you audit a program with a lot of gaps, it could indicate the company providing the binaries does not have a mature engineering process or has gaps in its internal QA processes. For those who lack mature quality assurance or acceptance and testing criteria, then this article will also provide helpful suggestions.
 
 
Proper use of auditing tools such as <tt>[http://www.trapkit.de/tools/checksec.html checksec]</tt> and <tt>[http://linux.die.net/man/1/readelf readelf]</tt> on Linux and <tt>[http://www.microsoft.com/en-us/download/details.aspx?id=11910 BinScope]</tt> on Windows means source code will be rarely needed for some portions of an audit. Lack of source code clears a number of legal obstacles in the acceptance testing process since NDAs or other agreements may not be required. For those who are not aware, the US's DMCA (PUBLIC LAW 105–304) has proper exceptions for reverse engineering and security testing and evaluation. The RE exemption is in Section 1205 (f) REVERSE ENGINEERING; and the ST&E exemption is in Section 1205 (i) SECURITY TESTING. If you don't need source code access, then you can decompile, re-engineer, and test without the need for consent or worry of reprisals.
 
 
This is a prescriptive article, and it will not debate semantics or speculate on behavior. As such, it will specify semantics, assign behaviors, and present a position. If you find the posture is too aggressive, then you should back off as required to suite your taste.
 
 
A secure toolchain is not a silver bullet. It is one piece of an overall strategy in the engineering process to help ensure success. It will compliment existing processes such as static analysis, dynamic analysis, secure coding, negative test suites, and the like. And a project will still require solid designs and architectures.
 
 
Finally, the OWASP [http://code.google.com/p/owasp-esapi-cplusplus/source ESAPI C++] project eats its own dog food. Many of the examples you will see in this article come directly from the ESAPI C++ project.
 
 
== Wisdom ==
 
 
Code '''must''' be correct. It '''should''' be secure. It '''can''' be efficient.
 
 
[http://en.wikipedia.org/wiki/Jon_Bentley Dr. Jon Bentley]: ''"If it doesn't have to be correct, I can make it as fast as you'd like it to be"''.
 
 
[http://en.wikipedia.org/wiki/Gary_McGraw Dr. Gary McGraw]: ''"Thou shalt not rely solely on security features and functions to build secure software as security is an emergent property of the entire system and thus relies on building and integrating all parts properly"''.
 
 
== Configuration ==
 
 
Configuration is the first opportunity to configure your project for success. Not only do you have to configure your project to meet reliability and security goals, you must also configure integrated libraries properly. You typically have has three choices. First, you can use auto-configuration utilities if on Linux or Unix. Second, you can write a makefile by hand. This is predominant on Linux, Mac OS X, and Unix, but it applies to Windows as well. Finally, you can use an integrated development environment or IDE.
 
 
At this stage in the process, you should concentrate on configuring for two builds: Debug and Release. Debug will be used for development and include full instrumentation. Release will be configured for production. The difference between the two settings is usually ''optimization level'' and ''debug level''. A third build configuration is Test, and its usually a special case of Release.
 
 
For debug and release builds, the settings are typically diametrically opposed. Debug configurations have no optimizations and full debug information; while Release builds have optimizations and minimal to moderate debug information. The Test configuration is often a Release configuration that makes everything public for testing and builds a test harness. For example, all member functions public (a C++ class) and all interfaces (library or shared object) should be made available for testing.
 
 
Though many do not realize, debug code is more highly valued than release code because it holds additional instrumentation. The debug instrumentation will cause a program to become nearly "self-debugging". Self-debugging code reduces your time during trouble shooting and debugging. Reducing time under the debugger means you have more time for development and feature requests. The additional debug instrumentation will be removed in production code via preprocessor macros.
 
 
=== Auto Tools ===
 
 
Auto configuration tools are popular on many Linux and Unix based systems, and the tools include ''Autosetup'', ''Autoconf'', ''Automake'', ''config'', and ''Configure''. The tools work together to produce project files from scripts and template files. After the process completes, your project should be setup and ready to be made with <tt>make</tt>.
 
 
When using auto configuration tools, there are a few files of interest worth mentioning. The files are part of the auto tools chain and include <tt>m4</tt> and the various <tt>*.in</tt>, <tt>*.ac</tt> (autoconf), and <tt>*.am</tt> (automake) files. At times, you will have to open them, or the resulting makefiles, to tune the "stock" configuration.
 
 
There are three downsides to the command line configuration tools in the toolchain: (1) they often ignore user requests, (2) they cannot create configurations, and (3) security is often not a goal.
 
 
To demonstrate the first issue, confider your project with the following: <tt>configure CFLAGS="-Wall -fPIE" CXXFLAGS="-Wall -fPIE" LDFLAGS="-pie"</tt>. You will probably find the auto tools ignored your request. You will have to open an <tt>m4</tt> scripts, <tt>Makefile.in</tt> or <tt>Makefile.am</tt> and fix the configuration.
 
 
For the second point, you will probably be disappointed to learn [https://lists.gnu.org/archive/html/automake/2012-12/msg00019.html Automake does not support the concept of configurations]. Its not entirely Autoconf's or Automake's fault - ''Make'' and its inability to detect changes is the underlying problem. Specifically, ''Make'' only [http://pubs.opengroup.org/onlinepubs/009695399/utilities/make.html checks modification times of prerequisites and targets], and does not check things like <tt>CFLAGS</tt> and <tt>CXXFLAGS</tt>. The net effect is you will not receive expected results when you issue <tt>make debug</tt> and then <tt>make test</tt> or <tt>make release</tt>.
 
 
Finally, you will probably be disappointed to learn tools such as Autoconf and Automake miss many security related opportunities and ship insecure out of the box. There are a number of compiler switches and linker flags that improve the defensive posture of a program, but they are not 'on' by default. Tools like Autoconf - which are supposed to handle this situation - often provides setting to serve the lowest of all denominators.
 
 
A recent discussion on the Automake mailing list illuminates the issue: ''[https://lists.gnu.org/archive/html/autoconf/2012-12/msg00038.html Enabling compiler warning flags]''. Attempts to improve default configurations were met with resistance and no action was taken. The resistance is often of the form, "<nowiki><some useful warning></nowiki> also produces false positives" or "<nowiki><some obscure platform></nowiki> does not support <nowiki><established security feature></nowiki>". Its noteworthy that David Wheeler, the author of ''[http://www.dwheeler.com/secure-programs/ Secure Programming for Linux and Unix HOWTO]'', was one of the folks trying to improve the posture.
 
 
=== Makefiles ===
 
 
Make is one of the earliest build systems dating back to the 1970s. Its available on Linux, Mac OS X and Unix, so you will frequently encounter projects using it. Unfortunately, Make has a number of short comings (''[http://aegis.sourceforge.net/auug97.pdf Recursive Make Considered Harmful]'' and ''[http://www.conifersystems.com/whitepapers/gnu-make/ What’s Wrong With GNU make?]''), and can cause some discomfort. Despite issues with Make, ESAPI C++ uses Make primarily for three reasons: first, its omnipresent; second, its easier to manage than the Auto Tools family; and third, <tt>libtool</tt> was out of the question.
 
 
Consider what happens when you: (1) type <tt>make debug</tt>, and then type <tt>make release</tt>. Each build would require different <tt>CFLAGS</tt> due to optimizations and level of debug support. In your makefile, you would extract the relevant target and set <tt>CFLAGS</tt> and <tt>CXXFLAGS</tt> similar to below (taken from [http://code.google.com/p/owasp-esapi-cplusplus/source/browse/trunk/Makefile ESAPI C++ Makefile]):
 
 
<pre># Makefile
 
DEBUG_GOALS = $(filter $(MAKECMDGOALS), debug)
 
ifneq ($(DEBUG_GOALS),)
 
  WANT_DEBUG := 1
 
  WANT_TEST := 0
 
  WANT_RELEASE := 0
 
endif
 
 
 
ifeq ($(WANT_DEBUG),1)
 
  ESAPI_CFLAGS += -DDEBUG=1 -UNDEBUG -g3 -ggdb -O0
 
  ESAPI_CXXFLAGS += -DDEBUG=1 -UNDEBUG -g3 -ggdb -O0
 
endif
 
 
 
# Merge ESAPI flags with user supplied flags. We perform the extra step to ensure
 
# user options follow our options, which should give user option's a preference.
 
override CFLAGS := $(ESAPI_CFLAGS) $(CFLAGS)
 
override CXXFLAGS := $(ESAPI_CXXFLAGS) $(CXXFLAGS)
 
override LDFLAGS := $(ESAPI_LDFLAGS) $(LDFLAGS)
 
…</pre>
 
 
Make will first build the program in a debug configuration for a session under the debugger using a rule similar to:
 
 
<pre>%.cpp:%.o:
 
        $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@</pre>
 
 
When you want the release build, Make will do nothing because it considers everything up to date despite the fact <tt>CFLAGS</tt> and <tt>CXXFLAGS</tt> have changed. Hence, your program will actually be in a debug configuration and risk a <tt>SIGABRT</tt> at runtime because debug instrumentation is present (recall <tt>assert</tt> calls <tt>abort()</tt> when <tt>NDEBUG</tt> is '''not''' defined). In essence, you have DoS'd yourself due to <tt>make</tt>.
 
 
In addition, many projects do not honor the user's command line. ESAPI C++ does its best to ensure a user's flags are honored via <tt>override</tt> as shown above, but other projects do not. For example, consider a project that should be built with Position Independent Executable (PIE or ASLR) enabled and data execution prevention (DEP) enabled. Dismissing user settings combined with insecure out of the box settings (and not picking them up during auto-setup or auto-configure) means a program built with the following ail likely have neither defense:
 
 
<pre>$ make CFLAGS="-fPIE" CXXFLAGS="-fPIE" LDFLAGS="-pie -z,noexecstack, -z,noexecheap"</pre>
 
 
Defenses such as ASLR and DEP are especially important on Linux because [http://linux.die.net/man/5/elf Data Execution - not Prevention - is the norm].
 
 
=== Integration ===
 
 
Project level integration presents opportunities to harden your program or library with domain specific knowledge. For example, if the platform supports Position Independent Executables (PIE or ASLR) and data execution prevention (DEP), then you should integrate with it. The consequences of not doing so could result in exploitation. As a case in point, see KingCope's 0-days for MySQL in December, 2012 (CVE-2012-5579 and CVE-2012-5612, among others). Integration with platform security would have neutered a number of the 0-days.
 
 
In addition, its an opportunity to harden third party libraries you chose to include. Because you chose to include them, you and your users are responsible for them. If you or your users endure a SP800-53 audit, third party libraries will be in scope because the supply chain is included (specifically, item SA-12, Supply Chain Protection). The audits are not limited to those in the US Federal arena - financial institutions perform reviews too.
 
 
As an example, suppose you are including OpenSSL. You know (1) [http://www.schneier.com/paper-ssl-revised.pdf SSLv2 is insecure], (2) [http://www.yaksman.org/~lweith/ssl.pdf SSLv3 is insecure], and (3) [http://arstechnica.com/security/2012/09/crime-hijacks-https-sessions/ compression is insecure] (among others). In addition, suppose you don't use hardware and engines, and only allow static linking. Given the knowledge and specifications, you would configure the OpenSSL library as follows:
 
 
<pre>$ Configure darwin64-x86_64-cc -no-hw -no-engines -no-comp -no-shared -no-dso -no-sslv2 -no-sslv3 --openssldir=…</pre>
 
 
If you configure without the switches, then you will likely have vulnerable code/libraries and risk failing an audit. <tt>nm</tt> or <tt>openssl s_client</tt> will reveal that, for example, compression is enabled. If the program is a remote server, then the following command will reveal if compression is active:
 
 
<pre>$ echo "GET / HTTP1.0" | openssl s_client -connect <nowiki>example.com:443</nowiki></pre>
 
 
If the program is a client, the following will expose if compression is available:
 
 
<pre>$ nm /usr/local/ssl/iphoneos/lib/libcrypto.a 2>/dev/null | egrep -i "(COMP_CTX_new|COMP_CTX_free)"
 
0000000000000110 T COMP_CTX_free
 
0000000000000000 T COMP_CTX_new</pre>
 
 
In fact, any symbol within the <tt>OPENSSL_NO_COMP</tt> preprocessor macro will bear witness since <tt>-no-comp</tt> is translated into a <tt>CFLAGS</tt> define.
 
 
Even more egregious is the answer given to auditors who specifically ask about configurations and protocols: "we don't use weak/wounded/broken ciphers" or "we follow best practices." The use of compression tells the auditor that you are using wounded protocol in an insecure configuration and you don't follow best practices. That will likely set off alarm bells, and ensure the auditor dives deeper on more items.
 
 
== Preprocessor ==
 
 
The preprocessor is crucial to setting up a project for success. The C committee provided one macro - <tt>NDEBUG</tt> - and the macro can be used to derive a number of configurations and drive engineering processes. Unfortunately, the committee also left many related items to chance, which has resulted in programmers abusing builtin facilities. This section will help you set up you projects to integrate well with other projects and ensure reliability and security.
 
 
There are three topics to discuss when hardening the preprocessor. The first is well defined configurations which produce well defined behaviors, the second is useful behavior from assert, and the third is proper use of macros when integrating vendor code and third party libraries.
 
 
=== Configurations ===
 
 
To remove ambiguity, you should recognize two configurations: Release and Debug. Release is for production code on live servers, and its behavior is requested via the C/C++ <tt>NDEBUG</tt> macro. Its also the only macro observed by the C and C++ Committees and Posix. Diametrically opposed to release is Debug. While there is a compelling argument for <tt>!defined(NDEBUG)</tt>, you should have an explicit macro for the configuration and that macro should be <tt>DEBUG</tt>. This is because vendors and outside libraries use <tt>DEBUG</tt> (or similar) macro for their configuration. For example, Carnegie Mellon's Mach kernel uses <tt>DEBUG</tt>, Microsoft's CRT uses [http://msdn.microsoft.com/en-us/library/ww5t02fa%28v=vs.71%29.aspx<tt>_DEBUG</tt>], and Wind River Workbench uses <tt>DEBUG_MODE</tt>.
 
 
In addition to <tt>NDEBUG</tt> (Release) and <tt>DEBUG</tt> (Debug), you have two additional cross products: both are defined or neither are defined. Defining both should be an error, and defining neither should default to a release configuration. Below is from [http://code.google.com/p/owasp-esapi-cplusplus/source/browse/trunk/esapi/EsapiCommon.h ESAPI C++ EsapiCommon.h], which is the configuration file used by all source files:
 
 
<pre>// Only one or the other, but not both
 
#if (defined(DEBUG) || defined(_DEBUG)) && (defined(NDEBUG) || defined(_NDEBUG))
 
# error Both DEBUG and NDEBUG are defined.
 
#endif
 
 
// The only time we switch to debug is when asked. NDEBUG or {nothing} results
 
// in release build (fewer surprises at runtime).
 
#if defined(DEBUG) || defined(_DEBUG)
 
# define ESAPI_BUILD_DEBUG 1
 
#else
 
# define ESAPI_BUILD_RELEASE 1
 
#endif</pre>
 
 
When <tt>DEBUG</tt> is in effect, your code should receive full debug instrumentation, including the full force of assertions.
 
 
=== ASSERT ===
 
 
Asserts will help you create self-debugging code. They help you find the point of first failure quickly and easily. Asserts should be used throughout your program, including parameter validation, return value checking and program state. If you have thorough code coverage, you will spend less time debugging and more time developing because f_DEBUG will debug themselves.
 
 
To use asserts effectively, you should assert everything. That includes parameters upon entering a function, return values from function calls, and any program state. Everywhere you place an <tt>if</tt> statement for validation or checking, you should have an assert. Everywhere you have an <tt>assert</tt> for validation or checking, you should have an <tt>if</tt> statement. They go hand-in-hand.
 
 
There is one problem with using asserts - [http://pubs.opengroup.org/onlinepubs/009604499/functions/assert.html Posix states <tt>assert</tt> should call <tt>abort()</tt>] if <tt>NDEBUG</tt> is '''not''' defined. When debugging, <tt>NDEBUG</tt> will never be defined since you want the "program diagnostics" (quote from the Posix description). That makes <tt>assert</tt> and its accompanying <tt>abort()</tt> completely useless. The result of "program diagnostics" calling <tt>abort()</tt> due to standard C/C++ behavior is disuse - developers simply don't use them. Its incredibly bad for the development community because self-debugging programs can help eradicate so many stability problems.
 
 
Since self-debugging programs are so powerful, you will have to have to supply your own assert and signal handler with improved behavior. Your assert will exchange auto-aborting behavior for auto-debugging behavior. The auto-debugging facility will ensure the debugger snaps when a problem is detected, and you will find the point of first failure quickly and easily.
 
 
ESAPI C++ supplies its own assert with the behavior described above. In the code below, <tt>ASSERT</tt> raises <tt>SIGTRAP</tt> when in effect or it evaluates to <tt>void</tt> in other cases.
 
 
<pre>// A debug assert which should be sprinkled liberally. This assert fires and then continues rather
 
// than calling abort(). Useful when examining negative test cases from the command line.
 
#if (defined(ESAPI_BUILD_DEBUG) && defined(ESAPI_OS_STARNIX))
 
#  define ESAPI_ASSERT1(exp) {                                    \
 
    if(!(exp)) {                                                  \
 
      std::ostringstream oss;                                    \
 
      oss << "Assertion failed: " << (char*)(__FILE__) << "("    \
 
          << (int)__LINE__ << "): " << (char*)(__func__)          \
 
          << std::endl;                                          \
 
      std::cerr << oss.str();                                    \
 
      raise(SIGTRAP);                                            \
 
    }                                                            \
 
  }
 
#  define ESAPI_ASSERT2(exp, msg) {                              \
 
    if(!(exp)) {                                                  \
 
      std::ostringstream oss;                                    \
 
      oss << "Assertion failed: " << (char*)(__FILE__) << "("    \
 
          << (int)__LINE__ << "): " << (char*)(__func__)          \
 
          << ": \"" << (msg) << "\"" << std::endl;                \
 
      std::cerr << oss.str();                                    \
 
      raise(SIGTRAP);                                            \
 
    }                                                            \
 
  }
 
#elif (defined(ESAPI_BUILD_DEBUG) && defined(ESAPI_OS_WINDOWS))
 
#  define ESAPI_ASSERT1(exp)      assert(exp)
 
#  define ESAPI_ASSERT2(exp, msg) assert(exp)
 
#else
 
#  define ESAPI_ASSERT1(exp)      ((void)(exp))
 
#  define ESAPI_ASSERT2(exp, msg) ((void)(exp))
 
#endif
 
 
#if !defined(ASSERT)
 
#  define ASSERT(exp)    ESAPI_ASSERT1(exp)
 
#endif</pre>
 
 
At program startup, a <tt>SIGTRAP</tt> handler will be installed if one is not provided by another component:
 
 
<pre>struct DebugTrapHandler
 
{
 
  DebugTrapHandler()
 
  {
 
    struct sigaction new_handler, old_handler;
 
 
    do
 
      {
 
        int ret = 0;
 
 
        ret = sigaction (SIGTRAP, NULL, &old_handler);
 
        if (ret != 0) break; // Failed
 
 
        // Don't step on another's handler
 
        if (old_handler.sa_handler != NULL) break;
 
 
        new_handler.sa_handler = &DebugTrapHandler::NullHandler;
 
        new_handler.sa_flags = 0;
 
 
        ret = sigemptyset (&new_handler.sa_mask);
 
        if (ret != 0) break; // Failed
 
 
        ret = sigaction (SIGTRAP, &new_handler, NULL);
 
        if (ret != 0) break; // Failed
 
 
      } while(0);
 
  }
 
 
  static void NullHandler(int /*unused*/) { }
 
 
};
 
 
// We specify a relatively low priority, to make sure we run before other CTORs
 
// http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html#C_002b_002b-Attributes
 
static const DebugTrapHandler g_dummyHandler __attribute__ ((init_priority (110)));</pre>
 
 
On a Windows platform, you would call <tt>_set_invalid_parameter_handler</tt> (and possibly <tt>set_unexpected</tt> or <tt>set_terminate</tt>) to install a new handler.
 
 
Live hosts running production code should always define <tt>NDEBUG</tt> (i.e., release configuration), which means they do not assert or auto-abort. Auto-abortion is not acceptable behavior, and anyone who asks for the behavior is completely abusing the functionality of "program diagnostics". If a program wants a core dump, then it should create the dump rather than crashing.
 
 
=== Additional Macros ===
 
 
Additional macros include any macros needed to integrate properly and securely. It includes integrating the program with the platform (for example MFC or Cocoa/CocoaTouch) and libraries (for example, Crypto++ or OpenSSL). It can be a challenge because you have to have proficiency with your platform and all included libraries and frameworks. The list below illustrates the level of detail you will need when integrating.
 
 
Though Boost is missing from the list, it appears to lack recommendations, additional debug diagnostics, and a hardening guide. See ''[http://stackoverflow.com/questions/14927033/boost-hardening-guide-preprocessor-macros BOOST Hardening Guide (Preprocessor Macros)]'' for details. In addition, Tim Day points to ''[http://boost.2283326.n4.nabble.com/boost-build-should-we-not-define-SECURE-SCL-0-by-default-for-all-msvc-toolsets-td2654710.html <nowiki>[boost.build] should we not define _SECURE_SCL=0 by default for all msvc toolsets</nowiki>]'' for a recent discussion related to hardening (or lack thereof).
 
 
In addition to what you should define, defining some macros and undefining others should trigger a security related defect. For example, <tt>-U_FORTIFY_SOURCES</tt> on Linux and <tt>_CRT_SECURE_NO_WARNINGS=1</tt>, <tt>_SCL_SECURE_NO_WARNINGS</tt>, <tt>_ATL_SECURE_NO_WARNINGS</tt> or <tt>STRSAFE_NO_DEPRECATE</tt> on Windows.
 
 
{| border="1"
 
 
|-style="background:#DADADA"
 
!Platform/Library!!Debug!!Release
 
|+ Table 1: Additional Platform/Library Macros
 
 
|-
 
|width="175pt"|All
 
|width="250pt"|DEBUG=1
 
|width="250pt"|NDEBUG=1
 
 
|-
 
|Linux
 
|_GLIBCXX_DEBUG=1<sup>a</sup>
 
|_FORTIFY_SOURCE=2
 
 
|-
 
|Android (4.2 and above)
 
|
 
|_FORTIFY_SOURCE=1
 
 
|-
 
|Cocoa/CocoaTouch
 
|
 
|NS_BLOCK_ASSERTIONS=1<br>
 
<tt>#define NSLog(...)</tt> (define to nothing, preempt ASL)
 
 
|-
 
|SafeInt
 
|SAFEINT_DISALLOW_UNSIGNED_NEGATION=1
 
|SAFEINT_DISALLOW_UNSIGNED_NEGATION=1
 
 
|-
 
|Microsoft
 
|_DEBUG=1, STRICT,<br>
 
_SECURE_SCL=1, _HAS_ITERATOR_DEBUGGING=1<br>
 
_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1<br>
 
_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1
 
|STRICT<br>
 
_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1<br>
 
_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1
 
 
|-
 
|Microsoft ATL & MFC
 
|_SECURE_ATL, _ATL_ALL_WARNINGS<br>
 
_ATL_CSTRING_EXPLICIT_CONSTRUCTORS
 
|_SECURE_ATL, _ATL_ALL_WARNINGS<br>
 
_ATL_CSTRING_EXPLICIT_CONSTRUCTORS
 
 
|-
 
|STLPort
 
|_STLP_DEBUG=1, _STLP_USE_DEBUG_LIB=1<br>
 
_STLP_DEBUG_ALLOC=1, _STLP_DEBUG_UNINITIALIZED=1
 
|
 
 
|-
 
|SQLite
 
|SQLITE_DEBUG, SQLITE_MEMDEBUG<br>
 
SQLITE_OMIT_WAL, SQLITE_SECURE_DELETE<sup>b</sup><br>
 
SQLITE_DEFAULT_FILE_PERMISSIONS=N<sup>c</sup>
 
|SQLITE_OMIT_WAL, SQLITE_SECURE_DELETE<sup>b</sup><br>
 
SQLITE_DEFAULT_FILE_PERMISSIONS=N<sup>c</sup>
 
 
|-
 
|SQLCipher
 
|Remove '''<tt>NDEBUG</tt>''' from Debug builds (Xcode)<br>
 
SQLITE_HAS_CODEC=1
 
|SQLITE_HAS_CODEC=1
 
 
|-
 
|SQLite/SQLCipher
 
|SQLITE_TEMP_STORE=3<sup>d</sup>
 
|SQLITE_TEMP_STORE=3<sup>d</sup>
 
 
|}
 
 
<sup>a</sup> Be careful with <tt>_GLIBCXX_DEBUG</tt> when using pre-compiled libraries such as Boost from a distribution. There are ABI incompatibilities, and the result will likely be a crash. You will have to compile Boost with <tt>_GLIBCXX_DEBUG</tt> or omit <tt>_GLIBCXX_DEBUG</tt>.
 
 
<sup>b</sup> SQLite secure deletion zeroizes memory on destruction. Define as required, and always define in US Federal since zeroization is required for FIPS 140-2, Level 1.
 
 
<sup>c</sup> ''N'' is 0644 by default, which means everyone has some access.
 
 
<sup>d</sup> Force temporary tables into memory (no unencrypted data to disk).
 
 
<!--
 
##########################################
 
-->
 
 
 
== Compiler ==
 
== Compiler ==
  
Line 375: Line 50:
 
|GCC
 
|GCC
 
|Stack Smashing Protector (SSP). Improves stack layout and adds a guard to detect stack based buffer overflows.<sup>c</sup>
 
|Stack Smashing Protector (SSP). Improves stack layout and adds a guard to detect stack based buffer overflows.<sup>c</sup>
 
|-
 
|<nowiki>-fstack-protector or -fstack-protector-all</nowiki>
 
|GCC
 
|Stack Smashing Protector (SSP). Improves stack layout and adds a guard to detect stack based buffer overflows.<sup>c</sup>
 
 
|-
 
|<nowiki>-fPIE</nowiki>
 
|GCC, Binutils 2.16
 
|Position Independent Executable, also known as Address Space Layout Randomization (ASLR). Both -fPIE and -pie are required.
 
  
 
|-
 
|-
Line 395: Line 60:
 
|GCC 4.3
 
|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.
 
|Reduces C++ warning noise for t < 0 when template T is an unsigned signed type. Clang's equivalent is -Wno-tautological-compare.
 +
 +
|-
 +
|<nowiki>-fPIE</nowiki>
 +
|GCC,<br>Binutils 2.16
 +
|Position Independent Executable, also known as Address Space Layout Randomization (ASLR). Both -fPIE and -pie are required.
  
 
|}
 
|}

Revision as of 15:27, 18 February 2013

Compiler

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.

GCC/Binutils

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
Table 1: Additional Platform/Library Macros
-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.
-fPIE GCC,
Binutils 2.16
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.

Visual Studio

Linker

The linker ….

GCC/Binutils

Visual Studio