Compiler defenses

Updated: April 19, 2023

Recommended compiler options

The following compiler options enable security features and are included by default when you compile using QNX Neutrino utilities (e.g., q++, qcc):

Option Description
-fPIC Compile a library as position-independent code (PIC).
-fpie Compile an executable as position-independent (position-independent executable (PIE)).
-fstack-protector-strong Inserts a stack cookie onto the stack frame for vulnerable functions, to protect against stack buffer overflow (see Stack protection in “Security features for developers”).

The following option that enables a security feature is not included by default when you compile using QNX Neutrino utilities:

Option Description
-msign-return-address For 64-bit ARM (AArch64) systems with CPUs that support Pointer Authentication, enables pointer signing for some or all functions. Pointer authentication can provide protection against, for example, ROP exploits. QNX recommends that you set this option to all.

Specify -U at startup to check for and set Pointer Authentication support. For more information, see startup-* options” in the Utilities Reference.

The following additional options configure the compiler to output warnings when vulnerable code is detected. Depending on the condition detected, the offending code might be prone to crashing, produce errors or unexpected behavior, or create an opportunity for attack:

Option Description
-Wall Enable additional warnings about questionable code construction. Includes -Wformat, which checks calls to printf()- and scanf()-style functions to make sure the arguments match the format strings.
-Wcast-align Warn if the way a pointer is cast causes the required alignment of the target to increased.
-Wcast-qual Warn whenever the way a pointer is cast removes a type qualifier from the target type.
-Wconversion Warn for implicit conversions that may alter a value.
-Wduplicated-branches Warn when an if-else has identical branches.
-Wduplicated-cond Warn about duplicated conditions in an if-else-if chain.
-Werror Treat warnings as errors, failing the build. May not be appropriate in all environments.
-Wextra Enable additional warnings not enabled by -Wall.
-Wfloat-equal Warn if floating-point values are used in equality comparisons.
-Wformat=2 Check calls to printf()- and scanf()-style functions to make sure the arguments match the format strings (-Wformat), plus additional format checks (-Wformat-nonliteral, -Wformat-security, -Wformat-y2k).
-Winit-self Warn about uninitialized variables that are initialized with themselves (requires -Wuninitialized, which is included in -Wall).
-Wlogical-op Warn about suspicious uses of logical operators in expressions.
-Wmissing-declarations Warn if a global function is defined without a previous declaration.
-Wmissing-prototypes Warn if there are missing prototypes.
-Wnull-dereference Warn if the compiler detects paths that trigger errors or undefined behavior because a null pointer is dereferenced.
-Wpointer-arith Warn about anything that depends on the “size of” a function type or of void.
-Wshadow Warn whenever a local variable or type declaration shadows another variable, parameter, type, or class member (in C++), or whenever a built-in function is shadowed.
-Wsuggest-attribute=format Warn about function pointers that might be candidates for format attributes. When the format attribute is set, the -Wformat=2 flags look for problems with invocations of the function.
-Wswitch-default Warn whenever a switch statement does not have a default case.
-Wswitch-enum Warn whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration.
-Wtrampolines Warn when “trampolines” are generated for pointers to nested functions. (A trampoline is a small piece of data or code that is created at runtime on the stack when the address of a nested function is taken, and is used to call the nested function indirectly.)
-Wunreachable-code Warn if the compiler detects code that will never be executed.
-Wvla-larger-than=4096 Warns if the size of a variable length array (VLA) is larger than 4096 bytes (one page of memory). VLA allocations of 4096 bytes or smaller cannot bypass the guard page at the top of the stack. This option requires an optimization level of 1 or higher.
-Wwrite-strings Issue a diagnostic message if const char * is converted to (non-const) char *.

For detailed information on the warning options, see the GNU compiler documentation at: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

Recommended preprocessor options

QNX recommends the following CPPFLAGS preprocessor option:

Option Description
-D_FORTIFY_SOURCE=2 Enables fortified system functions with more stringent parameter validation (see Fortified System Functions.)

Recommended linker options

QNX recommends the following linker (LDFLAGS) options:

Option Description
-pie -fpie Compile an executable as position-independent (position-independent executable (PIE)). Enabled by default with QNX Neutrino compile utilities.
-Wl,-z,relro -Wl,-z,now Enable Full RELRO (Relocation Read-Only). See RELRO in “Security features for developers”.) Enabled by default with QNX Neutrino compile utilities.
-Wl,-z,defs Prevents undefined symbols in object files.

Recommended compiler verification options

You can increase the probability of finding bugs in your code by compiling it with sanitizers enabled. These compiler options are not meant to be enabled in production binaries. Each option targets a different aspect of the code. To fully utilize the power of these options, make sure that your instrumented code is exercised as it would be in production.

Currently, QNX Neutrino supports the Undefined Behavior Sanitizer (UBSAN).

Option Description Information
--fsanitize=undefined Enables the UBSAN. Various computations are instrumented to detect undefined behavior at runtime. https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html