Use After Free in lucet
Description
Use-after-free in lucet-runtime when dropping an Instance, allowing memory corruption; upgrade to main branch required.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Use-after-free in lucet-runtime when dropping an Instance, allowing memory corruption; upgrade to main branch required.
Vulnerability
A use-after-free vulnerability exists in the lucet-runtime crate, affecting all versions published to crates.io [1][2]. The bug occurs when an Instance object is dropped; due to the order of destructors, the memory backing the instance may be returned to the pool allocator while other fields are still being destroyed, allowing a race condition [4]. This issue was introduced early in Lucet's development and is present in all releases [1].
Exploitation
An attacker with low privileges and network access can trigger the vulnerability by causing an Instance to be dropped while another thread concurrently allocates the same memory from the pool [2][4]. The attack complexity is high, requiring precise timing to exploit the race condition [2]. No user interaction is required [2].
Impact
Successful exploitation leads to memory corruption, data races, or other undefined behavior [1][4]. According to the CVSS vector, this can result in high confidentiality, integrity, and availability impact, with a score of 8.5 (HIGH) [2].
Mitigation
Users must upgrade to the main branch of the Lucet repository, as no versioned releases are provided on crates.io [1][4]. The fix is implemented in commit 7c7757c [3]. There are no workarounds [4]; upgrading is the only remediation.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
lucet-runtimecrates.io | <= 0.6.1 | — |
Affected products
2- bytecodealliance/lucetv5Range: <= 0.6.1
Patches
17c7757c772fbMerge pull request from GHSA-hf79-8hjp-rrvq
1 file changed · +26 −13
lucet-runtime/lucet-runtime-internals/src/instance.rs+26 −13 modified@@ -14,7 +14,6 @@ use crate::error::Error; #[cfg(feature = "concurrent_testpoints")] use crate::lock_testpoints::LockTestpoints; use crate::module::{self, FunctionHandle, Global, GlobalValue, Module, TrapCode}; -use crate::region::RegionInternal; use crate::sysdeps::HOST_PAGE_SIZE_EXPECTED; use crate::val::{UntypedRetVal, Val}; use crate::vmctx::Vmctx; @@ -27,6 +26,7 @@ use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut, UnsafeCell}; use std::convert::TryFrom; use std::marker::PhantomData; use std::mem; +use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; use std::ptr::{self, NonNull}; use std::sync::Arc; @@ -147,20 +147,29 @@ impl Drop for InstanceHandle { unsafe { let inst = self.inst.as_mut(); - // Grab a handle to the region to ensure it outlives `inst`. + // The `inst.alloc` field manages the memory of the instance + // itself. Note, though, that this field is in a `ManuallyDrop` + // so it won't get dropped automatically in `drop_in_place`. + // This is the point where we take over that precise drop. // - // This ensures that the region won't be dropped by `inst` being - // dropped, which could result in `inst` being unmapped by the - // Region *during* drop of the Instance's fields. - let region: Arc<dyn RegionInternal> = inst.alloc().region.clone(); + // By using `take` here we're basically calling `ptr::read` + // which "duplicates" the `alloc` since the `alloc` local + // variable here is the exact same as `inst.alloc`. All we do + // with `inst`, though, is call `drop_in_place`, which + // invalidates every other field in `inst`. + let alloc: Alloc = ManuallyDrop::take(&mut inst.alloc); // drop the actual instance std::ptr::drop_in_place(inst); - // and now we can drop what may be the last Arc<Region>. If it is - // it can safely do what it needs with memory; we're not running - // destructors on it anymore. - mem::drop(region); + // Now that we're 100% done with the instance, destructors and + // all, we can release the memory of the instance back to the + // original allocator from whence it came (be it mmap or uffd + // based). This will run the "official" destructor for `Alloc` + // which internally does the release. Note that after this + // operation the `inst` pointer is invalid and can no longer be + // used. + drop(alloc); } } } @@ -233,8 +242,12 @@ pub struct Instance { /// Conditionally-present helpers to force permutations of possible races in testing. pub lock_testpoints: Arc<LockTestpoints>, - /// The memory allocated for this instance - alloc: Alloc, + /// The memory allocated for this instance. + /// + /// Note that this is in a `ManuallyDrop` because this manages the memory of + /// this `Instance` itself. To have precise control over this memory we + /// handle this in `Drop for InstanceHandle`. + alloc: ManuallyDrop<Alloc>, /// Handler run for signals that do not arise from a known WebAssembly trap, or that involve /// memory outside of the current instance. @@ -1055,7 +1068,7 @@ impl Instance { kill_state, #[cfg(feature = "concurrent_testpoints")] lock_testpoints, - alloc, + alloc: ManuallyDrop::new(alloc), fatal_handler: default_fatal_handler, c_fatal_handler: None, signal_handler: Box::new(signal_handler_none) as Box<SignalHandler>,
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-hf79-8hjp-rrvqghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2021-43790ghsaADVISORY
- crates.io/crates/lucet-runtimeghsax_refsource_MISCWEB
- github.com/bytecodealliance/lucet/commit/7c7757c772fb709c61b1442bcc1e1fbee97bf4a8ghsax_refsource_MISCWEB
- github.com/bytecodealliance/lucet/security/advisories/GHSA-hf79-8hjp-rrvqghsax_refsource_CONFIRMWEB
- rustsec.org/advisories/RUSTSEC-2021-0155.htmlghsaWEB
News mentions
0No linked articles in our index yet.