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

[Unsound] Slice created from unaligned pointer #232

Open
shinmao opened this issue Oct 2, 2023 · 8 comments
Open

[Unsound] Slice created from unaligned pointer #232

shinmao opened this issue Oct 2, 2023 · 8 comments
Assignees

Comments

@shinmao
Copy link

shinmao commented Oct 2, 2023

Hi, I am the security researcher from SunLab. I am testing our personal tools on open-source repositories and find the following unsound implemenation.

The source of unsoundness

pprof-rs/src/collector.rs

Lines 223 to 225 in 4939f73

let length = self.file_vec.len() / std::mem::size_of::<T>();
let ts =
unsafe { std::slice::from_raw_parts(self.file_vec.as_ptr() as *const T, length) };

The function would cast file_vec which is aligned to 1 byte to the specified type, and the function can be called by try_iter() on Collector. The specified type can be decided the items in Collector. In other words, if we add the element which is aligned to more than 1 byte to the Collector, the unaligned pointer would be created and used to build the slice, which breaks the safety guarantee of slice::from_raw_parts.

This is how it could work:

fn main() {
    let a: u16 = 1;     // aligned to 2 bytes
    let mut c = Collector::new().unwrap();
    let _ = c.add(a, 1isize);
    c.try_iter().unwrap().for_each(|entry| {
        println!("{:?}", entry);
    });
}

try_iter() will call next with T as u16.

@shinmao shinmao changed the title [Unsound] Slice created from unaligned pointer in next [Unsound] Slice created from unaligned pointer Oct 2, 2023
@shinmao
Copy link
Author

shinmao commented Oct 2, 2023

We consider that the public safe api addr_validate::validate could also have the unsoundness:

