Skip to content

Potential Undefined Behavior in Unsound Function index_of_ptr #52

@lewismosciski

Description

@lewismosciski

Hello,

We are developing a static analysis tool for Rust, and our tool flagged a potential soundness issue in the public safe function index_of_ptr.

pub fn index_of_ptr<T>(slice: &[T], element_ptr: *const T) -> Option<usize> {
let element_ptr = element_ptr as usize;
let ptr = slice.as_ptr();
let ptr_beg = ptr as usize;
if element_ptr < ptr_beg {
None
} else {
let ptr_end = (unsafe { ptr.add(slice.len() - 1) }) as usize;

The function appears to cause Undefined Behavior when called with an empty slice. The line ptr.add(slice.len() - 1) underflows when slice.len() is 0. According to Rust's safety rules, creating a pointer with such a massive offset is immediate UB, which violates the core guarantee that a safe function cannot cause UB on any input.

This was confirmed with cargo miri. We've included the PoC and Miri's output below for your reference.

POC:

use orx_pinned_vec::utils::slice::index_of_ptr;
fn main() {
    let slice: &[u8] = &[]; 
    let ptr_to_check = slice.as_ptr();
    let _ = index_of_ptr(slice, ptr_to_check);
}

Miri's output:

ccuu@ccuu:~/rust/rtest/nnl_test$ cargo +nightly miri run --release
    Finished `release` profile [optimized] target(s) in 0.01s
     Running `/home/ccuu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/release/nnl_test`
warning: Miri does not support optimizations: the opt-level is ignored. The only effect of selecting a Cargo profile that enables optimizations (such as --release) is to apply its remaining settings, such as whether debug assertions and overflow checks are enabled.

error: Undefined Behavior: overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`
  --> /home/ccuu/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/orx-pinned-vec-3.10.0/src/utils/slice.rs:39:33
   |
39 |         let ptr_end = (unsafe { ptr.add(slice.len() - 1) }) as usize;
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
   |
   = 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:
   = note: inside `orx_pinned_vec::utils::slice::index_of_ptr::<u8>` at /home/ccuu/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/orx-pinned-vec-3.10.0/src/utils/slice.rs:39:33: 39:57
note: inside `main`
  --> src/main.rs:5:13
   |
 5 |     let _ = index_of_ptr(slice, ptr_to_check);
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

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

error: aborting due to 1 previous error; 1 warning emitted

A simple check such as if slice.is_empty() { return None; } at the beginning of the function could be a potential fix for this soundness hole.

Thank you for your time and for maintaining this library.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions