Skip to content

[BUG] Unsoundness: try_parse_{4,8}digits appear to advance iterators out of bounds #101

@Ralith

Description

@Ralith

BytesIter::read is documented as advancing the iterator's state:

/// Try to read a value of a different type from the iterator.
/// This advances the internal state of the iterator.
fn read<V>(&self) -> Option<V>;

However, the try_parse_4digits and try_parse_8digits methods advance the iterator's state manually after reading, without any other apparent length checks:

let bytes = u32::from_le(iter.read::<u32>()?);
if is_4digits::<FORMAT>(bytes) {
// SAFETY: safe since we have at least 4 bytes in the buffer.
unsafe { iter.step_by_unchecked(4) };

if is_8digits::<FORMAT>(bytes) {
// SAFETY: safe since we have at least 8 bytes in the buffer.
unsafe { iter.step_by_unchecked(8) };

This is unsound according to the docs of step_by_unchecked:

/// As long as the iterator is at least `N` elements, this
/// is safe.
unsafe fn step_by_unchecked(&mut self, count: usize);

Skimming around for actual implementations, it appears that read may not actually advance the state as advertised, which could explain how this has gone unnoticed so far. Note the absence of any mutation of self.index, contrary to the doc comment:

/// Read a value of a difference type from the iterator.
/// This advances the internal state of the iterator.
///
/// # Safety
///
/// Safe as long as the number of the buffer is contains as least as
/// many bytes as the size of V.
#[inline]
#[allow(clippy::assertions_on_constants)]
pub unsafe fn read_unchecked<V>(&self) -> V {
debug_assert!(Self::IS_CONTIGUOUS);
debug_assert!(self.as_slice().len() >= mem::size_of::<V>());
let slc = self.as_slice();
// SAFETY: safe as long as the slice has at least count elements.
unsafe { ptr::read_unaligned::<V>(slc.as_ptr() as *const _) }
}

Metadata

Metadata

Assignees

Labels

A-secIssues with potential security implications.bugSomething isn't workinghigh priorityHigh priority

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions