diff --git a/0001-upatch-hijacker-fix-compile-bug.patch b/0001-upatch-hijacker-fix-compile-bug.patch index f8c1c951630abb6b8f3dd8d955d1c71f1b92ab19..5fe1a818f61a47eab3e2b7b2c26ae906a1cf6a39 100644 --- a/0001-upatch-hijacker-fix-compile-bug.patch +++ b/0001-upatch-hijacker-fix-compile-bug.patch @@ -1,7 +1,7 @@ From 8c09e8b3d9d59012c1019c01ac2246c770501c75 Mon Sep 17 00:00:00 2001 From: ningyu <405888464@qq.com> Date: Sun, 7 Apr 2024 10:50:13 +0800 -Subject: [PATCH 01/10] upatch-hijacker: fix compile bug container_of_safe => +Subject: [PATCH 01/17] upatch-hijacker: fix compile bug container_of_safe => container_of --- diff --git a/0002-daemon-fix-cannot-get-file-selinux-xattr-when-selinu.patch b/0002-daemon-fix-cannot-get-file-selinux-xattr-when-selinu.patch index c796929b65df62a823733b1a067dd0a9b8b5dd5d..c52718b57a892f0bf5d459fc6fd69dde44414d05 100644 --- a/0002-daemon-fix-cannot-get-file-selinux-xattr-when-selinu.patch +++ b/0002-daemon-fix-cannot-get-file-selinux-xattr-when-selinu.patch @@ -1,7 +1,7 @@ From a535e14a7db49df3c8aab017e32b92d8e5bb4087 Mon Sep 17 00:00:00 2001 From: renoseven Date: Wed, 10 Apr 2024 10:25:21 +0800 -Subject: [PATCH 02/10] daemon: fix 'cannot get file selinux xattr when selinux +Subject: [PATCH 02/17] daemon: fix 'cannot get file selinux xattr when selinux is not enforcing' issue Signed-off-by: renoseven diff --git a/0003-syscared-fix-syscare-check-command-does-not-check-sy.patch b/0003-syscared-fix-syscare-check-command-does-not-check-sy.patch index 7ed3ba9bcac03e205150bd6a2c5c6d4468e597e1..9ed8a1898ec868dcc7f0cdaaece057992977a3cd 100644 --- a/0003-syscared-fix-syscare-check-command-does-not-check-sy.patch +++ b/0003-syscared-fix-syscare-check-command-does-not-check-sy.patch @@ -1,7 +1,7 @@ From e5294afa8135f54f44196bd92e5a32c2b09b9bda Mon Sep 17 00:00:00 2001 From: renoseven Date: Wed, 10 Apr 2024 12:19:51 +0800 -Subject: [PATCH 03/10] syscared: fix 'syscare check command does not check +Subject: [PATCH 03/17] syscared: fix 'syscare check command does not check symbol confiliction' issue Signed-off-by: renoseven diff --git a/0005-abi-change-uuid-type-from-string-to-uuid-bytes.patch b/0004-Change-uuid-type-to-Uuid.patch similarity index 97% rename from 0005-abi-change-uuid-type-from-string-to-uuid-bytes.patch rename to 0004-Change-uuid-type-to-Uuid.patch index a860450bfee072c7838c10ebce22d1b5a28cede3..a166e9c0ab406c2749bf9b2a0fbe794dd7f2a196 100644 --- a/0005-abi-change-uuid-type-from-string-to-uuid-bytes.patch +++ b/0004-Change-uuid-type-to-Uuid.patch @@ -1,7 +1,7 @@ -From c213504c02d73738a86935fb5883f2e59d083da7 Mon Sep 17 00:00:00 2001 +From b53cb3d2903ea8ee3667f892b813648da7bc59a7 Mon Sep 17 00:00:00 2001 From: ningyu Date: Tue, 9 Apr 2024 09:21:35 +0000 -Subject: [PATCH 05/10] abi: change uuid type from string to uuid bytes +Subject: [PATCH 04/17] Change uuid type to Uuid --- Cargo.lock | 1 + @@ -68,7 +68,7 @@ index 55618ae..08cc2c7 100644 pub version: String, pub release: u32, diff --git a/syscare-build/src/package/rpm/spec_builder.rs b/syscare-build/src/package/rpm/spec_builder.rs -index 88f57d8..a24954f 100644 +index 88f57d8..5570c34 100644 --- a/syscare-build/src/package/rpm/spec_builder.rs +++ b/syscare-build/src/package/rpm/spec_builder.rs @@ -62,7 +62,7 @@ impl RpmSpecBuilder { @@ -85,7 +85,7 @@ index 88f57d8..a24954f 100644 ); let pkg_version = format!("{}-{}", patch_info.version, patch_info.release); - let pkg_root = Path::new(PKG_INSTALL_DIR).join(&patch_info.uuid); -+ let pkg_root = Path::new(PKG_INSTALL_DIR).join(patch_info.uuid.to_string()); ++ let pkg_root = Path::new(PKG_INSTALL_DIR).join(&patch_info.uuid.to_string()); let mut spec = RpmSpecFile::new( pkg_name, diff --git a/0005-fix-clippy-warning.patch b/0005-fix-clippy-warning.patch new file mode 100644 index 0000000000000000000000000000000000000000..ffdef836d95ae08e0594e2daeea068bbd3f93199 --- /dev/null +++ b/0005-fix-clippy-warning.patch @@ -0,0 +1,39 @@ +From 41e5b9125fab50d4b3a137c5397443319e2365ec Mon Sep 17 00:00:00 2001 +From: ningyu <405888464@qq.com> +Date: Wed, 10 Apr 2024 17:19:35 +0800 +Subject: [PATCH 05/17] fix clippy warning + +--- + syscare-build/src/package/rpm/spec_builder.rs | 2 +- + syscared/src/patch/driver/upatch/mod.rs | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/syscare-build/src/package/rpm/spec_builder.rs b/syscare-build/src/package/rpm/spec_builder.rs +index 5570c34..a24954f 100644 +--- a/syscare-build/src/package/rpm/spec_builder.rs ++++ b/syscare-build/src/package/rpm/spec_builder.rs +@@ -113,7 +113,7 @@ impl RpmSpecBuilder { + patch_info.name + ); + let pkg_version = format!("{}-{}", patch_info.version, patch_info.release); +- let pkg_root = Path::new(PKG_INSTALL_DIR).join(&patch_info.uuid.to_string()); ++ let pkg_root = Path::new(PKG_INSTALL_DIR).join(patch_info.uuid.to_string()); + + let mut spec = RpmSpecFile::new( + pkg_name, +diff --git a/syscared/src/patch/driver/upatch/mod.rs b/syscared/src/patch/driver/upatch/mod.rs +index 98fc54c..98b1e34 100644 +--- a/syscared/src/patch/driver/upatch/mod.rs ++++ b/syscared/src/patch/driver/upatch/mod.rs +@@ -38,7 +38,7 @@ mod target; + use monitor::UserPatchMonitor; + use target::PatchTarget; + +-pub(self) type ActivePatchMap = Arc>>; ++type ActivePatchMap = Arc>>; + + #[derive(Default)] + struct ActivePatch { +-- +2.41.0 + diff --git a/0004-syscared-fix-cannot-find-process-of-dynlib-patch-iss.patch b/0006-syscared-fix-cannot-find-process-of-dynlib-patch-iss.patch similarity index 98% rename from 0004-syscared-fix-cannot-find-process-of-dynlib-patch-iss.patch rename to 0006-syscared-fix-cannot-find-process-of-dynlib-patch-iss.patch index 2f51c249a2cfa338954775fcc33a604f5b851095..117b069cb89e9b54d906f7caa8de8f9e949baf35 100644 --- a/0004-syscared-fix-cannot-find-process-of-dynlib-patch-iss.patch +++ b/0006-syscared-fix-cannot-find-process-of-dynlib-patch-iss.patch @@ -1,7 +1,7 @@ -From 32c3d16175b93627504981d05a1a3e3ec603415e Mon Sep 17 00:00:00 2001 +From 729f32db079e2aace7cf355d480627b0bbf37e8c Mon Sep 17 00:00:00 2001 From: renoseven Date: Wed, 10 Apr 2024 19:30:56 +0800 -Subject: [PATCH 04/10] syscared: fix 'cannot find process of dynlib patch' +Subject: [PATCH 06/17] syscared: fix 'cannot find process of dynlib patch' issue 1. For detecting process mapped dynamic library, @@ -21,7 +21,7 @@ Signed-off-by: renoseven 4 files changed, 270 insertions(+), 199 deletions(-) diff --git a/syscared/src/patch/driver/upatch/mod.rs b/syscared/src/patch/driver/upatch/mod.rs -index 98fc54c..a7fa154 100644 +index 98b1e34..a7fa154 100644 --- a/syscared/src/patch/driver/upatch/mod.rs +++ b/syscared/src/patch/driver/upatch/mod.rs @@ -21,7 +21,7 @@ use std::{ @@ -37,7 +37,7 @@ index 98fc54c..a7fa154 100644 use monitor::UserPatchMonitor; use target::PatchTarget; --pub(self) type ActivePatchMap = Arc>>; +-type ActivePatchMap = Arc>>; +type ElfPatchMap = Arc>>; #[derive(Default)] diff --git a/0006-syscared-optimize-patch-error-logic.patch b/0007-syscared-optimize-patch-error-logic.patch similarity index 96% rename from 0006-syscared-optimize-patch-error-logic.patch rename to 0007-syscared-optimize-patch-error-logic.patch index af4f01fd8f0528001dfc04986b22af050de6929c..392a485388dbb19aaf519d43e129459c50e648a8 100644 --- a/0006-syscared-optimize-patch-error-logic.patch +++ b/0007-syscared-optimize-patch-error-logic.patch @@ -1,7 +1,7 @@ -From 1fbb81935c66c47a68716580878f2b983272a2bc Mon Sep 17 00:00:00 2001 +From 520e46ddd8f393125509a436134255765c5960cc Mon Sep 17 00:00:00 2001 From: renoseven Date: Fri, 12 Apr 2024 11:35:57 +0800 -Subject: [PATCH 06/10] syscared: optimize patch error logic +Subject: [PATCH 07/17] syscared: optimize patch error logic Signed-off-by: renoseven --- diff --git a/0007-syscared-optimize-transaction-creation-logic.patch b/0008-syscared-optimize-transaction-creation-logic.patch similarity index 96% rename from 0007-syscared-optimize-transaction-creation-logic.patch rename to 0008-syscared-optimize-transaction-creation-logic.patch index a344865dd3fbd3c7e013a3fc289cc17df1697b94..7d7666340b09ff8bdc9ec10458706a640de5ccb2 100644 --- a/0007-syscared-optimize-transaction-creation-logic.patch +++ b/0008-syscared-optimize-transaction-creation-logic.patch @@ -1,7 +1,7 @@ -From bbf3396adbbd53709ab5a78c1035e6b9b010d549 Mon Sep 17 00:00:00 2001 +From 4ceb42b4a81cfb573aad4b4542f143be4c0ae90c Mon Sep 17 00:00:00 2001 From: renoseven Date: Fri, 12 Apr 2024 11:40:25 +0800 -Subject: [PATCH 07/10] syscared: optimize transaction creation logic +Subject: [PATCH 08/17] syscared: optimize transaction creation logic Signed-off-by: renoseven --- diff --git a/0008-upatch-manage-optimize-output.patch b/0009-upatch-manage-optimize-output.patch similarity index 97% rename from 0008-upatch-manage-optimize-output.patch rename to 0009-upatch-manage-optimize-output.patch index 8d2632921c2b9bfac10fe18811ed951c488e429b..80bdfc5dadea1e73a272a85b86bc0fa2d6cf4318 100644 --- a/0008-upatch-manage-optimize-output.patch +++ b/0009-upatch-manage-optimize-output.patch @@ -1,7 +1,7 @@ -From 7c976ffc72330c85bc815bc1983dd7096778bf1b Mon Sep 17 00:00:00 2001 +From 399de1f2021ae91ee6fc1271b1ee4f2f5933eaf1 Mon Sep 17 00:00:00 2001 From: renoseven Date: Fri, 12 Apr 2024 11:50:59 +0800 -Subject: [PATCH 08/10] upatch-manage: optimize output +Subject: [PATCH 09/17] upatch-manage: optimize output Signed-off-by: renoseven --- diff --git a/0009-syscared-optimize-patch-error-logic.patch b/0010-syscared-optimize-patch-error-logic.patch similarity index 89% rename from 0009-syscared-optimize-patch-error-logic.patch rename to 0010-syscared-optimize-patch-error-logic.patch index 4601bbd61189efdb75ee977609f97551520b032e..76fdc7d1d9580f564b07e5acf0ccfcfd764f4c61 100644 --- a/0009-syscared-optimize-patch-error-logic.patch +++ b/0010-syscared-optimize-patch-error-logic.patch @@ -1,7 +1,7 @@ -From 1a419fd88160f45a8fdabd8e6427811804735af1 Mon Sep 17 00:00:00 2001 +From 51aa26c1eeb7514bceb0194b601de560c6b9d74a Mon Sep 17 00:00:00 2001 From: renoseven Date: Fri, 12 Apr 2024 11:35:57 +0800 -Subject: [PATCH 09/10] syscared: optimize patch error logic +Subject: [PATCH 10/17] syscared: optimize patch error logic Signed-off-by: renoseven --- diff --git a/0010-syscared-optimize-transaction-creation-logic.patch b/0011-syscared-optimize-transaction-creation-logic.patch similarity index 89% rename from 0010-syscared-optimize-transaction-creation-logic.patch rename to 0011-syscared-optimize-transaction-creation-logic.patch index 0dd89cd39e0926f158d699db06a0d13e93cb9a08..77c86a5371706bbeb994ef390d00ca2737f154a6 100644 --- a/0010-syscared-optimize-transaction-creation-logic.patch +++ b/0011-syscared-optimize-transaction-creation-logic.patch @@ -1,7 +1,7 @@ -From 91b63792ed2b13ce8fc706df1ffa7d9fdadc31c7 Mon Sep 17 00:00:00 2001 +From 1d67bb57973cc0bc4b227c4359c15c4f31a1c82c Mon Sep 17 00:00:00 2001 From: renoseven Date: Fri, 12 Apr 2024 11:40:25 +0800 -Subject: [PATCH 10/10] syscared: optimize transaction creation logic +Subject: [PATCH 11/17] syscared: optimize transaction creation logic Signed-off-by: renoseven --- diff --git a/0012-common-impl-CStr-from_bytes_with_next_nul.patch b/0012-common-impl-CStr-from_bytes_with_next_nul.patch new file mode 100644 index 0000000000000000000000000000000000000000..17bff0875343ce8021b19cc5113ee1a7c48bf1c2 --- /dev/null +++ b/0012-common-impl-CStr-from_bytes_with_next_nul.patch @@ -0,0 +1,47 @@ +From b64fa8df5ef916510e345cdd0382c32364d0c255 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Tue, 16 Apr 2024 12:44:11 +0800 +Subject: [PATCH 12/17] common: impl CStr::from_bytes_with_next_nul() + +Signed-off-by: renoseven +--- + syscare-common/src/ffi/c_str.rs | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/syscare-common/src/ffi/c_str.rs b/syscare-common/src/ffi/c_str.rs +index 060149a..4f3f26d 100644 +--- a/syscare-common/src/ffi/c_str.rs ++++ b/syscare-common/src/ffi/c_str.rs +@@ -13,7 +13,7 @@ + */ + + use std::{ +- ffi::{CStr, OsStr, OsString}, ++ ffi::{CStr, CString, FromBytesWithNulError, OsStr, OsString}, + os::unix::{ffi::OsStringExt, prelude::OsStrExt}, + path::{Path, PathBuf}, + }; +@@ -34,9 +34,19 @@ pub trait CStrExt: AsRef { + fn to_path_buf(&self) -> PathBuf { + PathBuf::from(self.to_os_string()) + } ++ ++ fn from_bytes_with_next_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> { ++ let nul_pos = bytes.iter().position(|b| b == &b'\0').unwrap_or(0); ++ let cstr_bytes = &bytes[..=nul_pos]; ++ ++ CStr::from_bytes_with_nul(cstr_bytes) ++ } + } + +-impl> CStrExt for T {} ++impl CStrExt for CStr {} ++impl CStrExt for &CStr {} ++impl CStrExt for CString {} ++impl CStrExt for &CString {} + + #[test] + fn test_cstr() { +-- +2.41.0 + diff --git a/0013-syscared-improve-patch-management.patch b/0013-syscared-improve-patch-management.patch new file mode 100644 index 0000000000000000000000000000000000000000..6fe6056cd6edc593a72247e15810fc42cf7877d6 --- /dev/null +++ b/0013-syscared-improve-patch-management.patch @@ -0,0 +1,2317 @@ +From 13df37eba5f5b763922b7b2b91e4097e93b13158 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Tue, 16 Apr 2024 14:20:27 +0800 +Subject: [PATCH 13/17] syscared: improve patch management + +Signed-off-by: renoseven +--- + syscared/src/patch/driver/kpatch/mod.rs | 161 ++++-- + syscared/src/patch/driver/kpatch/sys.rs | 16 +- + syscared/src/patch/driver/kpatch/target.rs | 164 +++---- + syscared/src/patch/driver/mod.rs | 18 +- + syscared/src/patch/driver/upatch/entity.rs | 74 +++ + syscared/src/patch/driver/upatch/mod.rs | 511 +++++++++++--------- + syscared/src/patch/driver/upatch/monitor.rs | 72 +-- + syscared/src/patch/driver/upatch/process.rs | 100 ---- + syscared/src/patch/driver/upatch/sys.rs | 14 +- + syscared/src/patch/driver/upatch/target.rs | 138 +++--- + syscared/src/patch/entity/kpatch.rs | 20 +- + syscared/src/patch/entity/symbol.rs | 10 +- + syscared/src/patch/entity/upatch.rs | 12 +- + syscared/src/patch/resolver/kpatch.rs | 141 +++--- + syscared/src/patch/resolver/upatch.rs | 97 ++-- + 15 files changed, 832 insertions(+), 716 deletions(-) + create mode 100644 syscared/src/patch/driver/upatch/entity.rs + delete mode 100644 syscared/src/patch/driver/upatch/process.rs + +diff --git a/syscared/src/patch/driver/kpatch/mod.rs b/syscared/src/patch/driver/kpatch/mod.rs +index e4509d8..45dc719 100644 +--- a/syscared/src/patch/driver/kpatch/mod.rs ++++ b/syscared/src/patch/driver/kpatch/mod.rs +@@ -19,12 +19,12 @@ use std::{ + + use anyhow::{ensure, Result}; + use indexmap::{indexset, IndexMap, IndexSet}; +-use log::debug; ++use log::{debug, info}; + + use syscare_abi::PatchStatus; + use syscare_common::{concat_os, os, util::digest}; + +-use crate::patch::entity::KernelPatch; ++use crate::patch::entity::{KernelPatch, KernelPatchFunction}; + + mod sys; + mod target; +@@ -32,21 +32,84 @@ mod target; + use target::PatchTarget; + + pub struct KernelPatchDriver { +- patch_target_map: IndexMap, ++ target_map: IndexMap, + } + + impl KernelPatchDriver { + pub fn new() -> Result { + Ok(Self { +- patch_target_map: IndexMap::new(), ++ target_map: IndexMap::new(), + }) + } + } + ++impl KernelPatchDriver { ++ fn group_patch_targets(patch: &KernelPatch) -> IndexSet<&OsStr> { ++ let mut patch_targets = IndexSet::new(); ++ ++ for function in &patch.functions { ++ patch_targets.insert(function.object.as_os_str()); ++ } ++ patch_targets ++ } ++ ++ pub fn group_patch_functions( ++ patch: &KernelPatch, ++ ) -> IndexMap<&OsStr, Vec<&KernelPatchFunction>> { ++ let mut patch_function_map: IndexMap<&OsStr, Vec<&KernelPatchFunction>> = IndexMap::new(); ++ ++ for function in &patch.functions { ++ patch_function_map ++ .entry(function.object.as_os_str()) ++ .or_default() ++ .push(function); ++ } ++ patch_function_map ++ } ++} ++ ++impl KernelPatchDriver { ++ fn add_patch_target(&mut self, patch: &KernelPatch) { ++ for target_name in Self::group_patch_targets(patch) { ++ if !self.target_map.contains_key(target_name) { ++ self.target_map.insert( ++ target_name.to_os_string(), ++ PatchTarget::new(target_name.to_os_string()), ++ ); ++ } ++ } ++ } ++ ++ fn remove_patch_target(&mut self, patch: &KernelPatch) { ++ for target_name in Self::group_patch_targets(patch) { ++ if let Some(target) = self.target_map.get_mut(target_name) { ++ if !target.has_function() { ++ self.target_map.remove(target_name); ++ } ++ } ++ } ++ } ++ ++ fn add_patch_functions(&mut self, patch: &KernelPatch) { ++ for (target_name, functions) in Self::group_patch_functions(patch) { ++ if let Some(target) = self.target_map.get_mut(target_name) { ++ target.add_functions(patch.uuid, functions); ++ } ++ } ++ } ++ ++ fn remove_patch_functions(&mut self, patch: &KernelPatch) { ++ for (target_name, functions) in Self::group_patch_functions(patch) { ++ if let Some(target) = self.target_map.get_mut(target_name) { ++ target.remove_functions(&patch.uuid, functions); ++ } ++ } ++ } ++} ++ + impl KernelPatchDriver { + fn check_consistency(patch: &KernelPatch) -> Result<()> { +- let patch_file = patch.patch_file.as_path(); +- let real_checksum = digest::file(patch_file)?; ++ let real_checksum = digest::file(&patch.patch_file)?; + debug!("Target checksum: '{}'", patch.checksum); + debug!("Expected checksum: '{}'", real_checksum); + +@@ -78,7 +141,7 @@ impl KernelPatchDriver { + let mut non_exist_kmod = IndexSet::new(); + + let kmod_list = sys::list_kernel_modules()?; +- for kmod_name in Self::parse_target_modules(patch) { ++ for kmod_name in Self::group_patch_targets(patch) { + if kmod_name == VMLINUX_MODULE_NAME { + continue; + } +@@ -102,15 +165,15 @@ impl KernelPatchDriver { + Ok(()) + } + +- pub fn check_conflict_symbols(&self, patch: &KernelPatch) -> Result<()> { ++ pub fn check_conflict_functions(&self, patch: &KernelPatch) -> Result<()> { + let mut conflict_patches = indexset! {}; + +- let target_symbols = PatchTarget::classify_symbols(&patch.symbols); +- for (target_name, symbols) in target_symbols { +- if let Some(target) = self.patch_target_map.get(target_name) { ++ let target_functions = Self::group_patch_functions(patch); ++ for (target_name, functions) in target_functions { ++ if let Some(target) = self.target_map.get(target_name) { + conflict_patches.extend( + target +- .get_conflicts(symbols) ++ .get_conflicts(functions) + .into_iter() + .map(|record| record.uuid), + ); +@@ -131,15 +194,15 @@ impl KernelPatchDriver { + Ok(()) + } + +- pub fn check_override_symbols(&self, patch: &KernelPatch) -> Result<()> { ++ pub fn check_override_functions(&self, patch: &KernelPatch) -> Result<()> { + let mut override_patches = indexset! {}; + +- let target_symbols = PatchTarget::classify_symbols(&patch.symbols); +- for (target_name, symbols) in target_symbols { +- if let Some(target) = self.patch_target_map.get(target_name) { ++ let target_functions = Self::group_patch_functions(patch); ++ for (target_name, functions) in target_functions { ++ if let Some(target) = self.target_map.get(target_name) { + override_patches.extend( + target +- .get_overrides(&patch.uuid, symbols) ++ .get_overrides(&patch.uuid, functions) + .into_iter() + .map(|record| record.uuid), + ); +@@ -161,35 +224,6 @@ impl KernelPatchDriver { + } + } + +-impl KernelPatchDriver { +- fn parse_target_modules(patch: &KernelPatch) -> impl IntoIterator { +- patch.symbols.iter().map(|symbol| symbol.target.as_os_str()) +- } +- +- fn add_patch_symbols(&mut self, patch: &KernelPatch) { +- let target_symbols = PatchTarget::classify_symbols(&patch.symbols); +- +- for (target_name, symbols) in target_symbols { +- let target = self +- .patch_target_map +- .entry(target_name.to_os_string()) +- .or_insert_with(|| PatchTarget::new(target_name)); +- +- target.add_symbols(patch.uuid, symbols); +- } +- } +- +- fn remove_patch_symbols(&mut self, patch: &KernelPatch) { +- let target_symbols = PatchTarget::classify_symbols(&patch.symbols); +- +- for (target_name, symbols) in target_symbols { +- if let Some(target) = self.patch_target_map.get_mut(target_name) { +- target.remove_symbols(&patch.uuid, symbols); +- } +- } +- } +-} +- + impl KernelPatchDriver { + pub fn status(&self, patch: &KernelPatch) -> Result { + sys::read_patch_status(patch) +@@ -204,24 +238,51 @@ impl KernelPatchDriver { + } + + pub fn apply(&mut self, patch: &KernelPatch) -> Result<()> { ++ info!( ++ "Kpatch: Applying patch '{}' ({})", ++ patch.uuid, ++ patch.patch_file.display() ++ ); ++ + sys::selinux_relable_patch(patch)?; +- sys::apply_patch(patch) ++ sys::apply_patch(patch)?; ++ self.add_patch_target(patch); ++ ++ Ok(()) + } + + pub fn remove(&mut self, patch: &KernelPatch) -> Result<()> { +- sys::remove_patch(patch) ++ info!( ++ "Kpatch: Removing patch '{}' ({})", ++ patch.uuid, ++ patch.patch_file.display() ++ ); ++ sys::remove_patch(patch)?; ++ self.remove_patch_target(patch); ++ ++ Ok(()) + } + + pub fn active(&mut self, patch: &KernelPatch) -> Result<()> { ++ info!( ++ "Kpatch: Activating patch '{}' ({})", ++ patch.uuid, ++ patch.patch_file.display() ++ ); + sys::active_patch(patch)?; +- self.add_patch_symbols(patch); ++ self.add_patch_functions(patch); + + Ok(()) + } + + pub fn deactive(&mut self, patch: &KernelPatch) -> Result<()> { ++ info!( ++ "Kpatch: Deactivating patch '{}' ({})", ++ patch.uuid, ++ patch.patch_file.display() ++ ); + sys::deactive_patch(patch)?; +- self.remove_patch_symbols(patch); ++ self.remove_patch_functions(patch); + + Ok(()) + } +diff --git a/syscared/src/patch/driver/kpatch/sys.rs b/syscared/src/patch/driver/kpatch/sys.rs +index 5035d06..ea6b68f 100644 +--- a/syscared/src/patch/driver/kpatch/sys.rs ++++ b/syscared/src/patch/driver/kpatch/sys.rs +@@ -61,17 +61,11 @@ pub fn read_patch_status(patch: &KernelPatch) -> Result { + debug!("Reading {}", sys_file.display()); + + let status = match fs::read_to_string(sys_file) { +- Ok(str) => { +- let status = str.trim(); +- let patch_status = match status { +- KPATCH_STATUS_DISABLED => PatchStatus::Deactived, +- KPATCH_STATUS_ENABLED => PatchStatus::Actived, +- _ => { +- bail!("Kpatch: Invalid patch status"); +- } +- }; +- Ok(patch_status) +- } ++ Ok(str) => match str.trim() { ++ KPATCH_STATUS_DISABLED => Ok(PatchStatus::Deactived), ++ KPATCH_STATUS_ENABLED => Ok(PatchStatus::Actived), ++ _ => bail!("Kpatch: Invalid patch status"), ++ }, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(PatchStatus::NotApplied), + Err(e) => Err(e), + } +diff --git a/syscared/src/patch/driver/kpatch/target.rs b/syscared/src/patch/driver/kpatch/target.rs +index 0b01f2f..beab803 100644 +--- a/syscared/src/patch/driver/kpatch/target.rs ++++ b/syscared/src/patch/driver/kpatch/target.rs +@@ -12,69 +12,106 @@ + * See the Mulan PSL v2 for more details. + */ + +-use std::ffi::{OsStr, OsString}; ++use std::ffi::OsString; + + use indexmap::IndexMap; + use uuid::Uuid; + +-use crate::patch::entity::KernelPatchSymbol; ++use crate::patch::entity::KernelPatchFunction; + +-#[derive(Debug, PartialEq)] +-pub struct PatchTargetRecord { ++#[derive(Debug)] ++pub struct PatchFunction { + pub uuid: Uuid, + pub name: OsString, + pub size: u64, + } + ++impl PatchFunction { ++ fn new(uuid: Uuid, function: &KernelPatchFunction) -> Self { ++ Self { ++ uuid, ++ name: function.name.to_os_string(), ++ size: function.new_size, ++ } ++ } ++ ++ fn is_same_function(&self, uuid: &Uuid, function: &KernelPatchFunction) -> bool { ++ (self.uuid == *uuid) && (self.name == function.name) && (self.size == function.new_size) ++ } ++} ++ ++#[derive(Debug)] + pub struct PatchTarget { + name: OsString, +- symbol_map: IndexMap>, // symbol addr -> symbol collision list ++ function_map: IndexMap>, // function addr -> function collision list + } + + impl PatchTarget { +- fn match_record(record: &PatchTargetRecord, uuid: &Uuid, symbol: &KernelPatchSymbol) -> bool { +- (record.uuid == *uuid) && (record.name == symbol.name) && (record.size == symbol.new_size) ++ pub fn new(name: OsString) -> Self { ++ Self { ++ name, ++ function_map: IndexMap::new(), ++ } + } + } + + impl PatchTarget { +- pub fn new>(name: S) -> Self { +- Self { +- name: name.as_ref().to_os_string(), +- symbol_map: IndexMap::new(), +- } ++ pub fn has_function(&self) -> bool { ++ self.function_map.is_empty() + } + +- pub fn classify_symbols( +- symbols: &[KernelPatchSymbol], +- ) -> IndexMap<&OsStr, Vec<&KernelPatchSymbol>> { +- let mut symbol_map = IndexMap::new(); +- +- for symbol in symbols { +- let target_name = symbol.target.as_os_str(); +- +- symbol_map +- .entry(target_name) +- .or_insert_with(Vec::new) +- .push(symbol); ++ pub fn add_functions<'a, I>(&mut self, uuid: Uuid, functions: I) ++ where ++ I: IntoIterator, ++ { ++ for function in functions { ++ if self.name != function.object { ++ continue; ++ } ++ self.function_map ++ .entry(function.old_addr) ++ .or_default() ++ .push(PatchFunction::new(uuid, function)); + } ++ } + +- symbol_map ++ pub fn remove_functions<'a, I>(&mut self, uuid: &Uuid, functions: I) ++ where ++ I: IntoIterator, ++ { ++ for function in functions { ++ if self.name != function.object { ++ continue; ++ } ++ if let Some(collision_list) = self.function_map.get_mut(&function.old_addr) { ++ if let Some(index) = collision_list ++ .iter() ++ .position(|patch_function| patch_function.is_same_function(uuid, function)) ++ { ++ collision_list.remove(index); ++ if collision_list.is_empty() { ++ self.function_map.remove(&function.old_addr); ++ } ++ } ++ } ++ } + } ++} + ++impl PatchTarget { + pub fn get_conflicts<'a, I>( + &'a self, +- symbols: I, +- ) -> impl IntoIterator ++ functions: I, ++ ) -> impl IntoIterator + where +- I: IntoIterator, ++ I: IntoIterator, + { +- symbols.into_iter().filter_map(move |symbol| { +- if self.name != symbol.target { ++ functions.into_iter().filter_map(move |function| { ++ if self.name != function.object { + return None; + } +- self.symbol_map +- .get(&symbol.old_addr) ++ self.function_map ++ .get(&function.old_addr) + .and_then(|list| list.last()) + }) + } +@@ -82,66 +119,19 @@ impl PatchTarget { + pub fn get_overrides<'a, I>( + &'a self, + uuid: &'a Uuid, +- symbols: I, +- ) -> impl IntoIterator ++ functions: I, ++ ) -> impl IntoIterator + where +- I: IntoIterator, ++ I: IntoIterator, + { +- symbols.into_iter().filter_map(move |symbol| { +- if self.name != symbol.target { ++ functions.into_iter().filter_map(move |function| { ++ if self.name != function.object { + return None; + } +- self.symbol_map +- .get(&symbol.old_addr) ++ self.function_map ++ .get(&function.old_addr) + .and_then(|list| list.last()) +- .filter(|record| !Self::match_record(record, uuid, symbol)) ++ .filter(|patch_function| !patch_function.is_same_function(uuid, function)) + }) + } +- +- pub fn add_symbols<'a, I>(&mut self, uuid: Uuid, symbols: I) +- where +- I: IntoIterator, +- { +- for symbol in symbols { +- if self.name != symbol.target { +- continue; +- } +- +- let symbol_addr = symbol.old_addr; +- let symbol_record = PatchTargetRecord { +- uuid, +- name: symbol.name.to_os_string(), +- size: symbol.new_size, +- }; +- +- self.symbol_map +- .entry(symbol_addr) +- .or_default() +- .push(symbol_record); +- } +- } +- +- pub fn remove_symbols<'a, I>(&mut self, uuid: &Uuid, symbols: I) +- where +- I: IntoIterator, +- { +- for symbol in symbols { +- if self.name != symbol.target { +- continue; +- } +- +- let symbol_addr = symbol.old_addr; +- if let Some(collision_list) = self.symbol_map.get_mut(&symbol_addr) { +- if let Some(index) = collision_list +- .iter() +- .position(|record| Self::match_record(record, uuid, symbol)) +- { +- collision_list.remove(index); +- if collision_list.is_empty() { +- self.symbol_map.remove(&symbol_addr); +- } +- } +- } +- } +- } + } +diff --git a/syscared/src/patch/driver/mod.rs b/syscared/src/patch/driver/mod.rs +index e6dab94..d64c2d4 100644 +--- a/syscared/src/patch/driver/mod.rs ++++ b/syscared/src/patch/driver/mod.rs +@@ -37,17 +37,17 @@ pub struct PatchDriver { + } + + impl PatchDriver { +- fn check_conflict_symbols(&self, patch: &Patch) -> Result<()> { ++ fn check_conflict_functions(&self, patch: &Patch) -> Result<()> { + match patch { +- Patch::KernelPatch(patch) => self.kpatch.check_conflict_symbols(patch), +- Patch::UserPatch(patch) => self.upatch.check_conflict_symbols(patch), ++ Patch::KernelPatch(patch) => self.kpatch.check_conflict_functions(patch), ++ Patch::UserPatch(patch) => self.upatch.check_conflict_functions(patch), + } + } + +- fn check_override_symbols(&self, patch: &Patch) -> Result<()> { ++ fn check_override_functions(&self, patch: &Patch) -> Result<()> { + match patch { +- Patch::KernelPatch(patch) => self.kpatch.check_override_symbols(patch), +- Patch::UserPatch(patch) => self.upatch.check_override_symbols(patch), ++ Patch::KernelPatch(patch) => self.kpatch.check_override_functions(patch), ++ Patch::UserPatch(patch) => self.upatch.check_override_functions(patch), + } + } + } +@@ -96,7 +96,7 @@ impl PatchDriver { + if flag == PatchOpFlag::Force { + return Ok(()); + } +- self.check_conflict_symbols(patch) ++ self.check_conflict_functions(patch) + .with_context(|| format!("Patch '{}' is conflicted", patch)) + } + +@@ -124,7 +124,7 @@ impl PatchDriver { + /// After this action, the patch status would be changed to 'ACTIVED'. + pub fn active_patch(&mut self, patch: &Patch, flag: PatchOpFlag) -> Result<()> { + if flag != PatchOpFlag::Force { +- self.check_conflict_symbols(patch)?; ++ self.check_conflict_functions(patch)?; + } + match patch { + Patch::KernelPatch(patch) => self.kpatch.active(patch), +@@ -137,7 +137,7 @@ impl PatchDriver { + /// After this action, the patch status would be changed to 'DEACTIVED'. + pub fn deactive_patch(&mut self, patch: &Patch, flag: PatchOpFlag) -> Result<()> { + if flag != PatchOpFlag::Force { +- self.check_override_symbols(patch)?; ++ self.check_override_functions(patch)?; + } + match patch { + Patch::KernelPatch(patch) => self.kpatch.deactive(patch), +diff --git a/syscared/src/patch/driver/upatch/entity.rs b/syscared/src/patch/driver/upatch/entity.rs +new file mode 100644 +index 0000000..80932c4 +--- /dev/null ++++ b/syscared/src/patch/driver/upatch/entity.rs +@@ -0,0 +1,74 @@ ++// SPDX-License-Identifier: Mulan PSL v2 ++/* ++ * Copyright (c) 2024 Huawei Technologies Co., Ltd. ++ * syscared is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, ++ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, ++ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++use std::path::PathBuf; ++ ++use indexmap::{indexset, IndexSet}; ++ ++#[derive(Debug)] ++pub struct PatchEntity { ++ pub patch_file: PathBuf, ++ process_list: IndexSet, ++ ignored_list: IndexSet, ++} ++ ++impl PatchEntity { ++ pub fn new(patch_file: PathBuf) -> Self { ++ Self { ++ patch_file, ++ process_list: indexset! {}, ++ ignored_list: indexset! {}, ++ } ++ } ++} ++ ++impl PatchEntity { ++ pub fn add_process(&mut self, pid: i32) { ++ self.process_list.insert(pid); ++ } ++ ++ pub fn remove_process(&mut self, pid: i32) { ++ self.process_list.remove(&pid); ++ } ++ ++ pub fn ignore_process(&mut self, pid: i32) { ++ self.ignored_list.insert(pid); ++ } ++ ++ pub fn clean_dead_process(&mut self, process_list: &IndexSet) { ++ self.process_list.retain(|pid| process_list.contains(pid)); ++ self.ignored_list.retain(|pid| process_list.contains(pid)); ++ } ++ ++ pub fn need_ignored(&self, process_list: &IndexSet) -> IndexSet { ++ process_list ++ .intersection(&self.ignored_list) ++ .copied() ++ .collect() ++ } ++ ++ pub fn need_actived(&self, process_list: &IndexSet) -> IndexSet { ++ process_list ++ .difference(&self.process_list) ++ .copied() ++ .collect() ++ } ++ ++ pub fn need_deactived(&self, process_list: &IndexSet) -> IndexSet { ++ process_list ++ .intersection(&self.process_list) ++ .copied() ++ .collect() ++ } ++} +diff --git a/syscared/src/patch/driver/upatch/mod.rs b/syscared/src/patch/driver/upatch/mod.rs +index 0b82db9..dd07e9b 100644 +--- a/syscared/src/patch/driver/upatch/mod.rs ++++ b/syscared/src/patch/driver/upatch/mod.rs +@@ -13,65 +13,97 @@ + */ + + use std::{ +- ffi::OsString, ++ ffi::OsStr, + fmt::Write, ++ os::linux::fs::MetadataExt, + path::{Path, PathBuf}, + sync::Arc, + }; + +-use anyhow::{ensure, Context, Result}; ++use anyhow::{bail, ensure, Context, Result}; + use indexmap::{indexset, IndexMap, IndexSet}; +-use log::{debug, error}; +-use parking_lot::Mutex; ++use log::{debug, info, warn}; ++use parking_lot::RwLock; + use uuid::Uuid; + + use syscare_abi::PatchStatus; +-use syscare_common::util::digest; ++use syscare_common::{fs, util::digest}; + +-use crate::patch::entity::UserPatch; ++use crate::patch::{driver::upatch::entity::PatchEntity, entity::UserPatch}; + ++mod entity; + mod monitor; +-mod process; + mod sys; + mod target; + + use monitor::UserPatchMonitor; + use target::PatchTarget; + +-type ElfPatchMap = Arc>>; +- +-#[derive(Default)] +-struct ElfPatchRecord { +- patch_map: IndexMap, // Patch applied to target elf (uuid and patch file) +- processes: IndexSet, // Target elf process list +-} +- + pub struct UserPatchDriver { +- patch_target_map: IndexMap, +- patch_status_map: IndexMap, +- elf_patch_map: ElfPatchMap, +- patch_monitor: UserPatchMonitor, ++ status_map: IndexMap, ++ target_map: Arc>>, ++ monitor: UserPatchMonitor, + } + + impl UserPatchDriver { + pub fn new() -> Result { +- let elf_patch_map = Arc::new(Mutex::new(IndexMap::new())); +- let patch_monitor = UserPatchMonitor::new(elf_patch_map.clone(), Self::patch_new_process)?; +- ++ let status_map = IndexMap::new(); ++ let target_map = Arc::new(RwLock::new(IndexMap::new())); ++ let monitor = UserPatchMonitor::new(target_map.clone(), Self::patch_new_process)?; + let instance = Self { +- patch_target_map: IndexMap::new(), +- patch_status_map: IndexMap::new(), +- elf_patch_map, +- patch_monitor, ++ status_map, ++ target_map, ++ monitor, + }; ++ + Ok(instance) + } + } + ++impl UserPatchDriver { ++ #[inline] ++ fn get_patch_status(&self, uuid: &Uuid) -> PatchStatus { ++ self.status_map ++ .get(uuid) ++ .copied() ++ .unwrap_or(PatchStatus::NotApplied) ++ } ++ ++ #[inline] ++ fn set_patch_status(&mut self, uuid: &Uuid, value: PatchStatus) { ++ *self.status_map.entry(*uuid).or_default() = value; ++ } ++ ++ fn remove_patch_status(&mut self, uuid: &Uuid) { ++ self.status_map.remove(uuid); ++ } ++} ++ ++impl UserPatchDriver { ++ fn add_patch_target(&mut self, patch: &UserPatch) { ++ let target_elf = patch.target_elf.as_path(); ++ let mut target_map = self.target_map.write(); ++ ++ if !target_map.contains_key(target_elf) { ++ target_map.insert(target_elf.to_path_buf(), PatchTarget::default()); ++ } ++ } ++ ++ fn remove_patch_target(&mut self, patch: &UserPatch) { ++ let target_elf = patch.target_elf.as_path(); ++ let mut target_map = self.target_map.write(); ++ ++ if let Some(target) = target_map.get_mut(target_elf) { ++ if !target.is_patched() { ++ target_map.remove(target_elf); ++ } ++ } ++ } ++} ++ + impl UserPatchDriver { + fn check_consistency(patch: &UserPatch) -> Result<()> { +- let patch_file = patch.patch_file.as_path(); +- let real_checksum = digest::file(patch_file)?; ++ let real_checksum = digest::file(&patch.patch_file)?; + debug!("Target checksum: '{}'", patch.checksum); + debug!("Expected checksum: '{}'", real_checksum); + +@@ -86,12 +118,10 @@ impl UserPatchDriver { + Ok(()) + } + +- pub fn check_conflict_symbols(&self, patch: &UserPatch) -> Result<()> { +- let patch_symbols = patch.symbols.as_slice(); +- let target_name = patch.target_elf.as_os_str(); +- let conflict_patches = match self.patch_target_map.get(target_name) { ++ pub fn check_conflict_functions(&self, patch: &UserPatch) -> Result<()> { ++ let conflict_patches = match self.target_map.read().get(&patch.target_elf) { + Some(target) => target +- .get_conflicts(patch_symbols) ++ .get_conflicts(&patch.functions) + .into_iter() + .map(|record| record.uuid) + .collect(), +@@ -112,13 +142,10 @@ impl UserPatchDriver { + Ok(()) + } + +- pub fn check_override_symbols(&self, patch: &UserPatch) -> Result<()> { +- let patch_uuid = patch.uuid; +- let patch_symbols = patch.symbols.as_slice(); +- let target_name = patch.target_elf.as_os_str(); +- let override_patches = match self.patch_target_map.get(target_name) { ++ pub fn check_override_functions(&self, patch: &UserPatch) -> Result<()> { ++ let override_patches = match self.target_map.read().get(&patch.target_elf) { + Some(target) => target +- .get_overrides(&patch_uuid, patch_symbols) ++ .get_overrides(&patch.uuid, &patch.functions) + .into_iter() + .map(|record| record.uuid) + .collect(), +@@ -142,110 +169,109 @@ impl UserPatchDriver { + } + + impl UserPatchDriver { +- fn add_patch_symbols(&mut self, patch: &UserPatch) { +- let target_name = patch.target_elf.as_os_str(); +- +- let patch_uuid = patch.uuid; +- let patch_target = self +- .patch_target_map +- .entry(target_name.to_os_string()) +- .or_insert_with(PatchTarget::new); +- let patch_symbols = patch.symbols.as_slice(); +- +- patch_target.add_symbols(patch_uuid, patch_symbols); ++ #[inline] ++ fn parse_process_id(proc_path: &Path) -> Option { ++ proc_path ++ .file_name() ++ .and_then(OsStr::to_str) ++ .map(str::parse) ++ .and_then(Result::ok) + } + +- fn remove_patch_symbols(&mut self, patch: &UserPatch) { +- let patch_uuid = patch.uuid; +- let patch_symbols = patch.symbols.as_slice(); +- let target_name = patch.target_elf.as_os_str(); +- +- if let Some(patch_target) = self.patch_target_map.get_mut(target_name) { +- patch_target.remove_symbols(&patch_uuid, patch_symbols); ++ fn find_target_process>(target_elf: P) -> Result> { ++ let mut target_pids = IndexSet::new(); ++ let target_path = target_elf.as_ref(); ++ let target_inode = target_path.metadata()?.st_ino(); ++ ++ for proc_path in fs::list_dirs("/proc", fs::TraverseOptions { recursive: false })? { ++ let pid = match Self::parse_process_id(&proc_path) { ++ Some(pid) => pid, ++ None => continue, ++ }; ++ let exec_path = match fs::read_link(format!("/proc/{}/exe", pid)) { ++ Ok(file_path) => file_path, ++ Err(_) => continue, ++ }; ++ // Try to match binary path ++ if exec_path == target_path { ++ target_pids.insert(pid); ++ continue; ++ } ++ // Try to match mapped files ++ let map_files = fs::list_symlinks( ++ format!("/proc/{}/map_files", pid), ++ fs::TraverseOptions { recursive: false }, ++ )?; ++ for mapped_file in map_files { ++ if let Ok(mapped_inode) = mapped_file ++ .read_link() ++ .and_then(|file_path| Ok(file_path.metadata()?.st_ino())) ++ { ++ if mapped_inode == target_inode { ++ target_pids.insert(pid); ++ break; ++ } ++ }; ++ } + } ++ ++ Ok(target_pids) + } +-} + +-impl UserPatchDriver { +- fn patch_new_process(elf_patch_map: ElfPatchMap, target_elf: &Path) { +- let process_list = match process::find_target_process(target_elf) { +- Ok(processes) => processes, ++ fn patch_new_process( ++ target_map: Arc>>, ++ target_elf: &Path, ++ ) { ++ let process_list = match Self::find_target_process(target_elf) { ++ Ok(pids) => pids, + Err(_) => return, + }; + +- let mut patch_map = elf_patch_map.lock(); +- let patch_record = match patch_map.get_mut(target_elf) { +- Some(record) => record, ++ let mut target_map = target_map.write(); ++ let patch_target = match target_map.get_mut(target_elf) { ++ Some(target) => target, + None => return, + }; + +- let need_active = process_list +- .difference(&patch_record.processes) +- .copied() +- .collect::>(); ++ for (patch_uuid, patch_entity) in patch_target.all_patches() { ++ patch_entity.clean_dead_process(&process_list); + +- // Active patch +- for (uuid, patch_file) in &patch_record.patch_map { +- if !need_active.is_empty() { ++ // Active patch ++ let need_actived = patch_entity.need_actived(&process_list); ++ if !need_actived.is_empty() { + debug!( +- "Upatch: Activating patch '{}' ({}) to process {:?}", +- uuid, ++ "Upatch: Activating patch '{}' ({}) for process {:?}", ++ patch_uuid, + target_elf.display(), +- need_active, ++ need_actived, + ); + } +- for pid in &need_active { +- if let Err(e) = sys::active_patch(uuid, *pid, target_elf, patch_file) +- .with_context(|| format!("Failed to patch process, pid={}", pid)) +- { +- error!("{}", e); ++ ++ let ignore_list = patch_entity.need_ignored(&process_list); ++ for pid in need_actived { ++ if ignore_list.contains(&pid) { + continue; + } +- patch_record.processes.insert(*pid); ++ match sys::active_patch(patch_uuid, pid, target_elf, &patch_entity.patch_file) { ++ Ok(_) => patch_entity.add_process(pid), ++ Err(e) => { ++ warn!( ++ "Upatch: Failed to active patch '{}' for process {}, {}", ++ patch_uuid, ++ pid, ++ e.to_string().to_lowercase(), ++ ); ++ patch_entity.ignore_process(pid) ++ } ++ } + } + } +- +- // Remove process no longer exists +- let need_remove = patch_record +- .processes +- .difference(&process_list) +- .copied() +- .collect::>(); +- for pid in need_remove { +- patch_record.processes.remove(&pid); +- } +- } +-} +- +-impl UserPatchDriver { +- #[inline] +- fn get_patch_status(&self, uuid: Uuid) -> Result { +- let patch_status = self +- .patch_status_map +- .get(&uuid) +- .copied() +- .context("Upatch: Patch does not exist")?; +- +- Ok(patch_status) +- } +- +- #[inline] +- fn set_patch_status(&mut self, uuid: Uuid, value: PatchStatus) -> Result<()> { +- let patch_status = self +- .patch_status_map +- .get_mut(&uuid) +- .context("Upatch: Patch does not exist")?; +- +- *patch_status = value; +- Ok(()) + } + } + + impl UserPatchDriver { + pub fn status(&self, patch: &UserPatch) -> Result { +- Ok(self +- .get_patch_status(patch.uuid) +- .unwrap_or(PatchStatus::NotApplied)) ++ Ok(self.get_patch_status(&patch.uuid)) + } + + pub fn check(&self, patch: &UserPatch) -> Result<()> { +@@ -256,170 +282,189 @@ impl UserPatchDriver { + } + + pub fn apply(&mut self, patch: &UserPatch) -> Result<()> { +- let patch_uuid = patch.uuid; +- ensure!( +- self.get_patch_status(patch_uuid).is_err(), +- "Upatch: Patch already exists" +- ); +- +- debug!( ++ info!( + "Upatch: Applying patch '{}' ({})", +- patch_uuid, ++ patch.uuid, + patch.patch_file.display() + ); +- self.patch_status_map +- .insert(patch_uuid, PatchStatus::Deactived); ++ ++ self.add_patch_target(patch); ++ self.set_patch_status(&patch.uuid, PatchStatus::Deactived); + + Ok(()) + } + + pub fn remove(&mut self, patch: &UserPatch) -> Result<()> { +- let patch_uuid = patch.uuid; +- let patch_status = self.get_patch_status(patch_uuid)?; +- ensure!( +- patch_status == PatchStatus::Deactived, +- "Upatch: Invalid patch status" +- ); +- +- debug!( ++ info!( + "Upatch: Removing patch '{}' ({})", +- patch_uuid, ++ patch.uuid, + patch.patch_file.display() + ); +- self.patch_status_map.remove(&patch_uuid); ++ ++ self.remove_patch_target(patch); ++ self.remove_patch_status(&patch.uuid); + + Ok(()) + } + + pub fn active(&mut self, patch: &UserPatch) -> Result<()> { +- let uuid = patch.uuid; +- let patch_status = self.get_patch_status(uuid)?; +- ensure!( +- patch_status == PatchStatus::Deactived, +- "Upatch: Invalid patch status" +- ); +- +- let target_elf = patch.target_elf.as_path(); ++ let patch_uuid = &patch.uuid; + let patch_file = patch.patch_file.as_path(); +- let process_list = process::find_target_process(target_elf)?; ++ let patch_functions = patch.functions.as_slice(); ++ let target_elf = patch.target_elf.as_path(); + +- let mut patch_map = self.elf_patch_map.lock(); +- let patch_record = patch_map.entry(target_elf.to_path_buf()).or_default(); ++ let process_list = Self::find_target_process(target_elf)?; + +- let need_active = process_list +- .difference(&patch_record.processes) +- .copied() +- .collect::>(); +- let need_remove = patch_record +- .processes +- .difference(&process_list) +- .copied() +- .collect::>(); +- let mut need_start_watch = false; ++ let mut target_map = self.target_map.write(); ++ let patch_target = target_map ++ .get_mut(target_elf) ++ .context("Upatch: Cannot find patch target")?; ++ let mut patch_entity = match patch_target.get_patch(patch_uuid) { ++ Some(_) => bail!("Upatch: Patch is already exist"), ++ None => PatchEntity::new(patch_file.to_path_buf()), ++ }; + + // Active patch +- if !need_active.is_empty() { +- debug!( +- "Upatch: Activating patch '{}' ({}) to process {:?}", +- uuid, +- target_elf.display(), +- need_active, +- ); +- } +- for pid in need_active { +- sys::active_patch(&uuid, pid, target_elf, patch_file) +- .with_context(|| format!("Failed to patch process, pid={}", pid))?; +- patch_record.processes.insert(pid); ++ info!( ++ "Upatch: Activating patch '{}' ({}) for {}", ++ patch_uuid, ++ patch_file.display(), ++ target_elf.display(), ++ ); ++ let mut results = Vec::new(); ++ for pid in patch_entity.need_actived(&process_list) { ++ let result = sys::active_patch(patch_uuid, pid, target_elf, patch_file); ++ match result { ++ Ok(_) => patch_entity.add_process(pid), ++ Err(_) => patch_entity.ignore_process(pid), ++ } ++ results.push((pid, result)); + } + +- // Remove process no longer exists +- for pid in need_remove { +- patch_record.processes.remove(&pid); ++ // Check results, return error if all process fails ++ match results.iter().any(|(_, result)| result.is_ok()) { ++ true => { ++ for (pid, result) in &results { ++ if let Err(e) = result { ++ warn!( ++ "Upatch: Failed to active patch '{}' for process {}, {}", ++ patch_uuid, ++ pid, ++ e.to_string().to_lowercase(), ++ ); ++ } ++ } ++ } ++ false => { ++ let mut err_msg = String::new(); ++ ++ writeln!(err_msg, "Upatch: Failed to active patch")?; ++ for (pid, result) in &results { ++ if let Err(e) = result { ++ writeln!(err_msg, "* Process {}: {}", pid, e)?; ++ } ++ } ++ bail!(err_msg); ++ } + } + +- // If elf is not patched before, start watching it & add a new entry +- if !patch_record.patch_map.contains_key(&uuid) { +- patch_record +- .patch_map +- .insert(uuid, patch_file.to_path_buf()); +- need_start_watch = true; +- } ++ // If target is no patched before, start watching it ++ let need_start_watch = !patch_target.is_patched(); + +- drop(patch_map); ++ // Apply patch to target ++ patch_target.add_patch(*patch_uuid, patch_entity); ++ patch_target.add_functions(*patch_uuid, patch_functions); ++ ++ // Drop the lock ++ drop(target_map); + + if need_start_watch { +- self.patch_monitor.watch_file(target_elf)?; ++ self.monitor.watch_file(target_elf)?; + } +- self.set_patch_status(uuid, PatchStatus::Actived)?; +- self.add_patch_symbols(patch); ++ self.set_patch_status(patch_uuid, PatchStatus::Actived); + + Ok(()) + } + + pub fn deactive(&mut self, patch: &UserPatch) -> Result<()> { +- let uuid = patch.uuid; +- let patch_status = self.get_patch_status(uuid)?; +- ensure!( +- patch_status == PatchStatus::Actived, +- "Upatch: Invalid patch status" +- ); +- +- let target_elf = patch.target_elf.as_path(); ++ let patch_uuid = &patch.uuid; + let patch_file = patch.patch_file.as_path(); +- let process_list = process::find_target_process(target_elf)?; ++ let patch_functions = patch.functions.as_slice(); ++ let target_elf = patch.target_elf.as_path(); ++ ++ let process_list = Self::find_target_process(target_elf)?; + +- let mut patch_map = self.elf_patch_map.lock(); +- let patch_record = patch_map ++ let mut target_map = self.target_map.write(); ++ let patch_target = target_map + .get_mut(target_elf) +- .context("Failed to find elf patch record")?; ++ .context("Upatch: Cannot find patch target")?; ++ let patch_entity = patch_target ++ .get_patch(patch_uuid) ++ .context("Upatch: Cannot find patch entity")?; + +- let need_deactive = process_list +- .intersection(&patch_record.processes) +- .copied() +- .collect::>(); +- let need_removed = patch_record +- .processes +- .difference(&process_list) +- .copied() +- .collect::>(); +- let mut need_stop_watch = false; ++ // Remove dead process ++ patch_entity.clean_dead_process(&process_list); + + // Deactive patch +- if !need_deactive.is_empty() { +- debug!( +- "Upatch: Deactivating patch '{}' ({}) of process {:?}", +- uuid, +- target_elf.display(), +- need_deactive, +- ); +- } +- for pid in need_deactive { +- sys::deactive_patch(&uuid, pid, target_elf, patch_file) +- .with_context(|| format!("Failed to unpatch process, pid={}", pid))?; +- patch_record.processes.remove(&pid); // remove process from record ++ info!( ++ "Upatch: Deactivating patch '{}' ({}) for {}", ++ patch_uuid, ++ patch_file.display(), ++ target_elf.display(), ++ ); ++ let mut results = Vec::new(); ++ let ignore_list = patch_entity.need_ignored(&process_list); ++ for pid in patch_entity.need_deactived(&process_list) { ++ if ignore_list.contains(&pid) { ++ continue; ++ } ++ let result = sys::deactive_patch(patch_uuid, pid, target_elf, patch_file); ++ if result.is_ok() { ++ patch_entity.remove_process(pid) ++ } ++ results.push((pid, result)); + } + +- // Remove process no longer exists +- for pid in need_removed { +- patch_record.processes.remove(&pid); ++ // Check results, return error if any process failes ++ match results.iter().any(|(_, result)| result.is_err()) { ++ true => { ++ let mut err_msg = String::new(); ++ ++ writeln!(err_msg, "Upatch: Failed to deactive patch")?; ++ for (pid, result) in &results { ++ if let Err(e) = result { ++ writeln!(err_msg, "* Process {}: {}", pid, e)?; ++ } ++ } ++ bail!(err_msg) ++ } ++ false => { ++ for (pid, result) in &results { ++ if let Err(e) = result { ++ warn!( ++ "Upatch: Failed to deactive patch '{}' for process {}, {}", ++ patch_uuid, ++ pid, ++ e.to_string().to_lowercase(), ++ ); ++ } ++ } ++ } + } + +- // Remove patch from elf patch record +- patch_record.patch_map.remove(&uuid); ++ // Remove patch functions from target ++ patch_target.remove_patch(patch_uuid); ++ patch_target.remove_functions(patch_uuid, patch_functions); + +- // If elf has no more patch, stop watching it & remove the entry +- if patch_record.patch_map.is_empty() { +- patch_map.remove(target_elf); +- need_stop_watch = true; +- } ++ // If target is no longer patched, stop watching it ++ let need_stop_watch = !patch_target.is_patched(); + +- drop(patch_map); ++ drop(target_map); + + if need_stop_watch { +- self.patch_monitor.ignore_file(target_elf)?; ++ self.monitor.ignore_file(target_elf)?; + } +- self.set_patch_status(uuid, PatchStatus::Deactived)?; +- self.remove_patch_symbols(patch); ++ self.set_patch_status(patch_uuid, PatchStatus::Deactived); + + Ok(()) + } +diff --git a/syscared/src/patch/driver/upatch/monitor.rs b/syscared/src/patch/driver/upatch/monitor.rs +index 1dbb513..09df2a2 100644 +--- a/syscared/src/patch/driver/upatch/monitor.rs ++++ b/syscared/src/patch/driver/upatch/monitor.rs +@@ -21,12 +21,13 @@ use std::{ + }; + + use anyhow::{bail, Context, Result}; +-use indexmap::IndexMap; +-use inotify::{EventMask, Inotify, WatchDescriptor, WatchMask}; ++use indexmap::{IndexMap, IndexSet}; ++use inotify::{Inotify, WatchDescriptor, WatchMask}; + use log::info; + use parking_lot::{Mutex, RwLock}; ++use syscare_common::ffi::OsStrExt; + +-use super::ElfPatchMap; ++use super::target::PatchTarget; + + const MONITOR_THREAD_NAME: &str = "upatch_monitor"; + const MONITOR_CHECK_PERIOD: u64 = 100; +@@ -34,33 +35,36 @@ const MONITOR_EVENT_BUFFER_CAPACITY: usize = 16 * 64; // inotify event size: 16 + + pub(super) struct UserPatchMonitor { + inotify: Arc>>, +- watch_map: Arc>>, +- target_map: Arc>>, ++ watch_wd_map: Arc>>, ++ watch_file_map: Arc>>, + monitor_thread: Option>, + } + + impl UserPatchMonitor { +- pub fn new(elf_patch_map: ElfPatchMap, callback: F) -> Result ++ pub fn new( ++ patch_target_map: Arc>>, ++ callback: F, ++ ) -> Result + where +- F: Fn(ElfPatchMap, &Path) + Send + Sync + 'static, ++ F: Fn(Arc>>, &Path) + Send + Sync + 'static, + { + let inotify = Arc::new(Mutex::new(Some( + Inotify::init().context("Failed to initialize inotify")?, + ))); +- let watch_map = Arc::new(Mutex::new(IndexMap::new())); +- let target_map = Arc::new(RwLock::new(IndexMap::new())); ++ let watch_wd_map = Arc::new(Mutex::new(IndexMap::new())); ++ let watch_file_map = Arc::new(RwLock::new(IndexMap::new())); + let monitor_thread = MonitorThread { + inotify: inotify.clone(), +- target_map: target_map.clone(), +- elf_patch_map, ++ watch_file_map: watch_file_map.clone(), ++ patch_target_map, + callback, + } + .run()?; + + Ok(Self { + inotify, +- target_map, +- watch_map, ++ watch_wd_map, ++ watch_file_map, + monitor_thread: Some(monitor_thread), + }) + } +@@ -69,7 +73,7 @@ impl UserPatchMonitor { + impl UserPatchMonitor { + pub fn watch_file>(&self, file_path: P) -> Result<()> { + let watch_file = file_path.as_ref(); +- if self.watch_map.lock().contains_key(watch_file) { ++ if self.watch_wd_map.lock().contains_key(watch_file) { + return Ok(()); + } + +@@ -79,10 +83,10 @@ impl UserPatchMonitor { + .add_watch(watch_file, WatchMask::OPEN) + .with_context(|| format!("Failed to watch file {}", watch_file.display()))?; + +- self.target_map ++ self.watch_file_map + .write() + .insert(wd.clone(), watch_file.to_owned()); +- self.watch_map.lock().insert(watch_file.to_owned(), wd); ++ self.watch_wd_map.lock().insert(watch_file.to_owned(), wd); + info!("Start watching file {}", watch_file.display()); + } + None => bail!("Inotify does not exist"), +@@ -94,10 +98,10 @@ impl UserPatchMonitor { + pub fn ignore_file>(&self, file_path: P) -> Result<()> { + let ignore_file = file_path.as_ref(); + +- if let Some(wd) = self.watch_map.lock().remove(ignore_file) { ++ if let Some(wd) = self.watch_wd_map.lock().remove(ignore_file) { + match self.inotify.lock().as_mut() { + Some(inotify) => { +- self.target_map.write().remove(&wd); ++ self.watch_file_map.write().remove(&wd); + + inotify.rm_watch(wd).with_context(|| { + format!("Failed to stop watch file {}", ignore_file.display()) +@@ -114,14 +118,14 @@ impl UserPatchMonitor { + + struct MonitorThread { + inotify: Arc>>, +- target_map: Arc>>, +- elf_patch_map: ElfPatchMap, ++ watch_file_map: Arc>>, ++ patch_target_map: Arc>>, + callback: F, + } + + impl MonitorThread + where +- F: Fn(ElfPatchMap, &Path) + Send + Sync + 'static, ++ F: Fn(Arc>>, &Path) + Send + Sync + 'static, + { + fn run(self) -> Result> { + thread::Builder::new() +@@ -130,18 +134,30 @@ where + .with_context(|| format!("Failed to create thread '{}'", MONITOR_THREAD_NAME)) + } + ++ #[inline] ++ fn filter_blacklist_path(path: &Path) -> bool { ++ const BLACKLIST_KEYWORDS: [&str; 2] = ["syscare", "upatch"]; ++ ++ for keyword in BLACKLIST_KEYWORDS { ++ if path.contains(keyword) { ++ return false; ++ } ++ } ++ true ++ } ++ + fn thread_main(self) { + while let Some(inotify) = self.inotify.lock().as_mut() { + let mut buffer = [0; MONITOR_EVENT_BUFFER_CAPACITY]; + + if let Ok(events) = inotify.read_events(&mut buffer) { +- for event in events { +- if !event.mask.contains(EventMask::OPEN) { +- continue; +- } +- if let Some(patch_file) = self.target_map.read().get(&event.wd) { +- (self.callback)(self.elf_patch_map.clone(), patch_file); +- } ++ let watch_file_map = self.watch_file_map.read(); ++ let target_elfs = events ++ .filter_map(|event| watch_file_map.get(&event.wd)) ++ .filter(|path| Self::filter_blacklist_path(path)) ++ .collect::>(); ++ for target_elf in target_elfs { ++ (self.callback)(self.patch_target_map.clone(), target_elf); + } + } + +diff --git a/syscared/src/patch/driver/upatch/process.rs b/syscared/src/patch/driver/upatch/process.rs +deleted file mode 100644 +index 9b2f6de..0000000 +--- a/syscared/src/patch/driver/upatch/process.rs ++++ /dev/null +@@ -1,100 +0,0 @@ +-// SPDX-License-Identifier: Mulan PSL v2 +-/* +- * Copyright (c) 2024 Huawei Technologies Co., Ltd. +- * syscared is licensed under Mulan PSL v2. +- * You can use this software according to the terms and conditions of the Mulan PSL v2. +- * You may obtain a copy of Mulan PSL v2 at: +- * http://license.coscl.org.cn/MulanPSL2 +- * +- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +- * See the Mulan PSL v2 for more details. +- */ +- +-use std::{ffi::OsStr, os::linux::fs::MetadataExt, path::Path}; +- +-use anyhow::Result; +-use indexmap::IndexSet; +-use syscare_common::fs; +- +-const PROC_BLACK_LIST: [&str; 18] = [ +- "/usr/lib/systemd/systemd-journald", +- "/usr/lib/systemd/systemd-logind", +- "/usr/lib/systemd/systemd-udevd", +- "/usr/lib/systemd/systemd-hostnamed", +- "/usr/bin/udevadm", +- "/usr/sbin/auditd", +- "/usr/bin/syscare", +- "/usr/bin/syscared", +- "/usr/bin/upatchd", +- "/usr/libexec/syscare/as-hijacker", +- "/usr/libexec/syscare/cc-hijacker", +- "/usr/libexec/syscare/c++-hijacker", +- "/usr/libexec/syscare/gcc-hijacker", +- "/usr/libexec/syscare/g++-hijacker", +- "/usr/libexec/syscare/syscare-build", +- "/usr/libexec/syscare/upatch-build", +- "/usr/libexec/syscare/upatch-diff", +- "/usr/libexec/syscare/upatch-manage", +-]; +- +-#[inline] +-fn is_blacklisted(file_path: &Path) -> bool { +- PROC_BLACK_LIST +- .iter() +- .map(Path::new) +- .any(|blacklist_path| blacklist_path == file_path) +-} +- +-#[inline] +-fn parse_process_id(proc_path: &Path) -> Option { +- proc_path +- .file_name() +- .and_then(OsStr::to_str) +- .map(str::parse) +- .and_then(Result::ok) +-} +- +-pub fn find_target_process>(target_elf: P) -> Result> { +- let mut target_pids = IndexSet::new(); +- let target_path = target_elf.as_ref(); +- let target_inode = target_path.metadata()?.st_ino(); +- +- for proc_path in fs::list_dirs("/proc", fs::TraverseOptions { recursive: false })? { +- let pid = match self::parse_process_id(&proc_path) { +- Some(pid) => pid, +- None => continue, +- }; +- let exec_path = match fs::read_link(format!("/proc/{}/exe", pid)) { +- Ok(file_path) => file_path, +- Err(_) => continue, +- }; +- if is_blacklisted(&exec_path) { +- continue; +- } +- // Try to match binary path +- if exec_path == target_path { +- target_pids.insert(pid); +- continue; +- } +- // Try to match mapped files +- let map_files = fs::list_symlinks( +- format!("/proc/{}/map_files", pid), +- fs::TraverseOptions { recursive: false }, +- )?; +- for mapped_file in map_files { +- if let Ok(mapped_inode) = mapped_file +- .read_link() +- .and_then(|file_path| Ok(file_path.metadata()?.st_ino())) +- { +- if mapped_inode == target_inode { +- target_pids.insert(pid); +- break; +- } +- }; +- } +- } +- +- Ok(target_pids) +-} +diff --git a/syscared/src/patch/driver/upatch/sys.rs b/syscared/src/patch/driver/upatch/sys.rs +index f0745f0..bfeb1b8 100644 +--- a/syscared/src/patch/driver/upatch/sys.rs ++++ b/syscared/src/patch/driver/upatch/sys.rs +@@ -25,12 +25,10 @@ pub fn active_patch(uuid: &Uuid, pid: i32, target_elf: &Path, patch_file: &Path) + .exit_code(); + + match exit_code { +- 0 => {} +- EEXIST => {} +- _ => bail!("Upatch: {}", std::io::Error::from_raw_os_error(exit_code)), ++ 0 => Ok(()), ++ EEXIST => Ok(()), ++ _ => bail!(std::io::Error::from_raw_os_error(exit_code)), + } +- +- Ok(()) + } + + pub fn deactive_patch(uuid: &Uuid, pid: i32, target_elf: &Path, patch_file: &Path) -> Result<()> { +@@ -49,9 +47,7 @@ pub fn deactive_patch(uuid: &Uuid, pid: i32, target_elf: &Path, patch_file: &Pat + .exit_code(); + + match exit_code { +- 0 => {} +- _ => bail!("Upatch: {}", std::io::Error::from_raw_os_error(exit_code)), ++ 0 => Ok(()), ++ _ => bail!(std::io::Error::from_raw_os_error(exit_code)), + } +- +- Ok(()) + } +diff --git a/syscared/src/patch/driver/upatch/target.rs b/syscared/src/patch/driver/upatch/target.rs +index df1e075..26c3ed3 100644 +--- a/syscared/src/patch/driver/upatch/target.rs ++++ b/syscared/src/patch/driver/upatch/target.rs +@@ -17,98 +17,120 @@ use std::ffi::OsString; + use indexmap::IndexMap; + use uuid::Uuid; + +-use crate::patch::entity::UserPatchSymbol; ++use crate::patch::entity::UserPatchFunction; + +-#[derive(Debug, PartialEq)] +-pub struct PatchTargetRecord { ++use super::entity::PatchEntity; ++ ++#[derive(Debug)] ++pub struct PatchFunction { + pub uuid: Uuid, + pub name: OsString, + pub size: u64, + } + ++impl PatchFunction { ++ pub fn new(uuid: Uuid, function: &UserPatchFunction) -> Self { ++ Self { ++ uuid, ++ name: function.name.to_os_string(), ++ size: function.new_size, ++ } ++ } ++ ++ pub fn is_same_function(&self, uuid: &Uuid, function: &UserPatchFunction) -> bool { ++ (self.uuid == *uuid) && (self.name == function.name) && (self.size == function.new_size) ++ } ++} ++ ++#[derive(Debug, Default)] + pub struct PatchTarget { +- symbol_map: IndexMap>, // symbol addr -> symbol collision list ++ patch_map: IndexMap, // patched file data ++ function_map: IndexMap>, // function addr -> function collision list + } + + impl PatchTarget { +- fn match_record(record: &PatchTargetRecord, uuid: &Uuid, symbol: &UserPatchSymbol) -> bool { +- (record.uuid == *uuid) && (record.name == symbol.name) && (record.size == symbol.new_size) ++ pub fn is_patched(&self) -> bool { ++ !self.patch_map.is_empty() + } +-} + +-impl PatchTarget { +- pub fn new() -> Self { +- Self { +- symbol_map: IndexMap::new(), +- } ++ pub fn add_patch(&mut self, uuid: Uuid, entity: PatchEntity) { ++ self.patch_map.insert(uuid, entity); + } + +- pub fn get_conflicts<'a, I>( +- &'a self, +- symbols: I, +- ) -> impl IntoIterator +- where +- I: IntoIterator, +- { +- symbols.into_iter().filter_map(move |symbol| { +- self.symbol_map +- .get(&symbol.old_addr) +- .and_then(|list| list.last()) +- }) ++ pub fn remove_patch(&mut self, uuid: &Uuid) { ++ self.patch_map.remove(uuid); + } + +- pub fn get_overrides<'a, I>( +- &'a self, +- uuid: &'a Uuid, +- symbols: I, +- ) -> impl IntoIterator +- where +- I: IntoIterator, +- { +- symbols.into_iter().filter_map(move |symbol| { +- self.symbol_map +- .get(&symbol.old_addr) +- .and_then(|list| list.last()) +- .filter(|record| !Self::match_record(record, uuid, symbol)) +- }) ++ pub fn get_patch(&mut self, uuid: &Uuid) -> Option<&mut PatchEntity> { ++ self.patch_map.get_mut(uuid) ++ } ++ ++ pub fn all_patches(&mut self) -> impl IntoIterator { ++ self.patch_map.iter_mut() + } ++} + +- pub fn add_symbols<'a, I>(&mut self, uuid: Uuid, symbols: I) ++impl PatchTarget { ++ pub fn add_functions<'a, I>(&mut self, uuid: Uuid, functions: I) + where +- I: IntoIterator, ++ I: IntoIterator, + { +- for symbol in symbols { +- let symbol_addr = symbol.old_addr; +- let symbol_record = PatchTargetRecord { +- uuid, +- name: symbol.name.to_os_string(), +- size: symbol.new_size, +- }; +- +- self.symbol_map +- .entry(symbol_addr) ++ for function in functions { ++ self.function_map ++ .entry(function.old_addr) + .or_default() +- .push(symbol_record); ++ .push(PatchFunction::new(uuid, function)); + } + } + +- pub fn remove_symbols<'a, I>(&mut self, uuid: &Uuid, symbols: I) ++ pub fn remove_functions<'a, I>(&mut self, uuid: &Uuid, functions: I) + where +- I: IntoIterator, ++ I: IntoIterator, + { +- for symbol in symbols { +- let symbol_addr = symbol.old_addr; +- if let Some(collision_list) = self.symbol_map.get_mut(&symbol_addr) { ++ for function in functions { ++ if let Some(collision_list) = self.function_map.get_mut(&function.old_addr) { + if let Some(index) = collision_list + .iter() +- .position(|record| Self::match_record(record, uuid, symbol)) ++ .position(|patch_function| patch_function.is_same_function(uuid, function)) + { + collision_list.remove(index); + if collision_list.is_empty() { +- self.symbol_map.remove(&symbol_addr); ++ self.function_map.remove(&function.old_addr); + } + } + } + } + } + } ++ ++impl PatchTarget { ++ pub fn get_conflicts<'a, I>( ++ &'a self, ++ functions: I, ++ ) -> impl IntoIterator ++ where ++ I: IntoIterator, ++ { ++ functions.into_iter().filter_map(move |function| { ++ self.function_map ++ .get(&function.old_addr) ++ .and_then(|list| list.last()) ++ }) ++ } ++ ++ pub fn get_overrides<'a, I>( ++ &'a self, ++ uuid: &'a Uuid, ++ functions: I, ++ ) -> impl IntoIterator ++ where ++ I: IntoIterator, ++ { ++ functions.into_iter().filter_map(move |function| { ++ self.function_map ++ .get(&function.old_addr) ++ .and_then(|list| list.last()) ++ .filter(|patch_function| !patch_function.is_same_function(uuid, function)) ++ }) ++ } ++} +diff --git a/syscared/src/patch/entity/kpatch.rs b/syscared/src/patch/entity/kpatch.rs +index 9399920..ab2c8b2 100644 +--- a/syscared/src/patch/entity/kpatch.rs ++++ b/syscared/src/patch/entity/kpatch.rs +@@ -17,22 +17,22 @@ use std::{ffi::OsString, path::PathBuf, sync::Arc}; + use syscare_abi::{PatchInfo, PatchType}; + use uuid::Uuid; + +-/// Kernel patch symbol definition ++/// Kernel patch function definition + #[derive(Clone)] +-pub struct KernelPatchSymbol { ++pub struct KernelPatchFunction { + pub name: OsString, +- pub target: OsString, ++ pub object: OsString, + pub old_addr: u64, + pub old_size: u64, + pub new_addr: u64, + pub new_size: u64, + } + +-impl std::fmt::Debug for KernelPatchSymbol { ++impl std::fmt::Debug for KernelPatchFunction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +- f.debug_struct("KernelPatchSymbol") ++ f.debug_struct("KernelPatchFunction") + .field("name", &self.name) +- .field("target", &self.target) ++ .field("object", &self.object) + .field("old_addr", &format!("{:#x}", self.old_addr)) + .field("old_size", &format!("{:#x}", self.old_size)) + .field("new_addr", &format!("{:#x}", self.new_addr)) +@@ -41,13 +41,13 @@ impl std::fmt::Debug for KernelPatchSymbol { + } + } + +-impl std::fmt::Display for KernelPatchSymbol { ++impl std::fmt::Display for KernelPatchFunction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, +- "name: {}, target: {}, old_addr: {:#x}, old_size: {:#x}, new_addr: {:#x}, new_size: {:#x}", ++ "name: {}, object: {}, old_addr: {:#x}, old_size: {:#x}, new_addr: {:#x}, new_size: {:#x}", + self.name.to_string_lossy(), +- self.target.to_string_lossy(), ++ self.object.to_string_lossy(), + self.old_addr, + self.old_size, + self.new_addr, +@@ -65,7 +65,7 @@ pub struct KernelPatch { + pub info: Arc, + pub pkg_name: String, + pub module_name: OsString, +- pub symbols: Vec, ++ pub functions: Vec, + pub patch_file: PathBuf, + pub sys_file: PathBuf, + pub checksum: String, +diff --git a/syscared/src/patch/entity/symbol.rs b/syscared/src/patch/entity/symbol.rs +index 300775a..c7845aa 100644 +--- a/syscared/src/patch/entity/symbol.rs ++++ b/syscared/src/patch/entity/symbol.rs +@@ -14,9 +14,9 @@ + + use std::ffi::OsString; + +-/// Patch symbol definiation ++/// Patch function definiation + #[derive(Clone)] +-pub struct PatchSymbol { ++pub struct PatchFunction { + pub name: OsString, + pub target: OsString, + pub old_addr: u64, +@@ -25,9 +25,9 @@ pub struct PatchSymbol { + pub new_size: u64, + } + +-impl std::fmt::Debug for PatchSymbol { ++impl std::fmt::Debug for PatchFunction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +- f.debug_struct("PatchSymbol") ++ f.debug_struct("PatchFunction") + .field("name", &self.name) + .field("target", &self.target) + .field("old_addr", &format!("0x{}", self.old_addr)) +@@ -38,7 +38,7 @@ impl std::fmt::Debug for PatchSymbol { + } + } + +-impl std::fmt::Display for PatchSymbol { ++impl std::fmt::Display for PatchFunction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, +diff --git a/syscared/src/patch/entity/upatch.rs b/syscared/src/patch/entity/upatch.rs +index 4e62431..ef24866 100644 +--- a/syscared/src/patch/entity/upatch.rs ++++ b/syscared/src/patch/entity/upatch.rs +@@ -17,9 +17,9 @@ use std::{ffi::OsString, path::PathBuf, sync::Arc}; + use syscare_abi::{PatchInfo, PatchType}; + use uuid::Uuid; + +-/// User patch symbol definition ++/// User patch function definition + #[derive(Clone)] +-pub struct UserPatchSymbol { ++pub struct UserPatchFunction { + pub name: OsString, + pub old_addr: u64, + pub old_size: u64, +@@ -27,9 +27,9 @@ pub struct UserPatchSymbol { + pub new_size: u64, + } + +-impl std::fmt::Debug for UserPatchSymbol { ++impl std::fmt::Debug for UserPatchFunction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +- f.debug_struct("UserPatchSymbol") ++ f.debug_struct("UserPatchFunction") + .field("name", &self.name) + .field("old_addr", &format!("0x{}", self.old_addr)) + .field("old_size", &format!("0x{}", self.old_size)) +@@ -39,7 +39,7 @@ impl std::fmt::Debug for UserPatchSymbol { + } + } + +-impl std::fmt::Display for UserPatchSymbol { ++impl std::fmt::Display for UserPatchFunction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, +@@ -61,7 +61,7 @@ pub struct UserPatch { + pub kind: PatchType, + pub info: Arc, + pub pkg_name: String, +- pub symbols: Vec, ++ pub functions: Vec, + pub patch_file: PathBuf, + pub target_elf: PathBuf, + pub checksum: String, +diff --git a/syscared/src/patch/resolver/kpatch.rs b/syscared/src/patch/resolver/kpatch.rs +index 50711eb..524482e 100644 +--- a/syscared/src/patch/resolver/kpatch.rs ++++ b/syscared/src/patch/resolver/kpatch.rs +@@ -13,8 +13,7 @@ + */ + + use std::{ +- ffi::OsString, +- os::unix::ffi::OsStringExt, ++ ffi::{CStr, OsString}, + path::{Path, PathBuf}, + sync::Arc, + }; +@@ -23,10 +22,14 @@ use anyhow::{anyhow, Context, Result}; + use object::{NativeFile, Object, ObjectSection}; + + use syscare_abi::{PatchEntity, PatchInfo, PatchType}; +-use syscare_common::{concat_os, ffi::OsStrExt, fs}; ++use syscare_common::{ ++ concat_os, ++ ffi::{CStrExt, OsStrExt}, ++ fs, ++}; + + use super::PatchResolverImpl; +-use crate::patch::entity::{KernelPatch, KernelPatchSymbol, Patch}; ++use crate::patch::entity::{KernelPatch, KernelPatchFunction, Patch}; + + const KPATCH_SUFFIX: &str = ".ko"; + const KPATCH_SYS_DIR: &str = "/sys/kernel/livepatch"; +@@ -35,7 +38,10 @@ const KPATCH_SYS_FILE_NAME: &str = "enabled"; + mod ffi { + use std::os::raw::{c_char, c_long, c_ulong}; + +- use object::Pod; ++ use object::{ ++ read::elf::{ElfSectionRelocationIterator, FileHeader}, ++ Pod, Relocation, ++ }; + + #[repr(C)] + #[derive(Debug, Clone, Copy)] +@@ -52,9 +58,9 @@ mod ffi { + pub ref_offset: c_long, + } + +- pub const KPATCH_FUNC_SIZE: usize = std::mem::size_of::(); +- pub const KPATCH_FUNC_NAME_OFFSET: usize = 40; +- pub const KPATCH_OBJECT_NAME_OFFSET: usize = 48; ++ pub const KPATCH_FUNCTION_SIZE: usize = std::mem::size_of::(); ++ pub const KPATCH_FUNCTION_OFFSET: usize = 40; ++ pub const KPATCH_OBJECT_OFFSET: usize = 48; + + /* + * SAFETY: This struct is +@@ -64,24 +70,34 @@ mod ffi { + */ + unsafe impl Pod for KpatchFunction {} + +- pub enum KpatchRelocation { +- NewAddr = 0, +- Name = 1, +- ObjName = 2, ++ pub struct KpatchRelocation { ++ pub addr: (u64, Relocation), ++ pub name: (u64, Relocation), ++ pub object: (u64, Relocation), + } + +- impl From for KpatchRelocation { +- fn from(value: usize) -> Self { +- match value { +- 0 => KpatchRelocation::NewAddr, +- 1 => KpatchRelocation::Name, +- 2 => KpatchRelocation::ObjName, +- _ => unreachable!(), +- } ++ pub struct KpatchRelocationIterator<'data, 'file, Elf: FileHeader>( ++ ElfSectionRelocationIterator<'data, 'file, Elf, &'data [u8]>, ++ ); ++ ++ impl<'data, 'file, Elf: FileHeader> KpatchRelocationIterator<'data, 'file, Elf> { ++ pub fn new(relocations: ElfSectionRelocationIterator<'data, 'file, Elf>) -> Self { ++ Self(relocations) + } + } + +- pub const KPATCH_FUNC_RELA_TYPE_NUM: usize = 3; ++ impl<'data, 'file, Elf: FileHeader> Iterator for KpatchRelocationIterator<'data, 'file, Elf> { ++ type Item = KpatchRelocation; ++ ++ fn next(&mut self) -> Option { ++ if let (Some(addr), Some(name), Some(object)) = ++ (self.0.next(), self.0.next(), self.0.next()) ++ { ++ return Some(KpatchRelocation { addr, name, object }); ++ } ++ None ++ } ++ } + } + + use ffi::*; +@@ -113,19 +129,19 @@ impl KpatchResolverImpl { + .with_context(|| format!("Failed to read section '{}'", KPATCH_FUNCS_SECTION))?; + + // Resolve patch functions +- let patch_symbols = &mut patch.symbols; +- let patch_functions = object::slice_from_bytes::( ++ let patch_functions = &mut patch.functions; ++ let kpatch_function_slice = object::slice_from_bytes::( + function_data, +- function_data.len() / KPATCH_FUNC_SIZE, ++ function_data.len() / KPATCH_FUNCTION_SIZE, + ) + .map(|(f, _)| f) + .map_err(|_| anyhow!("Invalid data format")) + .context("Failed to resolve patch functions")?; + +- for function in patch_functions { +- patch_symbols.push(KernelPatchSymbol { ++ for function in kpatch_function_slice { ++ patch_functions.push(KernelPatchFunction { + name: OsString::new(), +- target: OsString::new(), ++ object: OsString::new(), + old_addr: function.old_addr, + old_size: function.old_size, + new_addr: function.new_addr, +@@ -134,44 +150,35 @@ impl KpatchResolverImpl { + } + + // Relocate patch functions +- for (index, (offset, relocation)) in function_section.relocations().enumerate() { +- match KpatchRelocation::from(index % KPATCH_FUNC_RELA_TYPE_NUM) { +- KpatchRelocation::Name => { +- let symbol_index = +- (offset as usize - KPATCH_FUNC_NAME_OFFSET) / KPATCH_FUNC_SIZE; +- let patch_symbol = patch_symbols +- .get_mut(symbol_index) +- .context("Failed to find patch symbol")?; +- +- let name_offset = relocation.addend() as usize; +- let mut name_bytes = &string_data[name_offset..]; +- let string_end = name_bytes +- .iter() +- .position(|b| b == &b'\0') +- .context("Failed to find termination char")?; +- name_bytes = &name_bytes[..string_end]; +- +- patch_symbol.name = OsString::from_vec(name_bytes.to_vec()); +- } +- KpatchRelocation::ObjName => { +- let symbol_index = +- (offset as usize - KPATCH_OBJECT_NAME_OFFSET) / KPATCH_FUNC_SIZE; +- let patch_symbol = patch_symbols +- .get_mut(symbol_index) +- .context("Failed to find patch symbol")?; +- +- let name_offset = relocation.addend() as usize; +- let mut name_bytes = &string_data[name_offset..]; +- let string_end = name_bytes +- .iter() +- .position(|b| b == &b'\0') +- .context("Failed to find termination char")?; +- name_bytes = &name_bytes[..string_end]; +- +- patch_symbol.target = OsString::from_vec(name_bytes.to_vec()); +- } +- _ => {} +- }; ++ for relocation in KpatchRelocationIterator::new(function_section.relocations()) { ++ let (name_reloc_offset, name_reloc) = relocation.name; ++ let (object_reloc_offset, obj_reloc) = relocation.object; ++ ++ // Relocate patch function name ++ let name_index = ++ (name_reloc_offset as usize - KPATCH_FUNCTION_OFFSET) / KPATCH_FUNCTION_SIZE; ++ let name_function = patch_functions ++ .get_mut(name_index) ++ .context("Failed to find patch function")?; ++ let name_offset = name_reloc.addend() as usize; ++ let name_string = CStr::from_bytes_with_next_nul(&string_data[name_offset..]) ++ .context("Failed to parse patch object name")? ++ .to_os_string(); ++ ++ name_function.name = name_string; ++ ++ // Relocate patch function object ++ let object_index = ++ (object_reloc_offset as usize - KPATCH_OBJECT_OFFSET) / KPATCH_FUNCTION_SIZE; ++ let object_function = patch_functions ++ .get_mut(object_index) ++ .context("Failed to find patch function")?; ++ let object_offset = obj_reloc.addend() as usize; ++ let object_string = CStr::from_bytes_with_next_nul(&string_data[object_offset..]) ++ .context("Failed to parse patch function name")? ++ .to_os_string(); ++ ++ object_function.object = object_string; + } + + Ok(()) +@@ -206,10 +213,10 @@ impl PatchResolverImpl for KpatchResolverImpl { + module_name, + patch_file, + sys_file, +- symbols: Vec::new(), ++ functions: Vec::new(), + checksum: patch_entity.checksum.clone(), + }; +- Self::resolve_patch_file(&mut patch).context("Failed to resolve patch elf")?; ++ Self::resolve_patch_file(&mut patch).context("Failed to resolve patch")?; + + Ok(Patch::KernelPatch(patch)) + } +diff --git a/syscared/src/patch/resolver/upatch.rs b/syscared/src/patch/resolver/upatch.rs +index 15c7363..5df11db 100644 +--- a/syscared/src/patch/resolver/upatch.rs ++++ b/syscared/src/patch/resolver/upatch.rs +@@ -12,21 +12,28 @@ + * See the Mulan PSL v2 for more details. + */ + +-use std::{ffi::OsString, os::unix::ffi::OsStringExt, path::Path, sync::Arc}; ++use std::{ ++ ffi::{CStr, OsString}, ++ path::Path, ++ sync::Arc, ++}; + + use anyhow::{anyhow, Context, Result}; + use object::{NativeFile, Object, ObjectSection}; + + use syscare_abi::{PatchEntity, PatchInfo, PatchType}; +-use syscare_common::{concat_os, fs}; ++use syscare_common::{concat_os, ffi::CStrExt, fs}; + + use super::PatchResolverImpl; +-use crate::patch::entity::{Patch, UserPatch, UserPatchSymbol}; ++use crate::patch::entity::{Patch, UserPatch, UserPatchFunction}; + + mod ffi { + use std::os::raw::{c_char, c_ulong}; + +- use object::Pod; ++ use object::{ ++ read::elf::{ElfSectionRelocationIterator, FileHeader}, ++ Pod, Relocation, ++ }; + + #[repr(C)] + #[derive(Debug, Clone, Copy)] +@@ -48,25 +55,34 @@ mod ffi { + */ + unsafe impl Pod for UpatchFunction {} + +- pub const UPATCH_FUNC_SIZE: usize = std::mem::size_of::(); +- pub const UPATCH_FUNC_NAME_OFFSET: usize = 40; ++ pub const UPATCH_FUNCTION_SIZE: usize = std::mem::size_of::(); ++ pub const UPATCH_FUNCTION_OFFSET: usize = 40; + +- pub enum UpatchRelocation { +- NewAddr = 0, +- Name = 1, ++ pub struct UpatchRelocation { ++ pub addr: (u64, Relocation), ++ pub name: (u64, Relocation), + } + +- impl From for UpatchRelocation { +- fn from(value: usize) -> Self { +- match value { +- 0 => UpatchRelocation::NewAddr, +- 1 => UpatchRelocation::Name, +- _ => unreachable!(), +- } ++ pub struct UpatchRelocationIterator<'data, 'file, Elf: FileHeader>( ++ ElfSectionRelocationIterator<'data, 'file, Elf, &'data [u8]>, ++ ); ++ ++ impl<'data, 'file, Elf: FileHeader> UpatchRelocationIterator<'data, 'file, Elf> { ++ pub fn new(relocations: ElfSectionRelocationIterator<'data, 'file, Elf>) -> Self { ++ Self(relocations) + } + } + +- pub const UPATCH_FUNC_RELA_TYPE_NUM: usize = 2; ++ impl<'data, 'file, Elf: FileHeader> Iterator for UpatchRelocationIterator<'data, 'file, Elf> { ++ type Item = UpatchRelocation; ++ ++ fn next(&mut self) -> Option { ++ if let (Some(addr), Some(name)) = (self.0.next(), self.0.next()) { ++ return Some(UpatchRelocation { addr, name }); ++ } ++ None ++ } ++ } + } + + use ffi::*; +@@ -98,17 +114,17 @@ impl UpatchResolverImpl { + .with_context(|| format!("Failed to read section '{}'", UPATCH_FUNCS_SECTION))?; + + // Resolve patch functions +- let patch_symbols = &mut patch.symbols; +- let patch_functions = object::slice_from_bytes::( ++ let patch_functions = &mut patch.functions; ++ let upatch_function_slice = object::slice_from_bytes::( + function_data, +- function_data.len() / UPATCH_FUNC_SIZE, ++ function_data.len() / UPATCH_FUNCTION_SIZE, + ) + .map(|(f, _)| f) + .map_err(|_| anyhow!("Invalid data format")) + .context("Failed to resolve patch functions")?; + +- for function in patch_functions { +- patch_symbols.push(UserPatchSymbol { ++ for function in upatch_function_slice { ++ patch_functions.push(UserPatchFunction { + name: OsString::new(), + old_addr: function.old_addr, + old_size: function.old_size, +@@ -118,25 +134,20 @@ impl UpatchResolverImpl { + } + + // Relocate patch functions +- for (index, (offset, relocation)) in function_section.relocations().enumerate() { +- if let UpatchRelocation::Name = +- UpatchRelocation::from(index % UPATCH_FUNC_RELA_TYPE_NUM) +- { +- let symbol_index = (offset as usize - UPATCH_FUNC_NAME_OFFSET) / UPATCH_FUNC_SIZE; +- let patch_symbol = patch_symbols +- .get_mut(symbol_index) +- .context("Failed to find patch symbol")?; +- +- let name_offset = relocation.addend() as usize; +- let mut name_bytes = &string_data[name_offset..]; +- let string_end = name_bytes +- .iter() +- .position(|b| b == &b'\0') +- .context("Failed to find termination char")?; +- name_bytes = &name_bytes[..string_end]; +- +- patch_symbol.name = OsString::from_vec(name_bytes.to_vec()); +- } ++ for relocation in UpatchRelocationIterator::new(function_section.relocations()) { ++ let (name_reloc_offset, name_reloc) = relocation.name; ++ ++ let name_index = ++ (name_reloc_offset as usize - UPATCH_FUNCTION_OFFSET) / UPATCH_FUNCTION_SIZE; ++ let name_function = patch_functions ++ .get_mut(name_index) ++ .context("Failed to find patch function")?; ++ let name_offset = name_reloc.addend() as usize; ++ let name_string = CStr::from_bytes_with_next_nul(&string_data[name_offset..]) ++ .context("Failed to parse patch function name")? ++ .to_os_string(); ++ ++ name_function.name = name_string; + } + + Ok(()) +@@ -164,10 +175,10 @@ impl PatchResolverImpl for UpatchResolverImpl { + pkg_name: patch_info.target.full_name(), + patch_file: patch_root.join(&patch_entity.patch_name), + target_elf: patch_entity.patch_target.clone(), +- symbols: Vec::new(), ++ functions: Vec::new(), + checksum: patch_entity.checksum.clone(), + }; +- Self::resolve_patch_elf(&mut patch).context("Failed to resolve patch elf")?; ++ Self::resolve_patch_elf(&mut patch).context("Failed to resolve patch")?; + + Ok(Patch::UserPatch(patch)) + } +-- +2.41.0 + diff --git a/0014-syscared-stop-activating-ignored-process-on-new-proc.patch b/0014-syscared-stop-activating-ignored-process-on-new-proc.patch new file mode 100644 index 0000000000000000000000000000000000000000..2224a4bfe0e6ba00523a05c86c0a2a10d51b0a38 --- /dev/null +++ b/0014-syscared-stop-activating-ignored-process-on-new-proc.patch @@ -0,0 +1,237 @@ +From 3ee829f2156651f2284e072ba63abd196ee43294 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Wed, 17 Apr 2024 19:14:19 +0800 +Subject: [PATCH 14/17] syscared: stop activating ignored process on new + process start + +Signed-off-by: renoseven +--- + syscared/src/patch/driver/kpatch/mod.rs | 8 +- + syscared/src/patch/driver/upatch/mod.rs | 109 ++++++++++++------------ + 2 files changed, 58 insertions(+), 59 deletions(-) + +diff --git a/syscared/src/patch/driver/kpatch/mod.rs b/syscared/src/patch/driver/kpatch/mod.rs +index 45dc719..307efb5 100644 +--- a/syscared/src/patch/driver/kpatch/mod.rs ++++ b/syscared/src/patch/driver/kpatch/mod.rs +@@ -239,7 +239,7 @@ impl KernelPatchDriver { + + pub fn apply(&mut self, patch: &KernelPatch) -> Result<()> { + info!( +- "Kpatch: Applying patch '{}' ({})", ++ "Applying patch '{}' ({})", + patch.uuid, + patch.patch_file.display() + ); +@@ -253,7 +253,7 @@ impl KernelPatchDriver { + + pub fn remove(&mut self, patch: &KernelPatch) -> Result<()> { + info!( +- "Kpatch: Removing patch '{}' ({})", ++ "Removing patch '{}' ({})", + patch.uuid, + patch.patch_file.display() + ); +@@ -265,7 +265,7 @@ impl KernelPatchDriver { + + pub fn active(&mut self, patch: &KernelPatch) -> Result<()> { + info!( +- "Kpatch: Activating patch '{}' ({})", ++ "Activating patch '{}' ({})", + patch.uuid, + patch.patch_file.display() + ); +@@ -277,7 +277,7 @@ impl KernelPatchDriver { + + pub fn deactive(&mut self, patch: &KernelPatch) -> Result<()> { + info!( +- "Kpatch: Deactivating patch '{}' ({})", ++ "Deactivating patch '{}' ({})", + patch.uuid, + patch.patch_file.display() + ); +diff --git a/syscared/src/patch/driver/upatch/mod.rs b/syscared/src/patch/driver/upatch/mod.rs +index dd07e9b..66eecf5 100644 +--- a/syscared/src/patch/driver/upatch/mod.rs ++++ b/syscared/src/patch/driver/upatch/mod.rs +@@ -237,21 +237,20 @@ impl UserPatchDriver { + patch_entity.clean_dead_process(&process_list); + + // Active patch +- let need_actived = patch_entity.need_actived(&process_list); ++ let need_ignored = patch_entity.need_ignored(&process_list); ++ ++ let mut need_actived = patch_entity.need_actived(&process_list); ++ need_actived.retain(|pid| !need_ignored.contains(pid)); + if !need_actived.is_empty() { + debug!( +- "Upatch: Activating patch '{}' ({}) for process {:?}", ++ "Activating patch '{}' ({}) for process {:?}", + patch_uuid, + target_elf.display(), + need_actived, + ); + } + +- let ignore_list = patch_entity.need_ignored(&process_list); + for pid in need_actived { +- if ignore_list.contains(&pid) { +- continue; +- } + match sys::active_patch(patch_uuid, pid, target_elf, &patch_entity.patch_file) { + Ok(_) => patch_entity.add_process(pid), + Err(e) => { +@@ -283,7 +282,7 @@ impl UserPatchDriver { + + pub fn apply(&mut self, patch: &UserPatch) -> Result<()> { + info!( +- "Upatch: Applying patch '{}' ({})", ++ "Applying patch '{}' ({})", + patch.uuid, + patch.patch_file.display() + ); +@@ -296,7 +295,7 @@ impl UserPatchDriver { + + pub fn remove(&mut self, patch: &UserPatch) -> Result<()> { + info!( +- "Upatch: Removing patch '{}' ({})", ++ "Removing patch '{}' ({})", + patch.uuid, + patch.patch_file.display() + ); +@@ -326,7 +325,7 @@ impl UserPatchDriver { + + // Active patch + info!( +- "Upatch: Activating patch '{}' ({}) for {}", ++ "Activating patch '{}' ({}) for {}", + patch_uuid, + patch_file.display(), + target_elf.display(), +@@ -342,29 +341,28 @@ impl UserPatchDriver { + } + + // Check results, return error if all process fails +- match results.iter().any(|(_, result)| result.is_ok()) { +- true => { +- for (pid, result) in &results { +- if let Err(e) = result { +- warn!( +- "Upatch: Failed to active patch '{}' for process {}, {}", +- patch_uuid, +- pid, +- e.to_string().to_lowercase(), +- ); +- } ++ if !results.is_empty() && results.iter().all(|(_, result)| result.is_err()) { ++ let mut err_msg = String::new(); ++ ++ writeln!(err_msg, "Upatch: Failed to active patch")?; ++ for (pid, result) in &results { ++ if let Err(e) = result { ++ writeln!(err_msg, "* Process {}: {}", pid, e)?; + } + } +- false => { +- let mut err_msg = String::new(); ++ err_msg.pop(); ++ bail!(err_msg); ++ } + +- writeln!(err_msg, "Upatch: Failed to active patch")?; +- for (pid, result) in &results { +- if let Err(e) = result { +- writeln!(err_msg, "* Process {}: {}", pid, e)?; +- } +- } +- bail!(err_msg); ++ // Print failure results ++ for (pid, result) in &results { ++ if let Err(e) = result { ++ warn!( ++ "Upatch: Failed to active patch '{}' for process {}, {}", ++ patch_uuid, ++ pid, ++ e.to_string().to_lowercase(), ++ ); + } + } + +@@ -407,17 +405,19 @@ impl UserPatchDriver { + + // Deactive patch + info!( +- "Upatch: Deactivating patch '{}' ({}) for {}", ++ "Deactivating patch '{}' ({}) for {}", + patch_uuid, + patch_file.display(), + target_elf.display(), + ); ++ ++ let need_ignored = patch_entity.need_ignored(&process_list); ++ ++ let mut need_deactived = patch_entity.need_deactived(&process_list); ++ need_deactived.retain(|pid| need_ignored.contains(pid)); ++ + let mut results = Vec::new(); +- let ignore_list = patch_entity.need_ignored(&process_list); + for pid in patch_entity.need_deactived(&process_list) { +- if ignore_list.contains(&pid) { +- continue; +- } + let result = sys::deactive_patch(patch_uuid, pid, target_elf, patch_file); + if result.is_ok() { + patch_entity.remove_process(pid) +@@ -426,29 +426,28 @@ impl UserPatchDriver { + } + + // Check results, return error if any process failes +- match results.iter().any(|(_, result)| result.is_err()) { +- true => { +- let mut err_msg = String::new(); +- +- writeln!(err_msg, "Upatch: Failed to deactive patch")?; +- for (pid, result) in &results { +- if let Err(e) = result { +- writeln!(err_msg, "* Process {}: {}", pid, e)?; +- } ++ if !results.is_empty() && results.iter().any(|(_, result)| result.is_err()) { ++ let mut err_msg = String::new(); ++ ++ writeln!(err_msg, "Upatch: Failed to deactive patch")?; ++ for (pid, result) in &results { ++ if let Err(e) = result { ++ writeln!(err_msg, "* Process {}: {}", pid, e)?; + } +- bail!(err_msg) + } +- false => { +- for (pid, result) in &results { +- if let Err(e) = result { +- warn!( +- "Upatch: Failed to deactive patch '{}' for process {}, {}", +- patch_uuid, +- pid, +- e.to_string().to_lowercase(), +- ); +- } +- } ++ err_msg.pop(); ++ bail!(err_msg); ++ } ++ ++ // Print failure results ++ for (pid, result) in &results { ++ if let Err(e) = result { ++ warn!( ++ "Upatch: Failed to deactive patch '{}' for process {}, {}", ++ patch_uuid, ++ pid, ++ e.to_string().to_lowercase(), ++ ); + } + } + +-- +2.41.0 + diff --git a/0015-syscared-adapt-upatch-manage-exit-code-change.patch b/0015-syscared-adapt-upatch-manage-exit-code-change.patch new file mode 100644 index 0000000000000000000000000000000000000000..de1d0e324520a0d8ff0d70cb6ea732dbf5894426 --- /dev/null +++ b/0015-syscared-adapt-upatch-manage-exit-code-change.patch @@ -0,0 +1,35 @@ +From 96ccd901456d950761835befde8979519575778d Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Fri, 19 Apr 2024 12:02:23 +0800 +Subject: [PATCH 15/17] syscared: adapt upatch-manage exit code change + +1. upatch driver treats EEXIST as an error + +Signed-off-by: renoseven +--- + syscared/src/patch/driver/upatch/sys.rs | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/syscared/src/patch/driver/upatch/sys.rs b/syscared/src/patch/driver/upatch/sys.rs +index bfeb1b8..a388bc6 100644 +--- a/syscared/src/patch/driver/upatch/sys.rs ++++ b/syscared/src/patch/driver/upatch/sys.rs +@@ -2,7 +2,6 @@ use std::path::Path; + + use anyhow::{bail, Result}; + use log::Level; +-use nix::libc::EEXIST; + use uuid::Uuid; + + use syscare_common::process::Command; +@@ -26,7 +25,6 @@ pub fn active_patch(uuid: &Uuid, pid: i32, target_elf: &Path, patch_file: &Path) + + match exit_code { + 0 => Ok(()), +- EEXIST => Ok(()), + _ => bail!(std::io::Error::from_raw_os_error(exit_code)), + } + } +-- +2.41.0 + diff --git a/0016-upatch-manage-change-exit-code.patch b/0016-upatch-manage-change-exit-code.patch new file mode 100644 index 0000000000000000000000000000000000000000..6fc5ed5b063efcb312d02ecac410f4f19d1abb94 --- /dev/null +++ b/0016-upatch-manage-change-exit-code.patch @@ -0,0 +1,446 @@ +From 10dc2c5843156d032277cc0a3a85e2e8df3a5146 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Fri, 19 Apr 2024 12:01:38 +0800 +Subject: [PATCH 16/17] upatch-manage: change exit code + +1. return more specific exit code +2. change exit code from EEXIST to 0 when patching existing patch (uuid) + +Signed-off-by: renoseven +--- + upatch-manage/log.h | 2 +- + upatch-manage/upatch-elf.c | 10 ++--- + upatch-manage/upatch-manage.c | 7 ++-- + upatch-manage/upatch-patch.c | 70 ++++++++++++++++++++-------------- + upatch-manage/upatch-process.c | 15 ++------ + upatch-manage/upatch-ptrace.c | 1 + + 6 files changed, 56 insertions(+), 49 deletions(-) + +diff --git a/upatch-manage/log.h b/upatch-manage/log.h +index a41bfc8..32e9c56 100644 +--- a/upatch-manage/log.h ++++ b/upatch-manage/log.h +@@ -52,7 +52,7 @@ enum exit_status { + /* it is time cost */ + #define log_debug(format, ...) log(DEBUG, format, ##__VA_ARGS__) + #define log_normal(format, ...) log(NORMAL, format, ##__VA_ARGS__) +-#define log_warn(format, ...) log(WARN, "%s: " format, logprefix, ##__VA_ARGS__) ++#define log_warn(format, ...) log(WARN, format, ##__VA_ARGS__) + #define log_error(format, ...) log(ERR, format, ##__VA_ARGS__) + + #define log(level, format, ...) \ +diff --git a/upatch-manage/upatch-elf.c b/upatch-manage/upatch-elf.c +index 165f0cf..02444eb 100644 +--- a/upatch-manage/upatch-elf.c ++++ b/upatch-manage/upatch-elf.c +@@ -54,20 +54,20 @@ static int open_elf(struct elf_info *einfo, const char *name) + fd = open(name, O_RDONLY); + if (fd == -1) { + ret = -errno; +- log_error("Failed to open file '%s', ret=%d\n", name, ret); ++ log_error("Failed to open file '%s'\n", name); + goto out; + } + + ret = stat(name, &st); + if (ret != 0) { + ret = -errno; +- log_error("Failed to stat file '%s', ret=%d\n", name, ret); ++ log_error("Failed to stat file '%s'\n", name); + goto out; + } + + ret = read_from_offset(fd, (void **)&einfo->patch_buff, st.st_size, 0); + if (ret != 0) { +- log_error("Failed to read file '%s', ret=%d\n", name, ret); ++ log_error("Failed to read file '%s'\n", name); + goto out; + } + +@@ -112,7 +112,7 @@ int upatch_init(struct upatch_elf *uelf, const char *name) + { + int ret = open_elf(&uelf->info, name); + if (ret) { +- log_error("Failed to open elf '%s', ret=%d\n", name, ret); ++ log_error("Failed to open file '%s'\n", name); + return ret; + } + +@@ -136,7 +136,7 @@ int binary_init(struct running_elf *relf, const char *name) + { + int ret = open_elf(&relf->info, name); + if (ret) { +- log_error("Failed to open elf '%s', ret=%d\n", name, ret); ++ log_error("Failed to open file '%s'\n", name); + return ret; + } + +diff --git a/upatch-manage/upatch-manage.c b/upatch-manage/upatch-manage.c +index e33eeb3..8a7ba60 100644 +--- a/upatch-manage/upatch-manage.c ++++ b/upatch-manage/upatch-manage.c +@@ -146,7 +146,7 @@ int patch_upatch(const char *uuid, const char *binary_path, const char *upatch_p + + int ret = upatch_init(&uelf, upatch_path); + if (ret) { +- log_error("Failed to initialize patch, ret=%d\n", ret); ++ log_error("Failed to initialize patch, pid=%d, ret=%d\n", pid, ret); + goto out; + } + +@@ -155,7 +155,6 @@ int patch_upatch(const char *uuid, const char *binary_path, const char *upatch_p + log_error("Failed to patch process, pid=%d, ret=%d\n", pid, ret); + goto out; + } +- log_normal("SUCCESS\n"); + + out: + upatch_close(&uelf); +@@ -173,7 +172,6 @@ int unpatch_upatch(const char *uuid, const char *binary_path, const char *upatch + log_error("Failed to unpatch process, pid=%d, ret=%d\n", pid, ret); + return ret; + } +- log_normal("SUCCESS\n"); + + return 0; + } +@@ -185,7 +183,6 @@ int info_upatch(const char *binary_path, const char *upatch_path, int pid) + log_error("Failed to get patch info, pid=%d, ret=%d\n", pid, ret); + return ret; + } +- log_normal("SUCCESS\n"); + + return 0; + } +@@ -207,6 +204,7 @@ int main(int argc, char *argv[]) + log_debug("Patch: %s\n", args.upatch); + log_debug("Binary: %s\n", args.binary); + ++ args.pid = args.pid & INT32_MAX; + switch (args.cmd) { + case PATCH: + ret = patch_upatch(args.uuid, args.binary, args.upatch, args.pid); +@@ -223,5 +221,6 @@ int main(int argc, char *argv[]) + break; + } + ++ (ret == 0) ? log_normal("SUCCESS\n\n") : log_error("FAILED\n\n"); + return abs(ret); + } +diff --git a/upatch-manage/upatch-patch.c b/upatch-manage/upatch-patch.c +index 5e16002..5a8f927 100644 +--- a/upatch-manage/upatch-patch.c ++++ b/upatch-manage/upatch-patch.c +@@ -291,7 +291,6 @@ static void *upatch_alloc(struct object_file *obj, size_t sz) + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, + 0); + if (addr == 0) { +- log_error("Failed to alloc remote patch memory\n"); + return NULL; + } + +@@ -308,7 +307,7 @@ static void *upatch_alloc(struct object_file *obj, size_t sz) + return (void *)addr; + } + +-static void __upatch_memfree(struct object_file *obj, void *base, ++static void upatch_free(struct object_file *obj, void *base, + unsigned int size) + { + log_debug("Free patch memory %p\n", base); +@@ -323,14 +322,13 @@ static int __alloc_memory(struct object_file *obj_file, + /* Do the allocs. */ + layout->base = upatch_alloc(obj_file, layout->size); + if (!layout->base) { +- log_error("Failed to alloc patch core layout %p\n", layout->base); +- return -ENOMEM; ++ return -errno; + } + + layout->kbase = malloc(layout->size); + if (!layout->kbase) { +- __upatch_memfree(obj_file, layout->base, layout->size); +- return -ENOMEM; ++ upatch_free(obj_file, layout->base, layout->size); ++ return -errno; + } + + memset(layout->kbase, 0, layout->size); +@@ -345,7 +343,6 @@ static int alloc_memory(struct upatch_elf *uelf, struct object_file *obj) + /* Do the allocs. */ + ret = __alloc_memory(obj, &uelf->core_layout); + if (ret) { +- log_error("Failed to alloc patch memory, ret=%d\n", ret); + return ret; + } + +@@ -634,11 +631,13 @@ static int upatch_apply_patches(struct upatch_process *proc, + */ + ret = alloc_memory(uelf, obj); + if (ret) { ++ log_error("Failed to alloc patch memory\n"); + goto free; + } + + ret = upatch_mprotect(uelf, obj); + if (ret) { ++ log_error("Failed to set patch memory permission\n"); + goto free; + } + +@@ -675,7 +674,7 @@ static int upatch_apply_patches(struct upatch_process *proc, + + // TODO: clear + free: +- __upatch_memfree(obj, uelf->core_layout.base, uelf->core_layout.size); ++ upatch_free(obj, uelf->core_layout.base, uelf->core_layout.size); + out: + return ret; + } +@@ -708,15 +707,16 @@ int process_patch(int pid, struct upatch_elf *uelf, struct running_elf *relf, co + // 查看process的信息,pid: maps, mem, cmdline, exe + ret = upatch_process_init(&proc, pid); + if (ret < 0) { +- log_error("Failed to init process %d, ret=%d\n", pid, ret); ++ log_error("Failed to init process\n"); + goto out; + } + +- printf("Patch "); ++ printf("Patch '%s' to ", uuid); + upatch_process_print_short(&proc); + + ret = upatch_process_mem_open(&proc, MEM_READ); + if (ret < 0) { ++ log_error("Failed to open process memory\n"); + goto out_free; + } + +@@ -731,15 +731,19 @@ int process_patch(int pid, struct upatch_elf *uelf, struct running_elf *relf, co + */ + // 解析process的mem-maps,获得各个块的内存映射以及phdr + ret = upatch_process_map_object_files(&proc, NULL); +- if (ret < 0) ++ if (ret < 0) { ++ log_error("Failed to read process memory mapping\n"); + goto out_free; ++ } + ret = upatch_process_uuid_exist(&proc, uuid); + if (ret != 0) { ++ ret = 0; ++ log_error("Patch '%s' already exists\n", uuid); + goto out_free; + } + ret = binary_init(relf, binary_path); + if (ret) { +- log_error("Failed to load binary, ret=%d\n", ret); ++ log_error("Failed to load binary\n"); + goto out_free; + } + +@@ -750,24 +754,27 @@ int process_patch(int pid, struct upatch_elf *uelf, struct running_elf *relf, co + + /* Finally, attach to process */ + ret = upatch_process_attach(&proc); +- if (ret < 0) ++ if (ret < 0) { ++ log_error("Failed to attach process\n"); + goto out_free; ++ } + + // TODO: 栈解析 + // 应用 + ret = upatch_apply_patches(&proc, uelf, uuid); +- if (ret < 0) ++ if (ret < 0) { ++ log_error("Failed to apply patch\n"); + goto out_free; +- +- ret = 0; ++ } + + out_free: + upatch_process_detach(&proc); ++ gettimeofday(&end_tv, NULL); ++ + upatch_process_destroy(&proc); + + out: + if (is_calc_time) { +- gettimeofday(&end_tv, NULL); + frozen_time = GET_MICROSECONDS(end_tv, start_tv); + log_normal("Process %d frozen time is %ld microsecond(s)\n", + pid, frozen_time); +@@ -800,7 +807,7 @@ static int upatch_unapply_patches(struct upatch_process *proc, const char *uuid) + } + + log_debug("munmap upatch layout core:\n"); +- __upatch_memfree(obj, ++ upatch_free(obj, + (void *)patch->uinfo->start, + patch->uinfo->end - patch->uinfo->start + ); +@@ -810,7 +817,7 @@ static int upatch_unapply_patches(struct upatch_process *proc, const char *uuid) + } + + if (!found) { +- log_debug("can't found patch info memory\n"); ++ log_warn("Patch '%s' is not found\n", uuid); + goto out; + } + +@@ -831,16 +838,18 @@ int process_unpatch(int pid, const char *uuid) + // 查看process的信息,pid: maps, mem, cmdline, exe + ret = upatch_process_init(&proc, pid); + if (ret < 0) { +- log_error("Failed to init process %d, ret=%d\n", pid, ret); ++ log_error("Failed to init process\n"); + goto out; + } + +- printf("Unpatch "); ++ printf("Unpatch '%s' from ", uuid); + upatch_process_print_short(&proc); + + ret = upatch_process_mem_open(&proc, MEM_READ); +- if (ret < 0) ++ if (ret < 0) { ++ log_error("Failed to open process memory\n"); + goto out_free; ++ } + + // use uprobe to hack function. the program has been executed to the entry + // point +@@ -853,8 +862,10 @@ int process_unpatch(int pid, const char *uuid) + */ + // 解析process的mem-maps,获得各个块的内存映射以及phdr + ret = upatch_process_map_object_files(&proc, NULL); +- if (ret < 0) ++ if (ret < 0) { ++ log_error("Failed to read process memory mapping\n"); + goto out_free; ++ } + + is_calc_time = true; + gettimeofday(&start_tv, NULL); +@@ -862,24 +873,25 @@ int process_unpatch(int pid, const char *uuid) + /* Finally, attach to process */ + ret = upatch_process_attach(&proc); + if (ret < 0) { ++ log_error("Failed to attach process\n"); + goto out_free; + } + + // 应用 + ret = upatch_unapply_patches(&proc, uuid); + if (ret < 0) { ++ log_error("Failed to remove patch\n"); + goto out_free; + } + +- ret = 0; +- + out_free: + upatch_process_detach(&proc); ++ gettimeofday(&end_tv, NULL); ++ + upatch_process_destroy(&proc); + + out: + if (is_calc_time) { +- gettimeofday(&end_tv, NULL); + frozen_time = GET_MICROSECONDS(end_tv, start_tv); + log_normal("Process %d frozen time is %ld microsecond(s)\n", + pid, frozen_time); +@@ -924,23 +936,25 @@ int process_info(int pid) + // 查看process的信息,pid: maps, mem, cmdline, exe + ret = upatch_process_init(&proc, pid); + if (ret < 0) { +- log_error("Failed to init process %d, ret=%d\n", pid, ret); ++ log_error("Failed to init process\n"); + goto out; + } + + ret = upatch_process_mem_open(&proc, MEM_READ); + if (ret < 0) { ++ log_error("Failed to open process memory\n"); + goto out_free; + } + + ret = upatch_process_map_object_files(&proc, NULL); + if (ret < 0) { ++ log_error("Failed to read process memory mapping\n"); + goto out_free; + } + + ret = upatch_info(&proc); + if (ret) { +- status = "active"; ++ status = "actived"; + } + else { + status = "removed"; +diff --git a/upatch-manage/upatch-process.c b/upatch-manage/upatch-process.c +index cd3f7e0..c368165 100644 +--- a/upatch-manage/upatch-process.c ++++ b/upatch-manage/upatch-process.c +@@ -57,7 +57,7 @@ static int lock_process(int pid) + + fd = open(path, O_RDONLY); + if (fd < 0) { +- log_error("Failed to open '%s'\n", path); ++ log_error("Failed to open file '%s'\n", path); + return -1; + } + log_debug("OK\n"); +@@ -204,7 +204,7 @@ static void process_print_cmdline(struct upatch_process *proc) + snprintf(buf, PATH_MAX, "/proc/%d/cmdline", proc->pid); + int fd = open(buf, O_RDONLY); + if (fd == -1) { +- log_error("Failed to open %s", buf); ++ log_error("Failed to open file '%s'\n", buf); + return; + } + +@@ -255,7 +255,7 @@ int upatch_process_mem_open(struct upatch_process *proc, int mode) + snprintf(path, sizeof(path), "/proc/%d/mem", proc->pid); + proc->memfd = open(path, mode == MEM_WRITE ? O_RDWR : O_RDONLY); + if (proc->memfd < 0) { +- log_error("Failed to open %s", path); ++ log_error("Failed to open file '%s'\n", path); + return -1; + } + +@@ -560,16 +560,9 @@ error: + int upatch_process_map_object_files(struct upatch_process *proc, + const char *patch_id) + { +- int ret; +- +- ret = upatch_process_parse_proc_maps(proc); +- if (ret < 0) +- return -1; +- + // we can get plt/got table from mem's elf_segments + // Now we read them from the running file +- +- return ret; ++ return upatch_process_parse_proc_maps(proc); + } + + // static int process_has_thread_pid(struct upatch_proces *proc, int pid) +diff --git a/upatch-manage/upatch-ptrace.c b/upatch-manage/upatch-ptrace.c +index 39e8f59..1309a6e 100644 +--- a/upatch-manage/upatch-ptrace.c ++++ b/upatch-manage/upatch-ptrace.c +@@ -19,6 +19,7 @@ + */ + + #include ++#include + #include + #include + #include +-- +2.41.0 + diff --git a/0017-upatch-manage-change-the-way-to-calculate-frozen-tim.patch b/0017-upatch-manage-change-the-way-to-calculate-frozen-tim.patch new file mode 100644 index 0000000000000000000000000000000000000000..fca756e180f41f2ec5859584c56f90f5bdff7327 --- /dev/null +++ b/0017-upatch-manage-change-the-way-to-calculate-frozen-tim.patch @@ -0,0 +1,140 @@ +From ce0702b2da3820a3e872fd6563d5ce9e51cab130 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Fri, 19 Apr 2024 14:19:27 +0800 +Subject: [PATCH 17/17] upatch-manage: change the way to calculate frozen time + +Signed-off-by: renoseven +--- + upatch-manage/upatch-patch.c | 58 +++++++++++++++++++----------------- + 1 file changed, 31 insertions(+), 27 deletions(-) + +diff --git a/upatch-manage/upatch-patch.c b/upatch-manage/upatch-patch.c +index 5a8f927..ab972ac 100644 +--- a/upatch-manage/upatch-patch.c ++++ b/upatch-manage/upatch-patch.c +@@ -679,6 +679,31 @@ out: + return ret; + } + ++static void upatch_time_tick(int pid) { ++ static struct timeval start_tv; ++ static struct timeval end_tv; ++ ++ if ((end_tv.tv_sec != 0) || (end_tv.tv_usec != 0)) { ++ memset(&start_tv, 0, sizeof(struct timeval)); ++ memset(&end_tv, 0, sizeof(struct timeval)); ++ } ++ ++ if ((start_tv.tv_sec == 0) && (start_tv.tv_usec == 0)) { ++ gettimeofday(&start_tv, NULL); ++ } else { ++ gettimeofday(&end_tv, NULL); ++ } ++ ++ if ((start_tv.tv_sec == 0) || (start_tv.tv_usec == 0) || ++ (end_tv.tv_sec == 0) || (end_tv.tv_usec == 0)) { ++ return; ++ } ++ ++ unsigned long frozen_time = GET_MICROSECONDS(end_tv, start_tv); ++ log_normal("Process %d frozen time is %ld microsecond(s)\n", ++ pid, frozen_time); ++} ++ + int upatch_process_uuid_exist(struct upatch_process *proc, const char *uuid) + { + struct object_file *obj; +@@ -698,14 +723,10 @@ int upatch_process_uuid_exist(struct upatch_process *proc, const char *uuid) + + int process_patch(int pid, struct upatch_elf *uelf, struct running_elf *relf, const char *uuid, const char *binary_path) + { +- int ret; +- bool is_calc_time = false; +- struct timeval start_tv, end_tv; +- unsigned long frozen_time; + struct upatch_process proc; + + // 查看process的信息,pid: maps, mem, cmdline, exe +- ret = upatch_process_init(&proc, pid); ++ int ret = upatch_process_init(&proc, pid); + if (ret < 0) { + log_error("Failed to init process\n"); + goto out; +@@ -748,9 +769,7 @@ int process_patch(int pid, struct upatch_elf *uelf, struct running_elf *relf, co + } + + uelf->relf = relf; +- +- is_calc_time = true; +- gettimeofday(&start_tv, NULL); ++ upatch_time_tick(pid); + + /* Finally, attach to process */ + ret = upatch_process_attach(&proc); +@@ -769,16 +788,11 @@ int process_patch(int pid, struct upatch_elf *uelf, struct running_elf *relf, co + + out_free: + upatch_process_detach(&proc); +- gettimeofday(&end_tv, NULL); ++ upatch_time_tick(pid); + + upatch_process_destroy(&proc); + + out: +- if (is_calc_time) { +- frozen_time = GET_MICROSECONDS(end_tv, start_tv); +- log_normal("Process %d frozen time is %ld microsecond(s)\n", +- pid, frozen_time); +- } + return ret; + } + +@@ -827,16 +841,12 @@ out: + + int process_unpatch(int pid, const char *uuid) + { +- int ret; +- bool is_calc_time = false; +- struct timeval start_tv, end_tv; +- unsigned long frozen_time; + struct upatch_process proc; + + // TODO: check build id + // TODO: 栈解析 + // 查看process的信息,pid: maps, mem, cmdline, exe +- ret = upatch_process_init(&proc, pid); ++ int ret = upatch_process_init(&proc, pid); + if (ret < 0) { + log_error("Failed to init process\n"); + goto out; +@@ -867,8 +877,7 @@ int process_unpatch(int pid, const char *uuid) + goto out_free; + } + +- is_calc_time = true; +- gettimeofday(&start_tv, NULL); ++ upatch_time_tick(pid); + + /* Finally, attach to process */ + ret = upatch_process_attach(&proc); +@@ -886,16 +895,11 @@ int process_unpatch(int pid, const char *uuid) + + out_free: + upatch_process_detach(&proc); +- gettimeofday(&end_tv, NULL); ++ upatch_time_tick(pid); + + upatch_process_destroy(&proc); + + out: +- if (is_calc_time) { +- frozen_time = GET_MICROSECONDS(end_tv, start_tv); +- log_normal("Process %d frozen time is %ld microsecond(s)\n", +- pid, frozen_time); +- } + return ret; + } + +-- +2.41.0 + diff --git a/syscare.spec b/syscare.spec index 7304b0be78bceeb93a23e95deb3e8a4f89ceb5db..42b52470d75c95aef841d4b37d83f9da792f6e6c 100644 --- a/syscare.spec +++ b/syscare.spec @@ -11,7 +11,7 @@ ############################################ Name: syscare Version: 1.2.1 -Release: 3 +Release: 4 Summary: System hot-fix service License: MulanPSL-2.0 and GPL-2.0-only URL: https://gitee.com/openeuler/syscare @@ -20,13 +20,20 @@ Source0: %{name}-%{version}.tar.gz Patch0001: 0001-upatch-hijacker-fix-compile-bug.patch Patch0002: 0002-daemon-fix-cannot-get-file-selinux-xattr-when-selinu.patch Patch0003: 0003-syscared-fix-syscare-check-command-does-not-check-sy.patch -Patch0004: 0004-syscared-fix-cannot-find-process-of-dynlib-patch-iss.patch -Patch0005: 0005-abi-change-uuid-type-from-string-to-uuid-bytes.patch -Patch0006: 0006-syscared-optimize-patch-error-logic.patch -Patch0007: 0007-syscared-optimize-transaction-creation-logic.patch -Patch0008: 0008-upatch-manage-optimize-output.patch -Patch0009: 0009-syscared-optimize-patch-error-logic.patch -Patch0010: 0010-syscared-optimize-transaction-creation-logic.patch +Patch0004: 0004-Change-uuid-type-to-Uuid.patch +Patch0005: 0005-fix-clippy-warning.patch +Patch0006: 0006-syscared-fix-cannot-find-process-of-dynlib-patch-iss.patch +Patch0007: 0007-syscared-optimize-patch-error-logic.patch +Patch0008: 0008-syscared-optimize-transaction-creation-logic.patch +Patch0009: 0009-upatch-manage-optimize-output.patch +Patch0010: 0010-syscared-optimize-patch-error-logic.patch +Patch0011: 0011-syscared-optimize-transaction-creation-logic.patch +Patch0012: 0012-common-impl-CStr-from_bytes_with_next_nul.patch +Patch0013: 0013-syscared-improve-patch-management.patch +Patch0014: 0014-syscared-stop-activating-ignored-process-on-new-proc.patch +Patch0015: 0015-syscared-adapt-upatch-manage-exit-code-change.patch +Patch0016: 0016-upatch-manage-change-exit-code.patch +Patch0017: 0017-upatch-manage-change-the-way-to-calculate-frozen-tim.patch BuildRequires: cmake >= 3.14 make BuildRequires: rust >= 1.51 cargo >= 1.51 @@ -177,6 +184,13 @@ fi ################ Change log ################ ############################################ %changelog +* Fri Apr 19 2024 ningyu - 1.2.1-4 +- common: impl CStr::from_bytes_with_next_nul() +- syscared: improve patch management +- syscared: stop activating ignored process on new process start +- syscared: adapt upatch-manage exit code change +- upatch-manage: change exit code +- upatch-manage: change the way to calculate frozen time * Fri Apr 12 2024 ningyu - 1.2.1-3 - upatch-hijacker: fix compile bug - daemon: fix 'cannot get file selinux xattr when selinux is not enforcing' issue