Skip to content

[Unsoundness] Undefined Behavior in public API alloc_buf due to uninitialized memory usage #1814

@lwz23

Description

@lwz23

Problem Summary

Hello,
While working on a static analysis tool designed to detect unsoundness and safety violations in Rust projects, we discovered a soundness issue in your codebase.

Location:
The vulnerability is located in the public function alloc_buf within storage/src/utils.rs. Since utils is a public module and alloc_buf is a public function, this unsound API is exposed to external crates and users.

let layout = Layout::from_size_align(size, 0x1000)

Description:
The function alloc_buf allocates memory using std::alloc::alloc, which returns uninitialized memory. However, it subsequently constructs a Vec from this pointer using Vec::from_raw_parts, setting the vector's length to size.
According to the safety contract of Vec::from_raw_parts:
The elements in the range [ptr, ptr + len) must be initialized.
Since the memory allocated by alloc is not initialized, returning this Vec allows safe code to read uninitialized memory, resulting in Undefined Behavior (UB).

Proof of Concept (PoC):
We have created a reproduction script. Running this code under Miri (Rust's interpreter for detecting UB) confirms the issue.

use std::alloc::{alloc, Layout};

// Extracted from storage/src/utils.rs
pub fn alloc_buf(size: usize) -> Vec<u8> {
    assert!(size < isize::MAX as usize);
    let layout = Layout::from_size_align(size, 0x1000)
        .unwrap()
        .pad_to_align();
    let ptr = unsafe { alloc(layout) };
    
    // UNSOUND: `ptr` points to uninitialized memory, but `len` is set to `size`.
    unsafe { Vec::from_raw_parts(ptr, size, layout.size()) }
}

fn main() {
    // PoC: reading from the returned Vec triggers Miri because the memory is
    // uninitialized yet marked as fully initialized via the Vec length.
    let buf = alloc_buf(16);
    
    // This safe operation triggers UB
    let first = buf[0];
    
    // Suppress unused warning
    let _ = first; 
}

miri output:

error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
  --> src\main.rs:16:17
   |
16 |     let first = buf[0];
   |                 ^^^^^^ using uninitialized data, but this operation requires initialized memory
   |
   = 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

Proposed Improvement

Recommendation:
To fix this soundness issue, ensure the memory is initialized before setting the vector's length.
If zero-initialization is acceptable, use std::alloc::alloc_zeroed instead of alloc.
Alternatively, use ptr::write_bytes to initialize the memory with a value before creating the Vec.
Or, if performance is critical and uninitialized memory is intended, consider returning Vec<MaybeUninit> or using a safer abstraction like the bytes crate if applicable, although changing the return type is a breaking change.

Additional Context

No response

Are you willing to submit PR?

  • Yes I am willing to submit a PR!

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions