Skip to content

Invalid utf8 str could still be created by from_utf8_unchecked #37

@shinmao

Description

@shinmao

Bypass debug_assert!

impl InlineString {
#[cfg_attr(feature = "nightly", allow(inline_always))]
#[inline(always)]
fn assert_sanity(&self) {
debug_assert!(
self.length as usize <= INLINE_STRING_CAPACITY,
"inlinable_string: internal error: length greater than capacity"
);
debug_assert!(
str::from_utf8(&self.bytes[0..self.length as usize]).is_ok(),
"inlinable_string: internal error: contents are not valid UTF-8!"
);
}

We consider that the protection of assert_sanity is not sufficient to check the validity of string due to removed debug_assert! in release mode.

PoC

fn main() {
    let mut s = InlineString::from("A");

    {
        let bytes: &mut [u8] = s.as_mut();
        bytes[0] = 0xFF; // invalid UTF-8 byte
    }

    // attack vector 1: AsRef<str>::as_ref -> from_utf8_unchecked
    let _a: &str = s.as_ref();

    // attack vector 2: Index<RangeFull> -> from_utf8_unchecked
    let _b: &str = &s[..];

    // attack vector 3: Deref -> from_utf8_unchecked
    let _c: &str = &*s;
}

With cargo run in nightly version

thread 'main' panicked at /home/usr/.cargo/registry/src/index.crates.io-6f17d22bba15001f/inlinable_string-0.1.15/src/inline_string.rs:283:9:
inlinable_string: internal error: contents are not valid UTF-8!

However, if run with cargo run --release, no error message will show. Maybe consider changing it to assert! instead? Or change it to str::from_utf8 to do error handling could be more straightforward.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions