blob: 097ad4b73b1262f706570c4f16d020a03911e5a9 [file] [log] [blame]
Konstantin Varlamov86070a82024-06-06 23:35:331.. _hardening:
Mark de Wever30d68062024-01-21 18:48:332
Konstantin Varlamovb85e1862023-09-12 19:01:363===============
4Hardening Modes
5===============
varconstd1367ca2023-07-12 17:12:516
7.. contents::
8 :local:
9
Konstantin Varlamovb85e1862023-09-12 19:01:3610.. _using-hardening-modes:
varconstd1367ca2023-07-12 17:12:5111
Konstantin Varlamovb85e1862023-09-12 19:01:3612Using hardening modes
13=====================
varconstd1367ca2023-07-12 17:12:5114
Konstantin Varlamov64d413e2023-11-08 19:10:0015libc++ provides several hardening modes, where each mode enables a set of
16assertions that prevent undefined behavior caused by violating preconditions of
17the standard library. Different hardening modes make different trade-offs
18between the amount of checking and runtime performance. The available hardening
19modes are:
Konstantin Varlamovb85e1862023-09-12 19:01:3620
Christopher Di Bella64454da2023-12-06 22:23:3521- **Unchecked mode/none**, which disables all hardening checks.
22- **Fast mode**, which contains a set of security-critical checks that can be
23 done with relatively little overhead in constant time and are intended to be
24 used in production. We recommend most projects adopt this.
25- **Extensive mode**, which contains all the checks from fast mode and some
26 additional checks for undefined behavior that incur relatively little overhead
27 but aren't security-critical. Production builds requiring a broader set of
28 checks than fast mode should consider enabling extensive mode. The additional
29 rigour impacts performance more than fast mode: we recommend benchmarking to
30 determine if that is acceptable for your program.
31- **Debug mode**, which enables all the available checks in the library,
Konstantin Varlamov86070a82024-06-06 23:35:3332 including heuristic checks that might have significant performance overhead as
33 well as internal library assertions. This mode should be used in
34 non-production environments (such as test suites, CI, or local development).
35 We don’t commit to a particular level of performance in this mode and it’s
36 *not* intended to be used in production.
Konstantin Varlamov64d413e2023-11-08 19:10:0037
Christopher Di Bella64454da2023-12-06 22:23:3538.. note::
Konstantin Varlamovb85e1862023-09-12 19:01:3639
Christopher Di Bella64454da2023-12-06 22:23:3540 Enabling hardening has no impact on the ABI.
varconstd1367ca2023-07-12 17:12:5141
Christopher Di Bella64454da2023-12-06 22:23:3542Notes for users
43---------------
varconstd1367ca2023-07-12 17:12:5144
Christopher Di Bella64454da2023-12-06 22:23:3545As a libc++ user, consult with your vendor to determine the level of hardening
46enabled by default.
varconstd1367ca2023-07-12 17:12:5147
Christopher Di Bella64454da2023-12-06 22:23:3548Users wishing for a different hardening level to their vendor default are able
49to control the level by passing **one** of the following options to the compiler:
Konstantin Varlamov64d413e2023-11-08 19:10:0050
Christopher Di Bella64454da2023-12-06 22:23:3551- ``-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE``
52- ``-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST``
53- ``-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE``
54- ``-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG``
Konstantin Varlamov64d413e2023-11-08 19:10:0055
Christopher Di Bella64454da2023-12-06 22:23:3556.. warning::
Konstantin Varlamov64d413e2023-11-08 19:10:0057
Christopher Di Bella64454da2023-12-06 22:23:3558 The exact numeric values of these macros are unspecified and users should not
59 rely on them (e.g. expect the values to be sorted in any way).
varconstf0dfe682023-07-14 23:58:1560
Christopher Di Bella64454da2023-12-06 22:23:3561.. warning::
62
63 If you would prefer to override the hardening level on a per-translation-unit
64 basis, you must do so **before** including any headers to avoid `ODR issues`_.
65
66.. _`ODR issues`: https://en.cppreference.com/w/cpp/language/definition#:~:text=is%20ill%2Dformed.-,One%20Definition%20Rule,-Only%20one%20definition
67
68.. note::
69
70 Since the static and shared library components of libc++ are built by the
71 vendor, setting this macro will have no impact on the hardening mode for the
72 pre-built components. Most libc++ code is header-based, so a user-provided
73 value for ``_LIBCPP_HARDENING_MODE`` will be mostly respected.
74
75Notes for vendors
76-----------------
77
Konstantin Varlamov86070a82024-06-06 23:35:3378Vendors can set the default hardening mode by providing
79``LIBCXX_HARDENING_MODE`` as a configuration option, with the possible values of
80``none``, ``fast``, ``extensive`` and ``debug``. The default value is ``none``
81which doesn't enable any hardening checks (this mode is sometimes called the
82``unchecked`` mode).
Christopher Di Bella64454da2023-12-06 22:23:3583
84This option controls both the hardening mode that the precompiled library is
85built with and the default hardening mode that users will build with. If set to
86``none``, the precompiled library will not contain any assertions, and user code
87will default to building without assertions.
varconstd1367ca2023-07-12 17:12:5188
Konstantin Varlamov86070a82024-06-06 23:35:3389Vendors can also override the way the program is terminated when an assertion
90fails by :ref:`providing a custom header <override-assertion-handler>`.
Christopher Di Bella64454da2023-12-06 22:23:3591
Konstantin Varlamov86070a82024-06-06 23:35:3392Assertion categories
93====================
94
95Inside the library, individual assertions are grouped into different
96*categories*. Each hardening mode enables a different set of assertion
97categories; categories provide an additional layer of abstraction that makes it
98easier to reason about the high-level semantics of a hardening mode.
99
100.. note::
101
102 Users are not intended to interact with these categories directly -- the
103 categories are considered internal to the library and subject to change.
104
105- ``valid-element-access`` -- checks that any attempts to access a container
106 element, whether through the container object or through an iterator, are
107 valid and do not attempt to go out of bounds or otherwise access
108 a non-existent element. This also includes operations that set up an imminent
109 invalid access (e.g. incrementing an end iterator). For iterator checks to
110 work, bounded iterators must be enabled in the ABI. Types like
111 ``std::optional`` and ``std::function`` are considered containers (with at
112 most one element) for the purposes of this check.
113
114- ``valid-input-range`` -- checks that ranges (whether expressed as an iterator
115 pair, an iterator and a sentinel, an iterator and a count, or
116 a ``std::range``) given as input to library functions are valid:
117 - the sentinel is reachable from the begin iterator;
118 - TODO(hardening): both iterators refer to the same container.
119
120 ("input" here refers to "an input given to an algorithm", not to an iterator
121 category)
122
123 Violating assertions in this category leads to an out-of-bounds access.
124
125- ``non-null`` -- checks that the pointer being dereferenced is not null. On
126 most modern platforms, the zero address does not refer to an actual location
127 in memory, so a null pointer dereference would not compromise the memory
128 security of a program (however, it is still undefined behavior that can result
129 in strange errors due to compiler optimizations).
130
131- ``non-overlapping-ranges`` -- for functions that take several ranges as
132 arguments, checks that those ranges do not overlap.
133
134- ``valid-deallocation`` -- checks that an attempt to deallocate memory is valid
135 (e.g. the given object was allocated by the given allocator). Violating this
136 category typically results in a memory leak.
137
138- ``valid-external-api-call`` -- checks that a call to an external API doesn't
139 fail in an unexpected manner. This includes triggering documented cases of
140 undefined behavior in an external library (like attempting to unlock an
141 unlocked mutex in pthreads). Any API external to the library falls under this
142 category (from system calls to compiler intrinsics). We generally don't expect
143 these failures to compromise memory safety or otherwise create an immediate
144 security issue.
145
146- ``compatible-allocator`` -- checks any operations that exchange nodes between
147 containers to make sure the containers have compatible allocators.
148
149- ``argument-within-domain`` -- checks that the given argument is within the
150 domain of valid arguments for the function. Violating this typically produces
151 an incorrect result (e.g. ``std::clamp`` returns the original value without
152 clamping it due to incorrect functors) or puts an object into an invalid state
153 (e.g. a string view where only a subset of elements is accessible). This
154 category is for assertions violating which doesn't cause any immediate issues
155 in the library -- whatever the consequences are, they will happen in the user
156 code.
157
158- ``pedantic`` -- checks preconditions that are imposed by the Standard, but
159 violating which happens to be benign in libc++.
160
161- ``semantic-requirement`` -- checks that the given argument satisfies the
162 semantic requirements imposed by the Standard. Typically, there is no simple
163 way to completely prove that a semantic requirement is satisfied; thus, this
164 would often be a heuristic check and it might be quite expensive.
165
166- ``internal`` -- checks that internal invariants of the library hold. These
167 assertions don't depend on user input.
168
169- ``uncategorized`` -- for assertions that haven't been properly classified yet.
170 This category is an escape hatch used for some existing assertions in the
171 library; all new code should have its assertions properly classified.
172
173Mapping between the hardening modes and the assertion categories
174================================================================
175
176.. list-table::
177 :header-rows: 1
178 :widths: auto
179
180 * - Category name
181 - ``fast``
182 - ``extensive``
183 - ``debug``
184 * - ``valid-element-access``
185 - ✅
186 - ✅
187 - ✅
188 * - ``valid-input-range``
189 - ✅
190 - ✅
191 - ✅
192 * - ``non-null``
193 - ❌
194 - ✅
195 - ✅
196 * - ``non-overlapping-ranges``
197 - ❌
198 - ✅
199 - ✅
200 * - ``valid-deallocation``
201 - ❌
202 - ✅
203 - ✅
204 * - ``valid-external-api-call``
205 - ❌
206 - ✅
207 - ✅
208 * - ``compatible-allocator``
209 - ❌
210 - ✅
211 - ✅
212 * - ``argument-within-domain``
213 - ❌
214 - ✅
215 - ✅
216 * - ``pedantic``
217 - ❌
218 - ✅
219 - ✅
220 * - ``semantic-requirement``
221 - ❌
222 - ❌
223 - ✅
224 * - ``internal``
225 - ❌
226 - ❌
227 - ✅
228 * - ``uncategorized``
229 - ❌
230 - ✅
231 - ✅
232
233.. note::
234
235 At the moment, each subsequent hardening mode is a strict superset of the
236 previous one (in other words, each subsequent mode only enables additional
237 assertion categories without disabling any), but this won't necessarily be
238 true for any hardening modes that might be added in the future.
239
240.. note::
241
242 The categories enabled by each mode are subject to change and users should not
243 rely on the precise assertions enabled by a mode at a given point in time.
244 However, the library does guarantee to keep the hardening modes stable and
245 to fulfill the semantics documented here.
246
247Hardening assertion failure
248===========================
249
250In production modes (``fast`` and ``extensive``), a hardening assertion failure
Louis Dionnedbfb29f2025-02-12 22:57:37251immediately ``_traps <https://clang.llvm.org/docs/LanguageExtensions.html#builtin-verbose-trap>``
Konstantin Varlamov86070a82024-06-06 23:35:33252the program. This is the safest approach that also minimizes the code size
253penalty as the failure handler maps to a single instruction. The downside is
254that the failure provides no additional details other than the stack trace
255(which might also be affected by optimizations).
256
Konstantin Varlamov86070a82024-06-06 23:35:33257In the ``debug`` mode, an assertion failure terminates the program in an
258unspecified manner and also outputs the associated error message to the error
259output. This is less secure and increases the size of the binary (among other
260things, it has to store the error message strings) but makes the failure easier
261to debug. It also allows testing the error messages in our test suite.
262
263.. _override-assertion-handler:
264
265Overriding the assertion failure handler
266----------------------------------------
267
268Vendors can override the default assertion handler mechanism by following these
269steps:
270
271- create a header file that provides a definition of a macro called
272 ``_LIBCPP_ASSERTION_HANDLER``. The macro will be invoked when a hardening
273 assertion fails, with a single parameter containing a null-terminated string
274 with the error message.
275- when configuring the library, provide the path to custom header (relative to
276 the root of the repository) via the CMake variable
277 ``LIBCXX_ASSERTION_HANDLER_FILE``.
278
279Note that almost all libc++ headers include the assertion handler header which
280means it should not include anything non-trivial from the standard library to
281avoid creating circular dependencies.
282
283There is no existing mechanism for users to override the assertion handler
284because the ability to do the override other than at configure-time carries an
285unavoidable code size penalty that would otherwise be imposed on all users,
286whether they require such customization or not. Instead, we let vendors decide
287what's right on their platform for their users -- a vendor who wishes to provide
288this capability is free to do so, e.g. by declaring the assertion handler as an
289overridable function.
290
291ABI
292===
293
294Setting a hardening mode does **not** affect the ABI. Each mode uses the subset
295of checks available in the current ABI configuration which is determined by the
296platform.
297
298It is important to stress that whether a particular check is enabled depends on
299the combination of the selected hardening mode and the hardening-related ABI
300options. Some checks require changing the ABI from the "default" to store
301additional information in the library classes -- e.g. checking whether an
302iterator is valid upon dereference generally requires storing data about bounds
303inside the iterator object. Using ``std::span`` as an example, setting the
304hardening mode to ``fast`` will always enable the ``valid-element-access``
305checks when accessing elements via a ``std::span`` object, but whether
306dereferencing a ``std::span`` iterator does the equivalent check depends on the
307ABI configuration.
308
309ABI options
310-----------
311
Louis Dionne18553332025-01-07 21:47:39312Vendors can use some ABI options at CMake configuration time (when building libc++
313itself) to enable additional hardening checks. This is done by passing these
314macros as ``-DLIBCXX_ABI_DEFINES="_LIBCPP_ABI_FOO;_LIBCPP_ABI_BAR;etc"`` at
315CMake configuration time. The available options are:
Konstantin Varlamov86070a82024-06-06 23:35:33316
317- ``_LIBCPP_ABI_BOUNDED_ITERATORS`` -- changes the iterator type of select
318 containers (see below) to a bounded iterator that keeps track of whether it's
319 within the bounds of the original container and asserts valid bounds on every
320 dereference.
321
322 ABI impact: changes the iterator type of the relevant containers.
323
324 Supported containers:
325
326 - ``span``;
327 - ``string_view``.
328
David Benjaminbcf9fb92024-07-23 05:44:25329- ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING`` -- changes the iterator type of
330 ``basic_string`` to a bounded iterator that keeps track of whether it's within
331 the bounds of the original container and asserts it on every dereference and
332 when performing iterator arithmetics.
333
334 ABI impact: changes the iterator type of ``basic_string`` and its
335 specializations, such as ``string`` and ``wstring``.
336
337- ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR`` -- changes the iterator type of
338 ``vector`` to a bounded iterator that keeps track of whether it's within the
339 bounds of the original container and asserts it on every dereference and when
340 performing iterator arithmetics. Note: this doesn't yet affect
341 ``vector<bool>``.
342
343 ABI impact: changes the iterator type of ``vector`` (except ``vector<bool>``).
344
Louis Dionne96121752025-01-07 21:47:06345- ``_LIBCPP_ABI_BOUNDED_UNIQUE_PTR`` -- tracks the bounds of the array stored inside
Louis Dionnedfe737f2024-11-04 15:45:12346 a ``std::unique_ptr<T[]>``, allowing it to trap when accessed out-of-bounds. This
347 requires the ``std::unique_ptr`` to be created using an API like ``std::make_unique``
348 or ``std::make_unique_for_overwrite``, otherwise the bounds information is not available
349 to the library.
350
351 ABI impact: changes the layout of ``std::unique_ptr<T[]>``, and the representation
352 of a few library types that use ``std::unique_ptr`` internally, such as
353 the unordered containers.
354
Louis Dionne427a5cf2024-11-07 14:23:21355- ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY`` -- changes the iterator type of ``std::array`` to a
356 bounded iterator that keeps track of whether it's within the bounds of the container and asserts it
357 on every dereference and when performing iterator arithmetic.
358
359 ABI impact: changes the iterator type of ``std::array``, its size and its layout.
360
Konstantin Varlamov86070a82024-06-06 23:35:33361ABI tags
362--------
363
364We use ABI tags to allow translation units built with different hardening modes
365to interact with each other without causing ODR violations. Knowing how
366hardening modes are encoded into the ABI tags might be useful to examine
367a binary and determine whether it was built with hardening enabled.
368
369.. warning::
370 We don't commit to the encoding scheme used by the ABI tags being stable
371 between different releases of libc++. The tags themselves are never stable, by
372 design -- new releases increase the version number. The following describes
373 the state of the latest release and is for informational purposes only.
374
375The first character of an ABI tag encodes the hardening mode:
376
377- ``f`` -- [f]ast mode;
378- ``s`` -- extensive ("[s]afe") mode;
379- ``d`` -- [d]ebug mode;
380- ``n`` -- [n]one mode.
381
382Hardened containers status
383==========================
384
385.. list-table::
386 :header-rows: 1
387 :widths: auto
388
389 * - Name
390 - Member functions
391 - Iterators (ABI-dependent)
392 * - ``span``
393 - ✅
394 - ✅
395 * - ``string_view``
396 - ✅
397 - ✅
398 * - ``array``
399 - ✅
400 - ❌
401 * - ``vector``
402 - ✅
David Benjaminbcf9fb92024-07-23 05:44:25403 - ✅ (see note)
Konstantin Varlamov86070a82024-06-06 23:35:33404 * - ``string``
405 - ✅
David Benjaminbcf9fb92024-07-23 05:44:25406 - ✅ (see note)
Konstantin Varlamov86070a82024-06-06 23:35:33407 * - ``list``
408 - ✅
409 - ❌
410 * - ``forward_list``
Konstantin Varlamovbda7c9a2025-01-06 20:50:00411 - ✅
Konstantin Varlamov86070a82024-06-06 23:35:33412 - ❌
413 * - ``deque``
414 - ✅
415 - ❌
416 * - ``map``
417 - ❌
418 - ❌
419 * - ``set``
420 - ❌
421 - ❌
422 * - ``multimap``
423 - ❌
424 - ❌
425 * - ``multiset``
426 - ❌
427 - ❌
428 * - ``unordered_map``
429 - Partial
430 - Partial
431 * - ``unordered_set``
432 - Partial
433 - Partial
434 * - ``unordered_multimap``
435 - Partial
436 - Partial
437 * - ``unordered_multiset``
438 - Partial
439 - Partial
440 * - ``mdspan``
441 - ✅
442 - ❌
443 * - ``optional``
444 - ✅
445 - N/A
446 * - ``function``
447 - ❌
448 - N/A
449 * - ``variant``
450 - N/A
451 - N/A
452 * - ``any``
453 - N/A
454 - N/A
455 * - ``expected``
456 - ✅
457 - N/A
458 * - ``valarray``
459 - Partial
460 - N/A
461 * - ``bitset``
Konstantin Varlamovac1d5602024-12-25 02:22:18462 - ✅
Konstantin Varlamov86070a82024-06-06 23:35:33463 - N/A
464
David Benjaminbcf9fb92024-07-23 05:44:25465Note: for ``vector`` and ``string``, the iterator does not check for
466invalidation (accesses made via an invalidated iterator still lead to undefined
467behavior)
468
469Note: ``vector<bool>`` iterator is not currently hardened.
470
Konstantin Varlamov86070a82024-06-06 23:35:33471Testing
472=======
473
474Please see :ref:`Testing documentation <testing-hardening-assertions>`.
475
476Further reading
477===============
478
David Spickett1e6d5de2024-07-01 07:06:30479- `Hardening RFC <https://discourse.llvm.org/t/rfc-hardening-in-libc/73925>`_:
Konstantin Varlamov86070a82024-06-06 23:35:33480 contains some of the design rationale.