Skip to content

Parsers allocate based on a length field, not the number of elements that exist #1

@saethlin

Description

@saethlin

I've been fuzzing an internal project that uses the parsers in this crate. The fuzzer has found a number of crashes related to using a 32-bit value as the length for a nom::multi::count call. The crash occurs because nom attempts to pre-allocate for billions of elements. Even if the memory is never touched, at some size memory allocators do return a null pointer, and the Rust OOM handler aborts the program. I can provide example packets if you want/need.

I've been able to locally paper over this issue by applying a few diffs like this:

diff --git a/src/ospfv2.rs b/src/ospfv2.rs
index 7e591d1..cdc7418 100644
--- a/src/ospfv2.rs
+++ b/src/ospfv2.rs
@@ -185,6 +185,7 @@ pub struct OspfLinkStateUpdatePacket {
     #[nom(Verify = "header.packet_type == OspfPacketType::LinkStateUpdate")]
     pub header: Ospfv2PacketHeader,
     pub num_advertisements: u32,
+    #[nom(ErrorIf(num_advertisements as usize > i.len()))]
     #[nom(Count = "num_advertisements")]
     pub lsa: Vec<OspfLinkStateAdvertisement>,
 }

...but I strongly suspect I've only had to apply 3 so far because my initial corpus does not contain any actual OSPF packets, and given enough time a fuzzer will find a crash at every place this pattern occurs in the code.

This seems like it might be of interest for a security-minded parser because this a DoS vector. If it is, do you have any thoughts on a more complete solution to this? I'm not excited about the idea of sprinkling ErrorIfs all over this codebase.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions