From dac235934b576237420f192032973c6e2bc0babb Mon Sep 17 00:00:00 2001 From: Sam Lidder Date: Sun, 3 Aug 2025 00:52:11 -0400 Subject: [PATCH 1/4] fix(windows): `patch_binary` causing codesigning verification failure --- crates/tauri-bundler/src/bundle.rs | 33 ++++++++++++++++--- .../tauri-bundler/src/bundle/windows/util.rs | 5 +-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/crates/tauri-bundler/src/bundle.rs b/crates/tauri-bundler/src/bundle.rs index 9297bc5974fe..f3042286624d 100644 --- a/crates/tauri-bundler/src/bundle.rs +++ b/crates/tauri-bundler/src/bundle.rs @@ -53,7 +53,7 @@ pub use self::{ use anyhow::Context; pub use settings::{NsisSettings, WindowsSettings, WixLanguage, WixLanguageConfig, WixSettings}; -use std::{fmt::Write, path::PathBuf}; +use std::{fmt::Write, path::PathBuf, io::{Seek, SeekFrom}}; /// Generated bundle metadata. #[derive(Debug)] @@ -122,7 +122,23 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { .iter() .find(|b| b.main()) .expect("Main binary missing in settings"); + let main_binary_path = settings.binary_path(main_binary); + + // When packaging multiple binary types, we make a copy of the unsigned main_binary so that we can + // restore it after each package_type step. This avoids two issues: + // - modifying a signed binary without updating its PE checksum can break signature verification + // - codesigning tools should handle calculating+updating this, we just need to ensure + // (re)signing is performed after every `patch_binary()` operation + // - signing an already-signed binary can result in multiple signatures, causing verification errors + let main_binary_reset_required = + matches!(target_os, TargetPlatform::Windows) && settings.can_sign() && package_types.len() > 1; + let mut unsigned_main_binary_copy = tempfile::tempfile()?; + if main_binary_reset_required { + let mut unsigned_main_binary = std::fs::File::open(&main_binary_path)?; + std::io::copy(&mut unsigned_main_binary, &mut unsigned_main_binary_copy)?; + } + let mut main_binary_signed = false; let mut bundles = Vec::::new(); for package_type in &package_types { // bundle was already built! e.g. DMG already built .app @@ -130,14 +146,22 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { continue; } - if let Err(e) = patch_binary(&settings.binary_path(main_binary), package_type) { + if let Err(e) = patch_binary(&main_binary_path, package_type) { log::warn!("Failed to add bundler type to the binary: {e}. Updater plugin may not be able to update this package. This shouldn't normally happen, please report it to https://github.com/tauri-apps/tauri/issues"); } // sign main binary for every package type after patch if matches!(target_os, TargetPlatform::Windows) && settings.can_sign() { - let bin_path = settings.binary_path(main_binary); - windows::sign::try_sign(&bin_path, settings)?; + if main_binary_signed && main_binary_reset_required { + let mut signed_main_binary = std::fs::OpenOptions::new() + .write(true) + .truncate(true) + .open(&main_binary_path)?; + unsigned_main_binary_copy.seek(SeekFrom::Start(0))?; + std::io::copy(&mut unsigned_main_binary_copy, &mut signed_main_binary)?; + } + windows::sign::try_sign(&main_binary_path, settings)?; + main_binary_signed = true; } let bundle_paths = match package_type { @@ -160,6 +184,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { #[cfg(target_os = "windows")] PackageType::WindowsMsi => windows::msi::bundle_project(settings, false)?, + // note: don't restrict to windows as NSIS installers can be built in linux using cargo-xwin PackageType::Nsis => windows::nsis::bundle_project(settings, false)?, #[cfg(target_os = "linux")] diff --git a/crates/tauri-bundler/src/bundle/windows/util.rs b/crates/tauri-bundler/src/bundle/windows/util.rs index 897680adc8c7..b7a290332797 100644 --- a/crates/tauri-bundler/src/bundle/windows/util.rs +++ b/crates/tauri-bundler/src/bundle/windows/util.rs @@ -85,8 +85,7 @@ pub fn os_bitness<'a>() -> Option<&'a str> { } pub fn patch_binary(binary_path: &PathBuf, package_type: &crate::PackageType) -> crate::Result<()> { - let file_data = std::fs::read(binary_path)?; - let mut file_data = file_data; // make mutable + let mut file_data = std::fs::read(binary_path)?; let pe = match goblin::Object::parse(&file_data)? { goblin::Object::PE(pe) => pe, @@ -132,6 +131,8 @@ pub fn patch_binary(binary_path: &PathBuf, package_type: &crate::PackageType) -> ) })?; + // see "Relative virtual address (RVA)" for explanation of offset arithmetic here: + // https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#general-concepts let file_offset = rdata_section.pointer_to_raw_data as usize + (rva as usize).saturating_sub(rdata_section.virtual_address as usize); From 610065ead913ebb2f5949f4051a1e3ae8510606d Mon Sep 17 00:00:00 2001 From: Sam Lidder Date: Sun, 3 Aug 2025 12:21:39 -0400 Subject: [PATCH 2/4] `cargo fmt` --- crates/tauri-bundler/src/bundle.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/tauri-bundler/src/bundle.rs b/crates/tauri-bundler/src/bundle.rs index f3042286624d..3ee307eef2b7 100644 --- a/crates/tauri-bundler/src/bundle.rs +++ b/crates/tauri-bundler/src/bundle.rs @@ -53,7 +53,11 @@ pub use self::{ use anyhow::Context; pub use settings::{NsisSettings, WindowsSettings, WixLanguage, WixLanguageConfig, WixSettings}; -use std::{fmt::Write, path::PathBuf, io::{Seek, SeekFrom}}; +use std::{ + fmt::Write, + io::{Seek, SeekFrom}, + path::PathBuf, +}; /// Generated bundle metadata. #[derive(Debug)] From 86b72c607f3f0125351bdcbedc8194b09008d3b5 Mon Sep 17 00:00:00 2001 From: Sam Lidder Date: Sun, 3 Aug 2025 13:13:47 -0400 Subject: [PATCH 3/4] add change file --- .../fix-binary-patching-codesign-verification-failure.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changes/fix-binary-patching-codesign-verification-failure.md diff --git a/.changes/fix-binary-patching-codesign-verification-failure.md b/.changes/fix-binary-patching-codesign-verification-failure.md new file mode 100644 index 000000000000..948b43d2f683 --- /dev/null +++ b/.changes/fix-binary-patching-codesign-verification-failure.md @@ -0,0 +1,5 @@ +--- +'@tauri-apps/cli': 'patch:sec' +--- + +Fix codesigning verification failures caused by binary-patching during bundling From adf464c8f61601b0900ff7e1128e7da87b19584c Mon Sep 17 00:00:00 2001 From: Tony <68118705+Legend-Master@users.noreply.github.com> Date: Mon, 4 Aug 2025 10:54:15 +0800 Subject: [PATCH 4/4] Update .changes/fix-binary-patching-codesign-verification-failure.md --- .changes/fix-binary-patching-codesign-verification-failure.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.changes/fix-binary-patching-codesign-verification-failure.md b/.changes/fix-binary-patching-codesign-verification-failure.md index 948b43d2f683..3f0d26e925b0 100644 --- a/.changes/fix-binary-patching-codesign-verification-failure.md +++ b/.changes/fix-binary-patching-codesign-verification-failure.md @@ -1,5 +1,6 @@ --- -'@tauri-apps/cli': 'patch:sec' +'tauri-cli': 'patch:bug' +'@tauri-apps/cli': 'patch:bug' --- Fix codesigning verification failures caused by binary-patching during bundling