rust-lang/rust

Side effect handling in specialized zip implementation causes buffer overflow

Closed this issue · 2 comments

Qwaz commented

} else if A::may_have_side_effect() && self.index < self.a.size() {
let i = self.index;
self.index += 1;
// match the base implementation's potential side effects
// SAFETY: we just checked that `i` < `self.a.len()`
unsafe {
self.a.__iterator_get_unchecked(i);
}
None

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len - self.index;
(len, Some(len))
}

self.index can be set to a value greater than self.len in this branch. This causes integer overflow in size_hint() and lead to a buffer overflow.

Playground Link that demonstrates segfault with safe Rust code.

Qwaz commented

For the context, this causes a buffer overflow by violating the safety requirement of TrustedRandomAccess trait.

/// An iterator whose items are random-accessible efficiently
///
/// # Safety
///
/// The iterator's `size_hint` must be exact and cheap to call.
///
/// `size` may not be overridden.
///
/// `<Self as Iterator>::__iterator_get_unchecked` must be safe to call
/// provided the following conditions are met.
///
/// 1. `0 <= idx` and `idx < self.size()`.
/// 2. If `self: !Clone`, then `get_unchecked` is never called with the same
/// index on `self` more than once.
/// 3. After `self.get_unchecked(idx)` has been called then `next_back` will
/// only be called at most `self.size() - idx - 1` times.
/// 4. After `get_unchecked` is called, then only the following methods will be
/// called on `self`:
/// * `std::clone::Clone::clone()`
/// * `std::iter::Iterator::size_hint()`
/// * `std::iter::Iterator::next_back()`
/// * `std::iter::Iterator::__iterator_get_unchecked()`
/// * `std::iter::TrustedRandomAccess::size()`

Assigning P-critical as part of the WG-prioritization discussion on Zulip.