rust-lang / rust-lang/backtrace-rs

Soundness problem due to exception safety violation in lock design

Open
#764 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
628
Forks
291
PR merge metrics
No merged PRs in 30d

Description

Hello, we are security researchers targeting Rust security. By running our tool in this repository, we found a soundness issue. This report is written by 100% human. We promise that all you read will never be generated by LLM.

Proof of concept

static mut FOO: u8 = 0;

fn main() {
    // Pure safe code below
    let _ = std::panic::catch_unwind(|| {
        backtrace::resolve((&raw mut FOO).cast(), |_symbol| {
            panic!("poison the mutex");
        });
    });
    let _ = std::panic::catch_unwind(|| {
        backtrace::resolve((&raw mut FOO).cast(), |_| {});
    });
    // Soundness issue happens here
}

Explanation

In backtrace::resolve, crate::lock::lock() is called to get a mutex guard of global lock as here:

https://github.com/rust-lang/backtrace-rs/blob/06b2cc573703c98df4b543422c8339694420bb02/src/lib.rs#L217-L229

And in the drop implementation of LockGuard, the MutexGuard is simply dropped without cleaning the poison:

https://github.com/rust-lang/backtrace-rs/blob/06b2cc573703c98df4b543422c8339694420bb02/src/lib.rs#L152-L165

As a result, in above PoC, after the first backtrace::resolve, the global LOCK is actually poisoned. So in the second backtrace::resolve, the crate::lock::lock will panic at unwraping in the LOCK.lock().unwrap(). However, we caught the panic again by std::panic::catch_unwind, so after the second catch_unwind, the LOCK_HELD is true (the cleaning function will never be invoked).

Then, every call to any function in the library that requires the lock will be unguarded (as the lock will never be locked if LOCK_HELD is true), leading to race conditions.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/lib.rs at crate:🔒:lock(), the LockGuard Drop implementation, and the backtrace::resolve path cited in the report. Reproduce the two catch_unwind calls from the Rust proof of concept, then trace how poisoning affects LOCK and LOCK_HELD. Done means panic recovery cannot leave later lock-using calls unguarded, with regression coverage for the reported sequence.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
devtools, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.