Skip to content

Attributes::new panics instead of returning None when pos > buf.len() #989

Description

@kaixinlalala

Description:

quick_xml::events::attributes::Attributes::new(buf, pos) documents that if pos is greater than the buffer length, the iterator should immediately return None. However, when such an Attributes iterator is consumed, either directly via next() or indirectly via has_nil(), it panics due to an out-of-bounds slice access.

Environment:

quick-xml version: 0.41.0
rustc version: 1.94.1
OS: Ubuntu 20.04.6 LTS
Command: RUST_BACKTRACE=full cargo run

PoC

use quick_xml::events::attributes::Attributes;
use quick_xml::reader::NsReader;

fn main() {
    let mut attrs = Attributes::new("a", 2);
    let reader = NsReader::from_str("");
    let _ = attrs.has_nil(reader.resolver());
}

Expected behavior:

Since pos is greater than buf.len(), the iterator should terminate immediately.

Actual behavior

thread 'main' panicked at /Rust-Lib-Testing/test/tests/crates/quick-xml-0.41.0/src/events/attributes.rs:1224:49:
range start index 2 out of range for slice of length 1
stack backtrace:
   0:     0x55fe02a6e428 - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::h0f9d2e8e73f1bc7d
   1:     0x55fe02aad033 - core::fmt::write::h2b15537d64ec9505
   2:     0x55fe02a99f5f - std::io::Write::write_fmt::h7f766131a16fe05a
   3:     0x55fe02a6e273 - std::sys::backtrace::BacktraceLock::print::h5e38585c963961db
   4:     0x55fe02a73f7c - std::panicking::default_hook::{{closure}}::h7a475a2b7b7e4121
   5:     0x55fe02a73e1d - std::panicking::default_hook::hac0f4b95d0cecbc2
   6:     0x55fe02a74451 - std::panicking::rust_panic_with_hook::hb51ba0f67890aa28
   7:     0x55fe02a6e80a - std::panicking::begin_panic_handler::{{closure}}::h73d0277a9a02463b
   8:     0x55fe02a6e649 - std::sys::backtrace::__rust_end_short_backtrace::hf93dae6c307b4fe8
   9:     0x55fe02a7406d - __rustc[b6f6af4e11d2f413]::rust_begin_unwind
  10:     0x55fe02aac0a0 - core::panicking::panic_fmt::h3075732948299e49
  11:     0x55fe02aaa597 - core::slice::index::slice_start_index_len_fail::do_panic::runtime::hcc2a5aadc9262237
  12:     0x55fe02aaa4ca - core::slice::index::slice_start_index_len_fail::hc732b73cbbe828f6
  13:     0x55fe02a6accd - <core::ops::range::RangeFrom<usize> as core::slice::index::SliceIndex<[T]>>::index::he33b10440abe67b2
                               at /Rust-Lib-Testing/test/src/rust/library/core/src/slice/index.rs:570:13
  14:     0x55fe02a5ffa7 - core::slice::index::<impl core::ops::index::Index<I> for [T]>::index::h737ba69d80e4a2ac
                               at /Rust-Lib-Testing/test/src/rust/library/core/src/slice/index.rs:18:15
  15:     0x55fe02a5ffa7 - quick_xml::events::attributes::IterState::next::h1cab26926d07055b
                               at /Rust-Lib-Testing/test/tests/crates/quick-xml-0.41.0/src/events/attributes.rs:1224:49
  16:     0x55fe02a5efb0 - <quick_xml::events::attributes::Attributes as core::iter::traits::iterator::Iterator>::next::h19869966ebbf405f
                               at /Rust-Lib-Testing/test/tests/crates/quick-xml-0.41.0/src/events/attributes.rs:698:26
  17:     0x55fe02a63440 - core::iter::traits::iterator::Iterator::try_fold::hf926e2a9c4d7363f
                               at /Rust-Lib-Testing/test/src/rust/library/core/src/iter/traits/iterator.rs:2425:34
  18:     0x55fe02a633e4 - core::iter::traits::iterator::Iterator::any::h46c8a83f373b4437
                               at /Rust-Lib-Testing/test/src/rust/library/core/src/iter/traits/iterator.rs:2826:14
  19:     0x55fe02a5ef74 - quick_xml::events::attributes::Attributes::has_nil::h129362b91d57b1f7
                               at /Rust-Lib-Testing/test/tests/crates/quick-xml-0.41.0/src/events/attributes.rs:651:14
  20:     0x55fe02a56b5d - replay_quick_xml1::main::h26e7f01651a50c7a
                               at /Rust-Lib-Testing/replay_files/quick-xml-0.41.0/replay_quick-xml1/src/main.rs:7:19
  21:     0x55fe02a56d0b - core::ops::function::FnOnce::call_once::h76f46a5897c6fb29
                               at /Rust-Lib-Testing/test/src/rust/library/core/src/ops/function.rs:253:5
  22:     0x55fe02a56bce - std::sys::backtrace::__rust_begin_short_backtrace::h65002fbaeac49652
                               at /Rust-Lib-Testing/test/src/rust/library/std/src/sys/backtrace.rs:158:18
  23:     0x55fe02a56c31 - std::rt::lang_start::{{closure}}::h69d435d19a4676c4
                               at /Rust-Lib-Testing/test/src/rust/library/std/src/rt.rs:206:18
  24:     0x55fe02a99155 - std::rt::lang_start_internal::h9de2b5630c7cec4d
  25:     0x55fe02a56c17 - std::rt::lang_start::h830c9996d95df1a2
                               at /Rust-Lib-Testing/test/src/rust/library/std/src/rt.rs:205:5
  26:     0x55fe02a56bbe - main
  27:     0x7f674eaa6083 - __libc_start_main
                               at /build/glibc-B3wQXB/glibc-2.31/csu/../csu/libc-start.c:308:16
  28:     0x55fe02a569ee - _start
  29:                0x0 - <unknown>

Root cause:

The panic appears to happen in src/events/attributes.rs:

Some(offset) => (offset..).zip(slice[offset..].iter()),

recover(slice) can return Some(offset) where offset > slice.len(). The code then indexes slice[offset..] without checking the bound first.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions