CVE-2022-39393: Wasmtime may have data leakage between instances in the pooling allocator
(updated )
There is a bug in Wasmtime’s implementation of it’s pooling instance allocator where when a linear memory is reused for another instance the initial heap snapshot of the prior instance can be visible, erroneously to the next instance. The pooling instance allocator in Wasmtime works by preallocating virtual memory for a fixed number of instances to reside in and then new instantiations pick a slot to use. Most conventional modules additionally have an initial copy-on-write “heap image” which is mapped in Wasmtime into the linear memory slot. When a heap slot is deallocated Wasmtime resets all of its contents back to the initial state but it does not unmap the image in case the next instance is an instantiation of the same module.
The bug in Wasmtime occurs when a slot in the pooling allocator previously was used for a module with a heap image, meaning that its current state of memory contains the initial heap contents of that module. If the next instantiation within that slot does not itself contain a heap image then Wasmtime would leave the old heap image in place erroneously and continue with instantiation. This means that instantiations of modules without a heap image can see the initial heap image of the prior instantiation within that slot.
Heap images in Wasmtime are created by precomputing WebAssembly data
segments into one large mapping to be placed into linear memory at a particular offset. Most modules produced by toolchains today will have a heap image and an initialization snapshot. Creating a module without a heap image would require a hand-crafted *.wat
file or a specially crafted source program. This consequence means that this bug is highly unlikely to be accidentally triggered and would otherwise require an intentional trigger with a hand-crafted module.
One important part of this vulnerability is Wasmtime is highly likely to segfault when the slot is reused again with a module that itself has an initialization image. For example if module A has a heap initialization image and module B does not have a heap initialization image, then the following sequence of events could happen if they all are instantiated into the same instance slot:
- Module A is instantiated, and then deallocated. This leaves A’s heap image in place, reset to its initial contents.
- Module B is instantiated and erroneously can see the initial heap contents of A. Module B is then deallocated and the entire heap is unmapped and reset back to zero.
- Module A is instantiated again, but the state tracking the slot did not account for module B so it thinks the module image is still mapped and proceeds with instantiation. Any action on A’s part to access linear memory will then trap and if the host accesses A’s memory it will segfault because the data that’s supposed to be mapped is all unmapped.
Adding this all together this means that in practice modules must be deliberately crafted to not have an initial heap image to view the contents of a prior image. If this module is instantiated though then when the slot is reused the next, likely image-using, module will believe its memory is mapped when it isn’t, causing the host to segfault on unmapped memory it believed was mapped.
References
- github.com/advisories/GHSA-wh6w-3828-g9qf
- github.com/bytecodealliance/wasmtime
- github.com/bytecodealliance/wasmtime/commit/2614f2e9d2d36805ead8a8da0fa0c6e0d9e428a0
- github.com/bytecodealliance/wasmtime/commit/3535acbf3be032ef1ba0b469b8ab92538a8a18a6
- github.com/bytecodealliance/wasmtime/security/advisories/GHSA-wh6w-3828-g9qf
- groups.google.com/a/bytecodealliance.org/g/sec-announce/c/c1HBDDJwNPA
- nvd.nist.gov/vuln/detail/CVE-2022-39393
- rustsec.org/advisories/RUSTSEC-2022-0075.html
Detect and mitigate CVE-2022-39393 with GitLab Dependency Scanning
Secure your software supply chain by verifying that all open source dependencies used in your projects contain no disclosed vulnerabilities. Learn more about Dependency Scanning →