GHSA-m9qr-4rcq-3jhc: Data race and double free via unsound `Send`/`Sync` in `reblessive`
dbs::Executor drives every SurrealQL statement through reblessive::tree::TreeStack. In reblessive 0.4.3 the runtime types unconditionally assert Send/Sync (unsafe impl Send/Sync for Stack, TreeStack and Runner), while the public entry points accept any future without a Send bound and store it type-erased in a bump allocator.
Two safe-code consequences follow. First, Runner::stepasync/finishasync return driver futures tied to the stack borrow rather than to &mut self, so a driver future can be duplicated; because Stack is Sync those futures are Send, and polling two copies on different threads runs drivetoptask concurrently — racy Cell/UnsafeCell access, double poptask()/popdealloc() (double drop / double free) and a non-atomic Option::take. Second, TreeStack: Send lets safe code move a driver whose type-erased future captures !Send state (Rc, RefCell) to another thread while the creating thread keeps an alias of that state.
No unsafe is needed at the call site. surrealdb-core's own query futures are Send only because of the unsound unsafe impl Send for TreeStack, while the captured &mut tree::Stk is deliberately !Send.
The unsound dependency was removed in 4.0.0 and the parser now uses plain recursion (commit 75407c4bcc).
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
rust/surrealdb-coreto a version that resolves this vulnerability.Fixed in 4.0.0 - Upgrade
Upgrade
reblessiveto a version that resolves this vulnerability.Fixed in 4.0.0
Event History
Frequently Asked Questions
What conditions are required to exploit this issue?
An attacker needs the ability to invoke the affected asynchronous runtime APIs from safe Rust code. Exploitation can occur by duplicating a driver future and polling copies concurrently on different threads, or by moving a TreeStack driver that captures !Send state to another thread.
Can this affect applications that do not use unsafe Rust?
Yes. The described data race, double-drop/double-free behavior, and cross-thread use of !Send captured state can be triggered without unsafe code at the call site.
What can happen if driver futures are polled concurrently?
Concurrent polling can race on Cell and UnsafeCell state and can cause duplicate pop_task or pop_dealloc operations. The stated consequences include double drop, double free, and a race involving a non-atomic Option::take.
How can teams identify potentially affected code paths?
Review uses of surrealdb-core query execution that drive SurrealQL statements through reblessive::tree::TreeStack. Pay particular attention to code that duplicates futures returned by Runner::step_async or finish_async and polls them on multiple threads, or that moves TreeStack-related drivers across threads while they capture Rc or RefCell state.