Structure Protection

Introduction

Structure protection is an experimental mitigation against use-after-free vulnerabilities. For more information, please see the original RFC. An independent set of documentation will be contributed when the feature is promoted to stable.

Usage

To use structure protection, build your program using one or more of these flags:

  • -fexperimental-allow-pointer-field-protection-attr: Makes the [[clang::pointer_field_protection]] attribute described below available for use in code. Without this flag, use of the attribute will cause an error. This flag acts as a guard against use of the feature before it is stabilized. When the feature is stabilized, the intent is that this flag will become a no-op and the attribute will always be available.

  • -fexperimental-pointer-field-protection-abi: Enable pointer field protection on all types that are not considered standard-layout according to the C++ rules for standard layout. Because this flag changes the C++ ABI, we refer to this as the pointer field protection ABI. Specifying this flag also defines the predefined macro __POINTER_FIELD_PROTECTION_ABI__. Implies -fexperimental-allow-pointer-field-protection-attr.

  • -fexperimental-pointer-field-protection-tagged: On architectures that support it (currently only AArch64), for types that are not considered trivially copyable, use the address of the object to compute the pointer encoding. Specifying this flag also defines the predefined macro __POINTER_FIELD_PROTECTION_TAGGED__.

It is also possible to specify the attribute [[clang::pointer_field_protection]] on a struct type to opt the struct’s pointer fields into pointer field protection, even if the type is standard layout or none of the command line flags are specified. Note that this means that the type will not comply with pointer interconvertibility and other standard layout rules.

Pointer field protection is inherited from bases and non-static data members.

In order to avoid ABI breakage, the entire C++ part of the program must be built with a consistent set of -fexperimental-pointer-field-protection* flags, and the C++ standard library must also be built with the same flags and statically linked into the program.

To build libc++ with pointer field protection support, pass the following CMake flags:

"-DRUNTIMES_${triple}_LIBCXXABI_ENABLE_SHARED=OFF" \
"-DRUNTIMES_${triple}_LIBCXX_USE_COMPILER_RT=ON" \
"-DRUNTIMES_${triple}_LIBCXX_PFP=untagged" \
"-DRUNTIMES_${triple}_LIBCXX_ENABLE_SHARED=OFF" \
"-DRUNTIMES_${triple}_LIBCXX_TEST_CONFIG=llvm-libc++-static.cfg.in" \
"-DRUNTIMES_${triple}_LIBUNWIND_ENABLE_SHARED=OFF" \

where ${triple} is your target triple, such as aarch64-unknown-linux.

The resulting toolchain may then be used to build programs with pointer field protection by passing -stdlib=libc++ -fexperimental-pointer-field-protection-abi at compile time and -Wl,-Bstatic -lc++ -lc++abi -Wl,-Bdynamic -lm -fuse-ld=lld -static-libstdc++ at link time.

Implementation

TODO: Document everything else.

The implementation uses deactivation symbols as a mechanism for globally disabling pointer field protection for a particular field. For more information, see the deactivation symbol section of the LangRef. These symbols are named as follows:

__pfp_ds_ followed by the ABI encoding of the type’s RTTI object symbol name followed by . followed by the name of the field.