View on GitHub

Getting the maximum of your C compiler, for security

Security-related flags and options for C compilers

Clang

Note: this guide is valid for Clang 12

Clang compiler flags are described by a domain specific language call TableGen, and LLVM includes a tool called llvm-tblgen which parses the definition files, DiagnosticsGroups.td in particular.

Warnings

While Clang thankfully provides a -Weverything option which enables all warnings, it is strongly recommended by Clang developpers not to use it in production…

However, they (and I) recommend using -Weverything to identify warnings which are relevant for your code base and then selectively add them to your standard warning list.

Clang supports the following warnings which are compatible with GCC:

Some other warnings are of interest for security:

Note: You can disable warnings for system includes by using the -isystem option to specify the paths which will be used for “system” includes (#include <file.h>).

Compiler flags

Clang supports various options for stack based buffer overflow protection and mitigations against control flow attacks:

Other compilation flags:

Runtime sanitizers

LLVM support of sanitizers is first class, besides AddressSanitizer, ThreadSanitizer, LeakSanitizer and UndefinedBehaviorSanitizer, which are included in GCC, the following are available:

Use with fuzzing

Runtime sanitizers are particularly useful when:

as they may uncover runtime errors which would not necessarily trigger a crash.

In production

While most sanitizers are not intended to be used in production builds, UBSan integer’s checker is very interesting, as it will detect integer overflows and abort the program.

The code should be compiled with -fsanitize=integer -fsanitize-minimal-runtime -fno-sanitize-recover. The performance impact should be reasonable on modern CPUs (~1%). Android enables it in production builds for some libraries.

Code analysis

Clang static analyzer

Clang has a “modern” static analyzer which can be used to analyze whole projects and produce HTML reports of the potential problems identified by the tool.

“It implements path-sensitive, inter-procedural analysis based on symbolic execution technique.”

scan-build is simple to use and can wrap compilation tools such as make. It will replace the CC and CXX environment variables to analyze your build and produce the report.

$ scan-build make

The default checkers are relatively few, and do not really target security, however, “alpha” (which may have many false positives) checkers related to security can be enabled by using the -enable-checker alpha.security CLI option.

Other interesting checkers:

Others

Fuzzing

While fuzzing is out of scope, you should fuzz your code with sanitizers enabled. Options include:

Test files

Test files are a great way to understand in detail what is and what is not covered by a specific command line flag.

They are located in the clang/test directory. For example, the test for -Wshift-count-negative can be found in clang/test/Sema/warn-shift-negative.c:

// RUN: %clang_cc1 -fsyntax-only -Wshift-count-negative -fblocks -verify %s

int f(int a) {
  const int i = -1;
  return a << i; // expected-warning
}

References