Getting the maximum of your C compiler, for security

This guide is intended to help you determine which flags you should use to compile your C Code using GCC, Clang or MSVC, in order to:

  • detect the maximum number of bugs or potential security problems.
  • enable security mitigations in the produced binaries.
  • enable runtime sanitizers to detect errors (overflows, race conditions, etc.) and make fuzzing more efficient.

Disclaimer:

The flags selected and recommended here were chosen to maximize the number of classes of detected errors which could have a security benefit when enabled. Code generation options (such as -fstack-protector-strong) can also have performance impacts. It is up to you to assess the impact on your code base and choose the right set of command line options.

Comments are of course welcome.

GCC TL;DR

Detailed page

Always use the following warnings and flags on the command line:

-O2
-Werror
-Wall -Wextra -Wpedantic -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 -Wformat-security -Wnull-dereference -Wstack-protector -Wtrampolines -Walloca -Wvla -Warray-bounds=2 -Wimplicit-fallthrough=3 -Wtraditional-conversion -Wshift-overflow=2 -Wcast-qual -Wstringop-overflow=4 -Wconversion -Warith-conversion -Wlogical-op -Wduplicated-cond -Wduplicated-branches -Wformat-signedness -Wshadow -Wstrict-overflow=4 -Wundef -Wstrict-prototypes -Wswitch-default -Wswitch-enum -Wstack-usage=1000000 -Wcast-align=strict
-D_FORTIFY_SOURCE=2
-fstack-protector-strong -fstack-clash-protection -fPIE 
-Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -Wl,-z,separate-code

On legacy code bases, some of the warnings may produce some false positives. On code where the behavior is intended, pragmas can be used to disable the specific warning locally.

Run debug/test builds with sanitizers (in addition to the flags above): AddressSanitizer + UndefinedBehaviorSanitizer:

-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=leak -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=bounds-strict -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow
export ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:detect_invalid_pointer_pairs=2

If your program is multi-threaded, run with -fsanitize=thread (incompatible with ASan).

Finally, use -fanalyzer to spot potential issues.

Clang TL;DR

Detailed page

First compile with:

-O2
-Werror
-Walloca -Wcast-qual -Wconversion -Wformat=2 -Wformat-security -Wnull-dereference -Wstack-protector -Wstrict-overflow=3 -Wvla -Warray-bounds -Warray-bounds-pointer-arithmetic -Wassign-enum -Wbad-function-cast -Wconditional-uninitialized -Wconversion -Wfloat-equal -Wformat-type-confusion -Widiomatic-parentheses -Wimplicit-fallthrough -Wloop-analysis -Wpointer-arith -Wshift-sign-overflow -Wshorten-64-to-32 -Wswitch-enum -Wtautological-constant-in-range-compare -Wunreachable-code-aggressive 
-D_FORTIFY_SOURCE=2
-fstack-protector-strong -fsanitize=safe-stack -fPIE -fstack-clash-protection
-Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -Wl,-z,separate-code

On legacy code bases, some of the warnings may produce some false positives. On code where the behavior is intended, pragmas can be used to disable the specific warning locally.

Run debug/test builds with sanitizers (in addition to the flags above):

AddressSanitizer + UndefinedBehaviorSanitizer:

-fsanitize=address -fsanitize=leak -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=bounds-strict -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fsanitize=integer -fsanitize-no-recover
export ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:detect_invalid_pointer_pairs=2

If your program is multi-threaded, run with -fsanitize=thread (incompatible with ASan).

Finally, use scan-build to spot potential issues.

In addition, you can build production code with -fsanitize=integer -fsanitize-minimal-runtime -fsanitize-no-recover to catch integer overflows.

Microsoft Visual Studio 2019 TL;DR

Detailed page

  • Compile with /Wall /sdl /guard:cf /guard:ehcont /CETCOMPAT
  • Use ASan with /fsanitize=address
  • Analyze your code with /analyze

Tips

GitHub

GitHub - airbus-seclab/c-compiler-security: Security-related flags and options for C compilers
Security-related flags and options for C compilers - GitHub - airbus-seclab/c-compiler-security: Security-related flags and options for C compilers