-
-
Notifications
You must be signed in to change notification settings - Fork 14.9k
Unsafe code can't soundly rely on aborting in wasm (featuring Arc reference count overflow) #149708
Copy link
Copy link
Closed as duplicate of#117344
Closed as duplicate of#117344
Copy link
Labels
A-runtimeArea: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflowsArea: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflowsC-bugCategory: This is a bug.Category: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessO-wasmTarget: WASM (WebAssembly), http://webassembly.org/Target: WASM (WebAssembly), http://webassembly.org/T-langRelevant to the language teamRelevant to the language teamT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.
Metadata
Metadata
Assignees
Labels
A-runtimeArea: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflowsArea: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflowsC-bugCategory: This is a bug.Category: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessO-wasmTarget: WASM (WebAssembly), http://webassembly.org/Target: WASM (WebAssembly), http://webassembly.org/T-langRelevant to the language teamRelevant to the language teamT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.
Type
Fields
Give feedbackNo fields configured for issues without a type.
Background
In WASM, calling
core::intrinsics::abortdoes not actually abort the program. It throws an exception on the JS side, preserving the (potentially-corrupt) current state in the Rust side. (Thanks to @kpreid for bringing this to my attention.)In the Rust standard library, if the reference count in an
Arcgoes overusize::MAX / 2, Rust will abort the program. This is done to avoid an integer overflow that could happen if the reference count were to go overusize::MAX. This assumes that aborting the program will cause the bad state (of having a large reference count in anArc) to go away, which is not true in WASM.The unsoundness
src/lib.rs:
run.mjs:
Full code for reproducing the unsoundness can be found at https://github.com/theemathas/wasm-unsound. To run the code, use the following commands:
The code repeatedly leaks an
Arc, increasing its reference count. When the reference count is larger thanusize::MAX / 2, the Rust side aborts. The JS side then catches the resulting exception, then re-enters the Rust side, but with the reference count being 1 higher. Eventually, after aborting 2 billion times (which takes a long time), the reference count goes overusize::MAXand overflows. The Rust code then uses this to perform a use-after-free, and returns garbage data to the JS side. In my testing, the program printed the number1050364, which I assume is data read from some random address.Meta
rustc --version --verbose: