Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

try_transmute_mut, TryFromBytes::*mut* soundness issue #2226

Open
4 of 6 tasks
zeling opened this issue Jan 10, 2025 · 3 comments
Open
4 of 6 tasks

try_transmute_mut, TryFromBytes::*mut* soundness issue #2226

zeling opened this issue Jan 10, 2025 · 3 comments

Comments

@zeling
Copy link
Member

zeling commented Jan 10, 2025

Progress

  • Add Src: FromBytes bound to try_transmute_mut!
  • Release new crate version (0.8.16)
  • Add Self: IntoBytes bound to TryFromBytes::*mut*
    • For why this is required, consider that a MaybeUninit<u8> is TryFromBytes, but permits writing uninitialized bytes that would invalidated the shadowed src reference.
  • Release new crate version (0.8.18)
  • Yank old affected versions
  • Do deeper surgery to make try_cast_or_pme sound and TryFromBytes::*mut* sound

Original text

Using zerocopy 0.8.13:

use zerocopy::{TryFromBytes, IntoBytes, KnownLayout, Immutable, try_transmute_mut};

#[derive(TryFromBytes, IntoBytes, KnownLayout, Immutable)]
struct T {
    f: bool,
}

fn main() {
    let mut t = T { f: false };
    let slice: &mut [u8; 1] = try_transmute_mut!(&mut t).unwrap();

    slice[0] = u8::MAX;
    println!("f: {}", t.f);
}

cargo +nightly miri run caught an UB:

error: Undefined Behavior: constructing invalid value: encountered 0xff, but expected a boolean
    --> /home/zeling/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt/mod.rs:2682:25
     |
2682 |         Display::fmt(if *self { "true" } else { "false" }, f)
     |                         ^^^^^ constructing invalid value: encountered 0xff, but expected a boolean
     |
     = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
     = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
     = note: BACKTRACE:
....
     |
13   |     println!("f: {}", t.f);
     |     ^^^^^^^^^^^^^^^^^^^^^^
     = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

try_transmute_mut may not be a safe API that can be exposed because it only does validation when creating the reference but the user is free to write whatever bit pattern to the created reference.

@jswrenn
Copy link
Collaborator

jswrenn commented Jan 11, 2025

Ack; thanks for the report. It looks like we're missing a FromBytes bound on the source. I'll have a fix up this evening.

jswrenn added a commit that referenced this issue Jan 12, 2025
Ensures that the source reference remains valid after the
transmuted (and possibly mutated)  destination is dropped.

Fixes #2226
jswrenn added a commit that referenced this issue Jan 12, 2025
Ensures that the source reference remains valid after the
transmuted (and possibly mutated)  destination is dropped.

Fixes #2226
jswrenn added a commit that referenced this issue Jan 12, 2025
Ensures that the source reference remains valid after the
transmuted (and possibly mutated)  destination is dropped.

Fixes #2226
jswrenn added a commit that referenced this issue Jan 27, 2025
Ensures that the source reference remains valid after the
transmuted (and possibly mutated)  destination is dropped.

Makes progress on #2226
jswrenn added a commit that referenced this issue Feb 4, 2025
Ensures that the source reference remains valid after the
transmuted (and possibly mutated)  destination is dropped.

Makes progress on #2226
github-merge-queue bot pushed a commit that referenced this issue Feb 4, 2025
Ensures that the source reference remains valid after the
transmuted (and possibly mutated)  destination is dropped.

Makes progress on #2226
@joshlf
Copy link
Member

joshlf commented Feb 4, 2025

#2229, which fixes this issue at a surface level (it's sound, but doesn't fix the underlying internals that allowed this to slip through) is published in 0.8.16.

@jswrenn jswrenn changed the title try_transmute_mut soundness issue try_transmute_mut, TryTransmuteFrom::*mut* soundness issue Feb 11, 2025
@jswrenn
Copy link
Collaborator

jswrenn commented Feb 11, 2025

The underlying issue that led to us not enforce a FromBytes bound on try_transmute_mut also led us to omit a Self: IntoBytes bound on TryFromBytes's mut methods. Our intention is to release a surface-level fix in 0.8, and then overhaul Ptr in 0.9 to make such mistakes less likely (see #1866).

@jswrenn jswrenn changed the title try_transmute_mut, TryTransmuteFrom::*mut* soundness issue try_transmute_mut, TryFromBytes::*mut* soundness issue Feb 11, 2025
jswrenn added a commit that referenced this issue Feb 11, 2025
Consider that `MaybeUninit<u8>` is `TryFromBytes`. If a `&mut [u8]`
is cast into a `&mut MaybeUninit<u8>`, then uninit bytes are written,
the shadowed `&mut [u8]`'s referent will no longer be valid.

