fix(lib): bound untrusted count loops in existing protocol parsers
The same unbounded-count DoS class fixed in the room parsers also exists in three pre-existing parsers that read a length-prefixed vector count straight off the wire: FileSearchResponse (SearchResult), the browse SharedFileListResponse, and ExcludedSearchPhrases. A malicious/MITM server or peer could send a tiny frame with a ~4-billion element count and spin the actor thread into an OOM allocation loop. Bound each loop (and the inner attribute loops, where read_int32 does not advance past the buffer end) by the remaining payload. Regression tests feed a hostile count and assert prompt, empty parses.
This commit is contained in:
@@ -17,10 +17,30 @@ impl MessageHandler<ServerMessage> for ExcludedSearchPhrasesHandler {
|
||||
|
||||
let mut exluded_phrases: Vec<String> = Vec::new();
|
||||
for _ in 0..item_count {
|
||||
// Read the file name, size, and path (structure can vary)
|
||||
// Guard against a hostile item_count outrunning the payload.
|
||||
if message.get_pointer() + 4 > message.get_size() {
|
||||
break;
|
||||
}
|
||||
let phrase = message.read_string();
|
||||
exluded_phrases.push(phrase);
|
||||
}
|
||||
debug!("Excluded search phrases: {:?}", exluded_phrases);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn hostile_item_count_does_not_hang() {
|
||||
// item_count=u32::MAX with no phrases: the guard must make this return
|
||||
// promptly instead of looping ~4 billion times.
|
||||
let (tx, _rx) = std::sync::mpsc::channel();
|
||||
let mut message = Message::new();
|
||||
message.write_raw_bytes(vec![0u8; 8]);
|
||||
message.write_int32(u32::MAX);
|
||||
message.set_pointer(8);
|
||||
ExcludedSearchPhrasesHandler.handle(&mut message, tx);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user