brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.2 KiB · 5723f5a Raw
216 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef _LIBCPP___CONFIGURATION_HARDENING_H10#define _LIBCPP___CONFIGURATION_HARDENING_H11 12#include <__config_site>13#include <__configuration/experimental.h>14#include <__configuration/language.h>15 16#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER17#  pragma GCC system_header18#endif19 20// TODO(LLVM 23): Remove this. We're making these an error to catch folks who might not have migrated.21//       Since hardening went through several changes (many of which impacted user-facing macros),22//       we're keeping these checks around for a bit longer than usual. Failure to properly configure23//       hardening results in checks being dropped silently, which is a pretty big deal.24#if defined(_LIBCPP_ENABLE_ASSERTIONS)25#  error "_LIBCPP_ENABLE_ASSERTIONS has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"26#endif27#if defined(_LIBCPP_ENABLE_HARDENED_MODE)28#  error "_LIBCPP_ENABLE_HARDENED_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"29#endif30#if defined(_LIBCPP_ENABLE_SAFE_MODE)31#  error "_LIBCPP_ENABLE_SAFE_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"32#endif33#if defined(_LIBCPP_ENABLE_DEBUG_MODE)34#  error "_LIBCPP_ENABLE_DEBUG_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)"35#endif36 37// The library provides the macro `_LIBCPP_HARDENING_MODE` which can be set to one of the following values:38//39// - `_LIBCPP_HARDENING_MODE_NONE`;40// - `_LIBCPP_HARDENING_MODE_FAST`;41// - `_LIBCPP_HARDENING_MODE_EXTENSIVE`;42// - `_LIBCPP_HARDENING_MODE_DEBUG`.43//44// These values have the following effects:45//46// - `_LIBCPP_HARDENING_MODE_NONE` -- sets the hardening mode to "none" which disables all runtime hardening checks;47//48// - `_LIBCPP_HARDENING_MODE_FAST` -- sets that hardening mode to "fast". The fast mode enables security-critical checks49//   that can be done with relatively little runtime overhead in constant time;50//51// - `_LIBCPP_HARDENING_MODE_EXTENSIVE` -- sets the hardening mode to "extensive". The extensive mode is a superset of52//   the fast mode that additionally enables checks that are relatively cheap and prevent common types of logic errors53//   but are not necessarily security-critical;54//55// - `_LIBCPP_HARDENING_MODE_DEBUG` -- sets the hardening mode to "debug". The debug mode is a superset of the extensive56//   mode and enables all checks available in the library, including internal assertions. Checks that are part of the57//   debug mode can be very expensive and thus the debug mode is intended to be used for testing, not in production.58 59// Inside the library, assertions are categorized so they can be cherry-picked based on the chosen hardening mode. These60// macros are only for internal use -- users should only pick one of the high-level hardening modes described above.61//62// - `_LIBCPP_ASSERT_VALID_INPUT_RANGE` -- checks that ranges (whether expressed as an iterator pair, an iterator and63//   a sentinel, an iterator and a count, or a `std::range`) given as input to library functions are valid:64//   - the sentinel is reachable from the begin iterator;65//   - TODO(hardening): both iterators refer to the same container.66//67// - `_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS` -- checks that any attempts to access a container element, whether through68//   the container object or through an iterator, are valid and do not attempt to go out of bounds or otherwise access69//   a non-existent element. For iterator checks to work, bounded iterators must be enabled in the ABI. Types like70//   `optional` and `function` are considered one-element containers for the purposes of this check.71//72// - `_LIBCPP_ASSERT_NON_NULL` -- checks that the pointer being dereferenced is not null. On most modern platforms zero73//   address does not refer to an actual location in memory, so a null pointer dereference would not compromize the74//   memory security of a program (however, it is still undefined behavior that can result in strange errors due to75//   compiler optimizations).76//77// - `_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES` -- for functions that take several ranges as arguments, checks that the78//   given ranges do not overlap.79//80// - `_LIBCPP_ASSERT_VALID_DEALLOCATION` -- checks that an attempt to deallocate memory is valid (e.g. the given object81//   was allocated by the given allocator). Violating this category typically results in a memory leak.82//83// - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL` -- checks that a call to an external API doesn't fail in84//   an unexpected manner. This includes triggering documented cases of undefined behavior in an external library (like85//   attempting to unlock an unlocked mutex in pthreads). Any API external to the library falls under this category86//   (from system calls to compiler intrinsics). We generally don't expect these failures to compromize memory safety or87//   otherwise create an immediate security issue.88//89// - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure90//   the containers have compatible allocators.91//92// - `_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN` -- checks that the given argument is within the domain of valid arguments93//   for the function. Violating this typically produces an incorrect result (e.g. the clamp algorithm returns the94//   original value without clamping it due to incorrect functors) or puts an object into an invalid state (e.g.95//   a string view where only a subset of elements is possible to access). This category is for assertions violating96//   which doesn't cause any immediate issues in the library -- whatever the consequences are, they will happen in the97//   user code.98//99// - `_LIBCPP_ASSERT_PEDANTIC` -- checks prerequisites which are imposed by the Standard, but violating which happens to100//   be benign in our implementation.101//102// - `_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT` -- checks that the given argument satisfies the semantic requirements imposed103//   by the Standard. Typically, there is no simple way to completely prove that a semantic requirement is satisfied;104//   thus, this would often be a heuristic check and it might be quite expensive.105//106// - `_LIBCPP_ASSERT_INTERNAL` -- checks that internal invariants of the library hold. These assertions don't depend on107//   user input.108//109// - `_LIBCPP_ASSERT_UNCATEGORIZED` -- for assertions that haven't been properly classified yet.110 111// clang-format off112#  define _LIBCPP_HARDENING_MODE_NONE      (1 << 1)113#  define _LIBCPP_HARDENING_MODE_FAST      (1 << 2)114#  define _LIBCPP_HARDENING_MODE_EXTENSIVE (1 << 4) // Deliberately not ordered.115#  define _LIBCPP_HARDENING_MODE_DEBUG     (1 << 3)116// clang-format on117 118#ifndef _LIBCPP_HARDENING_MODE119 120#  ifndef _LIBCPP_HARDENING_MODE_DEFAULT121#    error _LIBCPP_HARDENING_MODE_DEFAULT is not defined. This definition should be set at configuration time in the \122`__config_site` header, please make sure your installation of libc++ is not broken.123#  endif124 125#  define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEFAULT126#endif127 128#if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_NONE && _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_FAST &&  \129    _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_EXTENSIVE &&                                                      \130    _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG131#  error _LIBCPP_HARDENING_MODE must be set to one of the following values: \132_LIBCPP_HARDENING_MODE_NONE, \133_LIBCPP_HARDENING_MODE_FAST, \134_LIBCPP_HARDENING_MODE_EXTENSIVE, \135_LIBCPP_HARDENING_MODE_DEBUG136#endif137 138// The library provides the macro `_LIBCPP_ASSERTION_SEMANTIC` for configuring the assertion semantic used by hardening;139// it can be set to one of the following values:140//141// - `_LIBCPP_ASSERTION_SEMANTIC_IGNORE`;142// - `_LIBCPP_ASSERTION_SEMANTIC_OBSERVE`;143// - `_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE`;144// - `_LIBCPP_ASSERTION_SEMANTIC_ENFORCE`.145//146// libc++ assertion semantics generally mirror the evaluation semantics of C++26 Contracts:147// - `ignore` evaluates the assertion but doesn't do anything if it fails (note that it differs from the Contracts148//   `ignore` semantic which wouldn't evaluate the assertion at all);149// - `observe` logs an error (indicating, if possible, that the error is fatal) and continues execution;150// - `quick-enforce` terminates the program as fast as possible (via trapping);151// - `enforce` logs an error and then terminates the program.152//153// Additionally, a special `hardening-dependent` value selects the assertion semantic based on the hardening mode in154// effect: the production-capable modes (`fast` and `extensive`) map to `quick_enforce` and the `debug` mode maps to155// `enforce`. The `hardening-dependent` semantic cannot be selected explicitly, it is only used when no assertion156// semantic is provided by the user _and_ the library's default semantic is configured to be dependent on hardening.157//158// Notes:159// - Continuing execution after a hardening check fails results in undefined behavior; the `observe` semantic is meant160//   to make adopting hardening easier but should not be used outside of this scenario;161// - C++26 wording for Library Hardening precludes a conforming Hardened implementation from using the Contracts162//   `ignore` semantic when evaluating hardened preconditions in the Library. Libc++ allows using this semantic for163//   hardened preconditions, however, be aware that using `ignore` does not produce a conforming "Hardened"164//   implementation, unlike the other semantics above.165// clang-format off166#  define _LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT (1 << 1)167#  define _LIBCPP_ASSERTION_SEMANTIC_IGNORE              (1 << 2)168#  define _LIBCPP_ASSERTION_SEMANTIC_OBSERVE             (1 << 3)169#  define _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE       (1 << 4)170#  define _LIBCPP_ASSERTION_SEMANTIC_ENFORCE             (1 << 5)171// clang-format on172 173// If the user attempts to configure the assertion semantic, check that it is allowed in the current environment.174#if defined(_LIBCPP_ASSERTION_SEMANTIC)175#  if !_LIBCPP_HAS_EXPERIMENTAL_LIBRARY176#    error "Assertion semantics are an experimental feature."177#  endif178#  if defined(_LIBCPP_CXX03_LANG)179#    error "Assertion semantics are not available in the C++03 mode."180#  endif181#endif // defined(_LIBCPP_ASSERTION_SEMANTIC)182 183// User-provided semantic takes top priority -- don't override if set.184#ifndef _LIBCPP_ASSERTION_SEMANTIC185 186#  ifndef _LIBCPP_ASSERTION_SEMANTIC_DEFAULT187#    error _LIBCPP_ASSERTION_SEMANTIC_DEFAULT is not defined. This definition should be set at configuration time in \188the `__config_site` header, please make sure your installation of libc++ is not broken.189#  endif190 191#  if _LIBCPP_ASSERTION_SEMANTIC_DEFAULT != _LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT192#    define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_DEFAULT193#  else194#    if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG195#      define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_ENFORCE196#    else197#      define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE198#    endif199#  endif // _LIBCPP_ASSERTION_SEMANTIC_DEFAULT != _LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT200 201#endif // #ifndef _LIBCPP_ASSERTION_SEMANTIC202 203// Finally, validate the selected semantic (in case the user tries setting it to an incorrect value):204#if _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_IGNORE &&                                                 \205    _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_OBSERVE &&                                                \206    _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE &&                                          \207    _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_ENFORCE208#  error _LIBCPP_ASSERTION_SEMANTIC must be set to one of the following values: \209_LIBCPP_ASSERTION_SEMANTIC_IGNORE, \210_LIBCPP_ASSERTION_SEMANTIC_OBSERVE, \211_LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE, \212_LIBCPP_ASSERTION_SEMANTIC_ENFORCE213#endif214 215#endif // _LIBCPP___CONFIGURATION_HARDENING_H216