-
Notifications
You must be signed in to change notification settings - Fork 236
Description
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.
Line 335 in 423703f
| 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!