17.3 Hardened Conditionals

GNAT can harden conditionals to protect against control-flow attacks.

This is accomplished by two complementary transformations, each activated by a separate command-line option.

The option -fharden-compares enables hardening of compares that compute results stored in variables, adding verification that the reversed compare yields the opposite result, turning:

B := X = Y;

into:

B := X = Y;
declare
  NotB : Boolean := X /= Y; -- Computed independently of B.
begin
  if B = NotB then
    <__builtin_trap>;
  end if;
end;

The option -fharden-conditional-branches enables hardening of compares that guard conditional branches, adding verification of the reversed compare to both execution paths, turning:

if X = Y then
  X := Z + 1;
else
  Y := Z - 1;
end if;

into:

if X = Y then
  if X /= Y then -- Computed independently of X = Y.
    <__builtin_trap>;
  end if;
  X := Z + 1;
else
  if X /= Y then -- Computed independently of X = Y.
    null;
  else
    <__builtin_trap>;
  end if;
  Y := Z - 1;
end if;

These transformations are introduced late in the compilation pipeline, long after boolean expressions are decomposed into separate compares, each one turned into either a conditional branch or a compare whose result is stored in a boolean variable or temporary. Compiler optimizations, if enabled, may also turn conditional branches into stored compares, and vice-versa, or into operations with implied conditionals (e.g. MIN and MAX). Conditionals may also be optimized out entirely, if their value can be determined at compile time, and occasionally multiple compares can be combined into one.

It is thus difficult to predict which of these two options will affect a specific compare operation expressed in source code. Using both options ensures that every compare that is neither optimized out nor optimized into implied conditionals will be hardened.

The addition of reversed compares can be observed by enabling the dump files of the corresponding passes, through command-line options -fdump-tree-hardcmp and -fdump-tree-hardcbr, respectively.

They are separate options, however, because of the significantly different performance impact of the hardening transformations.

For usage and more details on the command-line options, see Using the GNU Compiler Collection (GCC). These options can be used with other programming languages supported by GCC.