let write_fd = MEM_VALIDATE_PIPE.write_fd.load(Ordering::SeqCst);
loop {
let buf = unsafe { std::slice::from_raw_parts(addr as *const u8, CHECK_LENGTH) };
match write(write_fd, buf) {
Ok(bytes) => break bytes > 0,

This function allows casting c_void input to u8 pointer. However, based on the safety guarantee of from_raw_parts, caller should make sure the pointer is initialized for consecutive length. Here, we could cast arbitrary types to c_void and pass to this function which will make uninitialized memory exposure.

This is how it works:

use core::ffi::c_void;
use pprof::validate;

#[repr(align(256))]
#[derive(Copy, Clone, Debug)]
struct Padding {
    a: u8,
    b: u32,
    c: u8,
}

fn main() {
    let pd = Padding { a: 10, b: 11, c: 12 };
    println!("{}", validate(&pd as *const Padding as *const c_void));
}

@jdsaund
Copy link

jdsaund commented Feb 18, 2024

We're also experience this issue on macos m2. The PR solves it, will it get merged soon?

@finnbear
Copy link

finnbear commented Apr 30, 2024

After updating to a recent nightly compiler, I observed the following related panic on pprof@0.12.0 (debug build) as a result:

thread 'main' panicked at library/core/src/panicking.rs:215:5:
unsafe precondition(s) violated: slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`
stack backtrace:
   0: rust_begin_unwind
             at /rustc/f9b16149208c8a8a349c32813312716f6603eb6f/library/std/src/panicking.rs:652:5
   1: core::panicking::panic_nounwind_fmt::runtime
             at /rustc/f9b16149208c8a8a349c32813312716f6603eb6f/library/core/src/panicking.rs:110:18
   2: core::panicking::panic_nounwind_fmt
             at /rustc/f9b16149208c8a8a349c32813312716f6603eb6f/library/core/src/panicking.rs:120:5
   3: core::panicking::panic_nounwind
             at /rustc/f9b16149208c8a8a349c32813312716f6603eb6f/library/core/src/panicking.rs:215:5
   4: core::slice::raw::from_raw_parts::precondition_check
             at /rustc/f9b16149208c8a8a349c32813312716f6603eb6f/library/core/src/ub_checks.rs:66:21
   5: core::slice::raw::from_raw_parts
             at /rustc/f9b16149208c8a8a349c32813312716f6603eb6f/library/core/src/slice/raw.rs:96:9
   6: <pprof::collector::TempFdArrayIterator<T> as core::iter::traits::iterator::Iterator>::next
             at /home/finnb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/pprof-0.12.0/src/collector.rs:225:26
   7: core::iter::traits::iterator::Iterator::fold
             at /rustc/f9b16149208c8a8a349c32813312716f6603eb6f/library/core/src/iter/traits/iterator.rs:2586:29
   8: <core::iter::adapters::chain::Chain<A,B> as core::iter::traits::iterator::Iterator>::fold
             at /rustc/f9b16149208c8a8a349c32813312716f6603eb6f/library/core/src/iter/adapters/chain.rs:93:19
   9: core::iter::traits::iterator::Iterator::for_each
             at /rustc/f9b16149208c8a8a349c32813312716f6603eb6f/library/core/src/iter/traits/iterator.rs:817:9
  10: pprof::report::ReportBuilder::build
             at /home/finnb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/pprof-0.12.0/src/report.rs:110:17

Edit: The linked PR resolved the issue! ❤️

@markmandel
Copy link

Just ran into this issue on upgrade to Rust 1.78.0. We can't upgrade beyond 1.77.x at this time with this bug in place.

You can see it failing here: https://github.com/googleforgames/quilkin/actions/runs/9375621368/job/25814057518?pr=974 (since writing I've likely downgraded this update back to 1.77.1)

markmandel added a commit to markmandel/quilkin that referenced this issue Jun 5, 2024
* There's a joseluisq/rust-linux-darwin-builder:1.77.1 image, but no
  1.77.0 image 🤷🏻‍♂️ - so need to update so we can release macos
  binaries.
* Can't upgrade to 1.78.0 because of
  tikv/pprof-rs#232
XAMPPRocky pushed a commit to googleforgames/quilkin that referenced this issue Jun 5, 2024
* Build tooling updates and fixes.

I stared with documenting how to regenerate protos, and found a few
things that were blocking release, and also was just broken.

So this PR includes:

* Documenting how to regenerate protos with `cargo` and `make`.
* `make` targets for generating protobuf
* Fixes and updates for build tooling for release.
* Updates to rust version - which aligns with the available darwin
  builder image tags.
* Replace `live-server` which broke as unmaintained with `browser-sync`
  which is also way better.

* * Fixes for lint issues.

* Rollback to rust 1.77.1

* There's a joseluisq/rust-linux-darwin-builder:1.77.1 image, but no
  1.77.0 image 🤷🏻‍♂️ - so need to update so we can release macos
  binaries.
* Can't upgrade to 1.78.0 because of
  tikv/pprof-rs#232
XAMPPRocky pushed a commit to googleforgames/quilkin that referenced this issue Jun 10, 2024
* Build tooling updates and fixes.

I stared with documenting how to regenerate protos, and found a few
things that were blocking release, and also was just broken.

So this PR includes:

* Documenting how to regenerate protos with `cargo` and `make`.
* `make` targets for generating protobuf
* Fixes and updates for build tooling for release.
* Updates to rust version - which aligns with the available darwin
  builder image tags.
* Replace `live-server` which broke as unmaintained with `browser-sync`
  which is also way better.

* * Fixes for lint issues.

* Rollback to rust 1.77.1

* There's a joseluisq/rust-linux-darwin-builder:1.77.1 image, but no
  1.77.0 image 🤷🏻‍♂️ - so need to update so we can release macos
  binaries.
* Can't upgrade to 1.78.0 because of
  tikv/pprof-rs#232
XAMPPRocky added a commit to googleforgames/quilkin that referenced this issue Jun 10, 2024
* wip

* Checkpoint

* Ignore for now

* Fixup tests

* Update quilkin

* Cleanup

* Fix formatting

* Simplify apply_delta

* Add example

* Build tooling updates and fixes. (#974)

* Build tooling updates and fixes.

I stared with documenting how to regenerate protos, and found a few
things that were blocking release, and also was just broken.

So this PR includes:

* Documenting how to regenerate protos with `cargo` and `make`.
* `make` targets for generating protobuf
* Fixes and updates for build tooling for release.
* Updates to rust version - which aligns with the available darwin
  builder image tags.
* Replace `live-server` which broke as unmaintained with `browser-sync`
  which is also way better.

* * Fixes for lint issues.

* Rollback to rust 1.77.1

* There's a joseluisq/rust-linux-darwin-builder:1.77.1 image, but no
  1.77.0 image 🤷🏻‍♂️ - so need to update so we can release macos
  binaries.
* Can't upgrade to 1.78.0 because of
  tikv/pprof-rs#232

* Update agent documentation (#976)

Removes some outdated terminology and corrects incorrectly calling configuration sources control planes.

---------

Co-authored-by: Jake Shadle <jake.shadle@embark-studios.com>
Co-authored-by: Mark Mandel <markmandel@google.com>
@vorporeal
Copy link

Hi @YangKeao - this crate is currently broken for many users due to this (note that #250 is another report of this issue).

Can you take a look at PR #241? Without it, users of this crate are going to have to start forking it in order to have working pprof for their applications.

@markmandel
Copy link

Travelling at the moment, but anyone tried engaging on their Slack to see if we can get traction for this fix?

@plugwash
Copy link

Hi @YangKeao - this crate is currently broken for many users due to this (note that #250 is another report of this issue).

Afaict there are two seperate soundness issues, the one in collector.rs mentioned in the first post of this issue, and the one in addr_validate.rs mentioned in the second post of this issue and in issue #250.

It is the latter that is causing the testsuite to fail with recent rustc.

@shinmao
Copy link
Author

shinmao commented Aug 17, 2024

Hi, in this way, does it mean that any use of guard.report().build() will trigger panic in the program? Or panic will only be triggered in specific environment by core::slice::raw::from_raw_parts::precondition_check?

let guard = pprof::ProfilerGuardBuilder::default()
    .frequency(self.frequency)
    .blocklist(&["libc", "libgcc", "pthread", "vdso"])
    .build()
    .context(CreateGuardSnafu)?;
// ...
guard.report().build().context(CreateReportSnafu)

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

7 participants