Makes progress towards #2226 and #1866.
joshlf pushed a commit that referenced this issue Feb 14, 2025
Consider that `MaybeUninit<u8>` is `TryFromBytes`. If a `&mut [u8]`
is cast into a `&mut MaybeUninit<u8>`, then uninit bytes are written,
the shadowed `&mut [u8]`'s referent will no longer be valid.

Makes progress towards #2226 and #1866.

gherrit-pr-id: Ib233c4d0643e0690c53a37a08d9845e5fe43249c
joshlf pushed a commit that referenced this issue Feb 14, 2025
Consider that `MaybeUninit<u8>` is `TryFromBytes`. If a `&mut [u8]`
is cast into a `&mut MaybeUninit<u8>`, then uninit bytes are written,
the shadowed `&mut [u8]`'s referent will no longer be valid.

Makes progress towards #2226 and #1866.

gherrit-pr-id: Ib233c4d0643e0690c53a37a08d9845e5fe43249c
joshlf pushed a commit that referenced this issue Feb 14, 2025
Consider that `MaybeUninit<u8>` is `TryFromBytes`. If a `&mut [u8]`
is cast into a `&mut MaybeUninit<u8>`, then uninit bytes are written,
the shadowed `&mut [u8]`'s referent will no longer be valid.

Makes progress towards #2226 and #1866.

gherrit-pr-id: Ib233c4d0643e0690c53a37a08d9845e5fe43249c
joshlf pushed a commit that referenced this issue Feb 14, 2025
Consider that `MaybeUninit<u8>` is `TryFromBytes`. If a `&mut [u8]`
is cast into a `&mut MaybeUninit<u8>`, then uninit bytes are written,
the shadowed `&mut [u8]`'s referent will no longer be valid.

Makes progress towards #2226 and #1866.

gherrit-pr-id: Ib233c4d0643e0690c53a37a08d9845e5fe43249c
joshlf pushed a commit that referenced this issue Feb 14, 2025
Ensures that the source reference remains valid after the
transmuted (and possibly mutated)  destination is dropped.

Makes progress on #2226

gherrit-pr-id: I425e7d5103cb3b2a9e7107bf9df0743dca2e08cb
joshlf pushed a commit that referenced this issue Feb 14, 2025
Consider that `MaybeUninit<u8>` is `TryFromBytes`. If a `&mut [u8]`
is cast into a `&mut MaybeUninit<u8>`, then uninit bytes are written,
the shadowed `&mut [u8]`'s referent will no longer be valid.

Makes progress towards #2226 and #1866.

gherrit-pr-id: Ib233c4d0643e0690c53a37a08d9845e5fe43249c
github-merge-queue bot pushed a commit that referenced this issue Feb 14, 2025
Consider that `MaybeUninit<u8>` is `TryFromBytes`. If a `&mut [u8]`
is cast into a `&mut MaybeUninit<u8>`, then uninit bytes are written,
the shadowed `&mut [u8]`'s referent will no longer be valid.

Makes progress towards #2226 and #1866.

gherrit-pr-id: Ib233c4d0643e0690c53a37a08d9845e5fe43249c
joshlf pushed a commit that referenced this issue Feb 14, 2025
Consider that `MaybeUninit<u8>` is `TryFromBytes`. If a `&mut [u8]`
is cast into a `&mut MaybeUninit<u8>`, then uninit bytes are written,
the shadowed `&mut [u8]`'s referent will no longer be valid.

Makes progress towards #2226 and #1866.

gherrit-pr-id: Ib233c4d0643e0690c53a37a08d9845e5fe43249c
github-merge-queue bot pushed a commit that referenced this issue Feb 14, 2025
…ryFromBytes::try_mut*` (#2343)

* Enforce `Src: FromBytes` in `try_transmute_mut!` (#2229)

Ensures that the source reference remains valid after the
transmuted (and possibly mutated)  destination is dropped.

Makes progress on #2226

gherrit-pr-id: I425e7d5103cb3b2a9e7107bf9df0743dca2e08cb

* Add `Self: IntoBytes` bound to `TryFromBytes::try_mut*`

Consider that `MaybeUninit<u8>` is `TryFromBytes`. If a `&mut [u8]`
is cast into a `&mut MaybeUninit<u8>`, then uninit bytes are written,
the shadowed `&mut [u8]`'s referent will no longer be valid.

Makes progress towards #2226 and #1866.

gherrit-pr-id: Ib233c4d0643e0690c53a37a08d9845e5fe43249c

---------

Co-authored-by: Jack Wrenn <[email protected]>
Co-authored-by: Jack Wrenn <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants