From 5fab8dfc1b60b9795e123efc9c131ec5ab12f3d4 Mon Sep 17 00:00:00 2001 From: Thanasis Trispiotis Date: Tue, 2 Jun 2026 13:04:01 +0200 Subject: [PATCH] add advisories for metacall --- crates/metacall/RUSTSEC-0000-0000.1.md | 44 ++++++++++++++++++++++++++ crates/metacall/RUSTSEC-0000-0000.2.md | 25 +++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 crates/metacall/RUSTSEC-0000-0000.1.md create mode 100644 crates/metacall/RUSTSEC-0000-0000.2.md diff --git a/crates/metacall/RUSTSEC-0000-0000.1.md b/crates/metacall/RUSTSEC-0000-0000.1.md new file mode 100644 index 000000000..44cb1e48a --- /dev/null +++ b/crates/metacall/RUSTSEC-0000-0000.1.md @@ -0,0 +1,44 @@ +```toml +[advisory] +id = "RUSTSEC-0000-0000" +package = "metacall" +date = "2026-06-01" +url = "https://github.com/metacall/core/issues/809" +categories = ["memory-corruption"] +keywords = ["bad-free"] + +[versions] +patched = [] +``` + +# Bad-free in `MetaCallException::new` + +`exception_struct` is a local stack variable, but the code passes its address to the C language as `&mut exception_struct as *mut _ as *mut c_void`. Then, the returned `MetaCallException` value is stored here: +```rust +Ok(Self { + exception_struct: Arc::new(exception_struct), + value: exception_ptr, + leak: false, +}) +``` +Because leak is false, the destructor will run later. But the original exception pointer points to Rust stack memory. + +## Trigger + +```rust +#[test] +fn exception_bad_free_safe_api() { + let original = metacall::MetaCallException::new( + "test", + "test", + "test", + 1, + ); + + drop(original); // AddressSanitizer: bad-free +} +``` + +## Impact + +Every time the `MetaCallException` is created, when it is dropped, it leads to a bad-free. This can be triggered through the safe public API `MetaCallException::new()`, with no `unsafe` required from the caller. diff --git a/crates/metacall/RUSTSEC-0000-0000.2.md b/crates/metacall/RUSTSEC-0000-0000.2.md new file mode 100644 index 000000000..0852745ef --- /dev/null +++ b/crates/metacall/RUSTSEC-0000-0000.2.md @@ -0,0 +1,25 @@ +```toml +[advisory] +id = "RUSTSEC-0000-0000" +package = "metacall" +date = "2026-06-01" +url = "https://github.com/metacall/core/issues/809" +informational = "unsound" +categories = ["memory-corruption"] +keywords = ["use-after-free", "undefined-behavior"] + +[versions] +patched = [] +``` + +# Several memory corruption issues via safe APIs + +Several soundness violations exist in the Rust bindings for `MetaCall`, indicatively: + +**`MetaCallException::Clone`**: `Clone` is dangerous because it creates a second Rust object that still points to the same foreign `MetaCall` value, but does not actually own or keep that value alive. `value` is shallow copied and `leak=true` does not guarantee safety; `Clone` does not free the `MetaCall` value, but it still stores the same raw pointer. If the original is dropped, the `Clone` can retain a dangling pointer. + +**`MetaCallException::new_raw`**: is a safe function that accepts arbitrary raw pointer and dereferences C memory. This function is only correct if the caller gives it a valid, owned `MetaCall` value that must be destroyed by this wrapper. The method should be internal and not exposed to the public API or be declared as unsafe and be correctly documented. + +Same issues exist in `MetaCallThrowable::Clone`, `MetaCallThrowable::new_raw`, `MetaCallClass::Clone`, `MetaCallClass::new_raw`, `MetaCallFuture::Clone`, `MetaCallFuture::new_raw`, `MetaCallPointer::Clone`, `MetaCallPointer::new_raw`, `MetaCallFunction::Clone`, `MetaCallFunction::new_raw`, `MetaCallObject::Clone`, and `MetaCallObject::new_raw`. + +All issues can be triggered through safe public APIs.