Commit c613d551 authored by cypherpunks's avatar cypherpunks
Browse files

rust/protover: use .and_not_in() instead of .retain() in all_supported()

.retain() would allocating a Vec of billions of integers and check them
one at a time to separate the supported versions from the unsupported.
This leads to a memory DoS.

Closes ticket 27206. Bugfix on e6625113.
parent 578f7326
Loading
Loading
Loading
Loading

changes/bug27206

0 → 100644
+4 −0
Original line number Diff line number Diff line
  o Minor bugfixes (rust):
    - protover_all_supported() would attempt to allocate up to 16GB on some
      inputs, leading to a potential memory DoS. Fixes bug 27206; bugfix on
      0.3.3.5-rc.
+1 −3
Original line number Diff line number Diff line
@@ -365,7 +365,6 @@ impl UnvalidatedProtoEntry {

            let maybe_supported_versions: Option<&ProtoSet> = supported.get(&supported_protocol);
            let supported_versions: &ProtoSet;
            let mut unsupported_versions: ProtoSet;

            // If the protocol wasn't in the map, then we don't know about it
            // and don't support any of its versions.  Add its versions to the
@@ -378,8 +377,7 @@ impl UnvalidatedProtoEntry {
            } else {
                supported_versions = maybe_supported_versions.unwrap();
            }
            unsupported_versions = versions.clone();
            unsupported_versions.retain(|x| !supported_versions.contains(x));
            let unsupported_versions = versions.and_not_in(supported_versions);

            if !unsupported_versions.is_empty() {
                unsupported.insert(protocol.clone(), unsupported_versions);
+4 −4
Original line number Diff line number Diff line
@@ -354,18 +354,18 @@ fn protover_all_supported_should_exclude_some_versions_and_entire_protocols() {

#[test]
fn protover_all_supported_should_not_dos_anyones_computer() {
    let proto: UnvalidatedProtoEntry = "Sleen=1-2147483648".parse().unwrap();
    let proto: UnvalidatedProtoEntry = "Link=1-2147483648".parse().unwrap();
    let result: String = proto.all_supported().unwrap().to_string();

    assert_eq!(result, "Sleen=1-2147483648".to_string());
    assert_eq!(result, "Link=6-2147483648".to_string());
}

#[test]
fn protover_all_supported_should_not_dos_anyones_computer_max_versions() {
    let proto: UnvalidatedProtoEntry = "Sleen=1-4294967294".parse().unwrap();
    let proto: UnvalidatedProtoEntry = "Link=1-4294967294".parse().unwrap();
    let result: String = proto.all_supported().unwrap().to_string();

    assert_eq!(result, "Sleen=1-4294967294".to_string());
    assert_eq!(result, "Link=6-4294967294".to_string());
}

#[test]