Dear Stratis Storage Team,
I hope this email finds you well. I am writing to report a potential
Use-After-Free (UAF) vulnerability identified in the `libblkid-rs` library.
Vulnerability Details:
Library: libblkid-rs
Type: Use-After-Free (UAF)
Description: In the function below, this line of code
`filename_cstring.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut())` generates
a dangling pointer as a parameter when calling
libblkid_rs_sys::blkid_get_cache(), leading to a UAF vulnerability.
```
pub fn get_cache(filename: Option<&Path>) -> Result<Self> {
let mut cache = ptr::null_mut();
let filename_cstring = match filename {
Some(fname) =>
Some(CString::new(fname.to_str().ok_or(BlkidErr::InvalidConv)?)?),
None => None,
};
errno!(unsafe {
libblkid_rs_sys::blkid_get_cache(
&mut cache as *mut _,
filename_cstring
.map(|s| s.as_ptr())
.unwrap_or(ptr::null_mut()),
)
})?;
Ok(BlkidCache(cache, false))
}
```
Steps to Reproduce:
1. Compile the following code with `libblkid-rs = "0.3.2"`:
```
use libblkid_rs::BlkidCache;
use std::path::Path;
fn main() {
let cache_file_path = Some(Path::new("/dev"));
let cache = BlkidCache::get_cache(cache_file_path).expect("msg");
}
```
2. Run the compiled code with Valgrind to observe the UAF issue.
```
==3115644== 1 errors in context 1 of 1:
==3115644== Invalid read of size 1
==3115644== at 0x487DEED: blkid_get_cache (in
/usr/lib/x86_64-linux-gnu/libblkid.so.1.1.0)
==3115644== by 0x121A51: libblkid_rs::cache::BlkidCache::get_cache (
cache.rs:46)
==3115644== by 0x120971: test1::main (main.rs:8)
==3115644== by 0x12133A: core::ops::function::FnOnce::call_once (
function.rs:250)
==3115644== by 0x1209DD:
std::sys::backtrace::__rust_begin_short_backtrace (backtrace.rs:152)
==3115644== by 0x1205F0: std::rt::lang_start::{{closure}} (rt.rs:195)
==3115644== by 0x13DF76: call_once<(), (dyn core::ops::function::Fn<(),
Output=i32> + core::marker::Sync +
core::panic::unwind_safe::RefUnwindSafe)> (function.rs:284)
==3115644== by 0x13DF76: do_call<&(dyn core::ops::function::Fn<(),
Output=i32> + core::marker::Sync +
core::panic::unwind_safe::RefUnwindSafe), i32> (panicking.rs:573)
==3115644== by 0x13DF76: try<i32, &(dyn core::ops::function::Fn<(),
Output=i32> + core::marker::Sync +
core::panic::unwind_safe::RefUnwindSafe)> (panicking.rs:536)
==3115644== by 0x13DF76: catch_unwind<&(dyn core::ops::function::Fn<(),
Output=i32> + core::marker::Sync +
core::panic::unwind_safe::RefUnwindSafe), i32> (panic.rs:358)
==3115644== by 0x13DF76: {closure#1} (rt.rs:174)
==3115644== by 0x13DF76:
do_call<std::rt::lang_start_internal::{closure_env#1}, isize> (
panicking.rs:573)
==3115644== by 0x13DF76: try<isize,
std::rt::lang_start_internal::{closure_env#1}> (panicking.rs:536)
==3115644== by 0x13DF76:
catch_unwind<std::rt::lang_start_internal::{closure_env#1}, isize> (
panic.rs:358)
==3115644== by 0x13DF76: std::rt::lang_start_internal (rt.rs:174)
==3115644== by 0x1205C9: std::rt::lang_start (rt.rs:194)
==3115644== by 0x1209CD: main (in
/rust/test-libblkid/test1/target/debug/test1)
==3115644== Address 0x4afb8f0 is 0 bytes inside a block of size 5 free'd
==3115644== at 0x483FB3B: free (vg_replace_malloc.c:985)
==3115644== by 0x122735: dealloc (alloc.rs:116)
==3115644== by 0x122735: <alloc::alloc::Global as
core::alloc::Allocator>::deallocate (alloc.rs:269)
==3115644== by 0x122FCE: <alloc::boxed::Box<T,A> as
core::ops::drop::Drop>::drop (boxed.rs:1678)
==3115644== by 0x122D48:
core::ptr::drop_in_place<alloc::boxed::Box<[u8]>> (mod.rs:522)
==3115644== by 0x122C2F:
core::ptr::drop_in_place<alloc::ffi::c_str::CString> (mod.rs:522)
==3115644== by 0x121D54:
libblkid_rs::cache::BlkidCache::get_cache::{{closure}} (cache.rs:49)
==3115644== by 0x121DE8: core::option::Option<T>::map (option.rs:1113)
==3115644== by 0x121A33: libblkid_rs::cache::BlkidCache::get_cache (
cache.rs:48)
==3115644== by 0x120971: test1::main (main.rs:8)
==3115644== by 0x12133A: core::ops::function::FnOnce::call_once (
function.rs:250)
==3115644== by 0x1209DD:
std::sys::backtrace::__rust_begin_short_backtrace (backtrace.rs:152)
==3115644== by 0x1205F0: std::rt::lang_start::{{closure}} (rt.rs:195)
==3115644== Block was alloc'd at
==3115644== at 0x483C7F5: malloc (vg_replace_malloc.c:442)
==3115644== by 0x15D1A0: alloc (alloc.rs:96)
==3115644== by 0x15D1A0: alloc_impl (alloc.rs:192)
==3115644== by 0x15D1A0: allocate (alloc.rs:254)
==3115644== by 0x15D1A0: try_allocate_in<alloc::alloc::Global> (
raw_vec.rs:474)
==3115644== by 0x15D1A0: with_capacity_in<alloc::alloc::Global> (
raw_vec.rs:420)
==3115644== by 0x15D1A0: with_capacity_in<u8, alloc::alloc::Global> (
raw_vec.rs:192)
==3115644== by 0x15D1A0: with_capacity_in<u8, alloc::alloc::Global> (
mod.rs:803)
==3115644== by 0x15D1A0: with_capacity<u8> (mod.rs:483)
==3115644== by 0x15D1A0: spec_new_impl_bytes (c_str.rs:283)
==3115644== by 0x15D1A0: <&str as
alloc::ffi::c_str::CString::new::SpecNewImpl>::spec_new_impl (c_str.rs:302)
==3115644== by 0x122DCA: alloc::ffi::c_str::CString::new (c_str.rs:312)
==3115644== by 0x121AA6: libblkid_rs::cache::BlkidCache::get_cache (
cache.rs:42)
==3115644== by 0x120971: test1::main (main.rs:8)
==3115644== by 0x12133A: core::ops::function::FnOnce::call_once (
function.rs:250)
==3115644== by 0x1209DD:
std::sys::backtrace::__rust_begin_short_backtrace (backtrace.rs:152)
==3115644== by 0x1205F0: std::rt::lang_start::{{closure}} (rt.rs:195)
==3115644== by 0x13DF76: call_once<(), (dyn core::ops::function::Fn<(),
Output=i32> + core::marker::Sync +
core::panic::unwind_safe::RefUnwindSafe)> (function.rs:284)
==3115644== by 0x13DF76: do_call<&(dyn core::ops::function::Fn<(),
Output=i32> + core::marker::Sync +
core::panic::unwind_safe::RefUnwindSafe), i32> (panicking.rs:573)
==3115644== by 0x13DF76: try<i32, &(dyn core::ops::function::Fn<(),
Output=i32> + core::marker::Sync +
core::panic::unwind_safe::RefUnwindSafe)> (panicking.rs:536)
==3115644== by 0x13DF76: catch_unwind<&(dyn core::ops::function::Fn<(),
Output=i32> + core::marker::Sync +
core::panic::unwind_safe::RefUnwindSafe), i32> (panic.rs:358)
==3115644== by 0x13DF76: {closure#1} (rt.rs:174)
==3115644== by 0x13DF76:
do_call<std::rt::lang_start_internal::{closure_env#1}, isize> (
panicking.rs:573)
==3115644== by 0x13DF76: try<isize,
std::rt::lang_start_internal::{closure_env#1}> (panicking.rs:536)
==3115644== by 0x13DF76:
catch_unwind<std::rt::lang_start_internal::{closure_env#1}, isize> (
panic.rs:358)
==3115644== by 0x13DF76: std::rt::lang_start_internal (rt.rs:174)
==3115644== by 0x1205C9: std::rt::lang_start (rt.rs:194)
==3115644== by 0x1209CD: main (in
/rust/test-libblkid/test1/target/debug/test1)
```
Suggested Fix:
Change this line of code `filename_cstring.map(|s|
s.as_ptr()).unwrap_or(ptr::null_mut())` into
`filename_cstring.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut())`
Please let me know if you need any further information or assistance.
Thank you for your attention to this issue.
Best regards,
Quitbug