From eb0fc72b71187f6496cf8329e90c46419698e9f7 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 1 Jun 2026 10:19:33 -0400 Subject: [PATCH 01/55] Starting mimalloc integration with libresolve. This commit contains modifications to the Dockerfile and cargo files to ensure mimalloc source is correctly linked with libresolve. --- Dockerfile | 13 +++++++++++ resolve-cveassert/libresolve/Cargo.lock | 23 +++++++++++++++++++ resolve-cveassert/libresolve/Cargo.toml | 2 ++ resolve-cveassert/libresolve/src/build.rs | 6 +++++ resolve-cveassert/libresolve/src/remediate.rs | 14 +++++++++++ 5 files changed, 58 insertions(+) create mode 100644 resolve-cveassert/libresolve/src/build.rs diff --git a/Dockerfile b/Dockerfile index 60c3d6df..84a02384 100644 --- a/Dockerfile +++ b/Dockerfile @@ -63,6 +63,19 @@ COPY resolve-cli /resolve/resolve-cli COPY Makefile /resolve/Makefile COPY CMakeLists.txt /resolve/CMakeLists.txt +# Build/Install mimalloc +ARG MIMALLOC_REPO_URL="https://github.com/microsoft/mimalloc" +ARG MIMALLOC_VERSION="v3.3.2" +RUN git clone --depth 1 --branch "${MIMALLOC_VERSION}" "${MIMALLOC_REPO_URL}" \ + && cd /mimalloc \ + && mkdir -p build \ + && cd build \ + && cmake .. \ + -DMI_BUILD_SHARED=OFF \ + -DMI_BUILD_STATIC=ON \ + -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ + && make + # Build WORKDIR /resolve/ RUN PATH=$PATH:~/.cargo/bin make build-release install diff --git a/resolve-cveassert/libresolve/Cargo.lock b/resolve-cveassert/libresolve/Cargo.lock index a8530c12..50fad8ae 100644 --- a/resolve-cveassert/libresolve/Cargo.lock +++ b/resolve-cveassert/libresolve/Cargo.lock @@ -61,6 +61,16 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "cc" +version = "1.2.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +dependencies = [ + "find-msvc-tools", + "shlex", +] + [[package]] name = "colorchoice" version = "1.0.4" @@ -90,6 +100,12 @@ dependencies = [ "log", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -210,6 +226,7 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" name = "resolve" version = "0.1.0" dependencies = [ + "cc", "env_logger", "libc", "log", @@ -235,6 +252,12 @@ dependencies = [ "syn", ] +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + [[package]] name = "syn" version = "2.0.111" diff --git a/resolve-cveassert/libresolve/Cargo.toml b/resolve-cveassert/libresolve/Cargo.toml index 5e089cfd..8137e27d 100644 --- a/resolve-cveassert/libresolve/Cargo.toml +++ b/resolve-cveassert/libresolve/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "resolve" +build = "src/build.rs" version = "0.1.0" edition = "2024" @@ -7,6 +8,7 @@ edition = "2024" crate-type = ["cdylib"] [dependencies] +cc = "1.2.63" env_logger = "0.11.8" libc = "0.2.174" log = "0.4.29" diff --git a/resolve-cveassert/libresolve/src/build.rs b/resolve-cveassert/libresolve/src/build.rs new file mode 100644 index 00000000..b7fa313f --- /dev/null +++ b/resolve-cveassert/libresolve/src/build.rs @@ -0,0 +1,6 @@ +fn main() { + println!("cargo:warning=LINKING_MIMALLOC_ARCHIVE"); + // TODO: Fill in this with the correct path + println!("cargo:rustc-link-search=native=/mimalloc/build"); + println!("cargo:rustc-link-lib=static=mimalloc"); +} diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index bd17bfa5..ec35180b 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -8,6 +8,20 @@ use crate::shadowobjs::{ALIVE_OBJ_LIST, AllocType, FREED_OBJ_LIST, Vaddr}; use log::{info, warn}; + +#[link(name = "mimalloc")] +unsafe extern "C" { + fn mi_malloc(size: usize) -> *mut c_void; +} + +#[unsafe(no_mangle)] +pub extern "C" fn test_mi() { + unsafe { + let p = mi_malloc(16); + let _ = p; + } +} + /** * @brief - Allocator interface for stack objects * @input - size of the pointer allocation in bytes From e324817bb3068f3f2e2cffae5f015c7d990955fb Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 1 Jun 2026 14:09:56 -0400 Subject: [PATCH 02/55] Dockerfile: Removed mimalloc build from dockerfile. --- Dockerfile | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index 84a02384..60c3d6df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -63,19 +63,6 @@ COPY resolve-cli /resolve/resolve-cli COPY Makefile /resolve/Makefile COPY CMakeLists.txt /resolve/CMakeLists.txt -# Build/Install mimalloc -ARG MIMALLOC_REPO_URL="https://github.com/microsoft/mimalloc" -ARG MIMALLOC_VERSION="v3.3.2" -RUN git clone --depth 1 --branch "${MIMALLOC_VERSION}" "${MIMALLOC_REPO_URL}" \ - && cd /mimalloc \ - && mkdir -p build \ - && cd build \ - && cmake .. \ - -DMI_BUILD_SHARED=OFF \ - -DMI_BUILD_STATIC=ON \ - -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ - && make - # Build WORKDIR /resolve/ RUN PATH=$PATH:~/.cargo/bin make build-release install From 4373a3603151ec1e0ec174b10247261cbb428956 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 1 Jun 2026 14:10:52 -0400 Subject: [PATCH 03/55] WIP: Moved mimalloc build into CMake workflow. I will make sure to document workflow and after CI run. --- resolve-cveassert/libresolve/CMakeLists.txt | 31 +++++++++++++- .../libresolve/mimalloc_shadow.c | 26 ++++++++++++ resolve-cveassert/libresolve/src/build.rs | 8 ++-- resolve-cveassert/libresolve/src/remediate.rs | 42 +++++++++++++------ 4 files changed, 89 insertions(+), 18 deletions(-) create mode 100644 resolve-cveassert/libresolve/mimalloc_shadow.c diff --git a/resolve-cveassert/libresolve/CMakeLists.txt b/resolve-cveassert/libresolve/CMakeLists.txt index 53baf51e..2ba5dc25 100644 --- a/resolve-cveassert/libresolve/CMakeLists.txt +++ b/resolve-cveassert/libresolve/CMakeLists.txt @@ -3,6 +3,29 @@ include(GNUInstallDirs) include(ExternalProject) +include(FetchContent) + +# ### Pulling and building mimalloc project +FetchContent_Declare( + mimalloc + GIT_REPOSITORY https://github.com/microsoft/mimalloc.git + GIT_TAG v3.3.2 +) + +# # Force static build +set(MI_BUILD_SHARED OFF CACHE BOOL "" FORCE) +set(MI_BUILD_STATIC ON CACHE BOOL "" FORCE) + +FetchContent_MakeAvailable(mimalloc) + +target_sources(mimalloc-static PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/mimalloc_shadow.c +) +set(MIMALLOC_LIB_DIR ${mimalloc_BINARY_DIR}) + +set_target_properties(mimalloc-static PROPERTIES + POSITION_INDEPENDENT_CODE ON +) # Map CMake build type to Cargo flags if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "") @@ -24,10 +47,13 @@ file(GLOB_RECURSE RUST_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/sr add_custom_command( OUTPUT ${RUST_LIB} COMMAND - ${CMAKE_COMMAND} -E env CARGO_TARGET_DIR=${RUST_OUT_DIR} cargo build ${CARGO_FLAGS} + ${CMAKE_COMMAND} -E env + CARGO_TARGET_DIR=${RUST_OUT_DIR} + MIMALLOC_LIB_DIR=${MIMALLOC_LIB_DIR} + cargo build ${CARGO_FLAGS} WORKING_DIRECTORY ${RUST_CRATE_DIR} COMMENT "Building libresolve.so" VERBATIM - DEPENDS ${RUST_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/Cargo.lock ${CMAKE_CURRENT_SOURCE_DIR}/Cargo.toml ${CMAKE_CURRENT_SOURCE_DIR}/rust-toolchain.toml + DEPENDS mimalloc-static ${RUST_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/Cargo.lock ${CMAKE_CURRENT_SOURCE_DIR}/Cargo.toml ${CMAKE_CURRENT_SOURCE_DIR}/rust-toolchain.toml ) add_custom_target(test-libresolve @@ -37,4 +63,5 @@ add_custom_target(test-libresolve ) add_custom_target(libresolve ALL DEPENDS ${RUST_LIB}) +add_dependencies(libresolve mimalloc-static) install(FILES ${RUST_LIB} DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/resolve-cveassert/libresolve/mimalloc_shadow.c b/resolve-cveassert/libresolve/mimalloc_shadow.c new file mode 100644 index 00000000..16c97841 --- /dev/null +++ b/resolve-cveassert/libresolve/mimalloc_shadow.c @@ -0,0 +1,26 @@ +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include +#include + +typedef struct { + uint64_t page_id; + size_t block_index; + void *page_start; +} resolve_info_t; + +resolve_info_t mi_resolve_ptr(void *p) { + mi_page_t *page = _mi_ptr_page(p); + + resolve_info_t info; + + info.page_start = mi_page_start(p); + info.page_id = (uint64_t)(uintptr_t)page; + + size_t block_size = page->block_size; + uintptr_t offset = (uintptr_t)p - (uintptr_t)info.page_start; + + info.block_index = offset / block_size; + + return info; +} diff --git a/resolve-cveassert/libresolve/src/build.rs b/resolve-cveassert/libresolve/src/build.rs index b7fa313f..ee879105 100644 --- a/resolve-cveassert/libresolve/src/build.rs +++ b/resolve-cveassert/libresolve/src/build.rs @@ -1,6 +1,6 @@ fn main() { - println!("cargo:warning=LINKING_MIMALLOC_ARCHIVE"); - // TODO: Fill in this with the correct path - println!("cargo:rustc-link-search=native=/mimalloc/build"); - println!("cargo:rustc-link-lib=static=mimalloc"); + let dir = std::env::var("MIMALLOC_LIB_DIR").unwrap(); + println!("cargo::warning=LINKING_MIMALLOC_ARCHIVE"); + println!("cargo::rustc-link-search=native={}", dir); + println!("cargo::rustc-link-lib=static=mimalloc"); } diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index ec35180b..f86ba5f5 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -1,7 +1,7 @@ // Copyright (c) 2025 Riverside Research. // LGPL-3; See LICENSE.txt in the repo root for details. use libc::{ - c_char, c_void, calloc, free, malloc, realloc, strdup, strlen, strndup, strnlen, + c_char, c_void, strdup, strlen, strndup, strnlen, }; use crate::shadowobjs::{ALIVE_OBJ_LIST, AllocType, FREED_OBJ_LIST, Vaddr}; @@ -9,17 +9,21 @@ use crate::shadowobjs::{ALIVE_OBJ_LIST, AllocType, FREED_OBJ_LIST, Vaddr}; use log::{info, warn}; +#[repr(C)] +struct ResolveInfo { + page_id: u64, + block_size: usize, + page_start: *mut c_void, +} + #[link(name = "mimalloc")] unsafe extern "C" { fn mi_malloc(size: usize) -> *mut c_void; -} + fn mi_calloc(size: usize, count: usize) -> *mut c_void; + fn mi_realloc(ptr: *mut c_void, size: usize) -> *mut c_void; + fn mi_free(ptr: *mut c_void); -#[unsafe(no_mangle)] -pub extern "C" fn test_mi() { - unsafe { - let p = mi_malloc(16); - let _ = p; - } + fn mi_resolve_ptr(ptr: *mut c_void) -> ResolveInfo; } /** @@ -57,7 +61,7 @@ pub extern "C" fn __resolve_invalidate_stack(base: *mut c_void) { */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { - let ptr = unsafe { malloc(size + 1) }; + let ptr = unsafe { mi_malloc(size + 1) }; if ptr.is_null() { return ptr; @@ -122,7 +126,7 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); } - let _ = unsafe { free(ptr) }; + let _ = unsafe { mi_free(ptr) }; } /** @@ -141,7 +145,7 @@ pub extern "C" fn __resolve_realloc(ptr: *mut c_void, size: usize) -> *mut c_voi // Consideration: Pointer passed in may be invalidated so we need a mechanism // to remove the shadow object for the orignal allocation - let realloc_ptr = unsafe { realloc(ptr, size + 1) }; + let realloc_ptr = unsafe { mi_realloc(ptr, size + 1) }; if realloc_ptr.is_null() { return realloc_ptr; @@ -172,7 +176,7 @@ pub extern "C" fn __resolve_realloc(ptr: *mut c_void, size: usize) -> *mut c_voi */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_calloc(n_items: usize, item_size: usize) -> *mut c_void { - let ptr = unsafe { calloc(n_items, item_size) }; + let ptr = unsafe { mi_calloc(n_items, item_size) }; let size = n_items * item_size; if ptr.is_null() { @@ -349,4 +353,18 @@ mod tests { assert!(obj.is_none()); } } + + #[test] + fn test_mi_malloc_page() { + resolve_init(); + unsafe { + let ptr = __resolve_malloc(128); + let info = mi_resolve_ptr(ptr); + println!("ptr = {:p}", p); + println!("page_id = {}", info.page_id); + println!("block_idx = {}", info.block_index); + println!("page_start = {:p}", info.page_start); + __resolve_free(ptr); + } + } } From 95993c89b68ba467f93bbcebe6a66ac516e81f3b Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 1 Jun 2026 15:18:50 -0400 Subject: [PATCH 04/55] CMakeLists.txt: Fixed CMake file to correctly pass path to static mimalloc archive to cargo so that downstream tests pass. --- resolve-cveassert/libresolve/CMakeLists.txt | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/resolve-cveassert/libresolve/CMakeLists.txt b/resolve-cveassert/libresolve/CMakeLists.txt index 2ba5dc25..ba5df5f5 100644 --- a/resolve-cveassert/libresolve/CMakeLists.txt +++ b/resolve-cveassert/libresolve/CMakeLists.txt @@ -5,24 +5,28 @@ include(GNUInstallDirs) include(ExternalProject) include(FetchContent) -# ### Pulling and building mimalloc project +#### Fetching and building mimalloc project FetchContent_Declare( mimalloc GIT_REPOSITORY https://github.com/microsoft/mimalloc.git GIT_TAG v3.3.2 ) -# # Force static build +## Force static build set(MI_BUILD_SHARED OFF CACHE BOOL "" FORCE) set(MI_BUILD_STATIC ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(mimalloc) +# Add the shim source to the mimalloc proj target_sources(mimalloc-static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/mimalloc_shadow.c ) + set(MIMALLOC_LIB_DIR ${mimalloc_BINARY_DIR}) +message(STATUS "MIMALLOC_LIB_DIR=${MIMALLOC_LIB_DIR}") +## mimalloc proj must be PIC to ensure compatibility with libresolve set_target_properties(mimalloc-static PROPERTIES POSITION_INDEPENDENT_CODE ON ) @@ -49,7 +53,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env CARGO_TARGET_DIR=${RUST_OUT_DIR} - MIMALLOC_LIB_DIR=${MIMALLOC_LIB_DIR} + MIMALLOC_LIB_DIR=${MIMALLOC_LIB_DIR} # pass the static mimalloc path cargo build ${CARGO_FLAGS} WORKING_DIRECTORY ${RUST_CRATE_DIR} COMMENT "Building libresolve.so" VERBATIM @@ -57,7 +61,10 @@ add_custom_command( ) add_custom_target(test-libresolve - COMMAND cargo test + COMMAND + ${CMAKE_COMMAND} -E env + MIMALLOC_LIB_DIR=${MIMALLOC_LIB_DIR} # Note: Pass the static mimalloc loc so that build.rs does not panic + cargo test WORKING_DIRECTORY ${RUST_CRATE_DIR} COMMENT "Running regression tests for libresolve" ) From e742a9ecbcd53e8e1ab5a9afcf30f175437d3205 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 1 Jun 2026 15:19:26 -0400 Subject: [PATCH 05/55] remediate.rs: Fixed test but we need to test this on a small file to see if it works correctly. --- resolve-cveassert/libresolve/src/remediate.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index f86ba5f5..249257d2 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -12,17 +12,19 @@ use log::{info, warn}; #[repr(C)] struct ResolveInfo { page_id: u64, - block_size: usize, + block_index: usize, page_start: *mut c_void, } #[link(name = "mimalloc")] -unsafe extern "C" { +unsafe extern "C" { + // Allocator API fn mi_malloc(size: usize) -> *mut c_void; fn mi_calloc(size: usize, count: usize) -> *mut c_void; fn mi_realloc(ptr: *mut c_void, size: usize) -> *mut c_void; fn mi_free(ptr: *mut c_void); - + + // Shim API fn mi_resolve_ptr(ptr: *mut c_void) -> ResolveInfo; } @@ -358,9 +360,9 @@ mod tests { fn test_mi_malloc_page() { resolve_init(); unsafe { - let ptr = __resolve_malloc(128); + let ptr = __resolve_malloc(0x10); let info = mi_resolve_ptr(ptr); - println!("ptr = {:p}", p); + println!("ptr = {:p}", ptr); println!("page_id = {}", info.page_id); println!("block_idx = {}", info.block_index); println!("page_start = {:p}", info.page_start); From 1b952ca23c6d8d37eaf643f4921788e313773f8d Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 2 Jun 2026 10:18:20 -0400 Subject: [PATCH 06/55] shadowobjs.rs: Cleaned up some comments. --- resolve-cveassert/libresolve/src/shadowobjs.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/resolve-cveassert/libresolve/src/shadowobjs.rs b/resolve-cveassert/libresolve/src/shadowobjs.rs index 24dbe1a6..76cf3b91 100644 --- a/resolve-cveassert/libresolve/src/shadowobjs.rs +++ b/resolve-cveassert/libresolve/src/shadowobjs.rs @@ -22,11 +22,8 @@ pub enum AllocType { #[derive(Debug, Clone)] pub struct ShadowObject { - /// Allocation type (Heap, Stack, Global, etc..) pub alloc_type: AllocType, - // Base address of the allocated object mapped to u64 pub base: Vaddr, - /// Last address of the allocated object pub limit: Vaddr, size: usize, } @@ -82,6 +79,7 @@ impl ShadowObjectTable { base, limit: ShadowObject::limit(base, size), size, + allocid, }; self.table.insert(base, sobj); } From 3fe197c62f04ae65a45cdb49555fbabfa2d4e9f1 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Thu, 4 Jun 2026 13:26:32 -0400 Subject: [PATCH 07/55] mimalloc_shadow.c: Modified shim to lookup bounds of mimalloc allocation. --- .../libresolve/mimalloc_shadow.c | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/resolve-cveassert/libresolve/mimalloc_shadow.c b/resolve-cveassert/libresolve/mimalloc_shadow.c index 16c97841..d0b27cdb 100644 --- a/resolve-cveassert/libresolve/mimalloc_shadow.c +++ b/resolve-cveassert/libresolve/mimalloc_shadow.c @@ -4,23 +4,28 @@ #include typedef struct { - uint64_t page_id; + void *base; + void *limit; + size_t block_size; size_t block_index; - void *page_start; -} resolve_info_t; +} bounds_info_t; -resolve_info_t mi_resolve_ptr(void *p) { - mi_page_t *page = _mi_ptr_page(p); - - resolve_info_t info; - info.page_start = mi_page_start(p); - info.page_id = (uint64_t)(uintptr_t)page; +bounds_info_t mi_resolve_ptr(void* p) { + mi_page_t *page = _mi_ptr_page(p); + + const size_t block_size = page->block_size; - size_t block_size = page->block_size; - uintptr_t offset = (uintptr_t)p - (uintptr_t)info.page_start; + uintptr_t page_start = (uintptr_t)page->page_start; + uintptr_t ptr = (uintptr_t)p; - info.block_index = offset / block_size; + size_t block_index = (ptr - page_start) / block_size; + uintptr_t base_addr = page_start + block_index * block_size; - return info; + bounds_info_t bounds; + bounds.base = (void*)base_addr; + bounds.limit = (void*)(base_addr + block_size); + bounds.block_size = block_size; + bounds.block_index = block_index; + return bounds; } From efaa4a14f4a0199589594f68a6147721a3d1e01c Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Thu, 4 Jun 2026 13:27:06 -0400 Subject: [PATCH 08/55] WIP: Testing bounds-checking with mimalloc. --- resolve-cveassert/libresolve/src/remediate.rs | 306 +++++++++--------- .../libresolve/src/shadowobjs.rs | 1 - 2 files changed, 150 insertions(+), 157 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 249257d2..054e983c 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -1,19 +1,21 @@ // Copyright (c) 2025 Riverside Research. // LGPL-3; See LICENSE.txt in the repo root for details. use libc::{ - c_char, c_void, strdup, strlen, strndup, strnlen, + c_char, c_void, strlen,strnlen, }; -use crate::shadowobjs::{ALIVE_OBJ_LIST, AllocType, FREED_OBJ_LIST, Vaddr}; +use crate::shadowobjs::{ + ALIVE_OBJ_LIST, AllocType, FREED_OBJ_LIST, Vaddr +}; use log::{info, warn}; - #[repr(C)] -struct ResolveInfo { - page_id: u64, +struct BoundsInfo { + base: *mut c_void, + limit: *mut c_void, + block_size: usize, block_index: usize, - page_start: *mut c_void, } #[link(name = "mimalloc")] @@ -22,10 +24,12 @@ unsafe extern "C" { fn mi_malloc(size: usize) -> *mut c_void; fn mi_calloc(size: usize, count: usize) -> *mut c_void; fn mi_realloc(ptr: *mut c_void, size: usize) -> *mut c_void; + fn mi_strdup(ptr: *mut c_char) -> *mut c_char; + fn mi_strndup(ptr: *mut c_char, size: usize) -> *mut c_char; fn mi_free(ptr: *mut c_void); // Shim API - fn mi_resolve_ptr(ptr: *mut c_void) -> ResolveInfo; + fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; } /** @@ -35,25 +39,24 @@ unsafe extern "C" { */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_alloca(ptr: *mut c_void, size: usize) -> () { - let base = ptr as Vaddr; - { - let mut obj_list = ALIVE_OBJ_LIST.lock(); - obj_list.add_shadow_object(AllocType::Stack, base, size); - } - - info!("[STACK] Object allocated with size: {size}, address: 0x{base:x}"); + let base = ptr as Vaddr; + { + let mut obj_list = ALIVE_OBJ_LIST.lock(); + obj_list.add_shadow_object(AllocType::Stack, base, size); + } + info!("[STACK] Object allocated with size: {size}, address: 0x{base:x}"); } #[unsafe(no_mangle)] pub extern "C" fn __resolve_invalidate_stack(base: *mut c_void) { - let base = base as Vaddr; + let base = base as Vaddr; - { - let mut obj_list = ALIVE_OBJ_LIST.lock(); - obj_list.invalidate_at(base); - } + { + let mut obj_list = ALIVE_OBJ_LIST.lock(); + obj_list.invalidate_at(base); + } - info!("[STACK] Free addr 0x{base:x}"); + info!("[STACK] Free addr 0x{base:x}"); } /** @@ -64,6 +67,7 @@ pub extern "C" fn __resolve_invalidate_stack(base: *mut c_void) { #[unsafe(no_mangle)] pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { let ptr = unsafe { mi_malloc(size + 1) }; + let bounds_info = unsafe { mi_resolve_ptr(ptr) }; if ptr.is_null() { return ptr; @@ -79,6 +83,9 @@ pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { ptr as Vaddr ); + info!("[RESOLVE] bounds: (0x{:x}, 0x{:x})", bounds_info.base as Vaddr, bounds_info.limit as Vaddr); + info!("[RESOLVE] block index: {}", bounds_info.block_index); + info!("[RESOLVE] block size: {}", bounds_info.block_size); ptr } @@ -89,48 +96,48 @@ pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { - // Insert a function to find the object and return the pointer size - // Do I need to handle if the sobj cannot be found? - - info!( - "[FREE] Allocated object freed at address: 0x{:x}", - ptr as Vaddr - ); - - let ptr_size = { - let mut obj_list = ALIVE_OBJ_LIST.lock(); - let sobj_opt = obj_list.search_intersection(ptr as Vaddr); - let size = sobj_opt.map(|o| o.size()); - // remove shadow obj from live list - obj_list.invalidate_at(ptr as Vaddr); - size - }; - - // Check if the shadow object exists - match ptr_size { - Some(size) => { - info!( - "[FREE] Found shadow object for allocated object, 0x{:x}, size = {size}", - ptr as Vaddr, - ); - } - None => { - warn!( - "[FREE] No shadow object found for allocated object: 0x{:x}", - ptr as Vaddr - ); - } - } - - { - // Insert shadow object into freed object list - let mut freed_guard = FREED_OBJ_LIST.lock(); - freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); - } - - let _ = unsafe { mi_free(ptr) }; + // Insert a function to find the object and return the pointer size + // Do I need to handle if the sobj cannot be found? + + info!( + "[FREE] Allocated object freed at address: 0x{:x}", + ptr as Vaddr + ); + + let ptr_size = { + let mut obj_list = ALIVE_OBJ_LIST.lock(); + let sobj_opt = obj_list.search_intersection(ptr as Vaddr); + let size = sobj_opt.map(|o| o.size()); + // remove shadow obj from live list + obj_list.invalidate_at(ptr as Vaddr); + size + }; + + // Check if the shadow object exists + match ptr_size { + Some(size) => { + info!( + "[FREE] Found shadow object for allocated object, 0x{:x}, size = {size}", + ptr as Vaddr, + ); + } + None => { + warn!( + "[FREE] No shadow object found for allocated object: 0x{:x}", + ptr as Vaddr + ); + } + } + + { + // Insert shadow object into freed object list + let mut freed_guard = FREED_OBJ_LIST.lock(); + freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); + } + + let _ = unsafe { mi_free(ptr) }; } - +// /** * @brief - Allocator logging interface for realloc * @input @@ -169,13 +176,13 @@ pub extern "C" fn __resolve_realloc(ptr: *mut c_void, size: usize) -> *mut c_voi realloc_ptr } -/** - * @brief - Allocator logging interface for calloc - * @input - * - n_items: number of items in the allocation - * - size: size of the allocation in bytes - * @return - none - */ +// /** +// * @brief - Allocator logging interface for calloc +// * @input +// * - n_items: number of items in the allocation +// * - size: size of the allocation in bytes +// * @return - none +// */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_calloc(n_items: usize, item_size: usize) -> *mut c_void { let ptr = unsafe { mi_calloc(n_items, item_size) }; @@ -198,15 +205,15 @@ pub extern "C" fn __resolve_calloc(n_items: usize, item_size: usize) -> *mut c_v ptr } -/** - * @brief - Allocator logging interface for strdup - * @input - * - ptr: ptr to the original allocation - * @return - pointer to the copied string - */ -#[unsafe(no_mangle)] +// /** +// * @brief - Allocator logging interface for strdup +// * @input +// * - ptr: ptr to the original allocation +// * @return - pointer to the copied string +// */ +// #[unsafe(no_mangle)] pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { - let string_ptr = unsafe { strdup(ptr) }; + let string_ptr = unsafe { mi_strdup(ptr) }; if string_ptr.is_null() { return string_ptr; @@ -229,18 +236,18 @@ pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { string_ptr } -/** - * @brief - Allocator logging interface for strdup - * @input - * - ptr: ptr to the original allocation - * - size: number of bytes to copied - * @return - pointer to the copied string - * NOTE: Read this link to understand the nature of strdup & strndup - * https://pubs.opengroup.org/onlinepubs/9699919799/functions/strdup.html - */ -#[unsafe(no_mangle)] +// /** +// * @brief - Allocator logging interface for strdup +// * @input +// * - ptr: ptr to the original allocation +// * - size: number of bytes to copied +// * @return - pointer to the copied string +// * NOTE: Read this link to understand the nature of strdup & strndup +// * https://pubs.opengroup.org/onlinepubs/9699919799/functions/strdup.html +// */ +// #[unsafe(no_mangle)] pub extern "C" fn __resolve_strndup(ptr: *mut c_char, size: usize) -> *mut c_char { - let string_ptr = unsafe { strndup(ptr, size + 1) }; + let string_ptr = unsafe { mi_strndup(ptr, size + 1) }; if string_ptr.is_null() { return string_ptr; @@ -287,23 +294,24 @@ pub extern "C" fn __resolve_get_bounds(ptr: *mut c_void) -> ShadowObjBounds { return ShadowObjBounds { base: std::ptr::null_mut(), limit: std::ptr::null_mut() } }; + info!("[RESOLVE] Debugging: (0x{:x}, 0x{:x}, 0x{:x})", ptr as Vaddr, sobj.base as Vaddr, sobj.limit as Vaddr); return ShadowObjBounds { base: sobj.base as *mut c_void, limit: sobj.limit as *mut c_void } } - -#[unsafe(no_mangle)] -pub extern "C" fn resolve_obj_type(base_ptr: *mut c_void) -> AllocType { - let base = base_ptr as Vaddr; - - let find_in = |table: &crate::MutexWrap| { - let t = table.lock(); - t.search_intersection(base).map(|o| o.alloc_type) - }; - - // Why does this search freed before alive? - let alloc_type = find_in(&FREED_OBJ_LIST).or_else(|| find_in(&ALIVE_OBJ_LIST)); - - alloc_type.unwrap_or(AllocType::Unknown) -} +// +//#[unsafe(no_mangle)] +//pub extern "C" fn resolve_obj_type(base_ptr: *mut c_void) -> AllocType { +// let base = base_ptr as Vaddr; +// +// let find_in = |table: &crate::MutexWrap| { +// let t = table.lock(); +// t.search_intersection(base).map(|o| o.alloc_type) +// }; +// +// // Why does this search freed before alive? +// let alloc_type = find_in(&FREED_OBJ_LIST).or_else(|| find_in(&ALIVE_OBJ_LIST)); +// +// alloc_type.unwrap_or(AllocType::Unknown) +//} /** * @brief - Logs when program enters sanitization basic block @@ -315,58 +323,44 @@ pub extern "C" fn __resolve_report_violation() -> () { #[cfg(test)] mod tests { - use super::*; - use crate::{resolve_init, shadowobjs::AllocType}; - - #[test] - fn test_malloc_free() { - resolve_init(); - // Allocation should successfully return a memory block - let ptr = __resolve_malloc(0x10); - assert!(!ptr.is_null()); - - // We should track the obj correctly - { - let table = ALIVE_OBJ_LIST.lock(); - let obj = table.search_intersection(ptr as Vaddr); - - assert!(obj.is_some()); - let obj = obj.unwrap(); - assert!(obj.size() == 0x10); - assert!(obj.base == ptr as Vaddr); - assert!(obj.alloc_type == AllocType::Heap); - } - - __resolve_free(ptr); - - // After freeing a block we should track that it has been freed - { - let table = FREED_OBJ_LIST.lock(); - let obj = table.search_intersection(ptr as Vaddr); - - assert!(obj.is_some()); - } - - // And it should no longer be in the alive obj list. - { - let table = ALIVE_OBJ_LIST.lock(); - let obj = table.search_intersection(ptr as Vaddr); - - assert!(obj.is_none()); - } - } - - #[test] - fn test_mi_malloc_page() { - resolve_init(); - unsafe { - let ptr = __resolve_malloc(0x10); - let info = mi_resolve_ptr(ptr); - println!("ptr = {:p}", ptr); - println!("page_id = {}", info.page_id); - println!("block_idx = {}", info.block_index); - println!("page_start = {:p}", info.page_start); - __resolve_free(ptr); - } - } + use super::*; + use crate::{resolve_init, shadowobjs::AllocType}; + + #[test] + fn test_malloc_free() { + resolve_init(); + // Allocation should successfully return a memory block + let ptr = __resolve_malloc(0x10); + assert!(!ptr.is_null()); + + // We should track the obj correctly + { + let table = ALIVE_OBJ_LIST.lock(); + let obj = table.search_intersection(ptr as Vaddr); + + assert!(obj.is_some()); + let obj = obj.unwrap(); + assert!(obj.size() == 0x10); + assert!(obj.base == ptr as Vaddr); + assert!(obj.alloc_type == AllocType::Heap); + } + + __resolve_free(ptr); + + // After freeing a block we should track that it has been freed + { + let table = FREED_OBJ_LIST.lock(); + let obj = table.search_intersection(ptr as Vaddr); + + assert!(obj.is_some()); + } + + // And it should no longer be in the alive obj list. + { + let table = ALIVE_OBJ_LIST.lock(); + let obj = table.search_intersection(ptr as Vaddr); + + assert!(obj.is_none()); + } + } } diff --git a/resolve-cveassert/libresolve/src/shadowobjs.rs b/resolve-cveassert/libresolve/src/shadowobjs.rs index 76cf3b91..4e7fafc0 100644 --- a/resolve-cveassert/libresolve/src/shadowobjs.rs +++ b/resolve-cveassert/libresolve/src/shadowobjs.rs @@ -79,7 +79,6 @@ impl ShadowObjectTable { base, limit: ShadowObject::limit(base, size), size, - allocid, }; self.table.insert(base, sobj); } From 5ec89adc1d80f73944ab304674c4b65c191a8378 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 5 Jun 2026 10:48:56 -0400 Subject: [PATCH 09/55] remediate.rs: This will not pass CI tests, this is just so that I can compare the mimalloc approach to strict shadow object bounds approach. --- resolve-cveassert/libresolve/src/remediate.rs | 320 +++++++++--------- 1 file changed, 161 insertions(+), 159 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 054e983c..da66e26b 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -38,25 +38,25 @@ unsafe extern "C" { * @return - none */ #[unsafe(no_mangle)] -pub extern "C" fn __resolve_alloca(ptr: *mut c_void, size: usize) -> () { - let base = ptr as Vaddr; - { - let mut obj_list = ALIVE_OBJ_LIST.lock(); - obj_list.add_shadow_object(AllocType::Stack, base, size); - } - info!("[STACK] Object allocated with size: {size}, address: 0x{base:x}"); +pub extern "C" fn __resolve_alloca(_ptr: *mut c_void, _size: usize) -> () { +// let base = ptr as Vaddr; +// { +// let mut obj_list = ALIVE_OBJ_LIST.lock(); +// obj_list.add_shadow_object(AllocType::Stack, base, size); +// } +// info!("[STACK] Object allocated with size: {size}, address: 0x{base:x}"); } #[unsafe(no_mangle)] -pub extern "C" fn __resolve_invalidate_stack(base: *mut c_void) { - let base = base as Vaddr; - - { - let mut obj_list = ALIVE_OBJ_LIST.lock(); - obj_list.invalidate_at(base); - } - - info!("[STACK] Free addr 0x{base:x}"); +pub extern "C" fn __resolve_invalidate_stack(_base: *mut c_void) { +// let base = base as Vaddr; +// +// { +// let mut obj_list = ALIVE_OBJ_LIST.lock(); +// obj_list.invalidate_at(base); +// } +// +// info!("[STACK] Free addr 0x{base:x}"); } /** @@ -67,25 +67,25 @@ pub extern "C" fn __resolve_invalidate_stack(base: *mut c_void) { #[unsafe(no_mangle)] pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { let ptr = unsafe { mi_malloc(size + 1) }; - let bounds_info = unsafe { mi_resolve_ptr(ptr) }; + //let bounds_info = unsafe { mi_resolve_ptr(ptr) }; if ptr.is_null() { return ptr; } - { - let mut obj_list = ALIVE_OBJ_LIST.lock(); - obj_list.add_shadow_object(AllocType::Heap, ptr as Vaddr, size); - } + //{ + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // obj_list.add_shadow_object(AllocType::Heap, ptr as Vaddr, size); + //} - info!( - "[HEAP] Object allocated with size: {size}, address: 0x{:x}", - ptr as Vaddr - ); + //info!( + // "[HEAP] Object allocated with size: {size}, address: 0x{:x}", + // ptr as Vaddr + //); - info!("[RESOLVE] bounds: (0x{:x}, 0x{:x})", bounds_info.base as Vaddr, bounds_info.limit as Vaddr); - info!("[RESOLVE] block index: {}", bounds_info.block_index); - info!("[RESOLVE] block size: {}", bounds_info.block_size); + //info!("[RESOLVE] bounds: (0x{:x}, 0x{:x})", bounds_info.base as Vaddr, bounds_info.limit as Vaddr); + //info!("[RESOLVE] block index: {}", bounds_info.block_index); + //info!("[RESOLVE] block size: {}", bounds_info.block_size); ptr } @@ -99,43 +99,43 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { // Insert a function to find the object and return the pointer size // Do I need to handle if the sobj cannot be found? - info!( - "[FREE] Allocated object freed at address: 0x{:x}", - ptr as Vaddr - ); - - let ptr_size = { - let mut obj_list = ALIVE_OBJ_LIST.lock(); - let sobj_opt = obj_list.search_intersection(ptr as Vaddr); - let size = sobj_opt.map(|o| o.size()); - // remove shadow obj from live list - obj_list.invalidate_at(ptr as Vaddr); - size - }; - - // Check if the shadow object exists - match ptr_size { - Some(size) => { - info!( - "[FREE] Found shadow object for allocated object, 0x{:x}, size = {size}", - ptr as Vaddr, - ); - } - None => { - warn!( - "[FREE] No shadow object found for allocated object: 0x{:x}", - ptr as Vaddr - ); - } - } - - { - // Insert shadow object into freed object list - let mut freed_guard = FREED_OBJ_LIST.lock(); - freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); - } - - let _ = unsafe { mi_free(ptr) }; + // info!( + // "[FREE] Allocated object freed at address: 0x{:x}", + // ptr as Vaddr + // ); + + // let ptr_size = { + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // let sobj_opt = obj_list.search_intersection(ptr as Vaddr); + // let size = sobj_opt.map(|o| o.size()); + // // remove shadow obj from live list + // obj_list.invalidate_at(ptr as Vaddr); + // size + // }; + + // // Check if the shadow object exists + // match ptr_size { + // Some(size) => { + // info!( + // "[FREE] Found shadow object for allocated object, 0x{:x}, size = {size}", + // ptr as Vaddr, + // ); + // } + // None => { + // warn!( + // "[FREE] No shadow object found for allocated object: 0x{:x}", + // ptr as Vaddr + // ); + // } + // } + + // { + // // Insert shadow object into freed object list + // let mut freed_guard = FREED_OBJ_LIST.lock(); + // freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); + // } + + let _ = unsafe { mi_free(ptr) }; } // /** @@ -161,28 +161,28 @@ pub extern "C" fn __resolve_realloc(ptr: *mut c_void, size: usize) -> *mut c_voi } - { - let mut obj_list = ALIVE_OBJ_LIST.lock(); - // Remove shadow object for original pointer - obj_list.invalidate_at(ptr as Vaddr); // if ptr == NULL this does not do anything - obj_list.add_shadow_object(AllocType::Heap, realloc_ptr as Vaddr, size); - } + // { + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // // Remove shadow object for original pointer + // obj_list.invalidate_at(ptr as Vaddr); // if ptr == NULL this does not do anything + // obj_list.add_shadow_object(AllocType::Heap, realloc_ptr as Vaddr, size); + // } - info!( - "[HEAP] Allocated object reallocated mem from src: {ptr:?}, size: {size}, dst ptr: 0x{:x}", - realloc_ptr as Vaddr - ); + // info!( + // "[HEAP] Allocated object reallocated mem from src: {ptr:?}, size: {size}, dst ptr: 0x{:x}", + // realloc_ptr as Vaddr + // ); - realloc_ptr + realloc_ptr } -// /** -// * @brief - Allocator logging interface for calloc -// * @input -// * - n_items: number of items in the allocation -// * - size: size of the allocation in bytes -// * @return - none -// */ +/** + * @brief - Allocator logging interface for calloc + * @input + * - n_items: number of items in the allocation + * - size: size of the allocation in bytes + * @return - none + */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_calloc(n_items: usize, item_size: usize) -> *mut c_void { let ptr = unsafe { mi_calloc(n_items, item_size) }; @@ -192,15 +192,15 @@ pub extern "C" fn __resolve_calloc(n_items: usize, item_size: usize) -> *mut c_v return ptr; } - { - let mut obj_list = ALIVE_OBJ_LIST.lock(); - obj_list.add_shadow_object(AllocType::Heap, ptr as Vaddr, size); - } + //{ + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // obj_list.add_shadow_object(AllocType::Heap, ptr as Vaddr, size); + //} - info!( - "[HEAP] Logging allocation with {n_items} items, size (bytes): {size}, dst ptr: 0x{:x}", - ptr as Vaddr - ); + //info!( + // "[HEAP] Logging allocation with {n_items} items, size (bytes): {size}, dst ptr: 0x{:x}", + // ptr as Vaddr + //); ptr } @@ -222,16 +222,16 @@ pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { // +1 to include null termination byte. We should allow program to read this value. // Otherwise how would the program find the end of the string? // Although writing it to something else is probably a bad idea, this too should be allowed. - let sizeofstr = unsafe { strlen(ptr) + 1 }; - { - let mut obj_list = ALIVE_OBJ_LIST.lock(); - obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); - } + // let sizeofstr = unsafe { strlen(ptr) + 1 }; + // { + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); + // } - info!( - "[HEAP] Logging 'strdup' function call with dst ptr: 0x{:x}", - string_ptr as Vaddr - ); + // info!( + // "[HEAP] Logging 'strdup' function call with dst ptr: 0x{:x}", + // string_ptr as Vaddr + // ); string_ptr } @@ -257,17 +257,17 @@ pub extern "C" fn __resolve_strndup(ptr: *mut c_char, size: usize) -> *mut c_cha // We don't actually know how much memory the libc will allocate, but // strnlen(ptr, size) + 1 is a safe lower bound. // strlen(string_ptr) + 1 would also be valid I think. - let sizeofstr = unsafe { strnlen(ptr, size) + 1 }; + //let sizeofstr = unsafe { strnlen(ptr, size) + 1 }; - { - let mut obj_list = ALIVE_OBJ_LIST.lock(); - obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); - } + //{ + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); + //} - info!( - "[HEAP] Logging 'strndup' function call with size (bytes): {size}, dst ptr: {:?}", - string_ptr as Vaddr - ); + //info!( + // "[HEAP] Logging 'strndup' function call with size (bytes): {size}, dst ptr: {:?}", + // string_ptr as Vaddr + //); string_ptr } @@ -289,13 +289,15 @@ pub struct ShadowObjBounds { */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_get_bounds(ptr: *mut c_void) -> ShadowObjBounds { - let sobj_table = ALIVE_OBJ_LIST.lock(); - let Some(sobj) = sobj_table.search_intersection(ptr as Vaddr) else { - return ShadowObjBounds { base: std::ptr::null_mut(), limit: std::ptr::null_mut() } - }; - - info!("[RESOLVE] Debugging: (0x{:x}, 0x{:x}, 0x{:x})", ptr as Vaddr, sobj.base as Vaddr, sobj.limit as Vaddr); - return ShadowObjBounds { base: sobj.base as *mut c_void, limit: sobj.limit as *mut c_void } + let bounds = unsafe { mi_resolve_ptr(ptr) }; + return ShadowObjBounds { base: bounds.base, limit: bounds.limit } + //let sobj_table = ALIVE_OBJ_LIST.lock(); + //let Some(sobj) = sobj_table.search_intersection(ptr as Vaddr) else { + // return ShadowObjBounds { base: std::ptr::null_mut(), limit: std::ptr::null_mut() } + //}; + + //info!("[RESOLVE] Debugging: (0x{:x}, 0x{:x}, 0x{:x})", ptr as Vaddr, sobj.base as Vaddr, sobj.limit as Vaddr); + //return ShadowObjBounds { base: sobj.base as *mut c_void, limit: sobj.limit as *mut c_void } } // //#[unsafe(no_mangle)] @@ -321,46 +323,46 @@ pub extern "C" fn __resolve_report_violation() -> () { info!("[RESOLVE] sanitizer triggered"); } -#[cfg(test)] -mod tests { - use super::*; - use crate::{resolve_init, shadowobjs::AllocType}; - - #[test] - fn test_malloc_free() { - resolve_init(); - // Allocation should successfully return a memory block - let ptr = __resolve_malloc(0x10); - assert!(!ptr.is_null()); - - // We should track the obj correctly - { - let table = ALIVE_OBJ_LIST.lock(); - let obj = table.search_intersection(ptr as Vaddr); - - assert!(obj.is_some()); - let obj = obj.unwrap(); - assert!(obj.size() == 0x10); - assert!(obj.base == ptr as Vaddr); - assert!(obj.alloc_type == AllocType::Heap); - } - - __resolve_free(ptr); - - // After freeing a block we should track that it has been freed - { - let table = FREED_OBJ_LIST.lock(); - let obj = table.search_intersection(ptr as Vaddr); - - assert!(obj.is_some()); - } - - // And it should no longer be in the alive obj list. - { - let table = ALIVE_OBJ_LIST.lock(); - let obj = table.search_intersection(ptr as Vaddr); - - assert!(obj.is_none()); - } - } -} +//#[cfg(test)] +//mod tests { +// use super::*; +// use crate::{resolve_init, shadowobjs::AllocType}; +// +// #[test] +// fn test_malloc_free() { +// resolve_init(); +// // Allocation should successfully return a memory block +// let ptr = __resolve_malloc(0x10); +// assert!(!ptr.is_null()); +// +// // We should track the obj correctly +// { +// let table = ALIVE_OBJ_LIST.lock(); +// let obj = table.search_intersection(ptr as Vaddr); +// +// assert!(obj.is_some()); +// let obj = obj.unwrap(); +// assert!(obj.size() == 0x10); +// assert!(obj.base == ptr as Vaddr); +// assert!(obj.alloc_type == AllocType::Heap); +// } +// +// __resolve_free(ptr); +// +// // After freeing a block we should track that it has been freed +// { +// let table = FREED_OBJ_LIST.lock(); +// let obj = table.search_intersection(ptr as Vaddr); +// +// assert!(obj.is_some()); +// } +// +// // And it should no longer be in the alive obj list. +// { +// let table = ALIVE_OBJ_LIST.lock(); +// let obj = table.search_intersection(ptr as Vaddr); +// +// assert!(obj.is_none()); +// } +// } +//} From 136fa0420b589f9e2355717b5b04ca4b66f95b26 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 5 Jun 2026 13:16:09 -0400 Subject: [PATCH 10/55] remediate.rs: Uncomment no_mangle attribute and comment logging command in __resolve_report_violation. --- resolve-cveassert/libresolve/src/remediate.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index da66e26b..22ec39af 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -211,7 +211,7 @@ pub extern "C" fn __resolve_calloc(n_items: usize, item_size: usize) -> *mut c_v // * - ptr: ptr to the original allocation // * @return - pointer to the copied string // */ -// #[unsafe(no_mangle)] +#[unsafe(no_mangle)] pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { let string_ptr = unsafe { mi_strdup(ptr) }; @@ -245,7 +245,7 @@ pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { // * NOTE: Read this link to understand the nature of strdup & strndup // * https://pubs.opengroup.org/onlinepubs/9699919799/functions/strdup.html // */ -// #[unsafe(no_mangle)] +#[unsafe(no_mangle)] pub extern "C" fn __resolve_strndup(ptr: *mut c_char, size: usize) -> *mut c_char { let string_ptr = unsafe { mi_strndup(ptr, size + 1) }; @@ -320,7 +320,7 @@ pub extern "C" fn __resolve_get_bounds(ptr: *mut c_void) -> ShadowObjBounds { */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_report_violation() -> () { - info!("[RESOLVE] sanitizer triggered"); + // info!("[RESOLVE] sanitizer triggered"); } //#[cfg(test)] From 4736ae4ccc7bb58e129e31431bcd2c34fa5f904b Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 5 Jun 2026 14:36:03 -0400 Subject: [PATCH 11/55] remediate.rs: Adding null pointer handling might fix compilation issue in challenge problem. --- resolve-cveassert/libresolve/src/remediate.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 22ec39af..e41a0c0c 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -289,6 +289,13 @@ pub struct ShadowObjBounds { */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_get_bounds(ptr: *mut c_void) -> ShadowObjBounds { + if ptr.is_null() { + return ShadowObjBounds { + base: std::ptr::null_mut(), + limit: std::ptr::null_mut(), + }; + } + let bounds = unsafe { mi_resolve_ptr(ptr) }; return ShadowObjBounds { base: bounds.base, limit: bounds.limit } //let sobj_table = ALIVE_OBJ_LIST.lock(); From 3300c7a64edcc954056544b5bccb2f77b04e2c49 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 8 Jun 2026 11:43:06 -0400 Subject: [PATCH 12/55] remediate.rs: Adding wrapper for getline function. Testing with challenge problem. --- resolve-cveassert/libresolve/src/remediate.rs | 58 ++++++++++++++++++- resolve-cveassert/src/instrument.cpp | 3 + 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index e41a0c0c..9d9207a9 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -1,7 +1,7 @@ // Copyright (c) 2025 Riverside Research. // LGPL-3; See LICENSE.txt in the repo root for details. use libc::{ - c_char, c_void, strlen,strnlen, + EOF, c_char, c_void, fgetc, getdelim, strlen, strnlen, ssize_t, }; use crate::shadowobjs::{ @@ -59,6 +59,62 @@ pub extern "C" fn __resolve_invalidate_stack(_base: *mut c_void) { // info!("[STACK] Free addr 0x{base:x}"); } +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_getline(line: *mut *mut c_char, size: *mut size_t, stream: *mut FILE) -> ssize_t { + if line.is_null() || size.is_null() || stream.is_null() { + return -1; + } + + unsafe { + if (*line).is_null() || *size == 0 { + *size = 128; + *line = __resolve_malloc(*size + 1) as *mut c_char; + + // check if the pointer is null + if (*line).is_null() { return -1; } + } + + let mut pos: size_t = 0; + let mut c: c_int; + + loop { + c = fgetc(stream); + if c == EOF { break; } + + if pos + 1 >= *size { // Expand buffer + let new_size = *size * 2; + let new_ptr = __resolve_realloc(*line as *mut c_void, new_size); + + if new_ptr.is_null() { + return -1; + } + + *line = new_ptr as *mut c_char; + *size = new_size; + } + + // (*lineptr)[pos++] = (char)c; + (*line).add(pos).write(c as c_char); + pos += 1; + + if c == b'\n' as c_int { + break; + } + + } + + if pos == 0 && c == EOF { // No data read + return -1; + } + + (*line).add(pos).write(0); // (*lineptr)[pos] = '\0' + } + + pos as ssize_t +} + + + /** * @brief - Allocator logging interface for malloc * @input - size of the allocation in bytes diff --git a/resolve-cveassert/src/instrument.cpp b/resolve-cveassert/src/instrument.cpp index c59f3985..3776b5a5 100644 --- a/resolve-cveassert/src/instrument.cpp +++ b/resolve-cveassert/src/instrument.cpp @@ -74,6 +74,9 @@ void instrumentLibraryAllocations(Function *F) { wrapLibraryFunction(F, "strdup", FunctionType::get(ptr_ty, {ptr_ty}, false)); wrapLibraryFunction(F, "strndup", FunctionType::get(ptr_ty, {ptr_ty, size_ty}, false)); + wrapLibraryFunction( + F, "getline", + FunctionType::get(size_ty, {ptr_ty, ptr_ty, ptr_ty}, false)); } void instrumentAlloca(Function *F) { From be15726a631e97389c110f39e48872adb7d3405c Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 8 Jun 2026 11:53:12 -0400 Subject: [PATCH 13/55] remediate.rs: Fixing Rust errors. --- resolve-cveassert/libresolve/src/remediate.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 9d9207a9..54e19aa7 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -1,7 +1,7 @@ // Copyright (c) 2025 Riverside Research. // LGPL-3; See LICENSE.txt in the repo root for details. use libc::{ - EOF, c_char, c_void, fgetc, getdelim, strlen, strnlen, ssize_t, + EOF, FILE, c_char, c_int, c_void, fgetc, strlen, strnlen, size_t, ssize_t, }; use crate::shadowobjs::{ @@ -108,9 +108,8 @@ pub extern "C" fn __resolve_getline(line: *mut *mut c_char, size: *mut size_t, s } (*line).add(pos).write(0); // (*lineptr)[pos] = '\0' + pos as ssize_t } - - pos as ssize_t } From 9ef62e864218276ef21fefaf8f310afaad5d11b0 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 8 Jun 2026 12:01:13 -0400 Subject: [PATCH 14/55] remediate.rs: Removed the plus one and using resolve wrapped malloc and realloc. --- resolve-cveassert/libresolve/src/remediate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 54e19aa7..2c01c176 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -68,7 +68,7 @@ pub extern "C" fn __resolve_getline(line: *mut *mut c_char, size: *mut size_t, s unsafe { if (*line).is_null() || *size == 0 { *size = 128; - *line = __resolve_malloc(*size + 1) as *mut c_char; + *line = __resolve_malloc(*size) as *mut c_char; // check if the pointer is null if (*line).is_null() { return -1; } From 3b9382ce8fab27326a1e4cee5e5fb1a129fde49f Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 8 Jun 2026 14:29:05 -0400 Subject: [PATCH 15/55] remediate.rs: Added resolve wrapper for getdelim function. --- resolve-cveassert/libresolve/src/remediate.rs | 62 +++++++++++++++---- resolve-cveassert/src/instrument.cpp | 3 + 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 2c01c176..94c1729b 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -60,18 +60,18 @@ pub extern "C" fn __resolve_invalidate_stack(_base: *mut c_void) { } #[unsafe(no_mangle)] -pub extern "C" fn __resolve_getline(line: *mut *mut c_char, size: *mut size_t, stream: *mut FILE) -> ssize_t { - if line.is_null() || size.is_null() || stream.is_null() { +pub extern "C" fn __resolve_getline(lineptr: *mut *mut c_char, size: *mut size_t, stream: *mut FILE) -> ssize_t { + if lineptr.is_null() || size.is_null() || stream.is_null() { return -1; } unsafe { - if (*line).is_null() || *size == 0 { + if (*lineptr).is_null() || *size == 0 { *size = 128; - *line = __resolve_malloc(*size) as *mut c_char; + *lineptr = __resolve_malloc(*size) as *mut c_char; // check if the pointer is null - if (*line).is_null() { return -1; } + if (*lineptr).is_null() { return -1; } } let mut pos: size_t = 0; @@ -83,18 +83,18 @@ pub extern "C" fn __resolve_getline(line: *mut *mut c_char, size: *mut size_t, s if pos + 1 >= *size { // Expand buffer let new_size = *size * 2; - let new_ptr = __resolve_realloc(*line as *mut c_void, new_size); + let new_buf = __resolve_realloc(*lineptr as *mut c_void, new_size); - if new_ptr.is_null() { + if new_buf.is_null() { return -1; } - *line = new_ptr as *mut c_char; + *lineptr = new_buf as *mut c_char; *size = new_size; } // (*lineptr)[pos++] = (char)c; - (*line).add(pos).write(c as c_char); + (*lineptr).add(pos).write(c as c_char); pos += 1; if c == b'\n' as c_int { @@ -107,12 +107,52 @@ pub extern "C" fn __resolve_getline(line: *mut *mut c_char, size: *mut size_t, s return -1; } - (*line).add(pos).write(0); // (*lineptr)[pos] = '\0' + (*lineptr).add(pos).write(0); // (*lineptr)[pos] = '\0' pos as ssize_t } } +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_t, delim: c_int, stream: *mut FILE) -> ssize_t { + if lineptr.is_null() || size.is_null() || stream.is_null() { + return -1; + } + + unsafe { + if (*lineptr).is_null() || *size == 0 { + *size = 128; + *lineptr = __resolve_malloc(*size) as *mut c_char; + + if (*lineptr).is_null() { return -1; } + } + + let mut pos: size_t = 0; + let mut c: c_int; + loop { + c = fgetc(stream); + if c == EOF { break; } + + if pos + 1 >= *size { + let new_size = *size * 2; + let new_buf = __resolve_realloc(*lineptr as *mut c_void, new_size); + + if new_buf.is_null() { return -1; } + + *lineptr = new_buf as *mut c_char; + *size = new_size; + } + + (*lineptr).add(pos).write(c as c_char); + pos += 1; + + if c == delim { break; } + } + + (*lineptr).add(pos).write(0); + pos as ssize_t + } +} /** * @brief - Allocator logging interface for malloc @@ -298,7 +338,7 @@ pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { // * - size: number of bytes to copied // * @return - pointer to the copied string // * NOTE: Read this link to understand the nature of strdup & strndup -// * https://pubs.opengroup.org/onlinepubs/9699919799/functions/strdup.html +// * https://pubs.opengroup.org/onlineptrpubs/9699919799/functions/strdup.html // */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_strndup(ptr: *mut c_char, size: usize) -> *mut c_char { diff --git a/resolve-cveassert/src/instrument.cpp b/resolve-cveassert/src/instrument.cpp index 3776b5a5..643c91c9 100644 --- a/resolve-cveassert/src/instrument.cpp +++ b/resolve-cveassert/src/instrument.cpp @@ -77,6 +77,9 @@ void instrumentLibraryAllocations(Function *F) { wrapLibraryFunction( F, "getline", FunctionType::get(size_ty, {ptr_ty, ptr_ty, ptr_ty}, false)); + wrapLibraryFunction( + F, "getdelim", + FunctionType::get(size_ty, {ptr_ty, ptr_ty, size_ty, ptr_ty}, false)); } void instrumentAlloca(Function *F) { From 9456e385a28b0be800d7014149d18fbc3e625af2 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 8 Jun 2026 15:54:44 -0400 Subject: [PATCH 16/55] remediate.rs: Added some logic to identify if the pointer is owned by mimalloc or not. If not log it and call libc free. --- resolve-cveassert/libresolve/src/remediate.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 94c1729b..f107f98d 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -1,7 +1,8 @@ // Copyright (c) 2025 Riverside Research. // LGPL-3; See LICENSE.txt in the repo root for details. use libc::{ - EOF, FILE, c_char, c_int, c_void, fgetc, strlen, strnlen, size_t, ssize_t, + EOF, FILE, c_char, c_int, c_void, fgetc, free, strlen, strnlen, size_t, ssize_t, + write, STDERR_FILENO, }; use crate::shadowobjs::{ @@ -229,8 +230,15 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { // let mut freed_guard = FREED_OBJ_LIST.lock(); // freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); // } - - let _ = unsafe { mi_free(ptr) }; + if mi_is_in_heap_region(ptr) { + let _ = unsafe { mi_free(ptr) }; + } else { + unsafe { + let msg = b"foreign allocation not owned by mimalloc\n"; + write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); + free(ptr); + } + } } // /** From b60a2839bd0eb641dab01e37c22bee6f8eb645e3 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 9 Jun 2026 08:36:15 -0400 Subject: [PATCH 17/55] remediate.rs: WIP debugging foreign allocation that occurs in dependency. Added debugging statement and logic to use libc free if the allocation is not from mimalloc. --- resolve-cveassert/libresolve/mimalloc_shadow.c | 6 ++++++ resolve-cveassert/libresolve/src/remediate.rs | 17 +++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/resolve-cveassert/libresolve/mimalloc_shadow.c b/resolve-cveassert/libresolve/mimalloc_shadow.c index d0b27cdb..0d9c1ee4 100644 --- a/resolve-cveassert/libresolve/mimalloc_shadow.c +++ b/resolve-cveassert/libresolve/mimalloc_shadow.c @@ -29,3 +29,9 @@ bounds_info_t mi_resolve_ptr(void* p) { bounds.block_index = block_index; return bounds; } + +bool mi_is_heap_owned(const void* p) { + return mi_check_owned(p); +} + + diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index f107f98d..c78fa315 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -31,6 +31,7 @@ unsafe extern "C" { // Shim API fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; + fn mi_is_heap_owned(ptr: *mut c_void) -> bool; } /** @@ -230,14 +231,14 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { // let mut freed_guard = FREED_OBJ_LIST.lock(); // freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); // } - if mi_is_in_heap_region(ptr) { - let _ = unsafe { mi_free(ptr) }; - } else { - unsafe { - let msg = b"foreign allocation not owned by mimalloc\n"; - write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); - free(ptr); - } + unsafe { + if mi_is_heap_owned(ptr) { + let _ = mi_free(ptr); + } else { + let msg = b"allocation not owned by mimalloc\n"; + write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); + let _ = free(ptr); + } } } // From e78ea0222eb767bf13a4a94893bf33974d3dfb5f Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 9 Jun 2026 09:13:02 -0400 Subject: [PATCH 18/55] remediate.rs: WIP debuggin allocator ownership issues. --- resolve-cveassert/libresolve/src/remediate.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index c78fa315..f6bef5b8 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -235,9 +235,14 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { if mi_is_heap_owned(ptr) { let _ = mi_free(ptr); } else { - let msg = b"allocation not owned by mimalloc\n"; - write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); - let _ = free(ptr); + let mut buf = [0u8; 64]; + let n = libc::snprintf( + buf.as_mut_ptr().cast(), + buf.len(), + b"free(%p)\n\0".as_ptr().cast(), + ptr, + ); + write(STDERR_FILENO, buf.as_ptr().cast(), n as usize); } } } From cfe52381d762f37f9e5d47e083e0ee05c951879b Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 9 Jun 2026 10:50:22 -0400 Subject: [PATCH 19/55] remediate.rs: Removed logging to test performance. --- resolve-cveassert/libresolve/src/remediate.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index f6bef5b8..b25b10e1 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -234,17 +234,17 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { unsafe { if mi_is_heap_owned(ptr) { let _ = mi_free(ptr); - } else { - let mut buf = [0u8; 64]; - let n = libc::snprintf( - buf.as_mut_ptr().cast(), - buf.len(), - b"free(%p)\n\0".as_ptr().cast(), - ptr, - ); - write(STDERR_FILENO, buf.as_ptr().cast(), n as usize); } - } + // } else { + // let mut buf = [0u8; 64]; + // let n = libc::snprintf( + // buf.as_mut_ptr().cast(), + // buf.len(), + // b"free(%p)\n\0".as_ptr().cast(), + // ptr, + // ); + // write(STDERR_FILENO, buf.as_ptr().cast(), n as usize); + } } // /** From b2ecfd9407c59b8bb8f7dae8a71680c96940cacc Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 12 Jun 2026 11:18:36 -0400 Subject: [PATCH 20/55] remediate.rs: Make sure all logging is commented out for poller testing. --- resolve-cveassert/libresolve/src/remediate.rs | 297 ++++++------------ .../libresolve/src/shadowobjs.rs | 127 ++++---- 2 files changed, 169 insertions(+), 255 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index b25b10e1..be8f11f6 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -41,119 +41,24 @@ unsafe extern "C" { */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_alloca(_ptr: *mut c_void, _size: usize) -> () { -// let base = ptr as Vaddr; -// { -// let mut obj_list = ALIVE_OBJ_LIST.lock(); -// obj_list.add_shadow_object(AllocType::Stack, base, size); -// } -// info!("[STACK] Object allocated with size: {size}, address: 0x{base:x}"); +// let base = ptr as Vaddr; +// { +// let mut obj_list = ALIVE_OBJ_LIST.lock(); +// obj_list.add_shadow_object(AllocType::Stack, base, size); +// } +// info!("[STACK] Object allocated with size: {size}, address: 0x{base:x}"); } #[unsafe(no_mangle)] pub extern "C" fn __resolve_invalidate_stack(_base: *mut c_void) { -// let base = base as Vaddr; -// -// { -// let mut obj_list = ALIVE_OBJ_LIST.lock(); -// obj_list.invalidate_at(base); -// } -// -// info!("[STACK] Free addr 0x{base:x}"); -} - -#[unsafe(no_mangle)] -pub extern "C" fn __resolve_getline(lineptr: *mut *mut c_char, size: *mut size_t, stream: *mut FILE) -> ssize_t { - if lineptr.is_null() || size.is_null() || stream.is_null() { - return -1; - } - - unsafe { - if (*lineptr).is_null() || *size == 0 { - *size = 128; - *lineptr = __resolve_malloc(*size) as *mut c_char; - - // check if the pointer is null - if (*lineptr).is_null() { return -1; } - } - - let mut pos: size_t = 0; - let mut c: c_int; +// let _base = base as Vaddr; - loop { - c = fgetc(stream); - if c == EOF { break; } +// { +// let mut obj_list = ALIVE_OBJ_LIST.lock(); +// obj_list.invalidate_at(base); +// } - if pos + 1 >= *size { // Expand buffer - let new_size = *size * 2; - let new_buf = __resolve_realloc(*lineptr as *mut c_void, new_size); - - if new_buf.is_null() { - return -1; - } - - *lineptr = new_buf as *mut c_char; - *size = new_size; - } - - // (*lineptr)[pos++] = (char)c; - (*lineptr).add(pos).write(c as c_char); - pos += 1; - - if c == b'\n' as c_int { - break; - } - - } - - if pos == 0 && c == EOF { // No data read - return -1; - } - - (*lineptr).add(pos).write(0); // (*lineptr)[pos] = '\0' - pos as ssize_t - } -} - -#[unsafe(no_mangle)] -pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_t, delim: c_int, stream: *mut FILE) -> ssize_t { - if lineptr.is_null() || size.is_null() || stream.is_null() { - return -1; - } - - unsafe { - if (*lineptr).is_null() || *size == 0 { - *size = 128; - *lineptr = __resolve_malloc(*size) as *mut c_char; - - if (*lineptr).is_null() { return -1; } - } - - let mut pos: size_t = 0; - let mut c: c_int; - - loop { - c = fgetc(stream); - if c == EOF { break; } - - if pos + 1 >= *size { - let new_size = *size * 2; - let new_buf = __resolve_realloc(*lineptr as *mut c_void, new_size); - - if new_buf.is_null() { return -1; } - - *lineptr = new_buf as *mut c_char; - *size = new_size; - } - - (*lineptr).add(pos).write(c as c_char); - pos += 1; - - if c == delim { break; } - } - - (*lineptr).add(pos).write(0); - pos as ssize_t - } +// info!("[STACK] Free addr 0x{base:x}"); } /** @@ -180,9 +85,9 @@ pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { // ptr as Vaddr //); - //info!("[RESOLVE] bounds: (0x{:x}, 0x{:x})", bounds_info.base as Vaddr, bounds_info.limit as Vaddr); - //info!("[RESOLVE] block index: {}", bounds_info.block_index); - //info!("[RESOLVE] block size: {}", bounds_info.block_size); + info!("[RESOLVE] block bounds: (0x{:x}, 0x{:x})", bounds_info.base as Vaddr, bounds_info.limit as Vaddr); + info!("[RESOLVE] block index: {}", bounds_info.block_index); + info!("[RESOLVE] block size: {}", bounds_info.block_size); ptr } @@ -285,34 +190,34 @@ pub extern "C" fn __resolve_realloc(ptr: *mut c_void, size: usize) -> *mut c_voi realloc_ptr } -/** - * @brief - Allocator logging interface for calloc - * @input - * - n_items: number of items in the allocation - * - size: size of the allocation in bytes - * @return - none - */ -#[unsafe(no_mangle)] -pub extern "C" fn __resolve_calloc(n_items: usize, item_size: usize) -> *mut c_void { - let ptr = unsafe { mi_calloc(n_items, item_size) }; - let size = n_items * item_size; +// /** +// * @brief - Allocator logging interface for calloc +// * @input +// * - n_items: number of items in the allocation +// * - size: size of the allocation in bytes +// * @return - none +// */ +// #[unsafe(no_mangle)] +// pub extern "C" fn __resolve_calloc(n_items: usize, item_size: usize) -> *mut c_void { +// let ptr = unsafe { mi_calloc(n_items, item_size) }; +// let size = n_items * item_size; - if ptr.is_null() { - return ptr; - } +// if ptr.is_null() { +// return ptr; +// } - //{ - // let mut obj_list = ALIVE_OBJ_LIST.lock(); - // obj_list.add_shadow_object(AllocType::Heap, ptr as Vaddr, size); - //} +// { +// let mut obj_list = ALIVE_OBJ_LIST.lock(); +// obj_list.add_shadow_object(AllocType::Heap, ptr as Vaddr, size); +// } - //info!( - // "[HEAP] Logging allocation with {n_items} items, size (bytes): {size}, dst ptr: 0x{:x}", - // ptr as Vaddr - //); +// info!( +// "[HEAP] Logging allocation with {n_items} items, size (bytes): {size}, dst ptr: 0x{:x}", +// ptr as Vaddr +// ); - ptr -} +// ptr +// } // /** // * @brief - Allocator logging interface for strdup @@ -320,30 +225,30 @@ pub extern "C" fn __resolve_calloc(n_items: usize, item_size: usize) -> *mut c_v // * - ptr: ptr to the original allocation // * @return - pointer to the copied string // */ -#[unsafe(no_mangle)] -pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { - let string_ptr = unsafe { mi_strdup(ptr) }; - - if string_ptr.is_null() { - return string_ptr; - } - - // +1 to include null termination byte. We should allow program to read this value. - // Otherwise how would the program find the end of the string? - // Although writing it to something else is probably a bad idea, this too should be allowed. - // let sizeofstr = unsafe { strlen(ptr) + 1 }; - // { - // let mut obj_list = ALIVE_OBJ_LIST.lock(); - // obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); - // } - - // info!( - // "[HEAP] Logging 'strdup' function call with dst ptr: 0x{:x}", - // string_ptr as Vaddr - // ); - - string_ptr -} +// #[unsafe(no_mangle)] +// pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { +// let string_ptr = unsafe { mi_strdup(ptr) }; + +// if string_ptr.is_null() { +// return string_ptr; +// } + +// // +1 to include null termination byte. We should allow program to read this value. +// // Otherwise how would the program find the end of the string? +// // Although writing it to something else is probably a bad idea, this too should be allowed. +// let sizeofstr = unsafe { strlen(ptr) + 1 }; +// { +// let mut obj_list = ALIVE_OBJ_LIST.lock(); +// obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); +// } + +// info!( +// "[HEAP] Logging 'strdup' function call with dst ptr: 0x{:x}", +// string_ptr as Vaddr +// ); + +// string_ptr +// } // /** // * @brief - Allocator logging interface for strdup @@ -354,32 +259,32 @@ pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { // * NOTE: Read this link to understand the nature of strdup & strndup // * https://pubs.opengroup.org/onlineptrpubs/9699919799/functions/strdup.html // */ -#[unsafe(no_mangle)] -pub extern "C" fn __resolve_strndup(ptr: *mut c_char, size: usize) -> *mut c_char { - let string_ptr = unsafe { mi_strndup(ptr, size + 1) }; +// #[unsafe(no_mangle)] +// pub extern "C" fn __resolve_strndup(ptr: *mut c_char, size: usize) -> *mut c_char { +// let string_ptr = unsafe { mi_strndup(ptr, size + 1) }; - if string_ptr.is_null() { - return string_ptr; - } +// if string_ptr.is_null() { +// return string_ptr; +// } - // +1 to include null termination byte. We should allow program to read this value. - // We don't actually know how much memory the libc will allocate, but - // strnlen(ptr, size) + 1 is a safe lower bound. - // strlen(string_ptr) + 1 would also be valid I think. - //let sizeofstr = unsafe { strnlen(ptr, size) + 1 }; +// // +1 to include null termination byte. We should allow program to read this value. +// // We don't actually know how much memory the libc will allocate, but +// // strnlen(ptr, size) + 1 is a safe lower bound. +// // strlen(string_ptr) + 1 would also be valid I think. +// let sizeofstr = unsafe { strnlen(ptr, size) + 1 }; - //{ - // let mut obj_list = ALIVE_OBJ_LIST.lock(); - // obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); - //} +// { +// let mut obj_list = ALIVE_OBJ_LIST.lock(); +// obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); +// } - //info!( - // "[HEAP] Logging 'strndup' function call with size (bytes): {size}, dst ptr: {:?}", - // string_ptr as Vaddr - //); +// info!( +// "[HEAP] Logging 'strndup' function call with size (bytes): {size}, dst ptr: {:?}", +// string_ptr as Vaddr +// ); - string_ptr -} +// string_ptr +// } #[repr(C)] pub struct ShadowObjBounds { @@ -412,24 +317,24 @@ pub extern "C" fn __resolve_get_bounds(ptr: *mut c_void) -> ShadowObjBounds { // return ShadowObjBounds { base: std::ptr::null_mut(), limit: std::ptr::null_mut() } //}; - //info!("[RESOLVE] Debugging: (0x{:x}, 0x{:x}, 0x{:x})", ptr as Vaddr, sobj.base as Vaddr, sobj.limit as Vaddr); - //return ShadowObjBounds { base: sobj.base as *mut c_void, limit: sobj.limit as *mut c_void } + //info!("[RESOLVE] Debugging: (ptr = 0x{:x}, lower = 0x{:x}, upper = 0x{:x})", ptr as Vaddr, sobj.base as Vaddr, sobj.limit as Vaddr); + return ShadowObjBounds { base: sobj.base as *mut c_void, limit: sobj.limit as *mut c_void } +} + +#[unsafe(no_mangle)] +pub extern "C" fn resolve_obj_type(base_ptr: *mut c_void) -> AllocType { + let base = base_ptr as Vaddr; + + let find_in = |table: &crate::MutexWrap| { + let t = table.lock(); + t.search_intersection(base).map(|o| o.alloc_type) + }; + + // Why does this search freed before alive? + let alloc_type = find_in(&FREED_OBJ_LIST).or_else(|| find_in(&ALIVE_OBJ_LIST)); + + alloc_type.unwrap_or(AllocType::Unknown) } -// -//#[unsafe(no_mangle)] -//pub extern "C" fn resolve_obj_type(base_ptr: *mut c_void) -> AllocType { -// let base = base_ptr as Vaddr; -// -// let find_in = |table: &crate::MutexWrap| { -// let t = table.lock(); -// t.search_intersection(base).map(|o| o.alloc_type) -// }; -// -// // Why does this search freed before alive? -// let alloc_type = find_in(&FREED_OBJ_LIST).or_else(|| find_in(&ALIVE_OBJ_LIST)); -// -// alloc_type.unwrap_or(AllocType::Unknown) -//} /** * @brief - Logs when program enters sanitization basic block diff --git a/resolve-cveassert/libresolve/src/shadowobjs.rs b/resolve-cveassert/libresolve/src/shadowobjs.rs index 4e7fafc0..e7086767 100644 --- a/resolve-cveassert/libresolve/src/shadowobjs.rs +++ b/resolve-cveassert/libresolve/src/shadowobjs.rs @@ -114,19 +114,20 @@ impl ShadowObjectTable { pub static ALIVE_OBJ_LIST: MutexWrap = MutexWrap::new(ShadowObjectTable::new()); pub static FREED_OBJ_LIST: MutexWrap = MutexWrap::new(ShadowObjectTable::new()); -#[cfg(test)] -mod tests { - use crate::shadowobjs::{AllocType, ShadowObjectTable}; +// #[cfg(test)] +// mod tests { +// use crate::shadowobjs::{AllocType, ShadowObjectTable}; - #[test] - fn test_add_and_print_shadow_objects() { - let mut table = ShadowObjectTable::new(); - table.add_shadow_object(AllocType::Heap, 0x1000, 8); - table.add_shadow_object(AllocType::Stack, 0x2000, 16); +// #[test] +// fn test_add_and_print_shadow_objects() { +// let mut table = ShadowObjectTable::new(); +// table.add_shadow_object(AllocType::Heap, 0x1000, 8); +// table.add_shadow_object(AllocType::Stack, 0x2000, 16); - //table.print_shadow_obj(); - } +// //table.print_shadow_obj(); +// } +<<<<<<< HEAD #[test] fn test_remove_shadow_objects() { let mut table = ShadowObjectTable::new(); @@ -135,52 +136,60 @@ mod tests { table.invalidate_at(0x1000); assert_eq!(table.table.len(), 1); } - - #[test] - fn test_search_intersection_found() { - let mut table = ShadowObjectTable::new(); - table.add_shadow_object(AllocType::Global, 0x3000, 4); - - let result = table.search_intersection(0x3002); - assert!(result.is_some()); - assert_eq!(result.unwrap().alloc_type, AllocType::Global); - } - - #[test] - fn test_search_intersection_not_found() { - let mut table = ShadowObjectTable::new(); - table.add_shadow_object(AllocType::Heap, 0x4000, 4); - - let result = table.search_intersection(0x5000); - assert!(result.is_none()); - } - - #[test] - fn test_is_allocation() { - let mut table = ShadowObjectTable::new(); - table.add_shadow_object(AllocType::Stack, 0x6000, 8); - - let typ = table.search_intersection(0x6004).unwrap().alloc_type; - assert_eq!(typ, AllocType::Stack); - } - #[test] - fn bounds_testing() { - let mut table = ShadowObjectTable::new(); - table.add_shadow_object(AllocType::Heap, 0x8000, 8); - - for x in 0x8000..0x8008 { - assert!(table.search_intersection(x).is_some()); - } - - assert!(table.search_intersection(0x8009).is_none()); - assert!(table.search_intersection(0x7FFF).is_none()); - } - - #[test] - #[should_panic] - #[ignore = "not implemented"] - fn test_bounds_invalid_address_panic() { - // let table = ShadowObjectTable::new(); - //table.bounds(0xDEADBEEF).unwrap(); // should panic since there is no interesection - } -} +======= +// #[test] +// fn test_remove_shadow_objects() { +// let mut table = ShadowObjectTable::new(); +// table.add_shadow_object(AllocType::Heap, 0x1000, 8); +// table.add_shadow_object(AllocType::Stack, 0x2000, 16); +// } +>>>>>>> ec6b0f1 (remediate.rs: Make sure all logging is commented out for poller testing.) + +// #[test] +// fn test_search_intersection_found() { +// let mut table = ShadowObjectTable::new(); +// table.add_shadow_object(AllocType::Global, 0x3000, 4); + +// let result = table.search_intersection(0x3002); +// assert!(result.is_some()); +// assert_eq!(result.unwrap().alloc_type, AllocType::Global); +// } + +// #[test] +// fn test_search_intersection_not_found() { +// let mut table = ShadowObjectTable::new(); +// table.add_shadow_object(AllocType::Heap, 0x4000, 4); + +// let result = table.search_intersection(0x5000); +// assert!(result.is_none()); +// } + +// #[test] +// fn test_is_allocation() { +// let mut table = ShadowObjectTable::new(); +// table.add_shadow_object(AllocType::Stack, 0x6000, 8); + +// let typ = table.search_intersection(0x6004).unwrap().alloc_type; +// assert_eq!(typ, AllocType::Stack); +// } +// #[test] +// fn bounds_testing() { +// let mut table = ShadowObjectTable::new(); +// table.add_shadow_object(AllocType::Heap, 0x8000, 8); + +// for x in 0x8000..0x8008 { +// assert!(table.search_intersection(x).is_some()); +// } + +// assert!(table.search_intersection(0x8009).is_none()); +// assert!(table.search_intersection(0x7FFF).is_none()); +// } + +// #[test] +// #[should_panic] +// #[ignore = "not implemented"] +// fn test_bounds_invalid_address_panic() { +// // let table = ShadowObjectTable::new(); +// //table.bounds(0xDEADBEEF).unwrap(); // should panic since there is no interesection +// } +// } From 6e43fe2ad356d3f6632c864ba1a8f8ab814687ad Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 12 Jun 2026 11:19:18 -0400 Subject: [PATCH 21/55] remediate.rs: Comment out all logging. --- resolve-cveassert/libresolve/src/remediate.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index be8f11f6..e1c29bb2 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -85,9 +85,9 @@ pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { // ptr as Vaddr //); - info!("[RESOLVE] block bounds: (0x{:x}, 0x{:x})", bounds_info.base as Vaddr, bounds_info.limit as Vaddr); - info!("[RESOLVE] block index: {}", bounds_info.block_index); - info!("[RESOLVE] block size: {}", bounds_info.block_size); + //info!("[RESOLVE] block bounds: (0x{:x}, 0x{:x})", bounds_info.base as Vaddr, bounds_info.limit as Vaddr); + //info!("[RESOLVE] block index: {}", bounds_info.block_index); + //info!("[RESOLVE] block size: {}", bounds_info.block_size); ptr } From 317e6454c1997ff842cfee3e524019e4f2fb4b4c Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 12 Jun 2026 11:33:59 -0400 Subject: [PATCH 22/55] remediate.rs: Commenting out extra line that caused bad compilation. --- resolve-cveassert/libresolve/src/remediate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index e1c29bb2..3655a170 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -318,7 +318,7 @@ pub extern "C" fn __resolve_get_bounds(ptr: *mut c_void) -> ShadowObjBounds { //}; //info!("[RESOLVE] Debugging: (ptr = 0x{:x}, lower = 0x{:x}, upper = 0x{:x})", ptr as Vaddr, sobj.base as Vaddr, sobj.limit as Vaddr); - return ShadowObjBounds { base: sobj.base as *mut c_void, limit: sobj.limit as *mut c_void } + //return ShadowObjBounds { base: sobj.base as *mut c_void, limit: sobj.limit as *mut c_void } } #[unsafe(no_mangle)] From 735b5e1e6009b47f93faf9cdc76d14cc752b900c Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 12 Jun 2026 11:51:10 -0400 Subject: [PATCH 23/55] remediate.rs: Restored commit 48dbed5 for testing. --- resolve-cveassert/libresolve/src/remediate.rs | 311 +++++++++++------- 1 file changed, 196 insertions(+), 115 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 3655a170..94c1729b 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -1,8 +1,7 @@ // Copyright (c) 2025 Riverside Research. // LGPL-3; See LICENSE.txt in the repo root for details. use libc::{ - EOF, FILE, c_char, c_int, c_void, fgetc, free, strlen, strnlen, size_t, ssize_t, - write, STDERR_FILENO, + EOF, FILE, c_char, c_int, c_void, fgetc, strlen, strnlen, size_t, ssize_t, }; use crate::shadowobjs::{ @@ -31,7 +30,6 @@ unsafe extern "C" { // Shim API fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; - fn mi_is_heap_owned(ptr: *mut c_void) -> bool; } /** @@ -41,24 +39,119 @@ unsafe extern "C" { */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_alloca(_ptr: *mut c_void, _size: usize) -> () { -// let base = ptr as Vaddr; -// { -// let mut obj_list = ALIVE_OBJ_LIST.lock(); -// obj_list.add_shadow_object(AllocType::Stack, base, size); -// } -// info!("[STACK] Object allocated with size: {size}, address: 0x{base:x}"); +// let base = ptr as Vaddr; +// { +// let mut obj_list = ALIVE_OBJ_LIST.lock(); +// obj_list.add_shadow_object(AllocType::Stack, base, size); +// } +// info!("[STACK] Object allocated with size: {size}, address: 0x{base:x}"); } #[unsafe(no_mangle)] pub extern "C" fn __resolve_invalidate_stack(_base: *mut c_void) { -// let _base = base as Vaddr; +// let base = base as Vaddr; +// +// { +// let mut obj_list = ALIVE_OBJ_LIST.lock(); +// obj_list.invalidate_at(base); +// } +// +// info!("[STACK] Free addr 0x{base:x}"); +} + +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_getline(lineptr: *mut *mut c_char, size: *mut size_t, stream: *mut FILE) -> ssize_t { + if lineptr.is_null() || size.is_null() || stream.is_null() { + return -1; + } + + unsafe { + if (*lineptr).is_null() || *size == 0 { + *size = 128; + *lineptr = __resolve_malloc(*size) as *mut c_char; + + // check if the pointer is null + if (*lineptr).is_null() { return -1; } + } + + let mut pos: size_t = 0; + let mut c: c_int; + + loop { + c = fgetc(stream); + if c == EOF { break; } + + if pos + 1 >= *size { // Expand buffer + let new_size = *size * 2; + let new_buf = __resolve_realloc(*lineptr as *mut c_void, new_size); + + if new_buf.is_null() { + return -1; + } + + *lineptr = new_buf as *mut c_char; + *size = new_size; + } + + // (*lineptr)[pos++] = (char)c; + (*lineptr).add(pos).write(c as c_char); + pos += 1; + + if c == b'\n' as c_int { + break; + } + + } + + if pos == 0 && c == EOF { // No data read + return -1; + } + + (*lineptr).add(pos).write(0); // (*lineptr)[pos] = '\0' + pos as ssize_t + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_t, delim: c_int, stream: *mut FILE) -> ssize_t { + if lineptr.is_null() || size.is_null() || stream.is_null() { + return -1; + } + + unsafe { + if (*lineptr).is_null() || *size == 0 { + *size = 128; + *lineptr = __resolve_malloc(*size) as *mut c_char; + + if (*lineptr).is_null() { return -1; } + } + + let mut pos: size_t = 0; + let mut c: c_int; + + loop { + c = fgetc(stream); + if c == EOF { break; } + + if pos + 1 >= *size { + let new_size = *size * 2; + let new_buf = __resolve_realloc(*lineptr as *mut c_void, new_size); + + if new_buf.is_null() { return -1; } + + *lineptr = new_buf as *mut c_char; + *size = new_size; + } + + (*lineptr).add(pos).write(c as c_char); + pos += 1; -// { -// let mut obj_list = ALIVE_OBJ_LIST.lock(); -// obj_list.invalidate_at(base); -// } + if c == delim { break; } + } -// info!("[STACK] Free addr 0x{base:x}"); + (*lineptr).add(pos).write(0); + pos as ssize_t + } } /** @@ -85,7 +178,7 @@ pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { // ptr as Vaddr //); - //info!("[RESOLVE] block bounds: (0x{:x}, 0x{:x})", bounds_info.base as Vaddr, bounds_info.limit as Vaddr); + //info!("[RESOLVE] bounds: (0x{:x}, 0x{:x})", bounds_info.base as Vaddr, bounds_info.limit as Vaddr); //info!("[RESOLVE] block index: {}", bounds_info.block_index); //info!("[RESOLVE] block size: {}", bounds_info.block_size); ptr @@ -136,20 +229,8 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { // let mut freed_guard = FREED_OBJ_LIST.lock(); // freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); // } - unsafe { - if mi_is_heap_owned(ptr) { - let _ = mi_free(ptr); - } - // } else { - // let mut buf = [0u8; 64]; - // let n = libc::snprintf( - // buf.as_mut_ptr().cast(), - // buf.len(), - // b"free(%p)\n\0".as_ptr().cast(), - // ptr, - // ); - // write(STDERR_FILENO, buf.as_ptr().cast(), n as usize); - } + + let _ = unsafe { mi_free(ptr) }; } // /** @@ -190,34 +271,34 @@ pub extern "C" fn __resolve_realloc(ptr: *mut c_void, size: usize) -> *mut c_voi realloc_ptr } -// /** -// * @brief - Allocator logging interface for calloc -// * @input -// * - n_items: number of items in the allocation -// * - size: size of the allocation in bytes -// * @return - none -// */ -// #[unsafe(no_mangle)] -// pub extern "C" fn __resolve_calloc(n_items: usize, item_size: usize) -> *mut c_void { -// let ptr = unsafe { mi_calloc(n_items, item_size) }; -// let size = n_items * item_size; +/** + * @brief - Allocator logging interface for calloc + * @input + * - n_items: number of items in the allocation + * - size: size of the allocation in bytes + * @return - none + */ +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_calloc(n_items: usize, item_size: usize) -> *mut c_void { + let ptr = unsafe { mi_calloc(n_items, item_size) }; + let size = n_items * item_size; -// if ptr.is_null() { -// return ptr; -// } + if ptr.is_null() { + return ptr; + } -// { -// let mut obj_list = ALIVE_OBJ_LIST.lock(); -// obj_list.add_shadow_object(AllocType::Heap, ptr as Vaddr, size); -// } + //{ + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // obj_list.add_shadow_object(AllocType::Heap, ptr as Vaddr, size); + //} -// info!( -// "[HEAP] Logging allocation with {n_items} items, size (bytes): {size}, dst ptr: 0x{:x}", -// ptr as Vaddr -// ); + //info!( + // "[HEAP] Logging allocation with {n_items} items, size (bytes): {size}, dst ptr: 0x{:x}", + // ptr as Vaddr + //); -// ptr -// } + ptr +} // /** // * @brief - Allocator logging interface for strdup @@ -225,30 +306,30 @@ pub extern "C" fn __resolve_realloc(ptr: *mut c_void, size: usize) -> *mut c_voi // * - ptr: ptr to the original allocation // * @return - pointer to the copied string // */ -// #[unsafe(no_mangle)] -// pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { -// let string_ptr = unsafe { mi_strdup(ptr) }; - -// if string_ptr.is_null() { -// return string_ptr; -// } - -// // +1 to include null termination byte. We should allow program to read this value. -// // Otherwise how would the program find the end of the string? -// // Although writing it to something else is probably a bad idea, this too should be allowed. -// let sizeofstr = unsafe { strlen(ptr) + 1 }; -// { -// let mut obj_list = ALIVE_OBJ_LIST.lock(); -// obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); -// } - -// info!( -// "[HEAP] Logging 'strdup' function call with dst ptr: 0x{:x}", -// string_ptr as Vaddr -// ); - -// string_ptr -// } +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { + let string_ptr = unsafe { mi_strdup(ptr) }; + + if string_ptr.is_null() { + return string_ptr; + } + + // +1 to include null termination byte. We should allow program to read this value. + // Otherwise how would the program find the end of the string? + // Although writing it to something else is probably a bad idea, this too should be allowed. + // let sizeofstr = unsafe { strlen(ptr) + 1 }; + // { + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); + // } + + // info!( + // "[HEAP] Logging 'strdup' function call with dst ptr: 0x{:x}", + // string_ptr as Vaddr + // ); + + string_ptr +} // /** // * @brief - Allocator logging interface for strdup @@ -259,32 +340,32 @@ pub extern "C" fn __resolve_realloc(ptr: *mut c_void, size: usize) -> *mut c_voi // * NOTE: Read this link to understand the nature of strdup & strndup // * https://pubs.opengroup.org/onlineptrpubs/9699919799/functions/strdup.html // */ -// #[unsafe(no_mangle)] -// pub extern "C" fn __resolve_strndup(ptr: *mut c_char, size: usize) -> *mut c_char { -// let string_ptr = unsafe { mi_strndup(ptr, size + 1) }; +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_strndup(ptr: *mut c_char, size: usize) -> *mut c_char { + let string_ptr = unsafe { mi_strndup(ptr, size + 1) }; -// if string_ptr.is_null() { -// return string_ptr; -// } + if string_ptr.is_null() { + return string_ptr; + } -// // +1 to include null termination byte. We should allow program to read this value. -// // We don't actually know how much memory the libc will allocate, but -// // strnlen(ptr, size) + 1 is a safe lower bound. -// // strlen(string_ptr) + 1 would also be valid I think. -// let sizeofstr = unsafe { strnlen(ptr, size) + 1 }; + // +1 to include null termination byte. We should allow program to read this value. + // We don't actually know how much memory the libc will allocate, but + // strnlen(ptr, size) + 1 is a safe lower bound. + // strlen(string_ptr) + 1 would also be valid I think. + //let sizeofstr = unsafe { strnlen(ptr, size) + 1 }; -// { -// let mut obj_list = ALIVE_OBJ_LIST.lock(); -// obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); -// } + //{ + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); + //} -// info!( -// "[HEAP] Logging 'strndup' function call with size (bytes): {size}, dst ptr: {:?}", -// string_ptr as Vaddr -// ); + //info!( + // "[HEAP] Logging 'strndup' function call with size (bytes): {size}, dst ptr: {:?}", + // string_ptr as Vaddr + //); -// string_ptr -// } + string_ptr +} #[repr(C)] pub struct ShadowObjBounds { @@ -317,24 +398,24 @@ pub extern "C" fn __resolve_get_bounds(ptr: *mut c_void) -> ShadowObjBounds { // return ShadowObjBounds { base: std::ptr::null_mut(), limit: std::ptr::null_mut() } //}; - //info!("[RESOLVE] Debugging: (ptr = 0x{:x}, lower = 0x{:x}, upper = 0x{:x})", ptr as Vaddr, sobj.base as Vaddr, sobj.limit as Vaddr); + //info!("[RESOLVE] Debugging: (0x{:x}, 0x{:x}, 0x{:x})", ptr as Vaddr, sobj.base as Vaddr, sobj.limit as Vaddr); //return ShadowObjBounds { base: sobj.base as *mut c_void, limit: sobj.limit as *mut c_void } } - -#[unsafe(no_mangle)] -pub extern "C" fn resolve_obj_type(base_ptr: *mut c_void) -> AllocType { - let base = base_ptr as Vaddr; - - let find_in = |table: &crate::MutexWrap| { - let t = table.lock(); - t.search_intersection(base).map(|o| o.alloc_type) - }; - - // Why does this search freed before alive? - let alloc_type = find_in(&FREED_OBJ_LIST).or_else(|| find_in(&ALIVE_OBJ_LIST)); - - alloc_type.unwrap_or(AllocType::Unknown) -} +// +//#[unsafe(no_mangle)] +//pub extern "C" fn resolve_obj_type(base_ptr: *mut c_void) -> AllocType { +// let base = base_ptr as Vaddr; +// +// let find_in = |table: &crate::MutexWrap| { +// let t = table.lock(); +// t.search_intersection(base).map(|o| o.alloc_type) +// }; +// +// // Why does this search freed before alive? +// let alloc_type = find_in(&FREED_OBJ_LIST).or_else(|| find_in(&ALIVE_OBJ_LIST)); +// +// alloc_type.unwrap_or(AllocType::Unknown) +//} /** * @brief - Logs when program enters sanitization basic block From 907fbdffc974c1342133cf0ef69b5eb4fd947371 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 12 Jun 2026 12:48:04 -0400 Subject: [PATCH 24/55] remediate.rs: Fixing remediate.rs since I lost some of the commits to git stash. --- resolve-cveassert/libresolve/src/remediate.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 94c1729b..9433a467 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -30,6 +30,7 @@ unsafe extern "C" { // Shim API fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; + fn mi_is_heap_owned(ptr: *mut c_void) -> bool; } /** @@ -229,8 +230,11 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { // let mut freed_guard = FREED_OBJ_LIST.lock(); // freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); // } - - let _ = unsafe { mi_free(ptr) }; + unsafe { + if mi_is_heap_owned(ptr) { + let _ = mi_free(ptr); + } + } } // /** From f282321e0fbc466c2321b808aad659fd65077e6c Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 12 Jun 2026 14:00:04 -0400 Subject: [PATCH 25/55] remediate.rs: Adding logic to call libc free if the pointer does not belong to mimalloc. --- resolve-cveassert/libresolve/src/remediate.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 9433a467..826e326d 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -233,6 +233,8 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { unsafe { if mi_is_heap_owned(ptr) { let _ = mi_free(ptr); + } else { + let _ = free(ptr); } } } From ddab667aac299b2132058c04f0ea76464fa1323e Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 12 Jun 2026 14:07:15 -0400 Subject: [PATCH 26/55] remediate.rs: Fixing issues in compilation. --- resolve-cveassert/libresolve/src/remediate.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 826e326d..713b1cc9 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -1,7 +1,7 @@ // Copyright (c) 2025 Riverside Research. // LGPL-3; See LICENSE.txt in the repo root for details. use libc::{ - EOF, FILE, c_char, c_int, c_void, fgetc, strlen, strnlen, size_t, ssize_t, + EOF, FILE, c_char, c_int, c_void, fgetc, free, strlen, strnlen, size_t, ssize_t, }; use crate::shadowobjs::{ @@ -230,7 +230,10 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { // let mut freed_guard = FREED_OBJ_LIST.lock(); // freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); // } + unsafe { + if ptr.is_null() { return; } + if mi_is_heap_owned(ptr) { let _ = mi_free(ptr); } else { From 7a135256d9cd6d7fedb87acf82c153a395b38128 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 12 Jun 2026 14:15:40 -0400 Subject: [PATCH 27/55] mimalloc_shadow.c: Switching to mi_is_in_heap to better handle arbitrary pointers. --- resolve-cveassert/libresolve/mimalloc_shadow.c | 2 +- resolve-cveassert/libresolve/src/remediate.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/resolve-cveassert/libresolve/mimalloc_shadow.c b/resolve-cveassert/libresolve/mimalloc_shadow.c index 0d9c1ee4..29ab840a 100644 --- a/resolve-cveassert/libresolve/mimalloc_shadow.c +++ b/resolve-cveassert/libresolve/mimalloc_shadow.c @@ -31,7 +31,7 @@ bounds_info_t mi_resolve_ptr(void* p) { } bool mi_is_heap_owned(const void* p) { - return mi_check_owned(p); + return mi_is_in_heap_region(p); } diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 713b1cc9..4490568b 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -234,7 +234,8 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { unsafe { if ptr.is_null() { return; } - if mi_is_heap_owned(ptr) { + let owned = mi_is_heap_owned(ptr); + if owned { let _ = mi_free(ptr); } else { let _ = free(ptr); From 93415fbffcf6d93cdd901f291678d9b78156e5c1 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 12 Jun 2026 15:05:38 -0400 Subject: [PATCH 28/55] WIP: Testing if the unknown pointer comes from C++ new/delete allocator. --- resolve-cveassert/libresolve/src/remediate.rs | 31 ++++++++++++++++++- resolve-cveassert/src/instrument.cpp | 2 ++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 4490568b..4256c93b 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -1,7 +1,7 @@ // Copyright (c) 2025 Riverside Research. // LGPL-3; See LICENSE.txt in the repo root for details. use libc::{ - EOF, FILE, c_char, c_int, c_void, fgetc, free, strlen, strnlen, size_t, ssize_t, + EOF, FILE, c_char, c_int, c_void, fgetc, free, delete, strlen, strnlen, size_t, ssize_t, }; use crate::shadowobjs::{ @@ -27,6 +27,8 @@ unsafe extern "C" { fn mi_strdup(ptr: *mut c_char) -> *mut c_char; fn mi_strndup(ptr: *mut c_char, size: usize) -> *mut c_char; fn mi_free(ptr: *mut c_void); + fn mi_new(size: usize) -> *mut c_void; + fn mi_delete(ptr: *mut c_void); // Shim API fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; @@ -185,6 +187,18 @@ pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { ptr } + +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_new(size: usize) -> *mut c_void { + let ptr = unsafe { mi_new(size + 1) }; + + if ptr.is_null() { + return ptr; + } + + ptr +} + /** * @brief - Allocator logging interface for free * @input - ptr to the allocation @@ -243,6 +257,21 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { } } // + + +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_delete(ptr: *mut c_void) -> () { + if ptr.is_null() { return; } + + unsafe { + let owned = mi_is_heap_owned(p); + if owned { + let_ = mi_free(ptr); + } else { + let _ = delete(ptr); + } + } +} /** * @brief - Allocator logging interface for realloc * @input diff --git a/resolve-cveassert/src/instrument.cpp b/resolve-cveassert/src/instrument.cpp index 643c91c9..8b1e7e8a 100644 --- a/resolve-cveassert/src/instrument.cpp +++ b/resolve-cveassert/src/instrument.cpp @@ -80,6 +80,8 @@ void instrumentLibraryAllocations(Function *F) { wrapLibraryFunction( F, "getdelim", FunctionType::get(size_ty, {ptr_ty, ptr_ty, size_ty, ptr_ty}, false)); + wrapLibraryFunction(F, "new", FunctionType::get(ptr_ty, {size_ty}, false)); + wrapLibraryFunction(F, "delete", FunctionType::get(void_ty, {ptr_ty}, false)); } void instrumentAlloca(Function *F) { From 1a4f7c38d79188240e65df76d90229c29b032ce6 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Fri, 12 Jun 2026 15:08:54 -0400 Subject: [PATCH 29/55] WIP: Fixing compilation issues. Testing if allocation comes from C++ new/delete. --- resolve-cveassert/libresolve/src/remediate.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 4256c93b..8c17e63a 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -1,7 +1,7 @@ // Copyright (c) 2025 Riverside Research. // LGPL-3; See LICENSE.txt in the repo root for details. use libc::{ - EOF, FILE, c_char, c_int, c_void, fgetc, free, delete, strlen, strnlen, size_t, ssize_t, + EOF, FILE, c_char, c_int, c_void, fgetc, free, strlen, strnlen, size_t, ssize_t, }; use crate::shadowobjs::{ @@ -262,15 +262,7 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { #[unsafe(no_mangle)] pub extern "C" fn __resolve_delete(ptr: *mut c_void) -> () { if ptr.is_null() { return; } - - unsafe { - let owned = mi_is_heap_owned(p); - if owned { - let_ = mi_free(ptr); - } else { - let _ = delete(ptr); - } - } + let _ = unsafe { mi_free(ptr) }; } /** * @brief - Allocator logging interface for realloc From 044acb62d113f195f1ae02e0c9325f46f125835e Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 15 Jun 2026 09:51:20 -0400 Subject: [PATCH 30/55] remediate.rs: Debugging __resolve_free. --- resolve-cveassert/libresolve/src/remediate.rs | 63 ++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 8c17e63a..d4baddec 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -1,7 +1,9 @@ // Copyright (c) 2025 Riverside Research. // LGPL-3; See LICENSE.txt in the repo root for details. + use libc::{ - EOF, FILE, c_char, c_int, c_void, fgetc, free, strlen, strnlen, size_t, ssize_t, + EOF, FILE, STDERR_FILENO, c_char, c_int, c_void, fgetc, free, strlen, strnlen, size_t, ssize_t, + write, }; use crate::shadowobjs::{ @@ -157,6 +159,53 @@ pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_ } } + +// #[unsafe(no_mangle)] +// pub extern "C" fn __resolve_asprintf(strp: *mut *mut char, fmt: *const char, mut args: ...) -> c_int { +// unsafe { +// if strp.is_null() || fmt.is_null() { +// return -1; +// } + +// let mut ap = args.clone(); + +// let len = snprintf( +// ptr::null_mut(), +// 0, +// fmt, +// ap.as_va_list(), +// ); + +// if len < 0 { +// return -1; +// } + +// let size = (len as usize) + 1; +// let buf = __resolve_malloc(size) as *mut char; + +// if buf.is_null() { +// return -1; +// } + +// let mut ap2 = args; + +// let written = snprintf( +// buf, +// size, +// fmt, +// ap2.as_va_list(), +// ); + +// if written < 0 { +// free(buf as *mut void); +// return -1; +// } + +// *strp = buf; +// written +// } + +// } /** * @brief - Allocator logging interface for malloc * @input - size of the allocation in bytes @@ -208,6 +257,18 @@ pub extern "C" fn __resolve_new(size: usize) -> *mut c_void { pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { // Insert a function to find the object and return the pointer size // Do I need to handle if the sobj cannot be found? + unsafe { + if ptr.is_null() { + return; + } + + if !mi_is_heap_owned(ptr) { + let msg = "foreign allocation\n"; + write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); + } else { + let _ = mi_free(ptr); + } + } // info!( // "[FREE] Allocated object freed at address: 0x{:x}", From 7b544e8ac4c9aaa2c4014235de23b0aea81b41d0 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 15 Jun 2026 10:55:42 -0400 Subject: [PATCH 31/55] WIP: Modified Cargo.toml to have cargo build with nightly and added __resolve_apsrintf to shim for testing. --- resolve-cveassert/libresolve/Cargo.toml | 2 + .../libresolve/mimalloc_shadow.c | 41 ++++++++++++++++ resolve-cveassert/libresolve/src/remediate.rs | 47 ------------------- resolve-cveassert/src/instrument.cpp | 7 +++ 4 files changed, 50 insertions(+), 47 deletions(-) diff --git a/resolve-cveassert/libresolve/Cargo.toml b/resolve-cveassert/libresolve/Cargo.toml index 8137e27d..032693c8 100644 --- a/resolve-cveassert/libresolve/Cargo.toml +++ b/resolve-cveassert/libresolve/Cargo.toml @@ -20,3 +20,5 @@ debug = true [profile.dev] panic = "abort" +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/resolve-cveassert/libresolve/mimalloc_shadow.c b/resolve-cveassert/libresolve/mimalloc_shadow.c index 29ab840a..240501f0 100644 --- a/resolve-cveassert/libresolve/mimalloc_shadow.c +++ b/resolve-cveassert/libresolve/mimalloc_shadow.c @@ -3,6 +3,9 @@ #include #include +extern void * __resolve_malloc(size_t); +extern void *__resolve_free(void*); + typedef struct { void *base; void *limit; @@ -35,3 +38,41 @@ bool mi_is_heap_owned(const void* p) { } +int __resolve_vasprintf(char **strp, const char *fmt, va_list ap) +{ + va_list ap_copy; + va_copy(ap_copy, ap); + + int len = vsnprintf(NULL, 0, fmt, ap_copy); + va_end(ap_copy); + + if (len < 0) { return -1; } + + char *buf = __resolve_malloc((size_t)len + 1); + if (!buf) { return -1; } + + va_copy(ap_copy, ap); + + int written = vsnprintf(buf, (size_t)len + 1, fmt, ap_copy); + + va_end(ap_copy); + + if (written < 0) { + __resolve_free(buf); + return -1; + } + + *strp = buf; + return written; +} + +int __resolve_asprintf(char **strp, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + int rc = __resolve_vasprintf(strp, fmt, ap); + + va_end(ap); + return rc; +} diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index d4baddec..f872c47d 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -159,53 +159,6 @@ pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_ } } - -// #[unsafe(no_mangle)] -// pub extern "C" fn __resolve_asprintf(strp: *mut *mut char, fmt: *const char, mut args: ...) -> c_int { -// unsafe { -// if strp.is_null() || fmt.is_null() { -// return -1; -// } - -// let mut ap = args.clone(); - -// let len = snprintf( -// ptr::null_mut(), -// 0, -// fmt, -// ap.as_va_list(), -// ); - -// if len < 0 { -// return -1; -// } - -// let size = (len as usize) + 1; -// let buf = __resolve_malloc(size) as *mut char; - -// if buf.is_null() { -// return -1; -// } - -// let mut ap2 = args; - -// let written = snprintf( -// buf, -// size, -// fmt, -// ap2.as_va_list(), -// ); - -// if written < 0 { -// free(buf as *mut void); -// return -1; -// } - -// *strp = buf; -// written -// } - -// } /** * @brief - Allocator logging interface for malloc * @input - size of the allocation in bytes diff --git a/resolve-cveassert/src/instrument.cpp b/resolve-cveassert/src/instrument.cpp index 8b1e7e8a..3c09284c 100644 --- a/resolve-cveassert/src/instrument.cpp +++ b/resolve-cveassert/src/instrument.cpp @@ -82,6 +82,13 @@ void instrumentLibraryAllocations(Function *F) { FunctionType::get(size_ty, {ptr_ty, ptr_ty, size_ty, ptr_ty}, false)); wrapLibraryFunction(F, "new", FunctionType::get(ptr_ty, {size_ty}, false)); wrapLibraryFunction(F, "delete", FunctionType::get(void_ty, {ptr_ty}, false)); + wrapLibraryFunction(F, "asprintf", + FunctionType::get(size_ty, + { + ptr_ty, + ptr_ty, + }, + true)); } void instrumentAlloca(Function *F) { From 31df459725c34e05bda8b3ce5685a846ca164334 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 15 Jun 2026 11:25:03 -0400 Subject: [PATCH 32/55] remediate.rs: WIP testing if __resolve_asprintf symbol shows up in libresolve. --- resolve-cveassert/libresolve/src/lib.rs | 2 +- resolve-cveassert/libresolve/src/remediate.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/src/lib.rs b/resolve-cveassert/libresolve/src/lib.rs index 02fb6334..cfad781d 100644 --- a/resolve-cveassert/libresolve/src/lib.rs +++ b/resolve-cveassert/libresolve/src/lib.rs @@ -2,7 +2,7 @@ // LGPL-3; See LICENSE.txt in the repo root for details. #![feature(btree_cursors)] - +#![feature(c_variadic)] mod remediate; mod shadowobjs; mod trace; diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index f872c47d..397fa9fb 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -35,6 +35,7 @@ unsafe extern "C" { // Shim API fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; fn mi_is_heap_owned(ptr: *mut c_void) -> bool; + fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int; } /** From ea3de0bfacdb268ae0ba583ab2eb69e998954558 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 15 Jun 2026 11:51:38 -0400 Subject: [PATCH 33/55] remediate.rs: WIP trying to get libresolve to resolve the __resolve_asprintf symbol. --- resolve-cveassert/libresolve/src/remediate.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 397fa9fb..bfd40f9f 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -35,7 +35,6 @@ unsafe extern "C" { // Shim API fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; fn mi_is_heap_owned(ptr: *mut c_void) -> bool; - fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int; } /** @@ -160,6 +159,9 @@ pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_ } } +#[unsafe(no_mangle)] +unsafe extern "C" { fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int; } + /** * @brief - Allocator logging interface for malloc * @input - size of the allocation in bytes From e3aaae08a786d321d4dca957b6f5ebb42f030f0b Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 15 Jun 2026 12:03:02 -0400 Subject: [PATCH 34/55] WIP: try adding no_mangle to mimalloc symbols to have libresolve export symbols. --- resolve-cveassert/libresolve/src/remediate.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index bfd40f9f..bba4d252 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -21,6 +21,7 @@ struct BoundsInfo { } #[link(name = "mimalloc")] +#[unsafe(no_mangle)] unsafe extern "C" { // Allocator API fn mi_malloc(size: usize) -> *mut c_void; @@ -35,6 +36,7 @@ unsafe extern "C" { // Shim API fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; fn mi_is_heap_owned(ptr: *mut c_void) -> bool; + fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int; } /** @@ -159,9 +161,6 @@ pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_ } } -#[unsafe(no_mangle)] -unsafe extern "C" { fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int; } - /** * @brief - Allocator logging interface for malloc * @input - size of the allocation in bytes From 9ac8127508f42f9e2f25d0d16b56f71c083643ab Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 15 Jun 2026 13:08:32 -0400 Subject: [PATCH 35/55] WIP: Trying to debug why the __resolve_asprintf symbol is not being resolved correctly. --- resolve-cveassert/libresolve/Cargo.toml | 3 +++ resolve-cveassert/libresolve/src/remediate.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/Cargo.toml b/resolve-cveassert/libresolve/Cargo.toml index 032693c8..1ee69573 100644 --- a/resolve-cveassert/libresolve/Cargo.toml +++ b/resolve-cveassert/libresolve/Cargo.toml @@ -20,5 +20,8 @@ debug = true [profile.dev] panic = "abort" +[build] +rustflags = ["C", "export-executable-symbols"] + [toolchain] channel = "nightly" \ No newline at end of file diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index bba4d252..4d4203c7 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -21,7 +21,6 @@ struct BoundsInfo { } #[link(name = "mimalloc")] -#[unsafe(no_mangle)] unsafe extern "C" { // Allocator API fn mi_malloc(size: usize) -> *mut c_void; @@ -36,6 +35,7 @@ unsafe extern "C" { // Shim API fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; fn mi_is_heap_owned(ptr: *mut c_void) -> bool; + #[unsafe(no_mangle)] fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int; } From 6808c743d010c41895fafdf14c75eec5f82a4b81 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 15 Jun 2026 13:25:27 -0400 Subject: [PATCH 36/55] remediate.rs: WIP debugging __resolve_asprintf symbol export. --- resolve-cveassert/libresolve/src/remediate.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 4d4203c7..43d6fd7d 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -31,13 +31,17 @@ unsafe extern "C" { fn mi_free(ptr: *mut c_void); fn mi_new(size: usize) -> *mut c_void; fn mi_delete(ptr: *mut c_void); - - // Shim API - fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; - fn mi_is_heap_owned(ptr: *mut c_void) -> bool; - #[unsafe(no_mangle)] - fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int; } + +#[unsafe(no_mangle)] +unsafe extern "C" { fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; } + +#[unsafe(no_mangle)] +unsafe extern "C" { fn mi_is_heap_owned(ptr: *mut c_void) -> bool; } + +#[unsafe(no_mangle)] +unsafe extern "C" { fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int ; } + /** * @brief - Allocator interface for stack objects From dd295e456f64dae62a0e009f2dbf040f7439face Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 15 Jun 2026 14:40:17 -0400 Subject: [PATCH 37/55] WIP: debugging __resolve_asprintf symbol visibility and resolution. --- resolve-cveassert/libresolve/Cargo.toml | 3 --- .../libresolve/mimalloc_shadow.c | 20 +++++++++++-------- resolve-cveassert/libresolve/src/remediate.rs | 19 +++++++++--------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/resolve-cveassert/libresolve/Cargo.toml b/resolve-cveassert/libresolve/Cargo.toml index 1ee69573..032693c8 100644 --- a/resolve-cveassert/libresolve/Cargo.toml +++ b/resolve-cveassert/libresolve/Cargo.toml @@ -20,8 +20,5 @@ debug = true [profile.dev] panic = "abort" -[build] -rustflags = ["C", "export-executable-symbols"] - [toolchain] channel = "nightly" \ No newline at end of file diff --git a/resolve-cveassert/libresolve/mimalloc_shadow.c b/resolve-cveassert/libresolve/mimalloc_shadow.c index 240501f0..9c5e7379 100644 --- a/resolve-cveassert/libresolve/mimalloc_shadow.c +++ b/resolve-cveassert/libresolve/mimalloc_shadow.c @@ -1,10 +1,12 @@ #include "mimalloc.h" #include "mimalloc/internal.h" +#include #include #include -extern void * __resolve_malloc(size_t); -extern void *__resolve_free(void*); +extern void* __resolve_malloc(size_t); +extern void __resolve_free(void*); + typedef struct { void *base; @@ -37,8 +39,7 @@ bool mi_is_heap_owned(const void* p) { return mi_is_in_heap_region(p); } - -int __resolve_vasprintf(char **strp, const char *fmt, va_list ap) +int __vasprintf(char **strp, const char *fmt, va_list ap) { va_list ap_copy; va_copy(ap_copy, ap); @@ -48,7 +49,8 @@ int __resolve_vasprintf(char **strp, const char *fmt, va_list ap) if (len < 0) { return -1; } - char *buf = __resolve_malloc((size_t)len + 1); + //char *buf = __resolve_malloc((size_t)len + 1); + char *buf = malloc((size_t)len + 1); if (!buf) { return -1; } va_copy(ap_copy, ap); @@ -58,7 +60,8 @@ int __resolve_vasprintf(char **strp, const char *fmt, va_list ap) va_end(ap_copy); if (written < 0) { - __resolve_free(buf); + //__resolve_free(buf); + free(buf); return -1; } @@ -66,12 +69,13 @@ int __resolve_vasprintf(char **strp, const char *fmt, va_list ap) return written; } -int __resolve_asprintf(char **strp, const char *fmt, ...) + +int __asprintf(char **strp, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - int rc = __resolve_vasprintf(strp, fmt, ap); + int rc = __vasprintf(strp, fmt, ap); va_end(ap); return rc; diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 43d6fd7d..34f65a75 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -31,17 +31,11 @@ unsafe extern "C" { fn mi_free(ptr: *mut c_void); fn mi_new(size: usize) -> *mut c_void; fn mi_delete(ptr: *mut c_void); -} - -#[unsafe(no_mangle)] -unsafe extern "C" { fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; } - -#[unsafe(no_mangle)] -unsafe extern "C" { fn mi_is_heap_owned(ptr: *mut c_void) -> bool; } - -#[unsafe(no_mangle)] -unsafe extern "C" { fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int ; } + fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; + fn mi_is_heap_owned(ptr: *mut c_void) -> bool; + fn __asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int; +} /** * @brief - Allocator interface for stack objects @@ -165,6 +159,11 @@ pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_ } } +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int { + return __asprintf(strp, fmt, args) +} + /** * @brief - Allocator logging interface for malloc * @input - size of the allocation in bytes From f665322925ef8f4c9fc83fb5387a4855ba457192 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 15 Jun 2026 14:45:20 -0400 Subject: [PATCH 38/55] Fixing compilation issues. Ready to test __resolve_asprintf symbol resolution. --- resolve-cveassert/libresolve/src/remediate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 34f65a75..8819b207 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -160,7 +160,7 @@ pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_ } #[unsafe(no_mangle)] -pub extern "C" fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int { +pub unsafe extern "C" fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int { return __asprintf(strp, fmt, args) } From 9fc5943c42b2becd9e300ece0fa9a17d981c4373 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 15 Jun 2026 15:21:11 -0400 Subject: [PATCH 39/55] WIP: Debugging ABI mismatch issues. --- .../libresolve/mimalloc_shadow.c | 24 ++++++------------- resolve-cveassert/libresolve/src/remediate.rs | 8 ++++--- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/resolve-cveassert/libresolve/mimalloc_shadow.c b/resolve-cveassert/libresolve/mimalloc_shadow.c index 9c5e7379..2cb50e16 100644 --- a/resolve-cveassert/libresolve/mimalloc_shadow.c +++ b/resolve-cveassert/libresolve/mimalloc_shadow.c @@ -47,10 +47,13 @@ int __vasprintf(char **strp, const char *fmt, va_list ap) int len = vsnprintf(NULL, 0, fmt, ap_copy); va_end(ap_copy); - if (len < 0) { return -1; } + if (len < 0) { + // to match glibc behavior + *strp = NULL; + return -1; + } - //char *buf = __resolve_malloc((size_t)len + 1); - char *buf = malloc((size_t)len + 1); + char *buf = __resolve_malloc((size_t)len + 1); if (!buf) { return -1; } va_copy(ap_copy, ap); @@ -60,23 +63,10 @@ int __vasprintf(char **strp, const char *fmt, va_list ap) va_end(ap_copy); if (written < 0) { - //__resolve_free(buf); - free(buf); + __resolve_free(buf); return -1; } *strp = buf; return written; } - - -int __asprintf(char **strp, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - - int rc = __vasprintf(strp, fmt, ap); - - va_end(ap); - return rc; -} diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 8819b207..d99abd34 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -6,6 +6,8 @@ use libc::{ write, }; +use std::ffi::VaList; + use crate::shadowobjs::{ ALIVE_OBJ_LIST, AllocType, FREED_OBJ_LIST, Vaddr }; @@ -34,7 +36,7 @@ unsafe extern "C" { fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; fn mi_is_heap_owned(ptr: *mut c_void) -> bool; - fn __asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int; + fn __vasprintf(strp: *mut *mut c_char, fmt: *const c_char, args: VaList<'_>) -> c_int; } /** @@ -160,8 +162,8 @@ pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_ } #[unsafe(no_mangle)] -pub unsafe extern "C" fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int { - return __asprintf(strp, fmt, args) +pub unsafe extern "C" fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, mut args: ...) -> c_int { + return __vasprintf(strp, fmt, args) } /** From d63d8685710d59d662729da5a94dcd06f686be57 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 15 Jun 2026 15:40:05 -0400 Subject: [PATCH 40/55] mimalloc_shadow.c: Removed the plus one from len argument in __resolve_malloc. --- resolve-cveassert/libresolve/mimalloc_shadow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/mimalloc_shadow.c b/resolve-cveassert/libresolve/mimalloc_shadow.c index 2cb50e16..99a60213 100644 --- a/resolve-cveassert/libresolve/mimalloc_shadow.c +++ b/resolve-cveassert/libresolve/mimalloc_shadow.c @@ -53,7 +53,7 @@ int __vasprintf(char **strp, const char *fmt, va_list ap) return -1; } - char *buf = __resolve_malloc((size_t)len + 1); + char *buf = __resolve_malloc((size_t)len); if (!buf) { return -1; } va_copy(ap_copy, ap); From d82f7e1d1ecb60e880d04d660a2e2fbcdbb9dd85 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Mon, 15 Jun 2026 15:47:26 -0400 Subject: [PATCH 41/55] remediate.rs: Adding free to see what happens. --- resolve-cveassert/libresolve/src/remediate.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index d99abd34..6cd8d40c 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -225,6 +225,7 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { if !mi_is_heap_owned(ptr) { let msg = "foreign allocation\n"; write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); + let _ = free(ptr); } else { let _ = mi_free(ptr); } From 0bfc51d932c3d0c820bc956ef7a3077cd28c4e06 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 16 Jun 2026 09:26:55 -0400 Subject: [PATCH 42/55] remediate.rs: Adding resolve wrappers for posx_memalign, reallocarray, aligned_alloc. --- resolve-cveassert/libresolve/src/lib.rs | 19 +- resolve-cveassert/libresolve/src/remediate.rs | 317 ++++++++++-------- .../libresolve/src/shadowobjs.rs | 12 +- resolve-cveassert/src/instrument.cpp | 8 + 4 files changed, 207 insertions(+), 149 deletions(-) diff --git a/resolve-cveassert/libresolve/src/lib.rs b/resolve-cveassert/libresolve/src/lib.rs index cfad781d..e955be4e 100644 --- a/resolve-cveassert/libresolve/src/lib.rs +++ b/resolve-cveassert/libresolve/src/lib.rs @@ -11,8 +11,8 @@ use libc::{Dl_info, atexit, c_void, dladdr, dlsym}; use std::ffi::{CStr, OsString}; use std::fmt::Display; use std::fs::{self, File}; -use std::path::PathBuf; use std::io::{self, Seek, Write}; +use std::path::PathBuf; use std::sync::{LazyLock, Mutex}; use std::{env, process}; @@ -34,7 +34,8 @@ impl MutexWrap { } fn idify_file_path(path: &mut PathBuf, id: impl Display) { - let file_name = path.file_name() + let file_name = path + .file_name() .expect("Path could not be found in file system.") .to_owned(); @@ -42,15 +43,14 @@ fn idify_file_path(path: &mut PathBuf, id: impl Display) { updated_file_name.push(file_name); updated_file_name.push("-"); - updated_file_name.push(id.to_string()); + updated_file_name.push(id.to_string()); path.set_file_name(updated_file_name); } /// File for "resolve_dlsym.json" pub static DLSYM_LOG_FILE: LazyLock> = LazyLock::new(|| { - let log_dir = env::var("RESOLVE_DLSYM_LOG_DIR") - .unwrap_or_else(|_| ".".to_string()); + let log_dir = env::var("RESOLVE_DLSYM_LOG_DIR").unwrap_or_else(|_| ".".to_string()); let mut path = PathBuf::from(log_dir); @@ -84,12 +84,12 @@ pub extern "C" fn resolve_init() { if cfg!(test) { builder.is_test(true); } else { - let file = open_resolve_log_file().unwrap_or_else(|err| { + let file = open_resolve_log_file().unwrap_or_else(|err| { eprintln!("Libresolve log file could not be created."); eprintln!("Error: {err:?}"); process::exit(12); }); - + builder.target(env_logger::Target::Pipe(Box::new(file))); } @@ -97,14 +97,13 @@ pub extern "C" fn resolve_init() { } fn open_resolve_log_file() -> Result { - let log_dir = env::var("RESOLVE_RUNTIME_LOG_DIR") - .unwrap_or_else(|_| ".".to_string()); + let log_dir = env::var("RESOLVE_RUNTIME_LOG_DIR").unwrap_or_else(|_| ".".to_string()); let mut path = PathBuf::from(log_dir); // Ensure the parent directories exist fs::create_dir_all(&path)?; - + // Append the file name path.push("resolve_log.out"); diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 6cd8d40c..9ae1664a 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -2,15 +2,13 @@ // LGPL-3; See LICENSE.txt in the repo root for details. use libc::{ - EOF, FILE, STDERR_FILENO, c_char, c_int, c_void, fgetc, free, strlen, strnlen, size_t, ssize_t, + EOF, FILE, STDERR_FILENO, c_char, c_int, c_void, fgetc, free, size_t, ssize_t, strlen, strnlen, write, }; use std::ffi::VaList; -use crate::shadowobjs::{ - ALIVE_OBJ_LIST, AllocType, FREED_OBJ_LIST, Vaddr -}; +use crate::shadowobjs::{ALIVE_OBJ_LIST, AllocType, FREED_OBJ_LIST, Vaddr}; use log::{info, warn}; @@ -24,12 +22,17 @@ struct BoundsInfo { #[link(name = "mimalloc")] unsafe extern "C" { - // Allocator API + // Allocator API fn mi_malloc(size: usize) -> *mut c_void; fn mi_calloc(size: usize, count: usize) -> *mut c_void; fn mi_realloc(ptr: *mut c_void, size: usize) -> *mut c_void; fn mi_strdup(ptr: *mut c_char) -> *mut c_char; fn mi_strndup(ptr: *mut c_char, size: usize) -> *mut c_char; + + fn mi_aligned_alloc(alignment: usize, n: usize) -> *mut c_void; + fn mi_reallocarray(ptr: *mut c_void, n: usize, size: usize) -> *mut c_void; + fn mi_posix_memalign(memptr: *mut *mut c_void, alignment: usize, size: usize) -> c_int; + fn mi_free(ptr: *mut c_void); fn mi_new(size: usize) -> *mut c_void; fn mi_delete(ptr: *mut c_void); @@ -46,28 +49,32 @@ unsafe extern "C" { */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_alloca(_ptr: *mut c_void, _size: usize) -> () { -// let base = ptr as Vaddr; -// { -// let mut obj_list = ALIVE_OBJ_LIST.lock(); -// obj_list.add_shadow_object(AllocType::Stack, base, size); -// } -// info!("[STACK] Object allocated with size: {size}, address: 0x{base:x}"); + // let base = ptr as Vaddr; + // { + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // obj_list.add_shadow_object(AllocType::Stack, base, size); + // } + // info!("[STACK] Object allocated with size: {size}, address: 0x{base:x}"); } #[unsafe(no_mangle)] pub extern "C" fn __resolve_invalidate_stack(_base: *mut c_void) { -// let base = base as Vaddr; -// -// { -// let mut obj_list = ALIVE_OBJ_LIST.lock(); -// obj_list.invalidate_at(base); -// } -// -// info!("[STACK] Free addr 0x{base:x}"); + // let base = base as Vaddr; + // + // { + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // obj_list.invalidate_at(base); + // } + // + // info!("[STACK] Free addr 0x{base:x}"); } #[unsafe(no_mangle)] -pub extern "C" fn __resolve_getline(lineptr: *mut *mut c_char, size: *mut size_t, stream: *mut FILE) -> ssize_t { +pub extern "C" fn __resolve_getline( + lineptr: *mut *mut c_char, + size: *mut size_t, + stream: *mut FILE, +) -> ssize_t { if lineptr.is_null() || size.is_null() || stream.is_null() { return -1; } @@ -78,7 +85,9 @@ pub extern "C" fn __resolve_getline(lineptr: *mut *mut c_char, size: *mut size_t *lineptr = __resolve_malloc(*size) as *mut c_char; // check if the pointer is null - if (*lineptr).is_null() { return -1; } + if (*lineptr).is_null() { + return -1; + } } let mut pos: size_t = 0; @@ -86,9 +95,12 @@ pub extern "C" fn __resolve_getline(lineptr: *mut *mut c_char, size: *mut size_t loop { c = fgetc(stream); - if c == EOF { break; } + if c == EOF { + break; + } - if pos + 1 >= *size { // Expand buffer + if pos + 1 >= *size { + // Expand buffer let new_size = *size * 2; let new_buf = __resolve_realloc(*lineptr as *mut c_void, new_size); @@ -106,11 +118,11 @@ pub extern "C" fn __resolve_getline(lineptr: *mut *mut c_char, size: *mut size_t if c == b'\n' as c_int { break; - } - + } } - if pos == 0 && c == EOF { // No data read + if pos == 0 && c == EOF { + // No data read return -1; } @@ -120,7 +132,12 @@ pub extern "C" fn __resolve_getline(lineptr: *mut *mut c_char, size: *mut size_t } #[unsafe(no_mangle)] -pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_t, delim: c_int, stream: *mut FILE) -> ssize_t { +pub extern "C" fn __resolve_getdelim( + lineptr: *mut *mut c_char, + size: *mut size_t, + delim: c_int, + stream: *mut FILE, +) -> ssize_t { if lineptr.is_null() || size.is_null() || stream.is_null() { return -1; } @@ -130,7 +147,9 @@ pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_ *size = 128; *lineptr = __resolve_malloc(*size) as *mut c_char; - if (*lineptr).is_null() { return -1; } + if (*lineptr).is_null() { + return -1; + } } let mut pos: size_t = 0; @@ -138,14 +157,18 @@ pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_ loop { c = fgetc(stream); - if c == EOF { break; } + if c == EOF { + break; + } if pos + 1 >= *size { let new_size = *size * 2; let new_buf = __resolve_realloc(*lineptr as *mut c_void, new_size); - if new_buf.is_null() { return -1; } - + if new_buf.is_null() { + return -1; + } + *lineptr = new_buf as *mut c_char; *size = new_size; } @@ -153,7 +176,9 @@ pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_ (*lineptr).add(pos).write(c as c_char); pos += 1; - if c == delim { break; } + if c == delim { + break; + } } (*lineptr).add(pos).write(0); @@ -162,8 +187,31 @@ pub extern "C" fn __resolve_getdelim(lineptr: *mut *mut c_char, size: *mut size_ } #[unsafe(no_mangle)] -pub unsafe extern "C" fn __resolve_asprintf(strp: *mut *mut c_char, fmt: *const c_char, mut args: ...) -> c_int { - return __vasprintf(strp, fmt, args) +pub unsafe extern "C" fn __resolve_asprintf( + strp: *mut *mut c_char, + fmt: *const c_char, + args: ... +) -> c_int { + return unsafe { __vasprintf(strp, fmt, args) }; +} + +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_aligned_alloc(alignment: usize, n: usize) -> *mut c_void { + return unsafe { mi_aligned_alloc(alignment, n) }; +} + +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_posix_memalign( + memptr: *mut *mut c_void, + alignment: usize, + size: usize, +) -> c_int { + return unsafe { mi_posix_memalign(memptr, alignment, size) }; +} + +#[unsafe(no_mangle)] +pub extern "C" fn __resolve_reallocarray(ptr: *mut c_void, n: usize, size: usize) -> *mut c_void { + return unsafe { mi_reallocarray(ptr, n, size + 1) }; } /** @@ -196,7 +244,6 @@ pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { ptr } - #[unsafe(no_mangle)] pub extern "C" fn __resolve_new(size: usize) -> *mut c_void { let ptr = unsafe { mi_new(size + 1) }; @@ -215,75 +262,77 @@ pub extern "C" fn __resolve_new(size: usize) -> *mut c_void { */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { - // Insert a function to find the object and return the pointer size - // Do I need to handle if the sobj cannot be found? - unsafe { - if ptr.is_null() { - return; - } + // Insert a function to find the object and return the pointer size + // Do I need to handle if the sobj cannot be found? + unsafe { + if ptr.is_null() { + return; + } - if !mi_is_heap_owned(ptr) { - let msg = "foreign allocation\n"; - write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); - let _ = free(ptr); - } else { - let _ = mi_free(ptr); + if !mi_is_heap_owned(ptr) { + let msg = "foreign allocation\n"; + write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); + } else { + let _ = mi_free(ptr); + } } - } - - // info!( - // "[FREE] Allocated object freed at address: 0x{:x}", - // ptr as Vaddr - // ); - - // let ptr_size = { - // let mut obj_list = ALIVE_OBJ_LIST.lock(); - // let sobj_opt = obj_list.search_intersection(ptr as Vaddr); - // let size = sobj_opt.map(|o| o.size()); - // // remove shadow obj from live list - // obj_list.invalidate_at(ptr as Vaddr); - // size - // }; - - // // Check if the shadow object exists - // match ptr_size { - // Some(size) => { - // info!( - // "[FREE] Found shadow object for allocated object, 0x{:x}, size = {size}", - // ptr as Vaddr, - // ); - // } - // None => { - // warn!( - // "[FREE] No shadow object found for allocated object: 0x{:x}", - // ptr as Vaddr - // ); - // } - // } - - // { - // // Insert shadow object into freed object list - // let mut freed_guard = FREED_OBJ_LIST.lock(); - // freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); - // } - - unsafe { - if ptr.is_null() { return; } - - let owned = mi_is_heap_owned(ptr); - if owned { - let _ = mi_free(ptr); - } else { - let _ = free(ptr); + + // info!( + // "[FREE] Allocated object freed at address: 0x{:x}", + // ptr as Vaddr + // ); + + // let ptr_size = { + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // let sobj_opt = obj_list.search_intersection(ptr as Vaddr); + // let size = sobj_opt.map(|o| o.size()); + // // remove shadow obj from live list + // obj_list.invalidate_at(ptr as Vaddr); + // size + // }; + + // // Check if the shadow object exists + // match ptr_size { + // Some(size) => { + // info!( + // "[FREE] Found shadow object for allocated object, 0x{:x}, size = {size}", + // ptr as Vaddr, + // ); + // } + // None => { + // warn!( + // "[FREE] No shadow object found for allocated object: 0x{:x}", + // ptr as Vaddr + // ); + // } + // } + + // { + // // Insert shadow object into freed object list + // let mut freed_guard = FREED_OBJ_LIST.lock(); + // freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); + // } + + unsafe { + if ptr.is_null() { + return; + } + + let owned = mi_is_heap_owned(ptr); + if owned { + let _ = mi_free(ptr); + } else { + let _ = free(ptr); + } } - } } // - #[unsafe(no_mangle)] pub extern "C" fn __resolve_delete(ptr: *mut c_void) -> () { - if ptr.is_null() { return; } + if ptr.is_null() { + return; + } let _ = unsafe { mi_free(ptr) }; } /** @@ -296,10 +345,10 @@ pub extern "C" fn __resolve_delete(ptr: *mut c_void) -> () { #[unsafe(no_mangle)] pub extern "C" fn __resolve_realloc(ptr: *mut c_void, size: usize) -> *mut c_void { // Edge cases - // 1. returned memory may not be allocated + // 1. returned memory may not be allocated // 2. pointer passed to realloc may be NULL // 3. size fits within original allocation (returns the original ptr) - + // Consideration: Pointer passed in may be invalidated so we need a mechanism // to remove the shadow object for the orignal allocation let realloc_ptr = unsafe { mi_realloc(ptr, size + 1) }; @@ -308,33 +357,32 @@ pub extern "C" fn __resolve_realloc(ptr: *mut c_void, size: usize) -> *mut c_voi return realloc_ptr; } + // { + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // // Remove shadow object for original pointer + // obj_list.invalidate_at(ptr as Vaddr); // if ptr == NULL this does not do anything + // obj_list.add_shadow_object(AllocType::Heap, realloc_ptr as Vaddr, size); + // } - // { - // let mut obj_list = ALIVE_OBJ_LIST.lock(); - // // Remove shadow object for original pointer - // obj_list.invalidate_at(ptr as Vaddr); // if ptr == NULL this does not do anything - // obj_list.add_shadow_object(AllocType::Heap, realloc_ptr as Vaddr, size); - // } + // info!( + // "[HEAP] Allocated object reallocated mem from src: {ptr:?}, size: {size}, dst ptr: 0x{:x}", + // realloc_ptr as Vaddr + // ); - // info!( - // "[HEAP] Allocated object reallocated mem from src: {ptr:?}, size: {size}, dst ptr: 0x{:x}", - // realloc_ptr as Vaddr - // ); - - realloc_ptr + realloc_ptr } /** - * @brief - Allocator logging interface for calloc - * @input - * - n_items: number of items in the allocation - * - size: size of the allocation in bytes - * @return - none - */ + * @brief - Allocator logging interface for calloc + * @input + * - n_items: number of items in the allocation + * - size: size of the allocation in bytes + * @return - none + */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_calloc(n_items: usize, item_size: usize) -> *mut c_void { let ptr = unsafe { mi_calloc(n_items, item_size) }; - let size = n_items * item_size; + //let size = n_items * item_size; if ptr.is_null() { return ptr; @@ -370,16 +418,16 @@ pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { // +1 to include null termination byte. We should allow program to read this value. // Otherwise how would the program find the end of the string? // Although writing it to something else is probably a bad idea, this too should be allowed. - // let sizeofstr = unsafe { strlen(ptr) + 1 }; - // { - // let mut obj_list = ALIVE_OBJ_LIST.lock(); - // obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); - // } + // let sizeofstr = unsafe { strlen(ptr) + 1 }; + // { + // let mut obj_list = ALIVE_OBJ_LIST.lock(); + // obj_list.add_shadow_object(AllocType::Heap, string_ptr as Vaddr, sizeofstr); + // } - // info!( - // "[HEAP] Logging 'strdup' function call with dst ptr: 0x{:x}", - // string_ptr as Vaddr - // ); + // info!( + // "[HEAP] Logging 'strdup' function call with dst ptr: 0x{:x}", + // string_ptr as Vaddr + // ); string_ptr } @@ -429,11 +477,11 @@ pub struct ShadowObjBounds { /** * @brief - Helper function that queries shadow obj list * to find a shadow obj where the ptr fits within - * its bounds of allocation + * its bounds of allocation * @input - * - ptr: ptr to allocation + * - ptr: ptr to allocation * @return struct containing the base and limit of the - * shadow object as pointers + * shadow object as pointers */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_get_bounds(ptr: *mut c_void) -> ShadowObjBounds { @@ -443,15 +491,18 @@ pub extern "C" fn __resolve_get_bounds(ptr: *mut c_void) -> ShadowObjBounds { limit: std::ptr::null_mut(), }; } - + let bounds = unsafe { mi_resolve_ptr(ptr) }; - return ShadowObjBounds { base: bounds.base, limit: bounds.limit } + return ShadowObjBounds { + base: bounds.base, + limit: bounds.limit, + }; //let sobj_table = ALIVE_OBJ_LIST.lock(); //let Some(sobj) = sobj_table.search_intersection(ptr as Vaddr) else { - // return ShadowObjBounds { base: std::ptr::null_mut(), limit: std::ptr::null_mut() } + // return ShadowObjBounds { base: std::ptr::null_mut(), limit: std::ptr::null_mut() } //}; - //info!("[RESOLVE] Debugging: (0x{:x}, 0x{:x}, 0x{:x})", ptr as Vaddr, sobj.base as Vaddr, sobj.limit as Vaddr); + //info!("[RESOLVE] Debugging: (0x{:x}, 0x{:x}, 0x{:x})", ptr as Vaddr, sobj.base as Vaddr, sobj.limit as Vaddr); //return ShadowObjBounds { base: sobj.base as *mut c_void, limit: sobj.limit as *mut c_void } } // diff --git a/resolve-cveassert/libresolve/src/shadowobjs.rs b/resolve-cveassert/libresolve/src/shadowobjs.rs index e7086767..fd7bba64 100644 --- a/resolve-cveassert/libresolve/src/shadowobjs.rs +++ b/resolve-cveassert/libresolve/src/shadowobjs.rs @@ -3,8 +3,8 @@ use crate::MutexWrap; use std::collections::BTreeMap; -use std::ops::RangeInclusive; use std::ops::Bound::Included; +use std::ops::RangeInclusive; /// An alias representing Virtual Address values pub type Vaddr = usize; @@ -101,13 +101,13 @@ impl ShadowObjectTable { /// Finds a shadow object that contains 'addr' in its bounds OR a shadow object with /// a past_limit value matching the input pub fn search_intersection(&self, addr: Vaddr) -> Option<&ShadowObject> { - let cursor = self.table - .upper_bound(Included(&addr)); + let cursor = self.table.upper_bound(Included(&addr)); - cursor.peek_prev() + cursor + .peek_prev() .filter(|(_, o)| o.contains(addr) || o.past_limit() == addr) - .map(|(_, o)| o) - } + .map(|(_, o)| o) + } } // static object lists to store all objects diff --git a/resolve-cveassert/src/instrument.cpp b/resolve-cveassert/src/instrument.cpp index 3c09284c..8516af36 100644 --- a/resolve-cveassert/src/instrument.cpp +++ b/resolve-cveassert/src/instrument.cpp @@ -89,6 +89,14 @@ void instrumentLibraryAllocations(Function *F) { ptr_ty, }, true)); + wrapLibraryFunction(F, "aligned_alloc", + FunctionType::get(ptr_ty, {size_ty, size_ty}, false)); + wrapLibraryFunction( + F, "reallocarray", + FunctionType::get(ptr_ty, {ptr_ty, size_ty, size_ty}, false)); + wrapLibraryFunction( + F, "posix_memalign", + FunctionType::get(size_ty, {ptr_ty, size_ty, size_ty}, false)); } void instrumentAlloca(Function *F) { From af20b688f06d930ad51754ab20f2837b96f2efb3 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 16 Jun 2026 13:07:26 -0400 Subject: [PATCH 43/55] remediate.rs: Testing with libc free. --- resolve-cveassert/libresolve/src/remediate.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 9ae1664a..97b45839 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -272,6 +272,7 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { if !mi_is_heap_owned(ptr) { let msg = "foreign allocation\n"; write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); + let _ = free(ptr); } else { let _ = mi_free(ptr); } @@ -312,19 +313,6 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { // let mut freed_guard = FREED_OBJ_LIST.lock(); // freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); // } - - unsafe { - if ptr.is_null() { - return; - } - - let owned = mi_is_heap_owned(ptr); - if owned { - let _ = mi_free(ptr); - } else { - let _ = free(ptr); - } - } } // From 726c366079e75ae373fac9db86bfcd1a27ca5c11 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 16 Jun 2026 13:25:57 -0400 Subject: [PATCH 44/55] remediate.rs: Comment out logging to test for performance. --- resolve-cveassert/libresolve/src/remediate.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 97b45839..ed3efc75 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -270,8 +270,8 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { } if !mi_is_heap_owned(ptr) { - let msg = "foreign allocation\n"; - write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); + //let msg = "foreign allocation\n"; + //write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); let _ = free(ptr); } else { let _ = mi_free(ptr); From 695c157a67840d3fc1884e7aed984368ee545194 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 16 Jun 2026 14:43:35 -0400 Subject: [PATCH 45/55] remediate.rs: Testing without +1 padding. --- resolve-cveassert/libresolve/src/remediate.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index ed3efc75..f70cbed0 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -211,7 +211,7 @@ pub extern "C" fn __resolve_posix_memalign( #[unsafe(no_mangle)] pub extern "C" fn __resolve_reallocarray(ptr: *mut c_void, n: usize, size: usize) -> *mut c_void { - return unsafe { mi_reallocarray(ptr, n, size + 1) }; + return unsafe { mi_reallocarray(ptr, n, size) }; } /** @@ -221,7 +221,7 @@ pub extern "C" fn __resolve_reallocarray(ptr: *mut c_void, n: usize, size: usize */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { - let ptr = unsafe { mi_malloc(size + 1) }; + let ptr = unsafe { mi_malloc(size) }; //let bounds_info = unsafe { mi_resolve_ptr(ptr) }; if ptr.is_null() { @@ -246,7 +246,7 @@ pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { #[unsafe(no_mangle)] pub extern "C" fn __resolve_new(size: usize) -> *mut c_void { - let ptr = unsafe { mi_new(size + 1) }; + let ptr = unsafe { mi_new(size) }; if ptr.is_null() { return ptr; @@ -339,7 +339,7 @@ pub extern "C" fn __resolve_realloc(ptr: *mut c_void, size: usize) -> *mut c_voi // Consideration: Pointer passed in may be invalidated so we need a mechanism // to remove the shadow object for the orignal allocation - let realloc_ptr = unsafe { mi_realloc(ptr, size + 1) }; + let realloc_ptr = unsafe { mi_realloc(ptr, size) }; if realloc_ptr.is_null() { return realloc_ptr; @@ -431,7 +431,7 @@ pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { // */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_strndup(ptr: *mut c_char, size: usize) -> *mut c_char { - let string_ptr = unsafe { mi_strndup(ptr, size + 1) }; + let string_ptr = unsafe { mi_strndup(ptr, size) }; if string_ptr.is_null() { return string_ptr; From 06315f02643452ede4219a400c5eec0efb125ce9 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 16 Jun 2026 14:59:21 -0400 Subject: [PATCH 46/55] remediate.rs: WIP skipping pointers that have not been allocated by mimalloc. --- resolve-cveassert/libresolve/src/remediate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index f70cbed0..3ffd7e85 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -272,7 +272,7 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { if !mi_is_heap_owned(ptr) { //let msg = "foreign allocation\n"; //write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); - let _ = free(ptr); + return; } else { let _ = mi_free(ptr); } From 5991b594c44e64437959f93c62868df1ac547867 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 16 Jun 2026 15:11:16 -0400 Subject: [PATCH 47/55] mimalloc_shadow.c: Testing __resolve_malloc call in __vasprintf --- resolve-cveassert/libresolve/mimalloc_shadow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/mimalloc_shadow.c b/resolve-cveassert/libresolve/mimalloc_shadow.c index 99a60213..2cb50e16 100644 --- a/resolve-cveassert/libresolve/mimalloc_shadow.c +++ b/resolve-cveassert/libresolve/mimalloc_shadow.c @@ -53,7 +53,7 @@ int __vasprintf(char **strp, const char *fmt, va_list ap) return -1; } - char *buf = __resolve_malloc((size_t)len); + char *buf = __resolve_malloc((size_t)len + 1); if (!buf) { return -1; } va_copy(ap_copy, ap); From 7af7c59c32f120acecf1129e0b5bc4fc7f74e446 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Tue, 16 Jun 2026 15:26:25 -0400 Subject: [PATCH 48/55] remediate.rs: Reverting commit that added ptr to strdup ref link. --- resolve-cveassert/libresolve/src/remediate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 3ffd7e85..a8297537 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -427,7 +427,7 @@ pub extern "C" fn __resolve_strdup(ptr: *mut c_char) -> *mut c_char { // * - size: number of bytes to copied // * @return - pointer to the copied string // * NOTE: Read this link to understand the nature of strdup & strndup -// * https://pubs.opengroup.org/onlineptrpubs/9699919799/functions/strdup.html +// * https://pubs.opengroup.org/onlinepubs/9699919799/functions/strdup.html // */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_strndup(ptr: *mut c_char, size: usize) -> *mut c_char { From 1970dad4871cdf7db6c55bf4afd8a959fb5d7042 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Thu, 18 Jun 2026 08:18:01 -0400 Subject: [PATCH 49/55] mimalloc_shadow.c: Modified mi_is_heap_owned fn to return a boolean if the pointer is owned by a mimalloc allocation. --- resolve-cveassert/libresolve/mimalloc_shadow.c | 5 +++-- resolve-cveassert/libresolve/src/remediate.rs | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/resolve-cveassert/libresolve/mimalloc_shadow.c b/resolve-cveassert/libresolve/mimalloc_shadow.c index 2cb50e16..bce8ace4 100644 --- a/resolve-cveassert/libresolve/mimalloc_shadow.c +++ b/resolve-cveassert/libresolve/mimalloc_shadow.c @@ -17,6 +17,7 @@ typedef struct { bounds_info_t mi_resolve_ptr(void* p) { + // Can return null if ptr is not owned by mimalloc mi_page_t *page = _mi_ptr_page(p); const size_t block_size = page->block_size; @@ -36,7 +37,7 @@ bounds_info_t mi_resolve_ptr(void* p) { } bool mi_is_heap_owned(const void* p) { - return mi_is_in_heap_region(p); + return _mi_ptr_page(p) != NULL; } int __vasprintf(char **strp, const char *fmt, va_list ap) @@ -53,7 +54,7 @@ int __vasprintf(char **strp, const char *fmt, va_list ap) return -1; } - char *buf = __resolve_malloc((size_t)len + 1); + char *buf = __resolve_malloc((size_t)len); if (!buf) { return -1; } va_copy(ap_copy, ap); diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index a8297537..5fe12c06 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -269,9 +269,11 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { return; } + // Cond: Is the given pointer owned by a mimalloc allocation? if !mi_is_heap_owned(ptr) { //let msg = "foreign allocation\n"; //write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); + let _ = free(ptr); return; } else { let _ = mi_free(ptr); From 145c7e71b3b4081df98cf87b49543d8e434f16e8 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Thu, 18 Jun 2026 08:28:39 -0400 Subject: [PATCH 50/55] mimalloc_shadow.c: Adding +1 back to __resolve_malloc call. --- resolve-cveassert/libresolve/mimalloc_shadow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resolve-cveassert/libresolve/mimalloc_shadow.c b/resolve-cveassert/libresolve/mimalloc_shadow.c index bce8ace4..84f0ae22 100644 --- a/resolve-cveassert/libresolve/mimalloc_shadow.c +++ b/resolve-cveassert/libresolve/mimalloc_shadow.c @@ -54,7 +54,7 @@ int __vasprintf(char **strp, const char *fmt, va_list ap) return -1; } - char *buf = __resolve_malloc((size_t)len); + char *buf = __resolve_malloc((size_t)len + 1); if (!buf) { return -1; } va_copy(ap_copy, ap); From 5916a1768b4c27600d19ee5895411a6564b6c362 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Thu, 18 Jun 2026 09:58:15 -0400 Subject: [PATCH 51/55] remediate.rs: WIP checking the ptr and return address that is passed to __resolve_free. --- .../libresolve/mimalloc_shadow.c | 9 +++++++ resolve-cveassert/libresolve/src/remediate.rs | 25 ++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/resolve-cveassert/libresolve/mimalloc_shadow.c b/resolve-cveassert/libresolve/mimalloc_shadow.c index 84f0ae22..62cc4bd3 100644 --- a/resolve-cveassert/libresolve/mimalloc_shadow.c +++ b/resolve-cveassert/libresolve/mimalloc_shadow.c @@ -71,3 +71,12 @@ int __vasprintf(char **strp, const char *fmt, va_list ap) *strp = buf; return written; } + +void *resolve_return_address(unsigned level) { + switch(level) { + case 0: return __builtin_return_address(0); + case 1: return __builtin_return_address(1); + case 2: return __builtin_return_address(2); + default: return NULL; + } +} \ No newline at end of file diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 5fe12c06..a5e7dbd0 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -2,8 +2,8 @@ // LGPL-3; See LICENSE.txt in the repo root for details. use libc::{ - EOF, FILE, STDERR_FILENO, c_char, c_int, c_void, fgetc, free, size_t, ssize_t, strlen, strnlen, - write, + EOF, FILE, STDERR_FILENO, c_char, c_int, c_uint, c_void, fgetc, free, size_t, ssize_t, strlen, strnlen, + snprintf, write, }; use std::ffi::VaList; @@ -40,6 +40,7 @@ unsafe extern "C" { fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; fn mi_is_heap_owned(ptr: *mut c_void) -> bool; fn __vasprintf(strp: *mut *mut c_char, fmt: *const c_char, args: VaList<'_>) -> c_int; + fn resolve_return_address(level: c_uint) -> *mut c_void; } /** @@ -221,7 +222,7 @@ pub extern "C" fn __resolve_reallocarray(ptr: *mut c_void, n: usize, size: usize */ #[unsafe(no_mangle)] pub extern "C" fn __resolve_malloc(size: usize) -> *mut c_void { - let ptr = unsafe { mi_malloc(size) }; + let ptr = unsafe { mi_malloc(size + 1) }; //let bounds_info = unsafe { mi_resolve_ptr(ptr) }; if ptr.is_null() { @@ -271,6 +272,24 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { // Cond: Is the given pointer owned by a mimalloc allocation? if !mi_is_heap_owned(ptr) { + let caller = resolve_return_address(1); + let mut buf = [0i8; 128]; + let len = snprintf( + buf.as_mut_ptr(), + buf.len(), + c"caller=%p, ptr=%p\n".as_ptr(), + caller, + ptr, + ); + + if len > 0 { + let _ = write( + STDERR_FILENO, + buf.as_ptr().cast(), + usize::min(len as usize, buf.len() - 1), + ); + } + //let msg = "foreign allocation\n"; //write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); let _ = free(ptr); From 71c28decd0741455a7d3585e062e420456123c7c Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Thu, 18 Jun 2026 10:23:58 -0400 Subject: [PATCH 52/55] remediate.rs: Testing with warn. --- resolve-cveassert/libresolve/src/remediate.rs | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index a5e7dbd0..7fbfb319 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -273,27 +273,26 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { // Cond: Is the given pointer owned by a mimalloc allocation? if !mi_is_heap_owned(ptr) { let caller = resolve_return_address(1); - let mut buf = [0i8; 128]; - let len = snprintf( - buf.as_mut_ptr(), - buf.len(), - c"caller=%p, ptr=%p\n".as_ptr(), - caller, - ptr, - ); - - if len > 0 { - let _ = write( - STDERR_FILENO, - buf.as_ptr().cast(), - usize::min(len as usize, buf.len() - 1), - ); - } + warn!("[RESOLVE] ptr = {:p}, caller = {:p}", ptr, caller); + // let len = snprintf( + // buf.as_mut_ptr(), + // buf.len(), + // c"caller=%p, ptr=%p\n".as_ptr(), + // caller, + // ptr, + // ); + + // if len > 0 { + // let _ = write( + // STDERR_FILENO, + // buf.as_ptr().cast(), + // usize::min(len as usize, buf.len() - 1), + // ); + // } //let msg = "foreign allocation\n"; //write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); - let _ = free(ptr); - return; + let _ = free(ptr); } else { let _ = mi_free(ptr); } From d3957df26eafca4179ab1dfea7432824baf5f5c7 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Thu, 18 Jun 2026 14:27:18 -0400 Subject: [PATCH 53/55] shadowobjs.rs: Fixing compilation issue. --- resolve-cveassert/libresolve/src/shadowobjs.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/resolve-cveassert/libresolve/src/shadowobjs.rs b/resolve-cveassert/libresolve/src/shadowobjs.rs index fd7bba64..795b1e92 100644 --- a/resolve-cveassert/libresolve/src/shadowobjs.rs +++ b/resolve-cveassert/libresolve/src/shadowobjs.rs @@ -127,23 +127,12 @@ pub static FREED_OBJ_LIST: MutexWrap = MutexWrap::new(ShadowO // //table.print_shadow_obj(); // } -<<<<<<< HEAD - #[test] - fn test_remove_shadow_objects() { - let mut table = ShadowObjectTable::new(); - table.add_shadow_object(AllocType::Heap, 0x1000, 8); - table.add_shadow_object(AllocType::Stack, 0x2000, 16); - table.invalidate_at(0x1000); - assert_eq!(table.table.len(), 1); - } -======= // #[test] // fn test_remove_shadow_objects() { // let mut table = ShadowObjectTable::new(); // table.add_shadow_object(AllocType::Heap, 0x1000, 8); // table.add_shadow_object(AllocType::Stack, 0x2000, 16); // } ->>>>>>> ec6b0f1 (remediate.rs: Make sure all logging is commented out for poller testing.) // #[test] // fn test_search_intersection_found() { From 9a06e2ba6e3f5216ff336dd24e048bed93e171c0 Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Thu, 18 Jun 2026 15:10:03 -0400 Subject: [PATCH 54/55] CMakeLists.txt: Fixing CMakeList file to correctly pass archive path to Cargo. --- resolve-cveassert/libresolve/CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/resolve-cveassert/libresolve/CMakeLists.txt b/resolve-cveassert/libresolve/CMakeLists.txt index ba5df5f5..709bc9dc 100644 --- a/resolve-cveassert/libresolve/CMakeLists.txt +++ b/resolve-cveassert/libresolve/CMakeLists.txt @@ -23,12 +23,10 @@ target_sources(mimalloc-static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/mimalloc_shadow.c ) -set(MIMALLOC_LIB_DIR ${mimalloc_BINARY_DIR}) -message(STATUS "MIMALLOC_LIB_DIR=${MIMALLOC_LIB_DIR}") - ## mimalloc proj must be PIC to ensure compatibility with libresolve set_target_properties(mimalloc-static PROPERTIES POSITION_INDEPENDENT_CODE ON + OUTPUT_NAME mimalloc ) # Map CMake build type to Cargo flags @@ -53,7 +51,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env CARGO_TARGET_DIR=${RUST_OUT_DIR} - MIMALLOC_LIB_DIR=${MIMALLOC_LIB_DIR} # pass the static mimalloc path + MIMALLOC_LIB_DIR=$ cargo build ${CARGO_FLAGS} WORKING_DIRECTORY ${RUST_CRATE_DIR} COMMENT "Building libresolve.so" VERBATIM From d0aaed4e4d9cd6963de1adb8a7721eee87ad2dfb Mon Sep 17 00:00:00 2001 From: Ethan Lazaro Date: Thu, 18 Jun 2026 15:46:03 -0400 Subject: [PATCH 55/55] remediate.rs: Try using the mi_is_in_heap_region function to check if the pointer is within a mimalloc-owned mem region. --- resolve-cveassert/libresolve/src/remediate.rs | 58 +++++++++++-------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/resolve-cveassert/libresolve/src/remediate.rs b/resolve-cveassert/libresolve/src/remediate.rs index 7fbfb319..a8fc8731 100644 --- a/resolve-cveassert/libresolve/src/remediate.rs +++ b/resolve-cveassert/libresolve/src/remediate.rs @@ -37,10 +37,12 @@ unsafe extern "C" { fn mi_new(size: usize) -> *mut c_void; fn mi_delete(ptr: *mut c_void); + fn mi_is_in_heap_region(ptr: *mut c_void) -> bool; fn mi_resolve_ptr(ptr: *mut c_void) -> BoundsInfo; fn mi_is_heap_owned(ptr: *mut c_void) -> bool; fn __vasprintf(strp: *mut *mut c_char, fmt: *const c_char, args: VaList<'_>) -> c_int; fn resolve_return_address(level: c_uint) -> *mut c_void; + } /** @@ -271,32 +273,41 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { } // Cond: Is the given pointer owned by a mimalloc allocation? - if !mi_is_heap_owned(ptr) { - let caller = resolve_return_address(1); - warn!("[RESOLVE] ptr = {:p}, caller = {:p}", ptr, caller); - // let len = snprintf( - // buf.as_mut_ptr(), - // buf.len(), - // c"caller=%p, ptr=%p\n".as_ptr(), - // caller, - // ptr, - // ); - - // if len > 0 { - // let _ = write( - // STDERR_FILENO, - // buf.as_ptr().cast(), - // usize::min(len as usize, buf.len() - 1), - // ); - // } - - //let msg = "foreign allocation\n"; - //write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); - let _ = free(ptr); + if mi_is_in_heap_region(ptr) { + if mi_is_heap_owned(ptr) { + let _ = mi_free(ptr); + } } else { - let _ = mi_free(ptr); + let _ = free(ptr); } } +} + // if !mi_is_heap_owned(ptr) { + // let caller = resolve_return_address(1); + // warn!("[RESOLVE] ptr = {:p}, caller = {:p}", ptr, caller); + // // let len = snprintf( + // // buf.as_mut_ptr(), + // // buf.len(), + // // c"caller=%p, ptr=%p\n".as_ptr(), + // // caller, + // // ptr, + // // ); + + // // if len > 0 { + // // let _ = write( + // // STDERR_FILENO, + // // buf.as_ptr().cast(), + // // usize::min(len as usize, buf.len() - 1), + // // ); + // // } + + // //let msg = "foreign allocation\n"; + // //write(STDERR_FILENO, msg.as_ptr().cast(), msg.len()); + // let _ = free(ptr); + // } else { + // let _ = mi_free(ptr); + // } + // } // info!( // "[FREE] Allocated object freed at address: 0x{:x}", @@ -333,7 +344,6 @@ pub extern "C" fn __resolve_free(ptr: *mut c_void) -> () { // let mut freed_guard = FREED_OBJ_LIST.lock(); // freed_guard.add_shadow_object(AllocType::Unallocated, ptr as Vaddr, ptr_size.unwrap_or(0)); // } -} // #[unsafe(no_mangle)]