rustsec-2026-0190
Vulnerability from osv_rustsec
Published
2026-06-25 12:00
Modified
2026-06-29 14:05
Summary
Unsoundness in `Error::downcast_mut()`
Details
Affected versions of this crate violate borrow rules, resulting in undefined behavior, when the user adds context to an error via Error::context and then later calls Error::downcast_mut on the returned Error.
The flaw was corrected in commit 6e8c000 by revising how the mutable reference is constructed, avoiding inclusion of a shared reference in the resulting borrow chain.
Example
use anyhow::Error;
use std::fmt;
#[derive(Debug)]
struct ErrorContext(&'static str);
impl fmt::Display for ErrorContext {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
fn main() {
let mut error = Error::msg("inner error").context(ErrorContext("old context"));
let context: &mut ErrorContext = error.downcast_mut().unwrap();
context.0 = "new context";
println!("{:?}", error);
}
Miri output
error: Undefined Behavior: trying to retag from <1538> for Unique permission at alloc602[0x38], but that tag only grants SharedReadOnly permission for this location
--> src/ptr.rs:170:18
|
170 | unsafe { &mut *self.ptr.as_ptr() }
| ^^^^^^^^^^^^^^^^^^^^^^^ this error occurs as part of retag at alloc602[0x38..0x48]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <1538> was created by a SharedReadOnly retag at offsets [0x38..0x48]
--> src/ptr.rs:89:18
|
89 | ptr: NonNull::from(ptr),
| ^^^^^^^^^^^^^^^^^^
= note: stack backtrace:
0: anyhow::ptr::Mut::<'_, ErrorContext>::deref_mut
at src/ptr.rs:170:18: 170:41
1: anyhow::error::<impl anyhow::Error>::downcast_mut::<ErrorContext>
at src/error.rs:560:18: 560:46
2: main
at examples/downcast_mut.rs:15:38: 15:58
{
"affected": [
{
"database_specific": {
"categories": [
"memory-corruption"
],
"cvss": null,
"informational": "unsound"
},
"ecosystem_specific": {
"affected_functions": null,
"affects": {
"arch": [],
"functions": [
"anyhow::Error::downcast_mut"
],
"os": []
}
},
"package": {
"ecosystem": "crates.io",
"name": "anyhow",
"purl": "pkg:cargo/anyhow"
},
"ranges": [
{
"events": [
{
"introduced": "0.0.0-0"
},
{
"fixed": "1.0.103"
}
],
"type": "SEMVER"
}
],
"versions": []
}
],
"aliases": [],
"database_specific": {
"license": "CC0-1.0"
},
"details": "Affected versions of this crate violate borrow rules, resulting in undefined behavior, when the user adds context to an error via `Error::context` and then later calls `Error::downcast_mut` on the returned `Error`.\n\nThe flaw was corrected in commit `6e8c000` by revising how the mutable reference is constructed, avoiding inclusion of a shared reference in the resulting borrow chain.\n\n## Example\n\n```rust\nuse anyhow::Error;\nuse std::fmt;\n\n#[derive(Debug)]\nstruct ErrorContext(\u0026\u0027static str);\n\nimpl fmt::Display for ErrorContext {\n fn fmt(\u0026self, f: \u0026mut fmt::Formatter\u003c\u0027_\u003e) -\u003e fmt::Result {\n fmt::Display::fmt(\u0026self.0, f)\n }\n}\n\nfn main() {\n let mut error = Error::msg(\"inner error\").context(ErrorContext(\"old context\"));\n let context: \u0026mut ErrorContext = error.downcast_mut().unwrap();\n context.0 = \"new context\";\n println!(\"{:?}\", error);\n}\n```\n\n## Miri output\n\n```\nerror: Undefined Behavior: trying to retag from \u003c1538\u003e for Unique permission at alloc602[0x38], but that tag only grants SharedReadOnly permission for this location\n --\u003e src/ptr.rs:170:18\n |\n170 | unsafe { \u0026mut *self.ptr.as_ptr() }\n | ^^^^^^^^^^^^^^^^^^^^^^^ this error occurs as part of retag at alloc602[0x38..0x48]\n |\n = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental\n = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information\nhelp: \u003c1538\u003e was created by a SharedReadOnly retag at offsets [0x38..0x48]\n --\u003e src/ptr.rs:89:18\n |\n 89 | ptr: NonNull::from(ptr),\n | ^^^^^^^^^^^^^^^^^^\n = note: stack backtrace:\n 0: anyhow::ptr::Mut::\u003c\u0027_, ErrorContext\u003e::deref_mut\n at src/ptr.rs:170:18: 170:41\n 1: anyhow::error::\u003cimpl anyhow::Error\u003e::downcast_mut::\u003cErrorContext\u003e\n at src/error.rs:560:18: 560:46\n 2: main\n at examples/downcast_mut.rs:15:38: 15:58\n```",
"id": "RUSTSEC-2026-0190",
"modified": "2026-06-29T14:05:53Z",
"published": "2026-06-25T12:00:00Z",
"references": [
{
"type": "PACKAGE",
"url": "https://crates.io/crates/anyhow"
},
{
"type": "ADVISORY",
"url": "https://rustsec.org/advisories/RUSTSEC-2026-0190.html"
},
{
"type": "REPORT",
"url": "https://github.com/dtolnay/anyhow/issues/451"
}
],
"related": [],
"severity": [],
"summary": "Unsoundness in `Error::downcast_mut()`"
}
Loading…
Loading…
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Loading…
Loading…