rustsec-2023-0078
Vulnerability from osv_rustsec
Published
2023-10-19 12:00
Modified
2024-02-10 15:57
Summary
Potential stack use-after-free in `Instrumented::into_inner`
Details

The implementation of the [Instrumented::into_inner] method in affected versions of this crate contains undefined behavior due to incorrect use of [std::mem::forget] The function creates *const pointers to self, calls [mem::forget(self)][std::mem::forget], and then moves values out of those pointers using [std::ptr::read].

// To manually destructure `Instrumented` without `Drop`, we
// move it into a ManuallyDrop and use pointers to its fields
let span: *const Span = &this.span;
let inner: *const ManuallyDrop<T> = &this.inner;
mem::forget(self);
// SAFETY: Those pointers are valid for reads, because `Drop` didn't
//         run, and properly aligned, because `Instrumented` isn't
//         `#[repr(packed)]`.
let _span = unsafe { span.read() };
let inner = unsafe { inner.read() };

However, the [mem::forget documentation][std::mem::forget] states:

Any resources the value manages, such as heap memory or a file handle, will linger forever in an unreachable state. However, it does not guarantee that pointers to this memory will remain valid.

This means that these pointers are no longer valid. This could result in a stack use-after-free if LLVM chooses to reuse self's stack slot for a rebinding after the call to [std::mem::forget].

This undefined behavior has not been observed to cause miscompilation as of Rust 1.73.0. However, any use of this method with the affected versions of tracing are unsound.

The flaw was corrected in commit 20a1762 (PR #2765) by replacing the use of [std::mem::forget] with std::mem::ManuallyDrop, ensuring that the stack slot is not reused and the pointers remain valid when they are read. The fix is published in tracing v0.1.40. Affected versions have been yanked from crates.io.

Thanks to Taylor Cramer and Manish Goregaokar for finding and correcting this issue!


{
  "affected": [
    {
      "database_specific": {
        "categories": [
          "memory-corruption"
        ],
        "cvss": null,
        "informational": "unsound"
      },
      "ecosystem_specific": {
        "affected_functions": null,
        "affects": {
          "arch": [],
          "functions": [
            "tracing::instrument::Instrumented::into_inner"
          ],
          "os": []
        }
      },
      "package": {
        "ecosystem": "crates.io",
        "name": "tracing",
        "purl": "pkg:cargo/tracing"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.1.38-0"
            },
            {
              "fixed": "0.1.40"
            }
          ],
          "type": "SEMVER"
        }
      ],
      "versions": []
    }
  ],
  "aliases": [
    "GHSA-8f24-6m29-wm2r"
  ],
  "database_specific": {
    "license": "CC0-1.0"
  },
  "details": "The implementation of the [`Instrumented::into_inner`] method in affected\nversions of this crate contains undefined behavior due to incorrect use of\n[`std::mem::forget`] The function creates `*const` pointers to `self`, calls\n[`mem::forget(self)`][`std::mem::forget`], and then moves values out of those\npointers using [`std::ptr::read`].\n\n```rust\n// To manually destructure `Instrumented` without `Drop`, we\n// move it into a ManuallyDrop and use pointers to its fields\nlet span: *const Span = \u0026this.span;\nlet inner: *const ManuallyDrop\u003cT\u003e = \u0026this.inner;\nmem::forget(self);\n// SAFETY: Those pointers are valid for reads, because `Drop` didn\u0027t\n//         run, and properly aligned, because `Instrumented` isn\u0027t\n//         `#[repr(packed)]`.\nlet _span = unsafe { span.read() };\nlet inner = unsafe { inner.read() };\n```\n\nHowever, the [`mem::forget` documentation][`std::mem::forget`] states:\n\n\u003e Any resources the value manages, such as heap memory or a file handle, will\n\u003e linger forever in an unreachable state. **However, it does not guarantee that\n\u003e pointers to this memory will remain valid.**\n\nThis means that these pointers are no longer valid. This could result in a stack\nuse-after-free if LLVM chooses to reuse `self`\u0027s stack slot for a rebinding\nafter the call to [`std::mem::forget`].\n\nThis undefined behavior has not been observed to cause miscompilation as of Rust\n1.73.0. However, any use of this method with the affected versions of `tracing`\nare unsound.\n\nThe flaw was corrected in commit [20a1762] ([PR #2765]) by replacing the use of\n[`std::mem::forget`] with `std::mem::ManuallyDrop`, ensuring that the stack slot\nis not reused and the pointers remain valid when they are read. The fix is\npublished in `tracing` [v0.1.40]. Affected versions have been yanked from\ncrates.io.\n\nThanks to [Taylor Cramer] and [Manish Goregaokar] for finding and correcting\nthis issue!\n\n[`Instrumented::into_inner`]:\n    https://docs.rs/tracing/latest/tracing/instrument/struct.Instrumented.html#method.into_inner\n[`std::mem::forget`]: https://doc.rust-lang.org/std/mem/fn.forget.html\n[`std::ptr::read`]:\n    https://doc.rust-lang.org/std/primitive.pointer.html#method.read-1\n[20a1762]:\n    https://github.com/tokio-rs/tracing/commit/20a1762b3fd5f1fafead198fd18e469c68683721\n[PR #2765]: https://github.com/tokio-rs/tracing/pull/2765\n[v0.1.40]: https://crates.io/crates/tracing/0.1.40\n[Taylor Cramer]: https://github.com/cramertj\n[Manish Goregaokar]: https://github.com/manishearth",
  "id": "RUSTSEC-2023-0078",
  "modified": "2024-02-10T15:57:43Z",
  "published": "2023-10-19T12:00:00Z",
  "references": [
    {
      "type": "PACKAGE",
      "url": "https://crates.io/crates/tracing"
    },
    {
      "type": "ADVISORY",
      "url": "https://rustsec.org/advisories/RUSTSEC-2023-0078.html"
    },
    {
      "type": "WEB",
      "url": "https://github.com/tokio-rs/tracing/pull/2765"
    }
  ],
  "related": [],
  "severity": [],
  "summary": "Potential stack use-after-free in `Instrumented::into_inner`"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

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…

Detection rules are retrieved from Rulezet.

Loading…

Loading…