Skip to content

Avoid exposed provenance#19

Merged
yvt merged 5 commits intomainfrom
fix-strict-provenance
Dec 8, 2025
Merged

Avoid exposed provenance#19
yvt merged 5 commits intomainfrom
fix-strict-provenance

Conversation

@yvt
Copy link
Copy Markdown
Owner

@yvt yvt commented Dec 7, 2025

Fixes #12

@yvt
Copy link
Copy Markdown
Owner Author

yvt commented Dec 8, 2025

Edit: Opened #20


Running MIRIFLAGS='-Zmiri-track-pointer-tag=539,262350,262351,262352,262353,262354,262355,262356,262357,262406,262408,262410,262412,262415,262417,262515,262518,262520,262523,262525,262528,262529,262538,262661,262662,262664,262669,262666 -Zmiri-track-alloc-accesses -Zmiri-track-alloc-id=469' cargo +nightly miri test -p rlsf --test global locally with a provenance-slicing patch (unpublished) for debugging:

error: Undefined Behavior: not granting access to tag <539> because that would remove [Unique for <262669>] which is weakly protected
    --> [..]/rlsf/crates/rlsf/src/tlsf.rs:380:9
     |
 380 |         *nn_field!(block, next_free) = next_free;
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
     |
     = 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
Details
help: <539> was created here, as the root tag for alloc469
    --> [..]/rlsf/crates/rlsf/src/global/unix.rs:82:19
     |
  82 |           let ptr = libc::mmap(
     |  ___________________^
  83 | |             null_mut(),
  84 | |             num_bytes,
  85 | |             libc::PROT_WRITE | libc::PROT_READ,
...    |
  88 | |             0,
  89 | |         );
     | |_________^
help: <262669> is this argument
    --> [..]/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/lifecycle.rs:151:17
     |
 151 |     pub fn init(self: Box<Self>) -> Box<dyn FnOnce() + Send> {
     |                 ^^^^
     = note: BACKTRACE (of the first span) on thread `foo`:
     = note: inside `rlsf::Tlsf::<'_, usize, usize, 64, 64>::link_free_block` at [..]/rlsf/crates/rlsf/src/tlsf.rs:380:9: 380:49
note: inside `rlsf::Tlsf::<'_, usize, usize, 64, 64>::deallocate_block`
    --> [..]/rlsf/crates/rlsf/src/tlsf.rs:1095:9
     |
1095 |         self.link_free_block(block, size);
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `rlsf::Tlsf::<'_, usize, usize, 64, 64>::deallocate`
    --> [..]/rlsf/crates/rlsf/src/tlsf.rs:1007:9
     |
1007 |         self.deallocate_block(block);
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `rlsf::FlexTlsf::<rlsf::global::unix::Source<rlsf::SmallGlobalTlsfOptions>, usize, usize, 64, 64>::deallocate`
    --> [..]/rlsf/crates/rlsf/src/flex.rs:545:9
     |
 545 |         self.tlsf.deallocate(ptr, align)
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `<rlsf::GlobalTlsf<rlsf::SmallGlobalTlsfOptions> as std::alloc::GlobalAlloc>::dealloc`
    --> [..]/rlsf/crates/rlsf/src/global.rs:196:9
     |
 196 |         inner.deallocate(ptr, layout.align());
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `_::__rust_dealloc`
    --> crates/rlsf/tests/global.rs:7:11
     |
   5 | #[global_allocator]
     | ------------------- in this attribute macro expansion
   6 | #[cfg(any(all(target_arch = "wasm32", not(target_feature = "atomics")), unix))]
   7 | static A: rlsf::SmallGlobalTlsf = rlsf::SmallGlobalTlsf::new();
     |           ^^^^^^^^^^^^^^^^^^^^^

The Miri logged an error error when ThreadInit::init was deallocatating self: Box<Self> at the end of the scope:

impl ThreadInit {
    /// Initialize the 'current thread' mechanism on this thread, returning the
    /// Rust entry point.
    pub fn init(self: Box<Self>) -> Box<dyn FnOnce() + Send> {
        // ...

        self.rust_start
    }  // <<<<<<< `self` is deallocated here
}

This looks like a false positive. Miri somehow thinks *self (address 816..840) is still "weakly protected" at this point, so when the deallocation code tried to write free-block metadata (FreeBlockHdr::next_free) to 816..824, Miri got very upset.

All memory accesses performed during deallocation
note: read access at alloc469[800..808]
    --> [..]/rlsf/crates/rlsf/src/tlsf.rs:145:20
     |
 145 |         let size = (*this).size;
     |                    ^^^^^^^^^^^^ tracking was triggered here
     |

note: read access at alloc469[864..872]
    --> [..]/rlsf/crates/rlsf/src/tlsf.rs:1044:46
     |
1044 |         let next_phys_block_size_and_flags = next_phys_block.as_ref().size;
     |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tracking was triggered here
     |

note: read access at alloc469[808..816]
    --> [..]/rlsf/crates/rlsf/src/tlsf.rs:1066:40
     |
1066 |         if let Some(prev_phys_block) = block.as_ref().prev_phys_block {
     |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tracking was triggered here
     |

note: read access at alloc469[808..816]
    --> [..]/rlsf/crates/rlsf/src/tlsf.rs:1066:21
     |
1066 |         if let Some(prev_phys_block) = block.as_ref().prev_phys_block {
     |                     ^^^^^^^^^^^^^^^ tracking was triggered here
     |

note: read access at alloc469[736..744]
    --> [..]/rlsf/crates/rlsf/src/tlsf.rs:1067:50
     |
1067 |             let prev_phys_block_size_and_flags = prev_phys_block.as_ref().size;
     |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tracking was triggered here
     |

note: write access at alloc469[800..808]
    --> [..]/rlsf/crates/rlsf/src/tlsf.rs:1091:9
     |
1091 |         block.as_mut().size = size;
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ tracking was triggered here
     |

note: write access at alloc469[816..824]
    --> [..]/rlsf/crates/rlsf/src/tlsf.rs:380:9
     |
 380 |         *nn_field!(block, next_free) = next_free;
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tracking was triggered here
     |
$ rustc +nightly --version
rustc 1.93.0-nightly (1d60f9e07 2025-12-01)

@yvt yvt force-pushed the fix-strict-provenance branch from 694fc1e to fe9f384 Compare December 8, 2025 02:26
yvt added 2 commits December 8, 2025 13:17
> Round `ptr`'s address down to the previous `align` bytes boundary.

> Round `ptr`'s address up to the next `align` bytes boundary.
…n,up}`

`pointer::map_addr` preserves the provenance of the original pointer.
@yvt yvt force-pushed the fix-strict-provenance branch from 2de228a to 7404284 Compare December 8, 2025 04:17
@yvt yvt marked this pull request as ready for review December 8, 2025 04:19
yvt added 3 commits December 8, 2025 13:28
Integer-to-pointer casts are not supported in Strict Provenance and
generates warnings when running in Miri.
Use `std::ptr::without_provenance_mut` instead of integer-to-pointer
cast to avoid Miri warnings.
Work-around for false positive in Miri (#20)
@yvt yvt force-pushed the fix-strict-provenance branch from 7404284 to 7712f27 Compare December 8, 2025 04:28
@yvt yvt merged commit 03664d5 into main Dec 8, 2025
7 checks passed
@yvt yvt deleted the fix-strict-provenance branch December 8, 2025 12:02
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

Successfully merging this pull request may close these issues.

Stop relying on exposed provenance

1 participant