danakj | 4e625fb | 2024-03-06 20:47:46 | [diff] [blame] | 1 | # Preventing OOB through Unsafe Buffers errors (aka Spanification) |
| 2 | |
| 3 | Out-of-bounds (OOB) security bugs commonly happen through pointers |
| 4 | which have no bounds checks associated with them. We prevent such |
| 5 | bugs by always using containers. |
| 6 | |
| 7 | Most pointers are unowned references into an array (or vector) |
| 8 | and the most appropriate replacement for the pointer is |
danakj | e7db1e3f3 | 2024-04-16 20:43:24 | [diff] [blame^] | 9 | [`base::span`](../base/containers/span.h). |
danakj | 4e625fb | 2024-03-06 20:47:46 | [diff] [blame] | 10 | |
danakj | e7db1e3f3 | 2024-04-16 20:43:24 | [diff] [blame^] | 11 | Entire directories have been opted out of unsafe pointer usage |
| 12 | warnings through the |
danakj | 4e625fb | 2024-03-06 20:47:46 | [diff] [blame] | 13 | [`//build/config/unsafe_buffers_paths.txt`](../build/config/unsafe_buffers_paths.txt) |
danakj | e7db1e3f3 | 2024-04-16 20:43:24 | [diff] [blame^] | 14 | file. As we convert unsafe pointers to safe constructs like |
| 15 | `base::span`, `base::HeapArray` and `std::vector`, we will |
| 16 | remove paths from that file to enable the warnings across the |
| 17 | codebase. |
| 18 | |
| 19 | ## Controlling warnings for a single file |
| 20 | |
| 21 | Warnings can be disabled for a single (C++ source or header) file by |
| 22 | writing `#pragma allow_unsafe_buffers` anywhere in the file. This can |
| 23 | be used to mark future work to drive down over time. |
| 24 | |
| 25 | Warnings can be enabled for a single (C++ source or header) file by |
| 26 | writing `#pragma check_unsafe_buffers` anywhere in the file. It's recommended |
| 27 | to place the pragma directly below the copyright and before any `#include` |
| 28 | directives. This can be used to work through files in a directory |
| 29 | incrementally. Though it's preferable to instead remove the whole directory |
| 30 | from opt-out in the |
| 31 | [`//build/config/unsafe_buffers_paths.txt`](../build/config/unsafe_buffers_paths.txt) |
| 32 | file, and temporarily mark any files with `#pragma allow_unsafe_buffers` |
| 33 | that need it. |
danakj | 4e625fb | 2024-03-06 20:47:46 | [diff] [blame] | 34 | |
| 35 | # Functions with array pointer parameters |
| 36 | |
| 37 | Functions that receive a pointer into an array may read |
| 38 | or write out of bounds of the pointer if given a pointer that |
| 39 | is incorrectly sized. Such functions should be marked with the |
danakj | e7db1e3f3 | 2024-04-16 20:43:24 | [diff] [blame^] | 40 | `UNSAFE_BUFFER_USAGE` attribute macro. |
danakj | 4e625fb | 2024-03-06 20:47:46 | [diff] [blame] | 41 | |
| 42 | The same is true for functions that accept an iterator instead |
danakj | e7db1e3f3 | 2024-04-16 20:43:24 | [diff] [blame^] | 43 | of a range type. Some examples of each are `memcpy()` and |
| 44 | `std::copy()`. |
danakj | 4e625fb | 2024-03-06 20:47:46 | [diff] [blame] | 45 | |
| 46 | Calling such functions is unsafe and should generally be avoided. |
| 47 | Instead, replace such functions with an API built on base::span |
| 48 | or other range types which prevents any chance of OOB memory |
| 49 | access. For instance, replace `memcpy()`, `std::copy()` and |
| 50 | `std::ranges::copy()` with `base::span::copy_from()`. And |
| 51 | replace `memset()` with `std::ranges::fill()`. |
| 52 | |
| 53 | # Writing unsafe data structures with pointers |
| 54 | |
| 55 | TODO: Write about `UNSAFE_BUFFERS()` for rare exceptions where |
| 56 | the correctness of pointer bounds can be fully explained and |
danakj | e7db1e3f3 | 2024-04-16 20:43:24 | [diff] [blame^] | 57 | encapsulated, such as within a data structure or when working |
| 58 | with Operating System and C-like APIs. |