You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This finding was identified during an agentic unsafe Rust code review orchestrated by @Manishearth and performed by Gemini AI.
In IpDefragBuf::add() (a safe function), the safety invariant of self.data is temporarily broken by self.data.set_len() but not always restored before returning. If the offset is greater than self.data.len() on entry, then any data in between is not initialized, and can be accessed with IpDefragBuf::data() (a safe function). The most simple fix is to use self.data.resize() instead of self.data.set_len(), but there are other options like initializing anything between the old length and the offset, or only exposing the longest initialized prefix through safe functions.
% cargo miri run
error: Undefined Behavior: reading memory at alloc313[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
--> src/main.rs:10:17
|
10 | let _byte = buf.data()[0]; // UB: reading uninit at u8
| ^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
Original AI finding
Location: src/defrag/ip_defrag_buf.rs:121
Description: IpDefragBuf reconstructs fragmented IP packets inside an internal backing vector self.data: Vec<u8>. When an out-of-order packet fragment arrives (i.e., a fragment whose starting byte offset is greater than the current vector length), IpDefragBuf::add calculates the required_len up to the end of that fragment. If self.data.len() < required_len, it reserves capacity and executes:
unsafe{self.data.set_len(required_len);}
While the incoming payload is copied into self.data[offset..end], any intervening memory range between old_len and offset remains uninitialized heap memory returned by the global allocator.
Although IpDefragBuf::is_complete() returns false until all gaps are filled, IpDefragBuf exposes safe public inspection APIs:
Derived trait implementations for Clone, Debug, PartialEq, Eq, Hash.
Soundness Violation: According to the Rust Reference and std::vec::Vec::set_len safety documentation, all elements up to vector length must be initialized. Integers (u8) do not permit uninitialized bit patterns (MaybeUninit<u8>). Invoking set_len over uninitialized memory is immediate Undefined Behavior. Furthermore, allowing safe external code to read this uninitialized memory via data(), Debug, or Clone introduces information disclosure vulnerabilities, potentially leaking sensitive stale heap data from concurrent server operations.
Note
This finding was identified during an agentic unsafe Rust code review orchestrated by @Manishearth and performed by Gemini AI.
In
IpDefragBuf::add()(a safe function), the safety invariant ofself.datais temporarily broken byself.data.set_len()but not always restored before returning. If the offset is greater thanself.data.len()on entry, then any data in between is not initialized, and can be accessed withIpDefragBuf::data()(a safe function). The most simple fix is to useself.data.resize()instead ofself.data.set_len(), but there are other options like initializing anything between the old length and the offset, or only exposing the longest initialized prefix through safe functions.Minimal Reproduction (Miri)
Original AI finding
Location:
src/defrag/ip_defrag_buf.rs:121Description:
IpDefragBufreconstructs fragmented IP packets inside an internal backing vectorself.data: Vec<u8>. When an out-of-order packet fragment arrives (i.e., a fragment whose starting byte offset is greater than the current vector length),IpDefragBuf::addcalculates therequired_lenup to the end of that fragment. Ifself.data.len() < required_len, it reserves capacity and executes:While the incoming payload is copied into
self.data[offset..end], any intervening memory range betweenold_lenandoffsetremains uninitialized heap memory returned by the global allocator.Although
IpDefragBuf::is_complete()returnsfalseuntil all gaps are filled,IpDefragBufexposes safe public inspection APIs:pub fn data(&self) -> &Vec<u8>(lines 48-50)pub fn take_bufs(self) -> (Vec<u8>, Vec<IpFragRange>)(line 167)Clone,Debug,PartialEq,Eq,Hash.Soundness Violation: According to the Rust Reference and
std::vec::Vec::set_lensafety documentation, all elements up to vector length must be initialized. Integers (u8) do not permit uninitialized bit patterns (MaybeUninit<u8>). Invokingset_lenover uninitialized memory is immediate Undefined Behavior. Furthermore, allowing safe external code to read this uninitialized memory viadata(),Debug, orCloneintroduces information disclosure vulnerabilities, potentially leaking sensitive stale heap data from concurrent server operations.Remediation: Remove
unsafe { self.data.set_len(required_len); }. Instead, advance vector length safely by zero-initializing newly exposed memory: