-
Notifications
You must be signed in to change notification settings - Fork 1.5k
STL Hardening
- Review:
- P3471R1 Standard Library Hardening
- libc++'s hardening modes
- Existing CDL checks (below)
- Design a consistent policy for what should be hardened
- Design how this will be controlled, and its defaults
- Opt-in means virtually no users will benefit, but has the least performance requirements
- Implied-by-
/sdl
means some users will benefit automatically - Opt-out means all users will benefit automatically, but has the most stringent performance requirements
- Design a termination mechanism:
- Is CDL's termination mechanism ideal?
- Should violations terminate the program differently?
- Should it be customizable?
- With a design, make the code changes (should be the easy part as 90% of the work is already present)
- Optimizations to mitigate perf impact, once we have examples of where the perf impact will be
- Loop in the compiler back-end
- Additional library changes may also be necessary
-
vector
pop_back
-
operator[]
- ✅ P3471R1's proposed wording
-
front
- ✅ P3471R1's design
-
back
- ✅ P3471R1's design
-
vector<bool>
-
operator[]
- ✅ P3471R1's proposed wording
-
front
- ✅ P3471R1's design
-
back
- ✅ P3471R1's design
-
-
deque
-
operator[]
- ✅ P3471R1's proposed wording
-
front
- ✅ P3471R1's design
-
back
- ✅ P3471R1's design
-
-
list
-
front
- ✅ P3471R1's design
-
back
- ✅ P3471R1's design
pop_front
pop_back
-
-
forward_list
-
front
- ✅ P3471R1's design
-
-
array
-
operator[]
- ✅ P3471R1's proposed wording
-
-
array<T, 0>
-
operator[]
- ✅ P3471R1's proposed wording
-
front
- ✅ P3471R1's design
-
back
- ✅ P3471R1's design
-
-
basic_string
-
operator[]
- ✅ P3471R1's proposed wording
-
front
- ✅ P3471R1's design
-
back
- ✅ P3471R1's design
resize_and_overwrite
-
-
basic_string_view
basic_string_view(const_pointer, size_type)
-
operator[]
- ✅ P3471R1's proposed wording
-
front
- ✅ P3471R1's design
-
back
- ✅ P3471R1's design
remove_prefix
remove_suffix
-
span
span(It, size_type)
span(It, End)
span(R&&)
span(const span<OtherElementType, OtherExtent>&)
first
last
subspan
size_bytes
-
operator[]
- ✅ P3471R1's proposed wording
-
front
- ✅ P3471R1's design
-
back
- ✅ P3471R1's design
-
mdspan
static_extent
mdspan(const mdspan<OtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessor>&)
-
operator[]
- ✅ P3471R1's design
size
-
optional
-
operator*
- ✅ P3471R1's proposed wording
-
operator->
- ✅ P3471R1's proposed wording
-
-
expected<T, E>
-
operator->
- ✅ P3471R1's proposed wording
-
operator*
- ✅ P3471R1's proposed wording
error
-
-
expected<void, E>
operator*
error
-
ranges::view_interface
front
back
operator[]
-
generator::iterator
operator*
operator++
-
generator
begin
-
iota_view
iota_view(W)
iota_view(type_identity_t<W>, type_identity_t<Bound>)
iota_view(Iter, Sent)
-
repeat_view::iterator
operator++
operator--
operator+=
operator-=
-
repeat_view
repeat_view(const T&, Bound)
repeat_view(T&&, Bound)
repeat_view(piecewise_construct_t, tuple<TArgs...>, tuple<BoundArgs...>)
-
filter_view
pred
begin
-
take_view
take_view(V, range_difference_t<V>)
-
take_while_view
pred
end
-
drop_view
drop_view(V, range_difference_t<V>)
-
drop_while_view
pred
begin
-
views::counted
operator()
-
chunk_view
chunk_view(V, range_difference_t<V>)
-
slide_view
slide_view(V, range_difference_t<V>)
-
chunk_by_view
pred
begin
-
stride_view
stride_view(V, range_difference_t<V>)
-
cartesian_product_view
size
-
valarray
operator*=
operator/=
operator%=
operator+=
operator-=
operator^=
operator|=
operator&=
operator<<=
operator>>=
operator[]
operator*
operator/
operator%
operator+
operator-
operator^
operator&
operator|
operator<<
operator>>
operator&&
operator||
operator==
operator!=
operator<
operator>
operator<=
operator>=
-
extents
extents(VARIOUS ARGS)
static_extent
extent
-
layout_left::mapping
mapping(VARIOUS ARGS)
stride
operator()
-
layout_right::mapping
mapping(VARIOUS ARGS)
stride
operator()
-
layout_stride::mapping
mapping(VARIOUS ARGS)
stride
operator()
-
condition_variable
wait_until(unique_lock&, const time_point&)
-
VSO-1556181
gsl::span
CQ deficiency: predicate inference weakness #1 -
VSO-1556194
gsl::span
CQ deficiency: useless multibyte copy -
VSO-1556195
gsl::span
CQ deficiency: predicate inference weakness #2
- #5090 "Implement a hardened mode"
P3471R1 Standard Library Hardening
Stephan's highlights:
Hardening needs to be lightweight enough to be used in production environments. In our experience, a debug-only approach is not sufficient to really move the needle security-wise. Thus, the goal is to identify the minimal set of checks that would deliver the most value to users while requiring minimal overhead, with a particular focus on memory safety as a major source of security vulnerabilities. Checking all preconditions in the library is an explicit non-goal, and would be impossible for many semantic requirements anyway.
To reiterate the last point, an important design principle is that hardening needs to be lightweight enough for production use by a wide variety of real-world programs. In our experience in libc++, a small set of checks that is widely used delivers far more value than a more extensive set of checks that is only enabled by select few users. Thankfully, many of the most valuable checks, such as checking for out-of-bounds access in standard containers, also happen to be relatively cheap.
In the initial proposal, we decide to focus on hardened preconditions that prevent out-of-bounds memory access, i.e., compromise the memory safety of the program. These are some of the most valuable for the user since they help prevent potential security vulnerabilities; many of them are also relatively cheap to implement. More hardened preconditions can potentially be added in the future, but the intent is for their number to be limited to keep hardening viable for production use. Specifically, the proposal is to add hardened preconditions to:
- Accessors of sequence containers,
std::span
,std::mdspan
,std::string
,std::string_view
and other similar classes that might attempt to access non-existent elements (e.g.back()
on an empty container oroperator[]
with an invalid index).- Modifiers of sequence containers and string classes that assume the container to be non-empty (e.g.
pop_back()
).- Accessors of
optional
andexpected
that expect the object to be non-empty.
In our experience, hardening all of these operations is trivial to implement and provides significant security value.