Compiler-powered hardening
Before August 2020, OpenBSD was using (and maintaining) GCC 4.2.1, the latest version released under GPLv2, released the 13th of July 2008.
Anil Madhavapeddy added __attribute__((__bounded__))
to it on June 2003, which landed in OpenBSD 3.4
Unfortunately, this attribute isn’t
really used in the codebase.
In 2017, Robert Nagy switched the default compiler to clang, for i386 and amd64. Since OpenBSD 6.6, released in October 2019, it’s also the default one for octeon and powerpc.
Unfortunately, starting with LLVM 9.0, released the 19 September 2019, LLVM is now released under Apache License v2.0 with LLVM Exceptions, a license that the OpenBSD people consider incompatible with their philosophy (while it looks like it actually is compatible).
In August 2020, they apparently decided that having a modern compiler was more important than licensing details and upgraded to LLVM 10.
OpenBSD patches clang to enable/add various things by default:
- “remove” ROP gadgets
- treat signed integer overflows as defined via
-fwrapv
, to “prevent dangerous optimizations which could remove security critical overflow checks.” - enable RETGUARD
- enable PIE
- a custom check for
%n
inprintf
-like functions, different than-Wformat
, which is not enabled.
Missing compiler-based mitigations
Constification of function points in kernel-land
PAX_CONSTIFY_PLUGIN
is a gcc plugin by Emese (ephox)
Revfy and pipacs,
marking all structures containing only function pointers as
read-only. It has been part of grsecurity since August 2011.
This prevents trivial control-flow highjacking by function pointer-overwriting.
Structures layout randomization
RANDSTRUCT
is a gcc plugin from grsecurity, now more or less
upstreamed into the Linux kernel in
2017,
and even in clang since
2022. It randomizes the layout of security-critical structures as well as the
ones composed entirely of functions pointers,
making it harder for an attacker without arbitrary read to manipulate those
structures.
Integer overflows in critical functions’ parameters
size_overflow
is an other plugin by ephox, written in 2011.
In ephox’s own
words:
This plugin recomputes expressions of function arguments marked by a
size_overflow
attribute with double integer precision (DImode
/TImode
for 32/64 bit integer types). The recomputed argument is checked againstTYPE_MAX
and an event is logged on overflow and the triggering process is killed.
It was added to grsecurity in March 2013, and was thoroughly documented for the occasion.
Automatic initialization of variables
In August 2011, pipacs published his PAX_MEMORY_STRUCTLEAK
gcc plugin,
which zero initialize some local variables that are going to be copied to userland.
In June 2014, Florian Weimer from Red Hat posted a patch on gcc’s mailing list to initialize all local variables to zero.
In August 2016, Daniel Micay, developer of GrapheneOS (previously CopperheadOS) implemented a patch for clang to provide zero-initialization.
JF Bastien, compiler engineer at Apple, suggested in November 2018 a patch for clang, to add a flag to automatically initialize variables, either with 0, or with a specific pattern, with only a couple of percent performance impact.
Also in November 2018, Microsoft
added the InitAll
flag to its compiler, providing a similar feature, with only noise-level
performance impact. Joseph Bialek, security engineer in the Microsoft Security
Response Center’s Vulnerability & Mitigations team
added:
Between 2017 and mid 2018, this feature would have killed 49 MSRC cases that involved uninitialized struct data leaking across a trust boundary. It would have also mitigated a number of bugs involving uninitialized struct data being used directly. cc @j00ru @TinySecEx