VYPR
High severityNVD Advisory· Published Nov 29, 2021· Updated Aug 4, 2024

Use After Free in lucet

CVE-2021-43790

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.

PackageAffected versionsPatched versions
lucet-runtimecrates.io
<= 0.6.1

Affected products

2

Patches

1
7c7757c772fb

Merge pull request from GHSA-hf79-8hjp-rrvq

https://github.com/bytecodealliance/lucetPat HickeyNov 29, 2021via ghsa
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

News mentions

0

No linked articles in our index yet.