From dcc3364c74ee755bf5a94825686434f11bb97cc4 Mon Sep 17 00:00:00 2001 From: Matt Stevens Date: Sat, 11 Jul 2026 19:55:32 +0100 Subject: [PATCH 1/3] fix: respect blocked_relocation_sources in x86 abs32 reconstruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `noreloc` symbol attribute (and config `block_relocations` sources) populate `blocked_relocation_sources`, but neither x86 abs32 pass consulted it: - `resolve_abs32_candidates` (analysis/x86.rs), which resolves the abs32 candidates collected during analysis, and - `reconstruct_abs32_relocations_by_scan` (util/coff.rs), the /FIXED image data scan. As a result, data whose contents merely look like in-image pointers still got relocations invented for it. Concrete case from BW1: UTF-16 string literals — e.g. the wide chars "X\0_\0" in "MAX_DEPTH" read as 0x005F0058, which lands in the image, so the scan stamped a reloc with addend over the string and the extracted bytes no longer matched the compiler's comdat. Skip candidates whose source address falls inside a blocked range in both passes, making `noreloc` effective for PE/COFF data. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014kEDAMC4whgcjekmVde9PA --- src/analysis/x86.rs | 5 +++++ src/util/coff.rs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/analysis/x86.rs b/src/analysis/x86.rs index 9845ee1..992bb88 100644 --- a/src/analysis/x86.rs +++ b/src/analysis/x86.rs @@ -903,6 +903,11 @@ pub fn resolve_abs32_candidates( if target_va == 0 || obj.sections[src_sec].relocations.at(operand_va).is_some() { continue; } + // Respect `noreloc` symbols (and config block_relocations): data whose + // contents merely look like in-image pointers must stay raw bytes. + if obj.blocked_relocation_sources.contains(SectionAddress::new(src_sec, operand_va)) { + continue; + } let Ok((tgt_sec, _)) = obj.sections.at_address(target_va) else { continue; }; diff --git a/src/util/coff.rs b/src/util/coff.rs index 25c2e46..6264ace 100644 --- a/src/util/coff.rs +++ b/src/util/coff.rs @@ -595,6 +595,11 @@ fn reconstruct_abs32_relocations_by_scan(obj: &mut ObjInfo) -> Result<()> { if obj.sections[src_idx].relocations.at(reloc_va).is_some() { continue; } + // Respect `noreloc` symbols (and config block_relocations): data whose + // contents merely look like in-image pointers must stay raw bytes. + if obj.blocked_relocation_sources.contains(SectionAddress::new(src_idx, reloc_va)) { + continue; + } // Skip IAT slots: the linker regenerates the import address table. if obj .symbols From 8492d5cdff391c8b4a0b1a7cd5beca4d2bfa436a Mon Sep 17 00:00:00 2001 From: Matt Stevens Date: Sat, 11 Jul 2026 21:49:06 +0100 Subject: [PATCH 2/3] chore: fix clippy 1.97 useless_borrows_in_formatting lints Pre-existing on coff_prototype; CI runs latest stable clippy. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014kEDAMC4whgcjekmVde9PA --- src/util/dwarf/print.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/util/dwarf/print.rs b/src/util/dwarf/print.rs index 7399ada..d327a05 100644 --- a/src/util/dwarf/print.rs +++ b/src/util/dwarf/print.rs @@ -670,7 +670,7 @@ pub fn subroutine_def_string( writeln!( out, "{};", - &indent_all_by(4, &ud_type_def(info, typedefs, inner_type, false)?) + indent_all_by(4, &ud_type_def(info, typedefs, inner_type, false)?) )?; } } @@ -678,7 +678,7 @@ pub fn subroutine_def_string( if !t.typedefs.is_empty() { writeln!(out, "\n // Typedefs")?; for typedef in &t.typedefs { - writeln!(out, "{}", &indent_all_by(4, &typedef_string(info, typedefs, typedef)?))?; + writeln!(out, "{}", indent_all_by(4, &typedef_string(info, typedefs, typedef)?))?; } } @@ -781,7 +781,7 @@ fn subroutine_block_string( writeln!( out, "{};", - &indent_all_by(4, &ud_type_def(info, typedefs, inner_type, false)?) + indent_all_by(4, &ud_type_def(info, typedefs, inner_type, false)?) )?; } } @@ -789,7 +789,7 @@ fn subroutine_block_string( if !block.typedefs.is_empty() { writeln!(out, "\n // Typedefs")?; for typedef in &block.typedefs { - writeln!(out, "{}", &indent_all_by(4, &typedef_string(info, typedefs, typedef)?))?; + writeln!(out, "{}", indent_all_by(4, &typedef_string(info, typedefs, typedef)?))?; } } @@ -967,7 +967,7 @@ pub fn structure_def_string( writeln!( out, "{};", - &indent_all_by(4, &ud_type_def(info, typedefs, inner_type, false)?) + indent_all_by(4, &ud_type_def(info, typedefs, inner_type, false)?) )?; } } @@ -975,7 +975,7 @@ pub fn structure_def_string( if !t.typedefs.is_empty() { writeln!(out, "\n // Typedefs")?; for typedef in &t.typedefs { - writeln!(out, "{}", &indent_all_by(4, &typedef_string(info, typedefs, typedef)?))?; + writeln!(out, "{}", indent_all_by(4, &typedef_string(info, typedefs, typedef)?))?; } } From 433aab94f7f4947eab4e72dd6375dbf30a3f36e9 Mon Sep 17 00:00:00 2001 From: Matt Stevens Date: Sat, 11 Jul 2026 21:49:06 +0100 Subject: [PATCH 3/3] chore: resolve cargo-deny advisories - anyhow 1.0.100 -> 1.0.103 (RUSTSEC-2026-0190) - crossbeam-epoch 0.9.18 -> 0.9.20 (RUSTSEC-2026-0204) - ignore RUSTSEC-2026-0194/0195: quick-xml 0.36 is pinned by nodtool 1.4; the fixed quick-xml (>=0.41) is only reachable via nodtool 2.0 alphas Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014kEDAMC4whgcjekmVde9PA --- Cargo.lock | 60 ++++++------------------------------------------------ deny.toml | 2 ++ 2 files changed, 8 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f522e26..df844d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - [[package]] name = "adler" version = "1.0.2" @@ -45,12 +36,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" -dependencies = [ - "backtrace", -] +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "ar" @@ -84,21 +72,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object 0.37.3", - "rustc-demangle", - "windows-link", -] - [[package]] name = "base16ct" version = "0.2.0" @@ -277,9 +250,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] @@ -376,7 +349,7 @@ dependencies = [ "nodtool", "num_enum", "objdiff-core", - "object 0.36.7", + "object", "once_cell", "orthrus-ncompress", "owo-colors", @@ -576,12 +549,6 @@ dependencies = [ "wasip2", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "glob" version = "0.3.3" @@ -1025,7 +992,7 @@ dependencies = [ "log", "memmap2", "num-traits", - "object 0.36.7", + "object", "pbjson-build", "ppc750cl", "prost-build", @@ -1048,15 +1015,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -1343,12 +1301,6 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustc-hash" version = "2.1.1" diff --git a/deny.toml b/deny.toml index 4d3b183..5e2585a 100644 --- a/deny.toml +++ b/deny.toml @@ -78,6 +78,8 @@ ignore = [ { id = "RUSTSEC-2025-0048", reason = "tsify-next is unmaintained but required by objdiff-core" }, { id = "RUSTSEC-2025-0119", reason = "unmaintained transient dependency (number_prefix)" }, { id = "RUSTSEC-2025-0141", reason = "unmaintained transient dependency (bincode)" }, + { id = "RUSTSEC-2026-0194", reason = "quick-xml 0.36 pinned by nodtool 1.4; fix requires quick-xml >=0.41 (nodtool 2.0, still alpha)" }, + { id = "RUSTSEC-2026-0195", reason = "quick-xml 0.36 pinned by nodtool 1.4; fix requires quick-xml >=0.41 (nodtool 2.0, still alpha)" }, ] # If this is true, then cargo deny will use the git executable to fetch advisory database. # If this is false, then it uses a built-in git library.