Skip to content

Heap-buffer-overflow in nftnl::Batch::with_page_size (nftnl-rs) #76

@cuiwenhao123

Description

@cuiwenhao123

A heap-buffer-overflow vulnerability exists in the Rust wrapper for libnftnl, triggered via the nftnl::Batch::with_page_size constructor. When a small or malformed page size is provided, the underlying C code allocates an insufficient buffer, leading to out-of-bounds writes during batch initialization.

Crash Information
Error Type: Heap-buffer-overflow (AddressSanitizer)
Input: 4 bytes, e.g.:

data = [255, 254, 240, 12]
data len = 4

ASan report

==2172050==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7b42c86e0040 at pc 0x563922b4b176 bp 0x7ffc4dac0090 sp 0x7ffc4dabf850
WRITE of size 4 at 0x7b42c86e0040 thread T0
    #0 0x563922b4b175 in memset /Rust-Lib-Testing/src/rust/src/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:87:3
    #1 0x7f22c93813d2 in mnl_nlmsg_put_extra_header (/lib/x86_64-linux-gnu/libmnl.so.0+0x23d2) (BuildId: 802cd79dcbdf324a4e373dfabcb6eaede0813d9a)
    #2 0x7f22c991774b in nftnl_batch_begin (/lib/x86_64-linux-gnu/libnftnl.so.11+0xb74b) (BuildId: 8751267ba57814422c1ce67b70d1392640e2fffb)
    #3 0x563922b8a5fe in nftnl::batch::Batch::write_begin_msg::hc994c1a26a827f39 /Rust-Lib-Testing/tests2/nftnl-rs/nftnl/src/batch.rs:107:18
    #4 0x563922b8a5fe in nftnl::batch::Batch::with_page_size::h05a4e8017eba0d90 /Rust-Lib-Testing/tests2/nftnl-rs/nftnl/src/batch.rs:61:9
    #5 0x563922b83325 in replay_nftnl0::test_function0::h9aa3123b4a034745 /Rust-Lib-Testing/tests2/nftnl-rs/fuzz_target/nftnl_wubfs_generic_fuzz/multipleTargets/replay_nftnl0/src/main.rs:40:23
    #6 0x563922b83325 in replay_nftnl0::main::h680382695cc4a2a9 /Rust-Lib-Testing/tests2/nftnl-rs/fuzz_target/nftnl_wubfs_generic_fuzz/multipleTargets/replay_nftnl0/src/main.rs:75:5
    #7 0x563922b7f8d2 in core::ops::function::FnOnce::call_once::h4f174a2df974819d /Rust-Lib-Testing/src/rust/library/core/src/ops/function.rs:250:5
    #8 0x563922b7f8d2 in std::sys::backtrace::__rust_begin_short_backtrace::h4d958b27e2608b20 /Rust-Lib-Testing/src/rust/library/std/src/sys/backtrace.rs:152:18
    #9 0x563922b7f8b8 in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hf29da7ae1471a052 /Rust-Lib-Testing/src/rust/library/std/src/rt.rs:199:18
    #10 0x563922bb1f14 in std::rt::lang_start_internal::h0cf56da6010e8a06 (/Rust-Lib-Testing/tests2/nftnl-rs/fuzz_target/nftnl_wubfs_generic_fuzz/multipleTargets/target/debug/replay_nftnl0+0x18bf14) (BuildId: ae369495f5b0e5b16d87bff14ba3361e81352396)
    #11 0x563922b844c3 in main (/Rust-Lib-Testing/tests2/nftnl-rs/fuzz_target/nftnl_wubfs_generic_fuzz/multipleTargets/target/debug/replay_nftnl0+0x15e4c3) (BuildId: ae369495f5b0e5b16d87bff14ba3361e81352396)
    #12 0x7f22c95ab082 in __libc_start_main /build/glibc-B3wQXB/glibc-2.31/csu/../csu/libc-start.c:308:16
    #13 0x563922a7e06d in _start (/Rust-Lib-Testing/tests2/nftnl-rs/fuzz_target/nftnl_wubfs_generic_fuzz/multipleTargets/target/debug/replay_nftnl0+0x5806d) (BuildId: ae369495f5b0e5b16d87bff14ba3361e81352396)

replay file

extern crate nftnl;
use std::ffi::{CString, CStr, OsString, OsStr};
use std::path::{PathBuf, Path};
use std::os::raw::{
c_char, c_int, c_uint, c_long, c_ulong, c_short, c_ushort,
c_longlong, c_ulonglong, c_float, c_double, c_void,
};
use std::str;
fn _to_u8(data:&[u8], index:usize)->u8 {
    if index >= data.len() {
        use std::process;
        process::exit(0);
    }
    data[index]
}

fn _to_u32(data:&[u8], index:usize)->u32 {
    if index + 3 >= data.len() {
        use std::process;
        process::exit(0);
    }
    let data0 = _to_u16(data, index) as u32;
    let data1 = _to_u16(data, index+2) as u32;
    data0 << 16 | data1
}

fn _to_u16(data:&[u8], index:usize)->u16 {
    if index + 1 >= data.len() {
        use std::process;
        process::exit(0);
    }
    let data0 = _to_u8(data, index) as u16;
    let data1 = _to_u8(data, index + 1) as u16;
    data0 << 8 | data1
}


fn test_function0(_param0: u32) {
    unsafe {
        let _local0 = nftnl::Batch::with_page_size(_param0);
        nftnl::Batch::as_raw_batch(&(_local0));
        let _local2 = nftnl::Batch::finalize(_local0);
        nftnl::FinalizedBatch::iter(&(_local2));
    }
}

fn _read_data()-> Vec<u8> {
    use std::env;
    use std::process::exit;
    let args:Vec<String> = env::args().collect();
    if args.len() < 2 {
        println!("No crash filename provided");
        exit(-1);
    }
    use std::path::PathBuf;
    let crash_file_name = &args[1];
    let crash_path = PathBuf::from(crash_file_name);
    if !crash_path.is_file() {
        println!("Not a valid crash file");
        exit(-1);
    }
    use std::fs;
    let data =  fs::read(crash_path).unwrap();
    data
}

fn main() {
    let _content = _read_data();
    let data = &_content;
    println!("data = {:?}", data);
    println!("data len = {:?}", data.len());
    //actual body emit
    if data.len() != 4 {return;}
    let _param0 = _to_u32(data, 0);
    test_function0(_param0);

}

Metadata

Metadata

Assignees

No one assigned

    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