From 25a934b89860dfe1d7e7aab5d4b8be61bf2124c7 Mon Sep 17 00:00:00 2001 From: ningyu <405888464@qq.com> Date: Tue, 14 May 2024 15:39:46 +0800 Subject: [PATCH] update to 1.2.1-7 Signed-off-by: ningyu <405888464@qq.com> --- ...-file-detection-cause-build-failure-.patch | 557 ++++++++++++ 0015-upatch-diff-optimize-log-output.patch | 469 ++++++++++ ...security-change-directory-permission.patch | 99 +++ ...rity-change-daemon-socket-permission.patch | 826 ++++++++++++++++++ ...xed-the-core-dump-issue-after-applyi.patch | 132 +++ ...ch-diff-fix-lookup_relf-failed-issue.patch | 144 +++ ...diff-only-check-changed-file-symbols.patch | 165 ++++ ...ve-rela-check-while-build-rebuilding.patch | 27 + syscare.spec | 54 +- 9 files changed, 2455 insertions(+), 18 deletions(-) create mode 100644 0014-upatch-build-fix-file-detection-cause-build-failure-.patch create mode 100644 0015-upatch-diff-optimize-log-output.patch create mode 100644 0016-security-change-directory-permission.patch create mode 100644 0017-security-change-daemon-socket-permission.patch create mode 100644 0018-upatch-manage-Fixed-the-core-dump-issue-after-applyi.patch create mode 100644 0019-upatch-diff-fix-lookup_relf-failed-issue.patch create mode 100644 0020-upatch-diff-only-check-changed-file-symbols.patch create mode 100644 0021-upatch-diff-remove-rela-check-while-build-rebuilding.patch diff --git a/0014-upatch-build-fix-file-detection-cause-build-failure-.patch b/0014-upatch-build-fix-file-detection-cause-build-failure-.patch new file mode 100644 index 0000000..a91866a --- /dev/null +++ b/0014-upatch-build-fix-file-detection-cause-build-failure-.patch @@ -0,0 +1,557 @@ +From 35ee9283c60a2d3e7d5ae2bcb9db31c71856d645 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Thu, 9 May 2024 18:49:29 +0800 +Subject: [PATCH 14/21] upatch-build: fix 'file detection cause build failure' + issue + + File relation detection does not work as we expected sometimes. +We changed the way to parse file relations from parsing dwarf info +to reading symlink, which is generated by hijacker. + + This method would list all generated symlinks after each build, +finding the file it points to and create a file map. Because of build results +are same, we can use the symlink path as a KEY to find the relationship +between patched objects and original objects, which is the previous step for +comparing difference of each build. + + Sometimes, the directory of generated objects may be different than source +directory. Thus, we provide a new argument '--object-dir', which would be +same as '--source-dir' by default. + +Signed-off-by: renoseven +--- + upatch-build/src/args.rs | 19 ++++- + upatch-build/src/build_root.rs | 8 +- + upatch-build/src/compiler.rs | 4 +- + upatch-build/src/dwarf/mod.rs | 22 +---- + upatch-build/src/file_relation.rs | 133 +++++++++++++++++------------- + upatch-build/src/main.rs | 33 ++++---- + upatch-build/src/project.rs | 2 +- + upatch-build/src/rpc/remote.rs | 2 +- + 8 files changed, 119 insertions(+), 104 deletions(-) + +diff --git a/upatch-build/src/args.rs b/upatch-build/src/args.rs +index 9f5fa15..c3b6f48 100644 +--- a/upatch-build/src/args.rs ++++ b/upatch-build/src/args.rs +@@ -23,6 +23,8 @@ use super::{CLI_ABOUT, CLI_NAME, CLI_VERSION}; + + const DEFAULT_WORK_DIR: &str = "/var/run/syscare"; + const DEFAULT_BUILD_ROOT: &str = "./upatch"; ++const DEFAULT_ELF_DIR: &str = ""; ++const DEFAULT_OBJECT_DIR: &str = ""; + const DEFAULT_CMD: &str = ""; + const DEFAULT_COMPILERS: &str = "cc"; + const DEFAULT_OUTPUT_DIR: &str = "."; +@@ -66,10 +68,14 @@ pub struct Arguments { + #[clap(short, long, multiple = true, required = true)] + pub debuginfo: Vec, + +- /// Specify the directory of searching elf [default: ] +- #[clap(long, default_value = "", hide_default_value = true)] ++ /// Specify the directory for searching elf [default: ] ++ #[clap(long, default_value = DEFAULT_ELF_DIR, hide_default_value = true)] + pub elf_dir: PathBuf, + ++ /// Specify the directory for searching object [default: ] ++ #[clap(long, default_value = DEFAULT_OBJECT_DIR, hide_default_value = true)] ++ pub object_dir: PathBuf, ++ + /// Specify elf's relative path relate to 'elf' or absolute patch list + #[clap(long, multiple = true, required = true)] + pub elf: Vec, +@@ -111,6 +117,10 @@ impl Arguments { + false => fs::normalize(&args.elf_dir)?, + true => args.source_dir.clone(), + }; ++ args.object_dir = match args.object_dir.as_os_str().is_empty() { ++ false => fs::normalize(&args.object_dir)?, ++ true => args.source_dir.clone(), ++ }; + + for elf_path in &mut args.elf { + *elf_path = args.elf_dir.join(&elf_path); +@@ -124,6 +134,7 @@ impl Arguments { + self.build_root = fs::normalize(self.build_root)?; + self.source_dir = fs::normalize(&self.source_dir)?; + self.elf_dir = fs::normalize(&self.elf_dir)?; ++ self.object_dir = fs::normalize(&self.object_dir)?; + self.output_dir = fs::normalize(&self.output_dir)?; + + for debuginfo in &mut self.debuginfo { +@@ -149,6 +160,10 @@ impl Arguments { + self.elf_dir.is_dir(), + format!("Cannot find elf directory {}", self.elf_dir.display()) + ); ++ ensure!( ++ self.object_dir.is_dir(), ++ format!("Cannot find object directory {}", self.object_dir.display()) ++ ); + for debuginfo in &self.debuginfo { + ensure!( + debuginfo.is_file(), +diff --git a/upatch-build/src/build_root.rs b/upatch-build/src/build_root.rs +index 0d703a7..556231d 100644 +--- a/upatch-build/src/build_root.rs ++++ b/upatch-build/src/build_root.rs +@@ -21,7 +21,7 @@ pub struct BuildRoot { + pub path: PathBuf, + pub original_dir: PathBuf, + pub patched_dir: PathBuf, +- pub output_dir: PathBuf, ++ pub temp_dir: PathBuf, + pub log_file: PathBuf, + } + +@@ -30,19 +30,19 @@ impl BuildRoot { + let path = path.as_ref().to_path_buf(); + let original_dir = path.join("original"); + let patched_dir = path.join("patched"); +- let output_dir = path.join("output"); ++ let temp_dir = path.join("temp"); + let log_file = path.join("build.log"); + + fs::create_dir_all(&path)?; + fs::create_dir_all(&original_dir)?; + fs::create_dir_all(&patched_dir)?; +- fs::create_dir_all(&output_dir)?; ++ fs::create_dir_all(&temp_dir)?; + + Ok(Self { + path, + original_dir, + patched_dir, +- output_dir, ++ temp_dir, + log_file, + }) + } +diff --git a/upatch-build/src/compiler.rs b/upatch-build/src/compiler.rs +index 9c282e2..7778f0b 100644 +--- a/upatch-build/src/compiler.rs ++++ b/upatch-build/src/compiler.rs +@@ -169,7 +169,7 @@ impl Compiler { + } + + impl Compiler { +- pub fn parse(compilers: I, build_dir: Q) -> Result> ++ pub fn parse(compilers: I, temp_dir: Q) -> Result> + where + I: IntoIterator, + P: AsRef, +@@ -183,7 +183,7 @@ impl Compiler { + .file_name() + .context("Failed to parse compiler name")?; + +- let output_dir = build_dir.as_ref().join(compiler_name); ++ let output_dir = temp_dir.as_ref().join(compiler_name); + fs::create_dir_all(&output_dir)?; + + debug!("- Checking {}", compiler.display()); +diff --git a/upatch-build/src/dwarf/mod.rs b/upatch-build/src/dwarf/mod.rs +index aded143..35f359e 100644 +--- a/upatch-build/src/dwarf/mod.rs ++++ b/upatch-build/src/dwarf/mod.rs +@@ -22,7 +22,7 @@ use std::{ + path::{Path, PathBuf}, + }; + +-use anyhow::{bail, Context, Result}; ++use anyhow::{Context, Result}; + use gimli::{ + constants, Attribute, AttributeValue, EndianSlice, Endianity, Reader, RunTimeEndian, SectionId, + }; +@@ -65,26 +65,6 @@ impl Dwarf { + Self::get_files(&object, endian) + } + +- pub fn parse_source_file>(object: P) -> Result { +- let source_files = Dwarf::parse(&object) +- .with_context(|| format!("Failed to read dwarf of {}", object.as_ref().display()))? +- .into_iter() +- .filter_map(|dwarf| { +- let file_path = dwarf.compile_dir.join(&dwarf.file_name); +- match file_path.exists() { +- true => Some(file_path), +- false => None, +- } +- }) +- .collect::>(); +- +- match source_files.len() { +- 1 => Ok(source_files[0].clone()), +- 0 => bail!("Object does not contain source file"), +- _ => bail!("Object contains to too many source files"), +- } +- } +- + pub fn parse_compiler_versions>(object: P) -> Result> { + let compiler_versions = Dwarf::parse(&object) + .with_context(|| format!("Failed to read dwarf of {}", object.as_ref().display()))? +diff --git a/upatch-build/src/file_relation.rs b/upatch-build/src/file_relation.rs +index ef67af1..5a58d04 100644 +--- a/upatch-build/src/file_relation.rs ++++ b/upatch-build/src/file_relation.rs +@@ -21,7 +21,6 @@ use indexmap::{IndexMap, IndexSet}; + use syscare_common::{ffi::OsStrExt, fs}; + + use super::{ +- dwarf::Dwarf, + elf::{check_elf, read}, + pattern_path::glob, + }; +@@ -29,25 +28,32 @@ use super::{ + const UPATCH_SYM_PREFIX: &str = ".upatch_"; + const OBJECT_EXTENSION: &str = "o"; + ++/* ++ * The task of this class is to find out: ++ * 1. relationship between binary and debuginfo ++ * 2. relationship between output binaries and objects ++ * 3. relationship between original objects and patched objects ++ */ ++ + #[derive(Debug)] + pub struct FileRelation { +- binary_debug_map: IndexMap, // Binary -> Debuginfo +- source_origin_map: IndexMap, // Source file -> Original object +- binary_patched_map: IndexMap>, // Binary -> Patched objects +- patched_original_map: IndexMap, // Patched object -> Original object ++ debuginfo_map: IndexMap, // Binary -> Debuginfo ++ symlink_map: IndexMap, // Symlink object -> Orignal object ++ patch_objects_map: IndexMap>, // Binary -> Patched objects ++ original_object_map: IndexMap, // Patched object -> Original object + } + + impl FileRelation { + pub fn new() -> Self { + Self { +- binary_debug_map: IndexMap::new(), +- binary_patched_map: IndexMap::new(), +- source_origin_map: IndexMap::new(), +- patched_original_map: IndexMap::new(), ++ debuginfo_map: IndexMap::new(), ++ symlink_map: IndexMap::new(), ++ patch_objects_map: IndexMap::new(), ++ original_object_map: IndexMap::new(), + } + } + +- pub fn collect_outputs(&mut self, binaries: I, debuginfos: J) -> Result<()> ++ pub fn collect_debuginfo(&mut self, binaries: I, debuginfos: J) -> Result<()> + where + I: IntoIterator, + J: IntoIterator, +@@ -61,86 +67,99 @@ impl FileRelation { + let binary = Self::find_binary_file(binary)?; + let debuginfo = debuginfo.as_ref().to_path_buf(); + +- self.binary_debug_map.insert(binary, debuginfo); ++ self.debuginfo_map.insert(binary, debuginfo); + } + + Ok(()) + } + +- pub fn collect_original_build>(&mut self, object_dir: P) -> Result<()> { +- for (binary, _) in &self.binary_debug_map { +- let upatch_ids = Self::parse_upatch_ids(binary) +- .with_context(|| format!("Failed to parse upatch id of {}", binary.display()))?; +- +- for upatch_id in upatch_ids { +- let original_object = Self::find_object_file(&object_dir, &upatch_id) +- .with_context(|| { +- format!("Failed to find object of {}", upatch_id.to_string_lossy()) +- })?; +- let source_file = +- Dwarf::parse_source_file(&original_object).with_context(|| { +- format!( +- "Failed to parse source file of {}", +- original_object.display() +- ) +- })?; +- +- self.source_origin_map.insert(source_file, original_object); ++ pub fn collect_original_build(&mut self, object_dir: P, expected_dir: Q) -> Result<()> ++ where ++ P: AsRef, ++ Q: AsRef, ++ { ++ let symlinks = fs::list_symlinks(&object_dir, fs::TraverseOptions { recursive: true })?; ++ for symlink in symlinks { ++ let object = fs::read_link(&symlink)?; ++ if !object.starts_with(expected_dir.as_ref().as_os_str()) { ++ continue; + } ++ self.symlink_map.insert(symlink, object); + } ++ ensure!( ++ !self.symlink_map.is_empty(), ++ "Cannot find any valid objects in {}", ++ object_dir.as_ref().display() ++ ); + + Ok(()) + } + +- pub fn collect_patched_build>(&mut self, object_dir: P) -> Result<()> { +- for (binary, _) in &self.binary_debug_map { ++ pub fn collect_patched_build(&mut self, object_dir: P, expected_dir: Q) -> Result<()> ++ where ++ P: AsRef, ++ Q: AsRef, ++ { ++ let mut symlink_map = IndexMap::new(); ++ let symlinks = fs::list_symlinks(&object_dir, fs::TraverseOptions { recursive: true })?; ++ for symlink in symlinks { ++ let object = fs::read_link(&symlink)?; ++ if !object.starts_with(expected_dir.as_ref().as_os_str()) { ++ continue; ++ } ++ symlink_map.insert(object, symlink); ++ } ++ ensure!( ++ !self.symlink_map.is_empty(), ++ "Cannot find any valid objects in {}", ++ object_dir.as_ref().display() ++ ); ++ ++ for (binary, _) in &self.debuginfo_map { ++ let mut objects = IndexSet::new(); ++ + let upatch_ids = Self::parse_upatch_ids(binary) + .with_context(|| format!("Failed to parse upatch id of {}", binary.display()))?; +- +- let mut patched_objects = IndexSet::new(); + for upatch_id in upatch_ids { +- let patched_object = +- Self::find_object_file(&object_dir, &upatch_id).with_context(|| { +- format!("Failed to find object of {}", upatch_id.to_string_lossy()) ++ let patched_object = Self::get_object_file(&expected_dir, &upatch_id) ++ .with_context(|| { ++ format!("Failed to get object of {}", upatch_id.to_string_lossy()) + })?; +- let source_file = Dwarf::parse_source_file(&patched_object).with_context(|| { +- format!( +- "Failed to parse source file of {}", +- patched_object.display() +- ) +- })?; +- let original_object = +- self.source_origin_map.get(&source_file).with_context(|| { ++ let original_object = symlink_map ++ .get(&patched_object) ++ .and_then(|path| self.symlink_map.get(path)) ++ .with_context(|| { + format!( +- "Failed to find original object of {}", ++ "failed to find original object of {}", + patched_object.display() + ) +- })?; ++ }) ++ .cloned()?; + +- patched_objects.insert(patched_object.clone()); +- self.patched_original_map +- .insert(patched_object, original_object.to_path_buf()); ++ // Update object relations ++ self.original_object_map ++ .insert(patched_object.to_owned(), original_object); ++ objects.insert(patched_object); + } +- +- self.binary_patched_map +- .insert(binary.to_path_buf(), patched_objects); ++ self.patch_objects_map.insert(binary.to_owned(), objects); + } ++ self.symlink_map.clear(); // clear useless records + + Ok(()) + } + + pub fn get_files(&self) -> impl IntoIterator { +- self.binary_debug_map ++ self.debuginfo_map + .iter() + .map(|(binary, debuginfo)| (binary.as_path(), debuginfo.as_path())) + } + + pub fn get_patched_objects>(&self, binary: P) -> Option<&IndexSet> { +- self.binary_patched_map.get(binary.as_ref()) ++ self.patch_objects_map.get(binary.as_ref()) + } + + pub fn get_original_object>(&self, object: P) -> Option<&Path> { +- self.patched_original_map ++ self.original_object_map + .get(object.as_ref()) + .map(|p| p.as_path()) + } +@@ -166,7 +185,7 @@ impl FileRelation { + } + } + +- fn find_object_file(object_dir: P, upatch_id: S) -> Result ++ fn get_object_file(object_dir: P, upatch_id: S) -> Result + where + P: AsRef, + S: AsRef, +diff --git a/upatch-build/src/main.rs b/upatch-build/src/main.rs +index 99de581..b5c14a8 100644 +--- a/upatch-build/src/main.rs ++++ b/upatch-build/src/main.rs +@@ -49,7 +49,7 @@ use file_relation::FileRelation; + use hijacker::Hijacker; + use project::Project; + +-const CLI_NAME: &str = "syscare build"; ++const CLI_NAME: &str = "upatch build"; + const CLI_VERSION: &str = env!("CARGO_PKG_VERSION"); + const CLI_ABOUT: &str = env!("CARGO_PKG_DESCRIPTION"); + const CLI_UMASK: u32 = 0o022; +@@ -59,7 +59,7 @@ const LOG_FILE_NAME: &str = "build"; + struct BuildInfo { + files: FileRelation, + linker: PathBuf, +- build_dir: PathBuf, ++ temp_dir: PathBuf, + output_dir: PathBuf, + verbose: bool, + } +@@ -256,11 +256,11 @@ impl UpatchBuild { + let debuginfo_name = debuginfo + .file_name() + .context("Failed to parse debuginfo name")?; +- let output_dir = build_info.build_dir.join(binary_name); +- let new_debuginfo = output_dir.join(debuginfo_name); ++ let temp_dir = build_info.temp_dir.join(binary_name); ++ let new_debuginfo = temp_dir.join(debuginfo_name); + + debug!("- Preparing to build patch"); +- fs::create_dir_all(&output_dir)?; ++ fs::create_dir_all(&temp_dir)?; + fs::copy(debuginfo, &new_debuginfo)?; + fs::set_permissions(&new_debuginfo, Permissions::from_mode(0o644))?; + +@@ -288,7 +288,7 @@ impl UpatchBuild { + original_object, + patched_object, + &new_debuginfo, +- &output_dir, ++ &temp_dir, + build_info.verbose, + ) + .with_context(|| format!("Failed to create diff objects for {}", binary.display()))?; +@@ -296,7 +296,7 @@ impl UpatchBuild { + + debug!("- Collecting changes"); + let mut changed_objects = fs::list_files_by_ext( +- &output_dir, ++ &temp_dir, + OBJECT_EXTENSION, + fs::TraverseOptions { recursive: false }, + )?; +@@ -306,7 +306,7 @@ impl UpatchBuild { + } + + debug!("- Creating patch notes"); +- let notes_object = output_dir.join(NOTES_OBJECT_NAME); ++ let notes_object = temp_dir.join(NOTES_OBJECT_NAME); + Self::create_note(&new_debuginfo, ¬es_object).context("Failed to create patch notes")?; + changed_objects.push(notes_object); + +@@ -332,10 +332,10 @@ impl UpatchBuild { + }; + let output_file = build_info.output_dir.join(&patch_name); + +- info!("Generating patch {}", patch_name.to_string_lossy()); ++ info!("Generating patch for '{}'", patch_name.to_string_lossy()); + self.build_patch(&build_info, binary, debuginfo, &output_file) + .with_context(|| { +- format!("Failed to build patch {}", patch_name.to_string_lossy()) ++ format!("Failed to build patch '{}'", patch_name.to_string_lossy()) + })?; + } + +@@ -346,11 +346,12 @@ impl UpatchBuild { + let work_dir = self.args.work_dir.as_path(); + let name = self.args.name.as_os_str(); + let output_dir = self.args.output_dir.as_path(); ++ let object_dir = self.args.object_dir.as_path(); + let binaries = self.args.elf.as_slice(); + let debuginfos = self.args.debuginfo.as_slice(); + let verbose = self.args.verbose; + +- let build_dir = self.build_root.output_dir.as_path(); ++ let temp_dir = self.build_root.temp_dir.as_path(); + let original_dir = self.build_root.original_dir.as_path(); + let patched_dir = self.build_root.patched_dir.as_path(); + +@@ -359,7 +360,7 @@ impl UpatchBuild { + info!("=============================="); + info!("Checking compiler(s)"); + +- let compilers = Compiler::parse(&self.args.compiler, build_dir)?; ++ let compilers = Compiler::parse(&self.args.compiler, temp_dir)?; + let linker = compilers + .iter() + .map(|c| c.linker.clone()) +@@ -406,8 +407,8 @@ impl UpatchBuild { + .with_context(|| format!("Failed to build {}", project))?; + + info!("Collecting file relations"); +- files.collect_outputs(binaries, debuginfos)?; +- files.collect_original_build(original_dir)?; ++ files.collect_debuginfo(binaries, debuginfos)?; ++ files.collect_original_build(object_dir, original_dir)?; + + info!("Preparing {}", project); + project +@@ -425,7 +426,7 @@ impl UpatchBuild { + .with_context(|| format!("Failed to rebuild {}", project))?; + + info!("Collecting file relations"); +- files.collect_patched_build(patched_dir)?; ++ files.collect_patched_build(object_dir, patched_dir)?; + + // Unhack compilers + drop(hijacker); +@@ -433,7 +434,7 @@ impl UpatchBuild { + let build_info = BuildInfo { + linker, + files, +- build_dir: build_dir.to_path_buf(), ++ temp_dir: temp_dir.to_path_buf(), + output_dir: output_dir.to_path_buf(), + verbose, + }; +diff --git a/upatch-build/src/project.rs b/upatch-build/src/project.rs +index b2f8230..b36c26b 100644 +--- a/upatch-build/src/project.rs ++++ b/upatch-build/src/project.rs +@@ -46,7 +46,7 @@ pub struct Project<'a> { + impl<'a> Project<'a> { + pub fn new(args: &'a Arguments, build_root: &'a BuildRoot) -> Self { + let root_dir = args.source_dir.as_path(); +- let build_dir = build_root.output_dir.as_path(); ++ let build_dir = build_root.temp_dir.as_path(); + let original_dir = build_root.original_dir.as_path(); + let patched_dir = build_root.patched_dir.as_path(); + +diff --git a/upatch-build/src/rpc/remote.rs b/upatch-build/src/rpc/remote.rs +index a34f713..9927ece 100644 +--- a/upatch-build/src/rpc/remote.rs ++++ b/upatch-build/src/rpc/remote.rs +@@ -56,7 +56,7 @@ impl RpcRemote { + match error { + Error::Transport(e) => { + anyhow!( +- "Cannot connect to syscare daemon at unix://{}, {}", ++ "Cannot connect to upatch daemon at unix://{}, {}", + self.socket.display(), + e.source() + .map(|e| e.to_string()) +-- +2.41.0 + diff --git a/0015-upatch-diff-optimize-log-output.patch b/0015-upatch-diff-optimize-log-output.patch new file mode 100644 index 0000000..f7ad2ad --- /dev/null +++ b/0015-upatch-diff-optimize-log-output.patch @@ -0,0 +1,469 @@ +From 2a4df8e1c7418c49fbad06e20b2a6af100b1ed16 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Sat, 11 May 2024 08:26:33 +0800 +Subject: [PATCH 15/21] upatch-diff: optimize log output + +Signed-off-by: renoseven +--- + upatch-diff/create-diff-object.c | 177 ++++++++++++++++++------------- + upatch-diff/elf-compare.c | 2 +- + upatch-diff/elf-correlate.c | 4 +- + upatch-diff/log.h | 18 ++-- + upatch-diff/running-elf.c | 6 +- + upatch-diff/running-elf.h | 6 +- + upatch-diff/upatch-elf.c | 2 +- + upatch-diff/upatch-elf.h | 4 +- + 8 files changed, 122 insertions(+), 97 deletions(-) + +diff --git a/upatch-diff/create-diff-object.c b/upatch-diff/create-diff-object.c +index 5dc7522..01c58b8 100644 +--- a/upatch-diff/create-diff-object.c ++++ b/upatch-diff/create-diff-object.c +@@ -62,9 +62,10 @@ + + #define PROG_VERSION "upatch-diff "BUILD_VERSION + +-enum loglevel loglevel = NORMAL; +-char *logprefix; +-char *upatch_elf_name; ++enum LogLevel g_loglevel = NORMAL; ++char *g_logprefix; ++char *g_uelf_name; ++char *g_relf_name; + + struct arguments { + char *source_obj; +@@ -334,72 +335,87 @@ enum LOCAL_MATCH { + EMPTY, + }; + +-static enum LOCAL_MATCH locals_match(struct running_elf *relf, int idx, +- struct symbol *file_sym, struct list_head *sym_list) ++static enum LOCAL_MATCH locals_match( ++ struct upatch_elf *uelf, struct running_elf *relf, ++ struct symbol *file_sym, int file_sym_idx) + { +- struct symbol *sym; +- struct object_symbol *running_sym; +- int i; ++ struct symbol *uelf_sym = NULL; ++ struct debug_symbol *relf_sym = NULL; + enum LOCAL_MATCH found = EMPTY; + +- for (i = idx + 1; i < relf->obj_nr; ++i) { +- running_sym = &relf->obj_syms[i]; +- if (running_sym->type == STT_FILE) +- break; +- if (running_sym->bind != STB_LOCAL) ++ for (int i = file_sym_idx + 1; i < relf->obj_nr; i++) { ++ relf_sym = &relf->obj_syms[i]; ++ ++ if (relf_sym->type == STT_FILE) { ++ break; // find until next file ++ } ++ if (relf_sym->bind != STB_LOCAL) { + continue; +- if (running_sym->type != STT_FUNC && running_sym->type != STT_OBJECT) ++ } ++ if ((relf_sym->type != STT_FUNC) && ++ (relf_sym->type != STT_OBJECT)) { + continue; ++ } + + found = NOT_FOUND; +- sym = file_sym; +- list_for_each_entry_continue(sym, sym_list, list) { +- if (sym->type == STT_FILE) +- break; +- if(sym->bind != STB_LOCAL) ++ uelf_sym = file_sym; ++ list_for_each_entry_continue(uelf_sym, &uelf->symbols, list) { ++ if (uelf_sym->type == STT_FILE) { ++ break; // find until next file ++ } ++ if(uelf_sym->bind != STB_LOCAL) { + continue; +- +- if (sym->type == running_sym->type && +- !strcmp(sym->name, running_sym->name)) { +- found = FOUND; +- break; ++ } ++ if ((uelf_sym->type == relf_sym->type) && ++ (strcmp(uelf_sym->name, relf_sym->name) == 0)) { ++ found = FOUND; ++ break; + } + } + + if (found == NOT_FOUND) { +- log_warn("Cannot find symbol '%s' in running binary\n", running_sym->name); ++ log_warn("Cannot find symbol '%s' in %s\n", ++ relf_sym->name, g_relf_name); + return NOT_FOUND; + } + } + +- sym = file_sym; +- list_for_each_entry_continue(sym, sym_list, list) { +- if (sym->type == STT_FILE) +- break; +- if(sym->bind != STB_LOCAL) ++ uelf_sym = file_sym; ++ list_for_each_entry_continue(uelf_sym, &uelf->symbols, list) { ++ if (uelf_sym->type == STT_FILE) { ++ break; // find until next file ++ } ++ if(uelf_sym->bind != STB_LOCAL) { + continue; +- if (sym->type != STT_FUNC && sym->type != STT_OBJECT) ++ } ++ if ((relf_sym->type != STT_FUNC) && ++ (relf_sym->type != STT_OBJECT)) { + continue; +- if (discarded_sym(relf, sym)) ++ } ++ if (discarded_sym(relf, uelf_sym)) { + continue; ++ } + + found = NOT_FOUND; +- for (i = idx + 1; i < relf->obj_nr; ++i) { +- running_sym = &relf->obj_syms[i]; +- if (running_sym->type == STT_FILE) +- break; +- if (running_sym->bind != STB_LOCAL) +- continue; ++ for (int i = file_sym_idx + 1; i < relf->obj_nr; i++) { ++ relf_sym = &relf->obj_syms[i]; + +- if (sym->type == running_sym->type && +- !strcmp(sym->name, running_sym->name)) { +- found = FOUND; +- break; ++ if (relf_sym->type == STT_FILE) { ++ break; // find until next file ++ } ++ if (relf_sym->bind != STB_LOCAL) { ++ continue; ++ } ++ if ((uelf_sym->type == relf_sym->type) && ++ (strcmp(uelf_sym->name, relf_sym->name) == 0)) { ++ found = FOUND; ++ break; + } + } + +- if (found == NOT_FOUND){ +- log_warn("Cannot find symbol '%s' in object\n", sym->name); ++ if (found == NOT_FOUND) { ++ log_warn("Cannot find symbol '%s' in %s\n", ++ uelf_sym->name, g_uelf_name); + return NOT_FOUND; + } + } +@@ -407,41 +423,48 @@ static enum LOCAL_MATCH locals_match(struct running_elf *relf, int idx, + return found; + } + +-static void find_local_syms(struct running_elf *relf, struct symbol *file_sym, +- struct list_head *sym_list) ++static void find_local_syms(struct upatch_elf *uelf, struct running_elf *relf, ++ struct symbol *file_sym) + { +- struct object_symbol *running_sym; +- struct object_symbol *lookup_running_file_sym = NULL; +- int i; ++ struct debug_symbol *relf_sym = NULL; ++ struct debug_symbol *found_sym = NULL; + enum LOCAL_MATCH found; + +- for (i = 0; i < relf->obj_nr; ++i) { +- running_sym = &relf->obj_syms[i]; +- if (running_sym->type != STT_FILE) ++ for (int i = 0; i < relf->obj_nr; i++) { ++ relf_sym = &relf->obj_syms[i]; ++ ++ if (relf_sym->type != STT_FILE) { + continue; +- if (strcmp(file_sym->name, running_sym->name)) ++ } ++ if (strcmp(file_sym->name, relf_sym->name)) { + continue; +- found = locals_match(relf, i, file_sym, sym_list); ++ } ++ ++ found = locals_match(uelf, relf, file_sym, i); + if (found == NOT_FOUND) { + continue; +- } else if (found == EMPTY) { +- lookup_running_file_sym = running_sym; ++ } ++ else if (found == EMPTY) { ++ found_sym = relf_sym; + break; +- } else { +- if (lookup_running_file_sym) +- ERROR("Found duplicate local symbols in '%s'", file_sym->name); +- +- lookup_running_file_sym = running_sym; ++ } ++ else { ++ if (found_sym) { ++ ERROR("Found duplicate local symbols in '%s'", g_relf_name); ++ } ++ found_sym = relf_sym; + } + } + +- if (!lookup_running_file_sym) +- ERROR("Cannot find a local symbol in '%s'", file_sym->name); ++ if (!found_sym) { ++ ERROR("Cannot find local symbol in '%s'", g_relf_name); ++ } + +- list_for_each_entry_continue(file_sym, sym_list, list) { +- if (file_sym->type == STT_FILE) ++ list_for_each_entry_continue(file_sym, &uelf->symbols, list) { ++ if (file_sym->type == STT_FILE) { + break; +- file_sym->lookup_running_file_sym = lookup_running_file_sym; ++ } ++ file_sym->relf_sym = found_sym; + } + } + +@@ -453,13 +476,14 @@ static void find_local_syms(struct running_elf *relf, struct symbol *file_sym, + * We then compare local symbol lists from both blocks and store the pointer + * to STT_FILE symbol in running elf for later using. + */ +-static void find_file_symbol(struct upatch_elf *uelf, struct running_elf *relf) ++static void find_debug_symbol(struct upatch_elf *uelf, struct running_elf *relf) + { +- struct symbol *sym; ++ struct symbol *file_sym = NULL; + +- list_for_each_entry(sym, &uelf->symbols, list) { +- if (sym->type == STT_FILE) +- find_local_syms(relf, sym, &uelf->symbols); ++ list_for_each_entry(file_sym, &uelf->symbols, list) { ++ if (file_sym->type == STT_FILE) { ++ find_local_syms(uelf, relf, file_sym); ++ } + } + } + +@@ -735,7 +759,7 @@ static int include_changed_functions(struct upatch_elf *uelf) + if (sym->status == CHANGED && + sym->type == STT_SECTION && + sym->sec && is_except_section(sym->sec)) { +- log_warn("Exeception section '%s' is changed\n", sym->sec->name); ++ log_warn("Exception section '%s' is changed\n", sym->sec->name); + changed_nr++; + include_symbol(sym); + } +@@ -886,15 +910,16 @@ int main(int argc, char*argv[]) + argp_parse(&argp, argc, argv, 0, NULL, &arguments); + + if (arguments.debug) +- loglevel = DEBUG; +- logprefix = basename(arguments.source_obj); ++ g_loglevel = DEBUG; ++ g_logprefix = basename(arguments.source_obj); + show_program_info(&arguments); + + if (elf_version(EV_CURRENT) == EV_NONE) + ERROR("ELF library initialization failed"); + + /* TODO: with debug info, this may changed */ +- upatch_elf_name = arguments.running_elf; ++ g_uelf_name = arguments.source_obj; ++ g_relf_name = arguments.running_elf; + + /* check error in log, since errno may be from libelf */ + upatch_elf_open(&uelf_source, arguments.source_obj); +@@ -912,7 +937,7 @@ int main(int argc, char*argv[]) + detect_child_functions(&uelf_source); + detect_child_functions(&uelf_patched); + +- find_file_symbol(&uelf_source, &relf); ++ find_debug_symbol(&uelf_source, &relf); + + mark_grouped_sections(&uelf_patched); + +diff --git a/upatch-diff/elf-compare.c b/upatch-diff/elf-compare.c +index 054f16a..9b857b1 100644 +--- a/upatch-diff/elf-compare.c ++++ b/upatch-diff/elf-compare.c +@@ -177,7 +177,7 @@ bool upatch_handle_redis_line(const char *symname) + /* TODO: let user support this list or generate by the compiler ? */ + bool check_line_func(struct upatch_elf *uelf, const char *symname) + { +- if (!strncmp(basename(upatch_elf_name), "redis-server", 12)) ++ if (!strncmp(basename(g_relf_name), "redis-server", 12)) + return upatch_handle_redis_line(symname); + + return false; +diff --git a/upatch-diff/elf-correlate.c b/upatch-diff/elf-correlate.c +index f25f252..a0fe669 100644 +--- a/upatch-diff/elf-correlate.c ++++ b/upatch-diff/elf-correlate.c +@@ -40,8 +40,8 @@ static void correlate_symbol(struct symbol *sym_orig, struct symbol *sym_patched + if (!sym_patched->name) + ERROR("strdup"); + } +- if (sym_orig->lookup_running_file_sym && !sym_patched->lookup_running_file_sym) +- sym_patched->lookup_running_file_sym = sym_orig->lookup_running_file_sym; ++ if (sym_orig->relf_sym && !sym_patched->relf_sym) ++ sym_patched->relf_sym = sym_orig->relf_sym; + } + + void upatch_correlate_symbols(struct upatch_elf *uelf_source, struct upatch_elf *uelf_patched) +diff --git a/upatch-diff/log.h b/upatch-diff/log.h +index 5af3e34..34b58bf 100644 +--- a/upatch-diff/log.h ++++ b/upatch-diff/log.h +@@ -28,9 +28,9 @@ + #include + #include + +-/* Files that include log.h must define loglevel and logprefix */ +-extern enum loglevel loglevel; +-extern char *logprefix; ++/* Files that include log.h must define g_loglevel and g_logprefix */ ++extern enum LogLevel g_loglevel; ++extern char *g_logprefix; + + enum exit_status{ + EXIT_STATUS_SUCCESS = 0, +@@ -41,19 +41,19 @@ enum exit_status{ + + /* Since upatch-build is an one-shot program, we do not care about failure handler */ + #define ERROR(format, ...) \ +- error(EXIT_STATUS_ERROR, 0, "ERROR: %s: %s: %d: " format, logprefix, __FUNCTION__, __LINE__, ##__VA_ARGS__) ++ error(EXIT_STATUS_ERROR, 0, "ERROR: %s: %s: %d: " format, g_logprefix, __FUNCTION__, __LINE__, ##__VA_ARGS__) + + #define DIFF_FATAL(format, ...) \ +- error(EXIT_STATUS_DIFF_FATAL, 0, "ERROR: %s: %s: %d: " format, logprefix, __FUNCTION__, __LINE__, ##__VA_ARGS__) ++ error(EXIT_STATUS_DIFF_FATAL, 0, "ERROR: %s: %s: %d: " format, g_logprefix, __FUNCTION__, __LINE__, ##__VA_ARGS__) + + /* it is time cost */ + #define log_debug(format, ...) log(DEBUG, format, ##__VA_ARGS__) +-#define log_normal(format, ...) log(NORMAL, "%s: " format, logprefix, ##__VA_ARGS__) +-#define log_warn(format, ...) log(WARN, "%s: " format, logprefix, ##__VA_ARGS__) ++#define log_normal(format, ...) log(NORMAL, "%s: " format, g_logprefix, ##__VA_ARGS__) ++#define log_warn(format, ...) log(WARN, "%s: " format, g_logprefix, ##__VA_ARGS__) + + #define log(level, format, ...) \ + ({ \ +- if (loglevel <= (level)) \ ++ if (g_loglevel <= (level)) \ + printf(format, ##__VA_ARGS__); \ + }) + +@@ -63,7 +63,7 @@ enum exit_status{ + ERROR(message); \ + while (0) + +-enum loglevel { ++enum LogLevel { + DEBUG, + NORMAL, + WARN, +diff --git a/upatch-diff/running-elf.c b/upatch-diff/running-elf.c +index e190691..037f5fc 100644 +--- a/upatch-diff/running-elf.c ++++ b/upatch-diff/running-elf.c +@@ -84,7 +84,7 @@ void relf_init(char *elf_name, struct running_elf *relf) + ERROR("elf_getdata with error %s", elf_errmsg(0)); + + relf->obj_nr = shdr.sh_size / shdr.sh_entsize; +- relf->obj_syms = calloc(relf->obj_nr, sizeof(struct object_symbol)); ++ relf->obj_syms = calloc(relf->obj_nr, sizeof(struct debug_symbol)); + if (!relf->obj_syms) + ERROR("calloc with errno = %d", errno); + +@@ -117,7 +117,7 @@ bool lookup_relf(struct running_elf *relf, struct symbol *lookup_sym, + struct lookup_result *result) + { + int i; +- struct object_symbol *sym; ++ struct debug_symbol *sym; + unsigned long sympos = 0; + bool in_file = false; + +@@ -128,7 +128,7 @@ bool lookup_relf(struct running_elf *relf, struct symbol *lookup_sym, + if (sym->bind == STB_LOCAL && !strcmp(sym->name, lookup_sym->name)) + sympos ++; + +- if (lookup_sym->lookup_running_file_sym == sym) { ++ if (lookup_sym->relf_sym == sym) { + in_file = true; + continue; + } +diff --git a/upatch-diff/running-elf.h b/upatch-diff/running-elf.h +index 0eb5c70..0646780 100644 +--- a/upatch-diff/running-elf.h ++++ b/upatch-diff/running-elf.h +@@ -35,12 +35,12 @@ + struct symbol; + + struct lookup_result { +- struct object_symbol *symbol; ++ struct debug_symbol *symbol; + unsigned long sympos; + bool global; + }; + +-struct object_symbol { ++struct debug_symbol { + char *name; + unsigned char type, bind; + unsigned int shndx; +@@ -50,7 +50,7 @@ struct object_symbol { + + struct running_elf { + int obj_nr; +- struct object_symbol *obj_syms; ++ struct debug_symbol *obj_syms; + int fd; + Elf *elf; + bool is_exec; +diff --git a/upatch-diff/upatch-elf.c b/upatch-diff/upatch-elf.c +index e39fb6a..fc4396a 100644 +--- a/upatch-diff/upatch-elf.c ++++ b/upatch-diff/upatch-elf.c +@@ -206,7 +206,7 @@ static void create_rela_list(struct upatch_elf *uelf, struct section *relasec) + if (skip) + continue; + +- log_debug("offset %d, type %d, %s %s %ld \n", rela->offset, ++ log_debug("offset %d, type %d, %s %s %ld", rela->offset, + rela->type, rela->sym->name, + (rela->addend < 0) ? "-" : "+", labs(rela->addend)); + if (rela->string) // rela->string is not utf8 +diff --git a/upatch-diff/upatch-elf.h b/upatch-diff/upatch-elf.h +index 2f7c777..b2d038b 100644 +--- a/upatch-diff/upatch-elf.h ++++ b/upatch-diff/upatch-elf.h +@@ -32,7 +32,7 @@ + #include "list.h" + #include "running-elf.h" + +-extern char *upatch_elf_name; ++extern char *g_relf_name; + + // these data structs contain each other + struct section; +@@ -102,7 +102,7 @@ struct symbol { + struct section *sec; + GElf_Sym sym; + char *name; +- struct object_symbol *lookup_running_file_sym; ++ struct debug_symbol *relf_sym; + unsigned int index; + unsigned char bind; + unsigned char type; +-- +2.41.0 + diff --git a/0016-security-change-directory-permission.patch b/0016-security-change-directory-permission.patch new file mode 100644 index 0000000..6c18c78 --- /dev/null +++ b/0016-security-change-directory-permission.patch @@ -0,0 +1,99 @@ +From 4626c401b541c46debd18e1a326a323f4f85f69d Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Sat, 11 May 2024 08:28:48 +0800 +Subject: [PATCH 16/21] security: change directory permission + +1. config_dir /etc/syscare drwx------. +2. data_dir /usr/lib/syscare drwx------. +3. log_dir /var/log/syscare drwx------. +4. work_dir /var/run/syscare drwxr-xr-x. + +Signed-off-by: renoseven +--- + syscared/src/main.rs | 9 +++++++-- + upatchd/src/args.rs | 2 +- + upatchd/src/main.rs | 13 +++++++++---- + 3 files changed, 17 insertions(+), 7 deletions(-) + +diff --git a/syscared/src/main.rs b/syscared/src/main.rs +index 74bd488..22f01df 100644 +--- a/syscared/src/main.rs ++++ b/syscared/src/main.rs +@@ -47,7 +47,9 @@ const DAEMON_VERSION: &str = env!("CARGO_PKG_VERSION"); + const DAEMON_ABOUT: &str = env!("CARGO_PKG_DESCRIPTION"); + const DAEMON_UMASK: u32 = 0o077; + +-const WORK_DIR_PERMISSION: u32 = 0o755; ++const DATA_DIR_PERM: u32 = 0o700; ++const WORK_DIR_PERM: u32 = 0o755; ++const LOG_DIR_PERM: u32 = 0o700; + const PID_FILE_NAME: &str = "syscared.pid"; + const SOCKET_FILE_NAME: &str = "syscared.sock"; + +@@ -102,7 +104,10 @@ impl SyscareDaemon { + fs::create_dir_all(&args.data_dir)?; + fs::create_dir_all(&args.work_dir)?; + fs::create_dir_all(&args.log_dir)?; +- fs::set_permissions(&args.work_dir, Permissions::from_mode(WORK_DIR_PERMISSION))?; ++ fs::set_permissions(&args.data_dir, Permissions::from_mode(DATA_DIR_PERM))?; ++ fs::set_permissions(&args.work_dir, Permissions::from_mode(WORK_DIR_PERM))?; ++ fs::set_permissions(&args.log_dir, Permissions::from_mode(LOG_DIR_PERM))?; ++ + std::env::set_current_dir(&args.work_dir).with_context(|| { + format!( + "Failed to change current directory to {}", +diff --git a/upatchd/src/args.rs b/upatchd/src/args.rs +index 9311047..0b9029b 100644 +--- a/upatchd/src/args.rs ++++ b/upatchd/src/args.rs +@@ -22,8 +22,8 @@ use syscare_common::fs; + + use super::{DAEMON_ABOUT, DAEMON_NAME, DAEMON_VERSION}; + +-const DEFAULT_WORK_DIR: &str = "/var/run/syscare"; + const DEFAULT_CONFIG_DIR: &str = "/etc/syscare"; ++const DEFAULT_WORK_DIR: &str = "/var/run/syscare"; + const DEFAULT_LOG_DIR: &str = "/var/log/syscare"; + const DEFAULT_LOG_LEVEL: &str = "info"; + +diff --git a/upatchd/src/main.rs b/upatchd/src/main.rs +index 86e2052..1007ebb 100644 +--- a/upatchd/src/main.rs ++++ b/upatchd/src/main.rs +@@ -43,8 +43,10 @@ const CONFIG_FILE_NAME: &str = "upatchd.yaml"; + const PID_FILE_NAME: &str = "upatchd.pid"; + const SOCKET_FILE_NAME: &str = "upatchd.sock"; + +-const WORK_DIR_PERMISSION: u32 = 0o755; +-const SOCKET_FILE_PERMISSION: u32 = 0o666; ++const CONFIG_DIR_PERM: u32 = 0o700; ++const WORK_DIR_PERM: u32 = 0o755; ++const LOG_DIR_PERM: u32 = 0o700; ++const SOCKET_FILE_PERM: u32 = 0o666; + + const MAIN_THREAD_NAME: &str = "main"; + const UNNAMED_THREAD_NAME: &str = ""; +@@ -97,7 +99,10 @@ impl UpatchDaemon { + fs::create_dir_all(&args.config_dir)?; + fs::create_dir_all(&args.work_dir)?; + fs::create_dir_all(&args.log_dir)?; +- fs::set_permissions(&args.work_dir, Permissions::from_mode(WORK_DIR_PERMISSION))?; ++ fs::set_permissions(&args.config_dir, Permissions::from_mode(CONFIG_DIR_PERM))?; ++ fs::set_permissions(&args.work_dir, Permissions::from_mode(WORK_DIR_PERM))?; ++ fs::set_permissions(&args.log_dir, Permissions::from_mode(LOG_DIR_PERM))?; ++ + std::env::set_current_dir(&args.work_dir).with_context(|| { + format!( + "Failed to change current directory to {}", +@@ -168,7 +173,7 @@ impl UpatchDaemon { + .context("Failed to convert socket path to string")?, + )?; + +- fs::set_permissions(&socket_file, Permissions::from_mode(SOCKET_FILE_PERMISSION))?; ++ fs::set_permissions(&socket_file, Permissions::from_mode(SOCKET_FILE_PERM))?; + + Ok(server) + } +-- +2.41.0 + diff --git a/0017-security-change-daemon-socket-permission.patch b/0017-security-change-daemon-socket-permission.patch new file mode 100644 index 0000000..3ecf5e9 --- /dev/null +++ b/0017-security-change-daemon-socket-permission.patch @@ -0,0 +1,826 @@ +From bb21560c6ab6217c06533ea85dd7db5a40379e5b Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Sat, 11 May 2024 10:21:58 +0800 +Subject: [PATCH 17/21] security: change daemon socket permission + +1. add socket uid & gid to config file + default uid: 0 + default gid: 0 + +2. set socket permission by its uid & gid + uid == gid: 0600 + uid != gid: 0660 + +Signed-off-by: renoseven +--- + Cargo.lock | 2 + + syscared/Cargo.toml | 1 + + syscared/src/args.rs | 8 ++- + syscared/src/config.rs | 88 ++++++++++++++++++++++++++++++ + syscared/src/main.rs | 70 ++++++++++++++++++------ + upatchd/Cargo.toml | 2 +- + upatchd/src/config.rs | 91 ++++++++++++++++++++++++++++++++ + upatchd/src/hijacker/config.rs | 85 +++++------------------------ + upatchd/src/hijacker/mod.rs | 47 +++-------------- + upatchd/src/main.rs | 55 ++++++++++++++----- + upatchd/src/rpc/skeleton_impl.rs | 8 +-- + 11 files changed, 310 insertions(+), 147 deletions(-) + create mode 100644 syscared/src/config.rs + create mode 100644 upatchd/src/config.rs + +diff --git a/Cargo.lock b/Cargo.lock +index 1d13df6..3e920ab 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -511,6 +511,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" + dependencies = [ + "autocfg", + "hashbrown", ++ "serde", + ] + + [[package]] +@@ -1184,6 +1185,7 @@ dependencies = [ + "object", + "parking_lot", + "serde", ++ "serde_yaml", + "signal-hook", + "syscare-abi", + "syscare-common", +diff --git a/syscared/Cargo.toml b/syscared/Cargo.toml +index 2b148e7..27f27e2 100644 +--- a/syscared/Cargo.toml ++++ b/syscared/Cargo.toml +@@ -26,5 +26,6 @@ nix = { version = "0.26" } + object = { version = "0.29" } + parking_lot = { version = "0.11" } + serde = { version = "1.0", features = ["derive"] } ++serde_yaml = { version = "0.8" } + signal-hook = { version = "0.3" } + uuid = { version = "0.8", features = ["v4", "serde"] } +diff --git a/syscared/src/args.rs b/syscared/src/args.rs +index 71cdf95..4c28dff 100644 +--- a/syscared/src/args.rs ++++ b/syscared/src/args.rs +@@ -22,6 +22,7 @@ use syscare_common::fs; + + use super::{DAEMON_ABOUT, DAEMON_NAME, DAEMON_VERSION}; + ++const DEFAULT_CONFIG_DIR: &str = "/etc/syscare"; + const DEFAULT_DATA_ROOT: &str = "/usr/lib/syscare"; + const DEFAULT_WORK_DIR: &str = "/var/run/syscare"; + const DEFAULT_LOG_DIR: &str = "/var/log/syscare"; +@@ -42,6 +43,10 @@ pub struct Arguments { + #[clap(short, long)] + pub daemon: bool, + ++ /// Daemon config directory ++ #[clap(long, default_value=DEFAULT_CONFIG_DIR)] ++ pub config_dir: PathBuf, ++ + /// Daemon data directory + #[clap(long, default_value = DEFAULT_DATA_ROOT)] + pub data_dir: PathBuf, +@@ -65,8 +70,9 @@ impl Arguments { + } + + fn normalize_path(mut self) -> Result { +- self.work_dir = fs::normalize(&self.work_dir)?; ++ self.config_dir = fs::normalize(&self.config_dir)?; + self.data_dir = fs::normalize(&self.data_dir)?; ++ self.work_dir = fs::normalize(&self.work_dir)?; + self.log_dir = fs::normalize(&self.log_dir)?; + + Ok(self) +diff --git a/syscared/src/config.rs b/syscared/src/config.rs +new file mode 100644 +index 0000000..af98a51 +--- /dev/null ++++ b/syscared/src/config.rs +@@ -0,0 +1,88 @@ ++// SPDX-License-Identifier: Mulan PSL v2 ++/* ++ * Copyright (c) 2024 Huawei Technologies Co., Ltd. ++ * upatchd 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::Path; ++ ++use anyhow::{anyhow, Result}; ++use serde::{Deserialize, Serialize}; ++use syscare_common::fs; ++ ++const DEFAULT_SOCKET_UID: u32 = 0; ++const DEFAULT_SOCKET_GID: u32 = 0; ++ ++#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] ++pub struct SocketConfig { ++ pub uid: u32, ++ pub gid: u32, ++} ++ ++impl Default for SocketConfig { ++ fn default() -> Self { ++ Self { ++ uid: DEFAULT_SOCKET_UID, ++ gid: DEFAULT_SOCKET_GID, ++ } ++ } ++} ++ ++#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] ++pub struct DaemonConfig { ++ pub socket: SocketConfig, ++} ++ ++#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] ++pub struct Config { ++ pub daemon: DaemonConfig, ++} ++ ++impl Config { ++ pub fn parse>(path: P) -> Result { ++ let config_path = path.as_ref(); ++ let instance = serde_yaml::from_reader(fs::open_file(config_path)?) ++ .map_err(|_| anyhow!("Failed to parse config {}", config_path.display()))?; ++ ++ Ok(instance) ++ } ++ ++ pub fn write>(&self, path: P) -> Result<()> { ++ let config_path = path.as_ref(); ++ let config_file = fs::create_file(config_path)?; ++ serde_yaml::to_writer(config_file, self) ++ .map_err(|_| anyhow!("Failed to write config {}", config_path.display()))?; ++ ++ Ok(()) ++ } ++} ++ ++#[test] ++fn test() -> Result<()> { ++ use anyhow::{ensure, Context}; ++ use std::path::PathBuf; ++ ++ let tmp_file = PathBuf::from("/tmp/syscared.yaml"); ++ ++ let orig_cfg = Config::default(); ++ println!("{:#?}", orig_cfg); ++ ++ orig_cfg ++ .write(&tmp_file) ++ .context("Failed to write config")?; ++ ++ let new_cfg = Config::parse(tmp_file).context("Failed to read config")?; ++ println!("{:#?}", new_cfg); ++ ++ ensure!(orig_cfg == new_cfg, "Config does not match"); ++ ++ Ok(()) ++} +diff --git a/syscared/src/main.rs b/syscared/src/main.rs +index 22f01df..b840abf 100644 +--- a/syscared/src/main.rs ++++ b/syscared/src/main.rs +@@ -22,7 +22,8 @@ use flexi_logger::{ + }; + use jsonrpc_core::IoHandler; + use jsonrpc_ipc_server::{Server, ServerBuilder}; +-use log::{error, info, LevelFilter, Record}; ++use log::{debug, error, info, warn, LevelFilter, Record}; ++use nix::unistd::{chown, Gid, Uid}; + use parking_lot::RwLock; + use patch::manager::PatchManager; + use signal_hook::{consts::TERM_SIGNALS, iterator::Signals, low_level::signal_name}; +@@ -30,38 +31,45 @@ use signal_hook::{consts::TERM_SIGNALS, iterator::Signals, low_level::signal_nam + use syscare_common::{fs, os}; + + mod args; ++mod config; + mod fast_reboot; + mod patch; + mod rpc; + + use args::Arguments; ++use config::Config; ++use patch::monitor::PatchMonitor; + use rpc::{ + skeleton::{FastRebootSkeleton, PatchSkeleton}, + skeleton_impl::{FastRebootSkeletonImpl, PatchSkeletonImpl}, + }; + +-use crate::patch::monitor::PatchMonitor; +- + const DAEMON_NAME: &str = env!("CARGO_PKG_NAME"); + const DAEMON_VERSION: &str = env!("CARGO_PKG_VERSION"); + const DAEMON_ABOUT: &str = env!("CARGO_PKG_DESCRIPTION"); + const DAEMON_UMASK: u32 = 0o077; + ++const CONFIG_FILE_NAME: &str = "syscared.yaml"; ++const PID_FILE_NAME: &str = "syscared.pid"; ++const SOCKET_FILE_NAME: &str = "syscared.sock"; ++ ++const CONFIG_DIR_PERM: u32 = 0o700; + const DATA_DIR_PERM: u32 = 0o700; + const WORK_DIR_PERM: u32 = 0o755; + const LOG_DIR_PERM: u32 = 0o700; +-const PID_FILE_NAME: &str = "syscared.pid"; +-const SOCKET_FILE_NAME: &str = "syscared.sock"; ++const SOCKET_FILE_PERM: u32 = 0o660; ++const SOCKET_FILE_PERM_STRICT: u32 = 0o600; + + const MAIN_THREAD_NAME: &str = "main"; + const UNNAMED_THREAD_NAME: &str = ""; + const LOG_FORMAT: &str = "%Y-%m-%d %H:%M:%S%.6f"; + +-struct SyscareDaemon { ++struct Daemon { + args: Arguments, ++ config: Config, + } + +-impl SyscareDaemon { ++impl Daemon { + fn format_log( + w: &mut dyn std::io::Write, + now: &mut DeferredNow, +@@ -101,9 +109,11 @@ impl SyscareDaemon { + os::umask::set_umask(DAEMON_UMASK); + + let args = Arguments::new()?; ++ fs::create_dir_all(&args.config_dir)?; + fs::create_dir_all(&args.data_dir)?; + fs::create_dir_all(&args.work_dir)?; + fs::create_dir_all(&args.log_dir)?; ++ fs::set_permissions(&args.config_dir, Permissions::from_mode(CONFIG_DIR_PERM))?; + fs::set_permissions(&args.data_dir, Permissions::from_mode(DATA_DIR_PERM))?; + fs::set_permissions(&args.work_dir, Permissions::from_mode(WORK_DIR_PERM))?; + fs::set_permissions(&args.log_dir, Permissions::from_mode(LOG_DIR_PERM))?; +@@ -138,14 +148,29 @@ impl SyscareDaemon { + .start() + .context("Failed to initialize logger")?; + ++ // Initialize config ++ debug!("Initializing configuation..."); ++ let config_file = args.config_dir.join(CONFIG_FILE_NAME); ++ let config = match Config::parse(&config_file) { ++ Ok(config) => config, ++ Err(e) => { ++ warn!("{:?}", e); ++ info!("Using default configuration..."); ++ let config = Config::default(); ++ config.write(&config_file)?; ++ ++ config ++ } ++ }; ++ + // Print panic to log incase it really happens + panic::set_hook(Box::new(|info| error!("{}", info))); + +- Ok(Self { args }) ++ Ok(Self { args, config }) + } + } + +-impl SyscareDaemon { ++impl Daemon { + fn daemonize(&self) -> Result<()> { + if !self.args.daemon { + return Ok(()); +@@ -171,13 +196,24 @@ impl SyscareDaemon { + + fn start_rpc_server(&self, io_handler: IoHandler) -> Result { + let socket_file = self.args.work_dir.join(SOCKET_FILE_NAME); +- let server = ServerBuilder::new(io_handler) +- .set_client_buffer_size(1) +- .start( +- socket_file +- .to_str() +- .context("Failed to convert socket path to string")?, +- )?; ++ let builder = ServerBuilder::new(io_handler).set_client_buffer_size(1); ++ let server = builder.start( ++ socket_file ++ .to_str() ++ .context("Failed to convert socket path to string")?, ++ )?; ++ ++ let socket_owner = Uid::from_raw(self.config.daemon.socket.uid); ++ let socket_group = Gid::from_raw(self.config.daemon.socket.gid); ++ chown(&socket_file, Some(socket_owner), Some(socket_group))?; ++ ++ fs::set_permissions( ++ &socket_file, ++ match socket_owner.as_raw() == socket_group.as_raw() { ++ true => Permissions::from_mode(SOCKET_FILE_PERM_STRICT), ++ false => Permissions::from_mode(SOCKET_FILE_PERM), ++ }, ++ )?; + + Ok(server) + } +@@ -227,7 +263,7 @@ impl SyscareDaemon { + } + + fn main() { +- let daemon = match SyscareDaemon::new() { ++ let daemon = match Daemon::new() { + Ok(instance) => instance, + Err(e) => { + eprintln!("Error: {:?}", e); +diff --git a/upatchd/Cargo.toml b/upatchd/Cargo.toml +index dd9f5ca..fea0859 100644 +--- a/upatchd/Cargo.toml ++++ b/upatchd/Cargo.toml +@@ -14,7 +14,7 @@ anyhow = { version = "1.0" } + clap = { version = "3.2", features = ["cargo", "derive"] } + daemonize = { version = "0.5" } + flexi_logger = { version = "0.24", features = ["compress"] } +-indexmap = { version = "1.9" } ++indexmap = { version = "1.9", features = ["serde"] } + jsonrpc-core = { version = "18.0" } + jsonrpc-derive = { version = "18.0" } + jsonrpc-ipc-server = { version = "18.0" } +diff --git a/upatchd/src/config.rs b/upatchd/src/config.rs +new file mode 100644 +index 0000000..125770d +--- /dev/null ++++ b/upatchd/src/config.rs +@@ -0,0 +1,91 @@ ++// SPDX-License-Identifier: Mulan PSL v2 ++/* ++ * Copyright (c) 2024 Huawei Technologies Co., Ltd. ++ * upatchd 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::Path; ++ ++use anyhow::{anyhow, Result}; ++use serde::{Deserialize, Serialize}; ++use syscare_common::fs; ++ ++use crate::hijacker::HijackerConfig; ++ ++const DEFAULT_SOCKET_UID: u32 = 0; ++const DEFAULT_SOCKET_GID: u32 = 0; ++ ++#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] ++pub struct SocketConfig { ++ pub uid: u32, ++ pub gid: u32, ++} ++ ++impl Default for SocketConfig { ++ fn default() -> Self { ++ Self { ++ uid: DEFAULT_SOCKET_UID, ++ gid: DEFAULT_SOCKET_GID, ++ } ++ } ++} ++ ++#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] ++pub struct DaemonConfig { ++ pub socket: SocketConfig, ++} ++ ++#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] ++pub struct Config { ++ pub daemon: DaemonConfig, ++ pub hijacker: HijackerConfig, ++} ++ ++impl Config { ++ pub fn parse>(path: P) -> Result { ++ let config_path = path.as_ref(); ++ let instance = serde_yaml::from_reader(fs::open_file(config_path)?) ++ .map_err(|_| anyhow!("Failed to parse config {}", config_path.display()))?; ++ ++ Ok(instance) ++ } ++ ++ pub fn write>(&self, path: P) -> Result<()> { ++ let config_path = path.as_ref(); ++ let config_file = fs::create_file(config_path)?; ++ serde_yaml::to_writer(config_file, self) ++ .map_err(|_| anyhow!("Failed to write config {}", config_path.display()))?; ++ ++ Ok(()) ++ } ++} ++ ++#[test] ++fn test() -> Result<()> { ++ use anyhow::{ensure, Context}; ++ use std::path::PathBuf; ++ ++ let tmp_file = PathBuf::from("/tmp/upatchd.yaml"); ++ ++ let orig_cfg = Config::default(); ++ println!("{:#?}", orig_cfg); ++ ++ orig_cfg ++ .write(&tmp_file) ++ .context("Failed to write config")?; ++ ++ let new_cfg = Config::parse(tmp_file).context("Failed to read config")?; ++ println!("{:#?}", new_cfg); ++ ++ ensure!(orig_cfg == new_cfg, "Config does not match"); ++ ++ Ok(()) ++} +diff --git a/upatchd/src/hijacker/config.rs b/upatchd/src/hijacker/config.rs +index f96cc05..5f97fb1 100644 +--- a/upatchd/src/hijacker/config.rs ++++ b/upatchd/src/hijacker/config.rs +@@ -12,15 +12,10 @@ + * See the Mulan PSL v2 for more details. + */ + +-use std::{ +- collections::HashMap, +- ops::Deref, +- path::{Path, PathBuf}, +-}; ++use std::path::PathBuf; + +-use anyhow::{anyhow, Result}; ++use indexmap::{indexmap, IndexMap}; + use serde::{Deserialize, Serialize}; +-use syscare_common::fs; + + const CC_BINARY: &str = "/usr/bin/cc"; + const CXX_BINARY: &str = "/usr/bin/c++"; +@@ -34,73 +29,21 @@ const GCC_HIJACKER: &str = "/usr/libexec/syscare/gcc-hijacker"; + const GXX_HIJACKER: &str = "/usr/libexec/syscare/g++-hijacker"; + const AS_HIJACKER: &str = "/usr/libexec/syscare/as-hijacker"; + +-#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +-pub struct HijackerConfig(HashMap); +- +-impl HijackerConfig { +- pub fn parse_from>(path: P) -> Result { +- let config_path = path.as_ref(); +- let config_file = fs::open_file(config_path)?; +- let instance: Self = serde_yaml::from_reader(config_file) +- .map_err(|_| anyhow!("Failed to parse config {}", config_path.display()))?; +- +- Ok(instance) +- } +- +- pub fn write_to>(&self, path: P) -> Result<()> { +- let config_path = path.as_ref(); +- let config_file = fs::create_file(config_path)?; +- serde_yaml::to_writer(config_file, self) +- .map_err(|_| anyhow!("Failed to write config {}", config_path.display()))?; +- +- Ok(()) +- } +-} +- +-impl Deref for HijackerConfig { +- type Target = HashMap; +- +- fn deref(&self) -> &Self::Target { +- &self.0 +- } ++#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] ++pub struct HijackerConfig { ++ pub mapping: IndexMap, + } + + impl Default for HijackerConfig { + fn default() -> Self { +- let mut map = HashMap::new(); +- map.insert(PathBuf::from(CC_BINARY), PathBuf::from(CC_HIJACKER)); +- map.insert(PathBuf::from(CXX_BINARY), PathBuf::from(CXX_HIJACKER)); +- map.insert(PathBuf::from(GCC_BINARY), PathBuf::from(GCC_HIJACKER)); +- map.insert(PathBuf::from(GXX_BINARY), PathBuf::from(GXX_HIJACKER)); +- map.insert(PathBuf::from(AS_BINARY), PathBuf::from(AS_HIJACKER)); +- +- Self(map) ++ Self { ++ mapping: indexmap! { ++ PathBuf::from(CC_BINARY) => PathBuf::from(CC_HIJACKER), ++ PathBuf::from(CXX_BINARY) => PathBuf::from(CXX_HIJACKER), ++ PathBuf::from(GCC_BINARY) => PathBuf::from(GCC_HIJACKER), ++ PathBuf::from(GXX_BINARY) => PathBuf::from(GXX_HIJACKER), ++ PathBuf::from(AS_BINARY) => PathBuf::from(AS_HIJACKER), ++ }, ++ } + } + } +- +-impl std::fmt::Display for HijackerConfig { +- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +- f.write_fmt(format_args!("{:#?}", &self.0)) +- } +-} +- +-#[test] +-fn test() -> Result<()> { +- use anyhow::{ensure, Context}; +- +- let tmp_file = PathBuf::from("/tmp/upatch_hijacker_config.yaml"); +- +- let orig_cfg = HijackerConfig::default(); +- println!("{}", orig_cfg); +- +- orig_cfg +- .write_to(&tmp_file) +- .context("Failed to write config")?; +- +- let new_cfg = HijackerConfig::parse_from(tmp_file).context("Failed to read config")?; +- println!("{}", new_cfg); +- +- ensure!(orig_cfg == new_cfg, "Config does not match"); +- +- Ok(()) +-} +diff --git a/upatchd/src/hijacker/mod.rs b/upatchd/src/hijacker/mod.rs +index 8ac12e7..d0f2c4d 100644 +--- a/upatchd/src/hijacker/mod.rs ++++ b/upatchd/src/hijacker/mod.rs +@@ -12,7 +12,6 @@ + * See the Mulan PSL v2 for more details. + */ + +-use std::os::unix::prelude::MetadataExt; + use std::path::{Path, PathBuf}; + + use anyhow::{bail, Context, Result}; +@@ -25,14 +24,14 @@ mod elf_resolver; + mod ioctl; + mod kmod; + +-use config::HijackerConfig; ++pub use config::HijackerConfig; + use elf_resolver::ElfResolver; + use ioctl::HijackerIoctl; + use kmod::HijackerKmodGuard; + + const KMOD_NAME: &str = "upatch_hijacker"; + const KMOD_DEV_PATH: &str = "/dev/upatch-hijacker"; +-const KMOD_FILE_PATH: &str = "/usr/libexec/syscare/upatch_hijacker.ko"; ++const KMOD_PATH: &str = "/usr/libexec/syscare/upatch_hijacker.ko"; + + const HIJACK_SYMBOL_NAME: &str = "execve"; + +@@ -43,36 +42,6 @@ pub struct Hijacker { + } + + impl Hijacker { +- fn initialize_config>(config_path: P) -> Result { +- const MODE_EXEC_MASK: u32 = 0o111; +- +- let config = match config_path.as_ref().exists() { +- true => HijackerConfig::parse_from(config_path)?, +- false => { +- info!("Generating default configuration..."); +- let config = HijackerConfig::default(); +- config.write_to(config_path)?; +- +- config +- } +- }; +- +- for hijacker in config.values() { +- let is_executable_file = hijacker +- .symlink_metadata() +- .map(|m| m.is_file() && (m.mode() & MODE_EXEC_MASK != 0)) +- .with_context(|| format!("Failed to read {} metadata", hijacker.display()))?; +- if !is_executable_file { +- bail!( +- "Hijack program {} is not an executable file", +- hijacker.display() +- ); +- } +- } +- +- Ok(config) +- } +- + fn find_symbol_addr(symbol_name: &str) -> Result<(PathBuf, u64)> { + let exec_file = MappedFile::open(os::process::path())?; + let exec_resolver = ElfResolver::new(exec_file.as_bytes())?; +@@ -91,14 +60,9 @@ impl Hijacker { + } + + impl Hijacker { +- pub fn new>(config_path: P) -> Result { +- debug!("Initializing hijacker configuation..."); +- let config = Self::initialize_config(config_path) +- .context("Failed to initialize hijacker configuration")?; +- info!("Using elf mapping: {}", config); +- ++ pub fn new(config: HijackerConfig) -> Result { + debug!("Initializing hijacker kernel module..."); +- let kmod = HijackerKmodGuard::new(KMOD_NAME, KMOD_FILE_PATH)?; ++ let kmod = HijackerKmodGuard::new(KMOD_NAME, KMOD_PATH)?; + + debug!("Initializing hijacker ioctl channel..."); + let ioctl = HijackerIoctl::new(KMOD_DEV_PATH)?; +@@ -113,9 +77,9 @@ impl Hijacker { + ioctl.enable_hijacker(lib_path, offset)?; + + Ok(Self { ++ config, + _kmod: kmod, + ioctl, +- config, + }) + } + } +@@ -124,6 +88,7 @@ impl Hijacker { + fn get_hijacker>(&self, exec_path: P) -> Result<&Path> { + let hijacker = self + .config ++ .mapping + .get(exec_path.as_ref()) + .with_context(|| format!("Cannot find hijacker for {}", exec_path.as_ref().display()))? + .as_path(); +diff --git a/upatchd/src/main.rs b/upatchd/src/main.rs +index 1007ebb..066e53e 100644 +--- a/upatchd/src/main.rs ++++ b/upatchd/src/main.rs +@@ -22,16 +22,19 @@ use flexi_logger::{ + }; + use jsonrpc_core::IoHandler; + use jsonrpc_ipc_server::{Server, ServerBuilder}; +-use log::{error, info, LevelFilter, Record}; ++use log::{debug, error, info, warn, LevelFilter, Record}; ++use nix::unistd::{chown, Gid, Uid}; + use signal_hook::{consts::TERM_SIGNALS, iterator::Signals, low_level::signal_name}; + + use syscare_common::{fs, os}; + + mod args; ++mod config; + mod hijacker; + mod rpc; + + use args::Arguments; ++use config::Config; + use rpc::{Skeleton, SkeletonImpl}; + + const DAEMON_NAME: &str = env!("CARGO_PKG_NAME"); +@@ -46,17 +49,19 @@ const SOCKET_FILE_NAME: &str = "upatchd.sock"; + const CONFIG_DIR_PERM: u32 = 0o700; + const WORK_DIR_PERM: u32 = 0o755; + const LOG_DIR_PERM: u32 = 0o700; +-const SOCKET_FILE_PERM: u32 = 0o666; ++const SOCKET_FILE_PERM: u32 = 0o660; ++const SOCKET_FILE_PERM_STRICT: u32 = 0o600; + + const MAIN_THREAD_NAME: &str = "main"; + const UNNAMED_THREAD_NAME: &str = ""; + const LOG_FORMAT: &str = "%Y-%m-%d %H:%M:%S%.6f"; + +-struct UpatchDaemon { ++struct Daemon { + args: Arguments, ++ config: Config, + } + +-impl UpatchDaemon { ++impl Daemon { + fn format_log( + w: &mut dyn std::io::Write, + now: &mut DeferredNow, +@@ -133,14 +138,28 @@ impl UpatchDaemon { + .start() + .context("Failed to initialize logger")?; + ++ // Initialize config ++ debug!("Initializing configuation..."); ++ let config_file = args.config_dir.join(CONFIG_FILE_NAME); ++ let config = match Config::parse(&config_file) { ++ Ok(config) => config, ++ Err(e) => { ++ warn!("{:?}", e); ++ info!("Using default configuration..."); ++ let config = Config::default(); ++ config.write(&config_file)?; ++ ++ config ++ } ++ }; ++ + // Print panic to log incase it really happens + panic::set_hook(Box::new(|info| error!("{}", info))); +- +- Ok(Self { args }) ++ Ok(Self { args, config }) + } + } + +-impl UpatchDaemon { ++impl Daemon { + fn daemonize(&self) -> Result<()> { + if !self.args.daemon { + return Ok(()); +@@ -156,10 +175,11 @@ impl UpatchDaemon { + } + + fn initialize_skeleton(&self) -> Result { +- let mut io_handler = IoHandler::new(); ++ let config = self.config.hijacker.clone(); ++ let methods = SkeletonImpl::new(config)?.to_delegate(); + +- let config_file = self.args.config_dir.join(CONFIG_FILE_NAME); +- io_handler.extend_with(SkeletonImpl::new(config_file)?.to_delegate()); ++ let mut io_handler = IoHandler::new(); ++ io_handler.extend_with(methods); + + Ok(io_handler) + } +@@ -173,7 +193,17 @@ impl UpatchDaemon { + .context("Failed to convert socket path to string")?, + )?; + +- fs::set_permissions(&socket_file, Permissions::from_mode(SOCKET_FILE_PERM))?; ++ let socket_owner = Uid::from_raw(self.config.daemon.socket.uid); ++ let socket_group = Gid::from_raw(self.config.daemon.socket.gid); ++ chown(&socket_file, Some(socket_owner), Some(socket_group))?; ++ ++ fs::set_permissions( ++ &socket_file, ++ match socket_owner.as_raw() == socket_group.as_raw() { ++ true => Permissions::from_mode(SOCKET_FILE_PERM_STRICT), ++ false => Permissions::from_mode(SOCKET_FILE_PERM), ++ }, ++ )?; + + Ok(server) + } +@@ -183,6 +213,7 @@ impl UpatchDaemon { + info!("Upatch Daemon - {}", DAEMON_VERSION); + info!("================================"); + info!("Start with {:#?}", self.args); ++ info!("Using {:#?}", self.config); + self.daemonize()?; + + info!("Initializing skeleton..."); +@@ -213,7 +244,7 @@ impl UpatchDaemon { + } + + fn main() { +- let daemon = match UpatchDaemon::new() { ++ let daemon = match Daemon::new() { + Ok(instance) => instance, + Err(e) => { + eprintln!("Error: {:?}", e); +diff --git a/upatchd/src/rpc/skeleton_impl.rs b/upatchd/src/rpc/skeleton_impl.rs +index a334120..d725166 100644 +--- a/upatchd/src/rpc/skeleton_impl.rs ++++ b/upatchd/src/rpc/skeleton_impl.rs +@@ -12,12 +12,12 @@ + * See the Mulan PSL v2 for more details. + */ + +-use std::path::{Path, PathBuf}; ++use std::path::PathBuf; + + use anyhow::{Context, Result}; + use log::{debug, info}; + +-use crate::hijacker::Hijacker; ++use crate::hijacker::{Hijacker, HijackerConfig}; + + use super::{ + function::{RpcFunction, RpcResult}, +@@ -29,10 +29,10 @@ pub struct SkeletonImpl { + } + + impl SkeletonImpl { +- pub fn new>(config_path: P) -> Result { ++ pub fn new(config: HijackerConfig) -> Result { + debug!("Initializing hijacker..."); + Ok(Self { +- hijacker: Hijacker::new(config_path).context("Failed to initialize hijacker")?, ++ hijacker: Hijacker::new(config).context("Failed to initialize hijacker")?, + }) + } + } +-- +2.41.0 + diff --git a/0018-upatch-manage-Fixed-the-core-dump-issue-after-applyi.patch b/0018-upatch-manage-Fixed-the-core-dump-issue-after-applyi.patch new file mode 100644 index 0000000..b73a31a --- /dev/null +++ b/0018-upatch-manage-Fixed-the-core-dump-issue-after-applyi.patch @@ -0,0 +1,132 @@ +From 270b6e91dc659aa52bde54facbc744d35fc67de4 Mon Sep 17 00:00:00 2001 +From: ningyu +Date: Sat, 11 May 2024 08:06:58 +0000 +Subject: [PATCH 18/21] upatch-manage: Fixed the core dump issue after applying + hot patches to nginx on x86_64 architecture. + +For non-dynamic library elf, do not place the global variables in the GOT table +--- + upatch-manage/arch/x86_64/resolve.c | 16 ++++++++++++--- + upatch-manage/upatch-elf.c | 32 +++++++++++++++++++++++++++-- + upatch-manage/upatch-elf.h | 5 ++++- + 3 files changed, 47 insertions(+), 6 deletions(-) + +diff --git a/upatch-manage/arch/x86_64/resolve.c b/upatch-manage/arch/x86_64/resolve.c +index 45261dd..5432b20 100644 +--- a/upatch-manage/arch/x86_64/resolve.c ++++ b/upatch-manage/arch/x86_64/resolve.c +@@ -123,10 +123,20 @@ unsigned long insert_got_table(struct upatch_elf *uelf, struct object_file *obj, + goto out; + } + +- elf_addr = setup_got_table(uelf, jmp_addr, tls_addr); ++ if (uelf->relf->info.is_dyn && !uelf->relf->info.is_pie) { ++ elf_addr = setup_got_table(uelf, jmp_addr, tls_addr); ++ ++ log_debug("0x%lx: jmp_addr=0x%lx\n", elf_addr, jmp_addr); ++ ++ } else { ++ /* ++ * For non-dynamic library files, global variables are not placed in the GOT table ++ */ ++ elf_addr = jmp_addr; ++ log_debug("For non-dynamic library: jmp_addr=0x%lx\n", jmp_addr); ++ } + +- log_debug("0x%lx: jmp_addr=0x%lx\n", elf_addr, jmp_addr); + + out: + return elf_addr; +-} +\ No newline at end of file ++} +diff --git a/upatch-manage/upatch-elf.c b/upatch-manage/upatch-elf.c +index 02444eb..c79637d 100644 +--- a/upatch-manage/upatch-elf.c ++++ b/upatch-manage/upatch-elf.c +@@ -132,6 +132,31 @@ int upatch_init(struct upatch_elf *uelf, const char *name) + return 0; + } + ++static bool is_pie_elf(struct running_elf *relf) ++{ ++ GElf_Shdr *shdr = &relf->info.shdrs[relf->index.dynamic]; ++ GElf_Dyn *dyns = (void *)relf->info.hdr + shdr->sh_offset; ++ if (relf->index.dynamic == 0) { ++ return false; ++ } ++ for (Elf64_Xword i = 0; i < shdr->sh_size / sizeof(GElf_Dyn); i++) { ++ log_debug("Syminfo %lx, %lx\n", dyns[i].d_tag, dyns[i].d_un.d_val); ++ if (dyns[i].d_tag == DT_FLAGS_1) { ++ if ((dyns[i].d_un.d_val & DF_1_PIE) != 0) ++ return true; ++ break; ++ } ++ } ++ return false; ++} ++ ++static bool is_dyn_elf(struct running_elf *relf) ++{ ++ GElf_Ehdr *ehdr = relf->info.hdr; ++ ++ return ehdr->e_type == ET_DYN; ++} ++ + int binary_init(struct running_elf *relf, const char *name) + { + int ret = open_elf(&relf->info, name); +@@ -156,7 +181,8 @@ int binary_init(struct running_elf *relf, const char *name) + relf->dynstrtab = (char *)relf->info.hdr + + relf->info.shdrs[relf->info.shdrs[i].sh_link].sh_offset; + } else if (relf->info.shdrs[i].sh_type == SHT_DYNAMIC) { +- /* Currently, we don't utilize it */ ++ log_debug("Found section '%s', idx=%d\n", DYNAMIC_NAME, i); ++ relf->index.dynamic = i; + } else if (streql(sec_name, PLT_RELA_NAME) && + relf->info.shdrs[i].sh_type == SHT_RELA) { + log_debug("Found section '%s', idx=%d\n", PLT_RELA_NAME, i); +@@ -177,7 +203,9 @@ int binary_init(struct running_elf *relf, const char *name) + break; + } + } +- ++ ++ relf->info.is_pie = is_pie_elf(relf); ++ relf->info.is_dyn = is_dyn_elf(relf); + return 0; + } + +diff --git a/upatch-manage/upatch-elf.h b/upatch-manage/upatch-elf.h +index fe68b7e..481fec9 100644 +--- a/upatch-manage/upatch-elf.h ++++ b/upatch-manage/upatch-elf.h +@@ -30,6 +30,7 @@ + + #define SYMTAB_NAME ".symtab" + #define DYNSYM_NAME ".dynsym" ++#define DYNAMIC_NAME ".dynamic" + #define GOT_RELA_NAME ".rela.dyn" + #define PLT_RELA_NAME ".rela.plt" + #define BUILD_ID_NAME ".note.gnu.build-id" +@@ -95,6 +96,8 @@ struct elf_info { + char *shstrtab; + + unsigned int num_build_id; ++ bool is_pie; ++ bool is_dyn; + }; + + struct running_elf { +@@ -111,7 +114,7 @@ struct running_elf { + struct { + unsigned int sym, str; + unsigned int rela_dyn, rela_plt; +- unsigned int dynsym, dynstr; ++ unsigned int dynsym, dynstr, dynamic; + } index; + + /* load bias, used to handle ASLR */ +-- +2.41.0 + diff --git a/0019-upatch-diff-fix-lookup_relf-failed-issue.patch b/0019-upatch-diff-fix-lookup_relf-failed-issue.patch new file mode 100644 index 0000000..8433ae1 --- /dev/null +++ b/0019-upatch-diff-fix-lookup_relf-failed-issue.patch @@ -0,0 +1,144 @@ +From e7baf4fef5dfa7ccbb0d639628a910a8099735ec Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Sat, 11 May 2024 17:31:46 +0800 +Subject: [PATCH 19/21] upatch-diff: fix 'lookup_relf failed' issue + +Signed-off-by: renoseven +--- + upatch-diff/elf-create.c | 24 ++++++++++------- + upatch-diff/running-elf.c | 57 +++++++++++++-------------------------- + 2 files changed, 32 insertions(+), 49 deletions(-) + +diff --git a/upatch-diff/elf-create.c b/upatch-diff/elf-create.c +index de4cb57..873b3a9 100644 +--- a/upatch-diff/elf-create.c ++++ b/upatch-diff/elf-create.c +@@ -135,8 +135,9 @@ void upatch_create_patches_sections(struct upatch_elf *uelf, struct running_elf + + /* find changed func */ + list_for_each_entry(sym, &uelf->symbols, list) { +- if (sym->type != STT_FUNC || sym->status != CHANGED || sym->parent) ++ if (sym->type != STT_FUNC || sym->status != CHANGED || sym->parent) { + continue; ++ } + nr++; + } + +@@ -146,24 +147,27 @@ void upatch_create_patches_sections(struct upatch_elf *uelf, struct running_elf + funcs = sec->data->d_buf; + + strsym = find_symbol_by_name(&uelf->symbols, ".upatch.strings"); +- if (!strsym) +- ERROR("can't find .upatch.strings symbol."); ++ if (!strsym) { ++ ERROR("Cannot find symbol '.upatch.strings'"); ++ } + + list_for_each_entry(sym, &uelf->symbols, list) { +- if (sym->type != STT_FUNC || sym->status != CHANGED || sym->parent) ++ if (sym->type != STT_FUNC || sym->status != CHANGED || sym->parent) { + continue; ++ } + +- if (!lookup_relf(relf, sym, &symbol)) +- ERROR("lookup_relf failed."); ++ if (!lookup_relf(relf, sym, &symbol)) { ++ ERROR("Cannot find symbol '%s' in %s", sym->name, g_relf_name); ++ } + +- if (sym->bind == STB_LOCAL && symbol.global) +- ERROR("can't find local symbol '%s' in symbol table.", sym->name); ++ if (sym->bind == STB_LOCAL && symbol.global) { ++ ERROR("Cannot find local symbol '%s' in symbol table.", sym->name); ++ } + +- log_debug("lookup for %s: symbol name %s sympos=%lu size=%lu .\n", ++ log_debug("lookup for %s: symbol name %s sympos=%lu size=%lu.\n", + sym->name, symbol.symbol->name, symbol.sympos, symbol.symbol->size); + + /* ATTENTION: kpatch convert global symbols to local symbols here. */ +- + funcs[index].old_addr = symbol.symbol->addr; + funcs[index].old_size = symbol.symbol->size; + funcs[index].new_size = sym->sym.st_size; +diff --git a/upatch-diff/running-elf.c b/upatch-diff/running-elf.c +index 037f5fc..3bb35e7 100644 +--- a/upatch-diff/running-elf.c ++++ b/upatch-diff/running-elf.c +@@ -113,55 +113,34 @@ int relf_destroy(struct running_elf *relf) + return 0; + } + +-bool lookup_relf(struct running_elf *relf, struct symbol *lookup_sym, +- struct lookup_result *result) ++bool lookup_relf(struct running_elf *relf, ++ struct symbol *lookup_sym, struct lookup_result *result) + { +- int i; +- struct debug_symbol *sym; ++ struct debug_symbol *symbol = NULL; + unsigned long sympos = 0; +- bool in_file = false; + ++ log_debug("looking up symbol '%s'\n", lookup_sym->name); + memset(result, 0, sizeof(*result)); + +- for (i = 0; i < relf->obj_nr; i ++) { +- sym = &relf->obj_syms[i]; +- if (sym->bind == STB_LOCAL && !strcmp(sym->name, lookup_sym->name)) +- sympos ++; ++ for (int i = 0; i < relf->obj_nr; i++) { ++ symbol = &relf->obj_syms[i]; ++ sympos++; + +- if (lookup_sym->relf_sym == sym) { +- in_file = true; ++ if (strcmp(symbol->name, lookup_sym->name) != 0) { + continue; + } +- +- if (!in_file) +- continue; +- +- if (sym->type == STT_FILE) +- break; +- +- if (sym->bind == STB_LOCAL && !strcmp(sym->name, lookup_sym->name)) { +- if (result->symbol) +- ERROR("duplicate local symbol found for %s", lookup_sym->name); +- +- result->symbol = sym; +- result->sympos = sympos; +- result->global = false; ++ if ((result->symbol != NULL) && ++ (result->symbol->bind == symbol->bind)) { ++ ERROR("Found duplicate symbol '%s' in %s", ++ lookup_sym->name, g_relf_name); + } +- } +- +- if (!!result->symbol) +- return !!result->symbol; + +- for (i = 0; i < relf->obj_nr; i ++) { +- sym = &relf->obj_syms[i]; +- if ((sym->bind == STB_GLOBAL || sym->bind == STB_WEAK) && +- !strcmp(sym->name, lookup_sym->name)) { +- if (result->symbol) +- ERROR("duplicated global symbol for %s \n", lookup_sym->name); +- result->symbol = sym; +- result->global = true; +- } ++ result->symbol = symbol; ++ result->sympos = sympos; ++ result->global = ++ ((symbol->bind == STB_GLOBAL) || (symbol->bind == STB_WEAK)); ++ log_normal("found symbol '%s'\n", lookup_sym->name); + } + +- return !!result->symbol; ++ return (result->symbol != NULL); + } +-- +2.41.0 + diff --git a/0020-upatch-diff-only-check-changed-file-symbols.patch b/0020-upatch-diff-only-check-changed-file-symbols.patch new file mode 100644 index 0000000..d60865e --- /dev/null +++ b/0020-upatch-diff-only-check-changed-file-symbols.patch @@ -0,0 +1,165 @@ +From d3a4f6a47f2151e9828bdfd805ff2af927c80ed9 Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Mon, 13 May 2024 21:27:13 +0800 +Subject: [PATCH 20/21] upatch-diff: only check changed file symbols + +1. sync compare results (SAME/NEW/CHANGED) to correlated objects +2. mark file changes by looking up symbol changes +3. check orignal object & debuginfo when file changes were detected +4. defer symbol check until after calculation changes + +Signed-off-by: renoseven +--- + upatch-diff/create-diff-object.c | 26 +++++++++++++-- + upatch-diff/elf-compare.c | 57 ++++++++++++++++++-------------- + upatch-diff/running-elf.c | 2 +- + 3 files changed, 56 insertions(+), 29 deletions(-) + +diff --git a/upatch-diff/create-diff-object.c b/upatch-diff/create-diff-object.c +index 01c58b8..1a05869 100644 +--- a/upatch-diff/create-diff-object.c ++++ b/upatch-diff/create-diff-object.c +@@ -481,12 +481,32 @@ static void find_debug_symbol(struct upatch_elf *uelf, struct running_elf *relf) + struct symbol *file_sym = NULL; + + list_for_each_entry(file_sym, &uelf->symbols, list) { +- if (file_sym->type == STT_FILE) { ++ if ((file_sym->type == STT_FILE) && (file_sym->status == CHANGED)) { ++ log_debug("file '%s' is CHANGED\n", file_sym->name); + find_local_syms(uelf, relf, file_sym); + } + } + } + ++static void mark_file_symbols(struct upatch_elf *uelf) ++{ ++ struct symbol *curr_sym = NULL; ++ struct symbol *file_sym = NULL; ++ ++ list_for_each_entry(curr_sym, &uelf->symbols, list) { ++ if (curr_sym->type == STT_FILE) { ++ file_sym = curr_sym; ++ continue; ++ } ++ if ((file_sym == NULL) || (file_sym->status == CHANGED)) { ++ continue; ++ } ++ if (curr_sym->status == CHANGED) { ++ file_sym->status = CHANGED; ++ } ++ } ++} ++ + static void mark_grouped_sections(struct upatch_elf *uelf) + { + struct section *groupsec, *sec; +@@ -937,8 +957,6 @@ int main(int argc, char*argv[]) + detect_child_functions(&uelf_source); + detect_child_functions(&uelf_patched); + +- find_debug_symbol(&uelf_source, &relf); +- + mark_grouped_sections(&uelf_patched); + + replace_section_syms(&uelf_source); +@@ -952,6 +970,8 @@ int main(int argc, char*argv[]) + mark_ignored_sections(&uelf_patched); + + upatch_compare_correlated_elements(&uelf_patched); ++ mark_file_symbols(&uelf_source); ++ find_debug_symbol(&uelf_source, &relf); + + mark_ignored_functions_same(&uelf_patched); + mark_ignored_sections_same(&uelf_patched); +diff --git a/upatch-diff/elf-compare.c b/upatch-diff/elf-compare.c +index 9b857b1..ef8dd23 100644 +--- a/upatch-diff/elf-compare.c ++++ b/upatch-diff/elf-compare.c +@@ -336,38 +336,45 @@ static bool line_macro_change_only(struct upatch_elf *uelf, struct section *sec) + return false; + } + ++static inline void update_section_status(struct section *sec, enum status status) ++{ ++ if (sec == NULL) { ++ return; ++ } ++ if (sec->twin != NULL) { ++ sec->twin->status = status; ++ } ++ if (is_rela_section(sec)) { ++ if ((sec->base != NULL) && ++ (sec->base->sym != NULL)) { ++ sec->base->sym->status = status; ++ } ++ } ++ else { ++ if (sec->sym != NULL) { ++ sec->sym->status = status; ++ } ++ } ++} ++ + void upatch_compare_sections(struct upatch_elf *uelf) + { +- struct section *sec; +- struct list_head *seclist = &uelf->sections; ++ struct section *sec = NULL; + +- /* compare all sections */ +- list_for_each_entry(sec, seclist, list) { +- if (sec->twin) +- compare_correlated_section(sec, sec->twin); +- else ++ list_for_each_entry(sec, &uelf->sections, list) { ++ if (sec->twin == NULL) { + sec->status = NEW; +- } +- +- /* exclude WARN-only, might_sleep changes */ +- list_for_each_entry(sec, seclist, list) { ++ } ++ else { ++ compare_correlated_section(sec, sec->twin); ++ } ++ /* exclude WARN-only, might_sleep changes */ + if (line_macro_change_only(uelf, sec)) { + log_debug("reverting macro / line number section %s status to SAME\n", sec->name); + sec->status = SAME; + } +- } +- +- /* sync symbol status */ +- list_for_each_entry(sec, seclist, list) { +- if (is_rela_section(sec)) { +- /* sync bundleable symbol for relocation section */ +- if (sec->base->sym && sec->base->sym->status != CHANGED) +- sec->base->sym->status = sec->status; +- } else { +- struct symbol *sym = sec->sym; +- if (sym && sym->status != CHANGED) +- sym->status = sec->status; +- /* TODO: handle child func */ +- } ++ /* sync status */ ++ update_section_status(sec, sec->status); ++ update_section_status(sec->twin, sec->status); + } + } +\ No newline at end of file +diff --git a/upatch-diff/running-elf.c b/upatch-diff/running-elf.c +index 3bb35e7..676880f 100644 +--- a/upatch-diff/running-elf.c ++++ b/upatch-diff/running-elf.c +@@ -139,7 +139,7 @@ bool lookup_relf(struct running_elf *relf, + result->sympos = sympos; + result->global = + ((symbol->bind == STB_GLOBAL) || (symbol->bind == STB_WEAK)); +- log_normal("found symbol '%s'\n", lookup_sym->name); ++ log_debug("found symbol '%s'\n", lookup_sym->name); + } + + return (result->symbol != NULL); +-- +2.41.0 + diff --git a/0021-upatch-diff-remove-rela-check-while-build-rebuilding.patch b/0021-upatch-diff-remove-rela-check-while-build-rebuilding.patch new file mode 100644 index 0000000..4264e20 --- /dev/null +++ b/0021-upatch-diff-remove-rela-check-while-build-rebuilding.patch @@ -0,0 +1,27 @@ +From 8103b361db40350131bdb7b01124ce1d0f23e09a Mon Sep 17 00:00:00 2001 +From: renoseven +Date: Tue, 14 May 2024 14:10:05 +0800 +Subject: [PATCH 21/21] upatch-diff: remove rela check while build rebuilding + .eh_frame + +Signed-off-by: renoseven +--- + upatch-diff/elf-debug.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/upatch-diff/elf-debug.c b/upatch-diff/elf-debug.c +index 6b5fc53..f9c5327 100644 +--- a/upatch-diff/elf-debug.c ++++ b/upatch-diff/elf-debug.c +@@ -181,8 +181,6 @@ void upatch_rebuild_eh_frame(struct section *sec) + if (found_rela) + break; + } +- if (!found_rela) +- ERROR("No FDE found for relocation at 0x%x \n", offset); + } + + /* +-- +2.41.0 + diff --git a/syscare.spec b/syscare.spec index a3737d1..e09866e 100644 --- a/syscare.spec +++ b/syscare.spec @@ -11,7 +11,7 @@ ############################################ Name: syscare Version: 1.2.1 -Release: 5 +Release: 7 Summary: System hot-fix service License: MulanPSL-2.0 and GPL-2.0-only URL: https://gitee.com/openeuler/syscare @@ -30,6 +30,14 @@ Patch0010: 0010-syscared-stop-activating-ignored-process-on-new-proc.patch Patch0011: 0011-syscared-adapt-upatch-manage-exit-code-change.patch Patch0012: 0012-upatch-manage-change-exit-code.patch Patch0013: 0013-upatch-manage-change-the-way-to-calculate-frozen-tim.patch +Patch0014: 0014-upatch-build-fix-file-detection-cause-build-failure-.patch +Patch0015: 0015-upatch-diff-optimize-log-output.patch +Patch0016: 0016-security-change-directory-permission.patch +Patch0017: 0017-security-change-daemon-socket-permission.patch +Patch0018: 0018-upatch-manage-Fixed-the-core-dump-issue-after-applyi.patch +Patch0019: 0019-upatch-diff-fix-lookup_relf-failed-issue.patch +Patch0020: 0020-upatch-diff-only-check-changed-file-symbols.patch +Patch0021: 0021-upatch-diff-remove-rela-check-while-build-rebuilding.patch BuildRequires: cmake >= 3.14 make BuildRequires: rust >= 1.51 cargo >= 1.51 @@ -104,10 +112,10 @@ fi %files %defattr(-,root,root,-) %dir /usr/libexec/syscare -%attr(644,root,root) /usr/lib/systemd/system/syscare.service -%attr(755,root,root) /usr/bin/syscared -%attr(755,root,root) /usr/bin/syscare -%attr(755,root,root) /usr/libexec/syscare/upatch-manage +%attr(550,root,root) /usr/lib/systemd/system/syscare.service +%attr(550,root,root) /usr/bin/syscared +%attr(555,root,root) /usr/bin/syscare +%attr(550,root,root) /usr/libexec/syscare/upatch-manage ############################################ ########## Package syscare-build ########### @@ -161,24 +169,34 @@ fi %files build %defattr(-,root,root,-) %dir /usr/libexec/syscare -%attr(644,root,root) /usr/lib/systemd/system/upatch.service -%attr(755,root,root) /usr/bin/upatchd -%attr(755,root,root) /usr/libexec/syscare/syscare-build -%attr(755,root,root) /usr/libexec/syscare/upatch-build -%attr(755,root,root) /usr/libexec/syscare/upatch-diff -%attr(755,root,root) /usr/libexec/syscare/as-hijacker -%attr(755,root,root) /usr/libexec/syscare/cc-hijacker -%attr(755,root,root) /usr/libexec/syscare/c++-hijacker -%attr(755,root,root) /usr/libexec/syscare/gcc-hijacker -%attr(755,root,root) /usr/libexec/syscare/g++-hijacker -%attr(755,root,root) /usr/libexec/syscare/gnu-as-hijacker -%attr(755,root,root) /usr/libexec/syscare/gnu-compiler-hijacker -%attr(755,root,root) /usr/libexec/syscare/upatch_hijacker.ko +%attr(550,root,root) /usr/lib/systemd/system/upatch.service +%attr(550,root,root) /usr/bin/upatchd +%attr(555,root,root) /usr/libexec/syscare/syscare-build +%attr(555,root,root) /usr/libexec/syscare/upatch-build +%attr(555,root,root) /usr/libexec/syscare/upatch-diff +%attr(555,root,root) /usr/libexec/syscare/as-hijacker +%attr(555,root,root) /usr/libexec/syscare/cc-hijacker +%attr(555,root,root) /usr/libexec/syscare/c++-hijacker +%attr(555,root,root) /usr/libexec/syscare/gcc-hijacker +%attr(555,root,root) /usr/libexec/syscare/g++-hijacker +%attr(555,root,root) /usr/libexec/syscare/gnu-as-hijacker +%attr(555,root,root) /usr/libexec/syscare/gnu-compiler-hijacker +%attr(440,root,root) /usr/libexec/syscare/upatch_hijacker.ko ############################################ ################ Change log ################ ############################################ %changelog +* Tue May 14 2024 ningyu - 1.2.1-7 +- upatch-diff: remove rela check while build rebuilding .eh_frame +- upatch-diff: only check changed file symbols +* Sat May 11 2024 renoseven - 1.2.1-6 +- upatch-diff: fix 'lookup_elf failed' issue +- upatch-manage: fixed the core dump issue after applying hot patches to nginx on x86_64 architecture +- security: change daemon socket permission +- security: change directory permission +- upatch-build: fix 'file detection cause build failure' issue +- syscared: stop activating ignored process on new process start * Mon May 6 2024 Peng Haitao - 1.2.1-5 - add BuildRequires: kernel-devel * Fri Apr 19 2024 ningyu - 1.2.1-4 -- Gitee