diff --git a/CMakeLists.txt b/CMakeLists.txt index ff219b9b326226887585c311572f0d9ea5edccd6..ca9fdfea4fdb7e6a6e7d4d24084c80bd5b2ae20d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,14 +53,14 @@ endif() # Build flags list(APPEND PROJECT_C_BUILD_FLAGS - -std=gnu99 -g -Wall -O2 -Werror -Wextra + -std=gnu99 -Wall -O2 -Werror -Wextra -DBUILD_VERSION="${PROJECT_BUILD_VERSION}" -D_FORTIFY_SOURCE=2 -Wtrampolines -Wformat=2 -Wstrict-prototypes -Wdate-time -Wstack-usage=8192 -Wfloat-equal -Wswitch-default -Wshadow -Wconversion -Wcast-qual -Wcast-align -Wunused -Wundef -funsigned-char -fstack-protector-all -fpic -fpie -ftrapv -fstack-check -freg-struct-return -fno-canonical-system-headers - -pipe -fdebug-prefix-map=old=new + -fno-common -pipe -fdebug-prefix-map=old=new ) list(APPEND PROJECT_RUST_FLAGS --cfg unsound_local_offset @@ -80,6 +80,12 @@ list(APPEND PROJECT_C_LINK_FLAGS -Wl,-no-undefined ) +if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + list(APPEND PROJECT_C_BUILD_FLAGS -g) +elseif(CMAKE_BUILD_TYPE STREQUAL "Release") + list(APPEND PROJECT_C_LINK_FLAGS -s) +endif() + # Install directories set(SYSCARE_BINARY_DIR "${CMAKE_INSTALL_FULL_BINDIR}") set(SYSCARE_LIBEXEC_DIR "${CMAKE_INSTALL_FULL_LIBEXECDIR}/syscare") @@ -94,7 +100,8 @@ message("╚════██║ ╚██╔╝ ╚════██║█ message("███████║ ██║ ███████║╚██████╗██║ ██║██║ ██║███████╗") message("╚══════╝ ╚═╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝") message("---------------------------------------------------------") -message("-- Verion: ${PROJECT_BUILD_VERSION}") +message("-- Build type: ${CMAKE_BUILD_TYPE}") +message("-- Build version: ${PROJECT_BUILD_VERSION}") message("-- Rust flags: ${PROJECT_RUST_FLAGS}") message("-- Build flags: ${PROJECT_C_BUILD_FLAGS}") message("-- Link flags: ${PROJECT_C_LINK_FLAGS}") diff --git a/Cargo.lock b/Cargo.lock index 30f2015e89f850a24f853cb7cb2a8ef61b4502a1..6ae9f369b98cf24c63559a072a55fa3ce0e8820e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -210,16 +210,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctrlc" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d778600249295e82b6ab12e291ed9029407efee0cfb7baf67157edc65964df" -dependencies = [ - "nix", - "windows-sys", -] - [[package]] name = "daemonize" version = "0.5.0" @@ -1140,7 +1130,6 @@ dependencies = [ "anyhow", "chrono", "clap", - "ctrlc", "flexi_logger", "lazy_static", "log", @@ -1317,7 +1306,6 @@ version = "1.2.2" dependencies = [ "anyhow", "clap", - "ctrlc", "flexi_logger", "function_name", "gimli", @@ -1474,15 +1462,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-targets" version = "0.48.5" diff --git a/syscare-build/Cargo.toml b/syscare-build/Cargo.toml index 558b2bcc778cf1834737872c11b55bbd0f825e65..ba4d1c8b230c63e8aa0b777c66732ca829f0a526 100644 --- a/syscare-build/Cargo.toml +++ b/syscare-build/Cargo.toml @@ -14,7 +14,6 @@ syscare-common = { package = "syscare-common", path = "../syscare-common" } anyhow = { version = "1.0" } clap = { version = "3.2", features = ["derive"] } chrono = { version = "0.4" } -ctrlc = { version = "3.3" } flexi_logger = { version = "0.24" } lazy_static = { version = "1.0" } log = { version = "0.4" } diff --git a/syscare-build/src/main.rs b/syscare-build/src/main.rs index 2fb714da228c3e486058ab195d01380e37d667fd..64363bf4e90aaf3f181c7c3291acac89f0a6e044 100644 --- a/syscare-build/src/main.rs +++ b/syscare-build/src/main.rs @@ -103,12 +103,6 @@ impl SyscareBuild { .start() .context("Failed to initialize logger")?; - // Initialize signal handler - ctrlc::set_handler(|| { - eprintln!("Interrupt"); - }) - .context("Failed to initialize signal handler")?; - Ok(Self { args, logger, diff --git a/syscare-build/src/package/rpm/mod.rs b/syscare-build/src/package/rpm/mod.rs index 4054f67c713e4e0a996a8a4c2dc0799a32984ed7..ee7f19f665baa5f73b42e009e74b779579df3ef4 100644 --- a/syscare-build/src/package/rpm/mod.rs +++ b/syscare-build/src/package/rpm/mod.rs @@ -50,6 +50,7 @@ impl RpmPackage { .arg("--query") .arg("--queryformat") .arg(format) + .arg("--nosignature") .arg("--package") .arg(pkg_path.as_ref().as_os_str()) .run_with_output()?; @@ -106,6 +107,7 @@ impl Package for RpmPackage { let output = Command::new(RPM_BIN) .arg("--query") .arg("--list") + .arg("--nosignature") .arg("--package") .arg(pkg_path) .run_with_output()?; diff --git a/syscare-common/src/ffi/os_str.rs b/syscare-common/src/ffi/os_str.rs index 375ef82069b5767b6ba4b1cc7c80afff9ab4cc86..0c414e1875f079ba05a496a34e8c67996764db47 100644 --- a/syscare-common/src/ffi/os_str.rs +++ b/syscare-common/src/ffi/os_str.rs @@ -119,7 +119,7 @@ pub trait OsStrExt: AsRef { } } - fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split

{ + fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { let haystack = self.as_ref().as_bytes(); Split(SplitImpl { diff --git a/syscare-common/src/fs/fs_impl.rs b/syscare-common/src/fs/fs_impl.rs index 23f849354582225de910d244b7d9b5115c0a7db4..30c11b78e5414d872897659b9824a23dabfeed39 100644 --- a/syscare-common/src/fs/fs_impl.rs +++ b/syscare-common/src/fs/fs_impl.rs @@ -379,10 +379,10 @@ where if !file_type.is_file() { return false; } - return file_path + file_path .extension() .map(|s| s == ext.as_ref()) - .unwrap_or(false); + .unwrap_or(false) }) } diff --git a/syscare-common/src/os_str/iter.rs b/syscare-common/src/os_str/iter.rs index 2868c2e8ffa00352b9720e1ccb5d411f3d1816bf..e472d0ca568f44d08a85b84dbc6c7a2f9495f861 100644 --- a/syscare-common/src/os_str/iter.rs +++ b/syscare-common/src/os_str/iter.rs @@ -165,7 +165,7 @@ impl<'a, P: Pattern<'a>> SplitImpl<'a, P> { } self.finished = true; - return Some(OsStr::from_bytes(&haystack[self.position..])); + Some(OsStr::from_bytes(&haystack[self.position..])) } } diff --git a/syscare-common/src/process/stdio.rs b/syscare-common/src/process/stdio.rs index 450019aec8d3ebc0ef9c632f2ef8ab93b2e491a3..9a93e563f4db79c4ba01b326d54a7bd6b89aeca0 100644 --- a/syscare-common/src/process/stdio.rs +++ b/syscare-common/src/process/stdio.rs @@ -160,10 +160,10 @@ impl Stdio { } } } - if stdout_buf.ends_with(&[b'\n']) { + if stdout_buf.ends_with(b"\n") { stdout_buf.pop(); } - if stderr_buf.ends_with(&[b'\n']) { + if stderr_buf.ends_with(b"\n") { stderr_buf.pop(); } diff --git a/syscare/src/args.rs b/syscare/src/args.rs index 4f034a08f879afa525bf6f74468aa08851991b42..5e7299dec47f58dbd78c9f5fd4eb2695e33e87db 100644 --- a/syscare/src/args.rs +++ b/syscare/src/args.rs @@ -14,7 +14,7 @@ use std::path::PathBuf; -use anyhow::{ensure, Result}; +use anyhow::Result; use clap::{AppSettings, ColorChoice, Parser, Subcommand}; use syscare_common::fs; @@ -131,7 +131,7 @@ pub enum SubCommand { impl Arguments { pub fn new() -> Result { - Self::parse().normalize_path().and_then(Self::check) + Self::parse().normalize_path() } fn normalize_path(mut self) -> Result { @@ -139,16 +139,6 @@ impl Arguments { Ok(self) } - - fn check(self) -> Result { - let work_dir = &self.work_dir; - ensure!( - work_dir.is_dir(), - format!("Cannot find directory {}", work_dir.display()) - ); - - Ok(self) - } } impl std::fmt::Display for Arguments { diff --git a/syscared/src/args.rs b/syscared/src/args.rs index 4c28dffd8c664921dc3c8733673e3a8ed23fa37d..f98b54b23dcb93fc51717cc854d084496558ed2f 100644 --- a/syscared/src/args.rs +++ b/syscared/src/args.rs @@ -37,7 +37,6 @@ const DEFAULT_LOG_LEVEL: &str = "info"; global_setting(AppSettings::DeriveDisplayOrder), term_width(120), )] - pub struct Arguments { /// Run as a daemon #[clap(short, long)] diff --git a/syscared/src/patch/resolver/kpatch.rs b/syscared/src/patch/resolver/kpatch.rs index 85ec18e376a78b1b474a30d6da87907d315c5c1e..863f65b4e62052ed6a0215db898453a2d26f3a0d 100644 --- a/syscared/src/patch/resolver/kpatch.rs +++ b/syscared/src/patch/resolver/kpatch.rs @@ -86,7 +86,7 @@ mod ffi { } } - impl<'data, 'file, Elf: FileHeader> Iterator for KpatchRelocationIterator<'data, 'file, Elf> { + impl Iterator for KpatchRelocationIterator<'_, '_, Elf> { type Item = KpatchRelocation; fn next(&mut self) -> Option { diff --git a/syscared/src/patch/resolver/upatch.rs b/syscared/src/patch/resolver/upatch.rs index e8c2f2cb8f8606f7496a56baa0a067d1319a5edf..e49dff9e1ff1a946df188600927dd1e882e05bcf 100644 --- a/syscared/src/patch/resolver/upatch.rs +++ b/syscared/src/patch/resolver/upatch.rs @@ -73,7 +73,7 @@ mod ffi { } } - impl<'data, 'file, Elf: FileHeader> Iterator for UpatchRelocationIterator<'data, 'file, Elf> { + impl Iterator for UpatchRelocationIterator<'_, '_, Elf> { type Item = UpatchRelocation; fn next(&mut self) -> Option { diff --git a/upatch-build/Cargo.toml b/upatch-build/Cargo.toml index 512314906493480ee5f76c5f12465633352e3fc7..88d88b3c16393e136af272948c3f7a82174e8f52 100644 --- a/upatch-build/Cargo.toml +++ b/upatch-build/Cargo.toml @@ -12,7 +12,6 @@ build = "build.rs" syscare-common = { package = "syscare-common", path = "../syscare-common" } anyhow = { version = "1.0" } clap = { version = "3.2", features = ["cargo", "derive"] } -ctrlc = { version = "3.3" } flexi_logger = { version = "0.24" } function_name = { version = "0.3" } gimli = { version = "0.26" } diff --git a/upatch-build/src/dwarf/mod.rs b/upatch-build/src/dwarf/mod.rs index 0c172c56b210b3e06c06002a4f6659fccd6324fe..4399b51f3cff921728e7d2d05725bea35c8c9c46 100644 --- a/upatch-build/src/dwarf/mod.rs +++ b/upatch-build/src/dwarf/mod.rs @@ -233,13 +233,13 @@ impl Dwarf { while let Some(attr) = attrs.next()? { match attr.name() { constants::DW_AT_comp_dir => { - element.compile_dir.push(&Self::attr_value(&attr, dwarf)); + element.compile_dir.push(Self::attr_value(&attr, dwarf)); } constants::DW_AT_name => { - element.file_name.push(&Self::attr_value(&attr, dwarf)); + element.file_name.push(Self::attr_value(&attr, dwarf)); } constants::DW_AT_producer => { - element.producer.push(&Self::attr_value(&attr, dwarf)); + element.producer.push(Self::attr_value(&attr, dwarf)); } _ => continue, } diff --git a/upatch-build/src/dwarf/relocate.rs b/upatch-build/src/dwarf/relocate.rs index e8c7cdfb8295c8bfe1119f657b323436f13491f1..a6e8fb9e22ab8cf203f841ba1e69e142c9b188af 100644 --- a/upatch-build/src/dwarf/relocate.rs +++ b/upatch-build/src/dwarf/relocate.rs @@ -25,7 +25,7 @@ pub struct Relocate<'a, R: gimli::Reader> { pub reader: R, } -impl<'a, R: gimli::Reader> Relocate<'a, R> { +impl> Relocate<'_, R> { pub fn relocate(&self, offset: usize, value: u64) -> u64 { if let Some(relocation) = self.relocations.get(&offset) { if relocation.kind() == object::RelocationKind::Absolute { @@ -41,7 +41,7 @@ impl<'a, R: gimli::Reader> Relocate<'a, R> { } } -impl<'a, R: gimli::Reader> gimli::Reader for Relocate<'a, R> { +impl> gimli::Reader for Relocate<'_, R> { type Endian = R::Endian; type Offset = R::Offset; diff --git a/upatch-build/src/main.rs b/upatch-build/src/main.rs index 77b256a703f3a6a00bf2c19940028647aabfbc64..09f907b7b127374d1c4cec7f78d14630cbe2f81f 100644 --- a/upatch-build/src/main.rs +++ b/upatch-build/src/main.rs @@ -98,12 +98,6 @@ impl UpatchBuild { .start() .context("Failed to initialize logger")?; - // Initialize signal handler - ctrlc::set_handler(|| { - eprintln!("Interrupt"); - }) - .context("Failed to initialize signal handler")?; - Ok(Self { args, logger, diff --git a/upatch-diff/create-diff-object.c b/upatch-diff/create-diff-object.c index 02d43c21b4b734c483238205cb0e92230b09727c..1c14b7a43e79b2d9759d6b8dfa0e33cca2f47608 100644 --- a/upatch-diff/create-diff-object.c +++ b/upatch-diff/create-diff-object.c @@ -680,24 +680,26 @@ static void replace_section_syms(struct upatch_elf *uelf) static void mark_ignored_sections(struct upatch_elf *uelf) { - /* Ignore any discarded sections */ - struct section *sec; + static const char *const IGNORED_SECTIONS[] = { + ".comment", + ".discard", + ".rela.discard", + ".GCC.command.line", + }; - list_for_each_entry(sec, &uelf->sections, list) { - if (!strncmp(sec->name, ".discard", strlen(".discard")) || - !strncmp(sec->name, ".rela.discard", strlen(".rela.discard"))) { - log_debug("Found discard section '%s'\n", sec->name); - sec->ignore = 1; + for (size_t i = 0; i < ARRAY_SIZE(IGNORED_SECTIONS); i++) { + const char *const ignored_name = IGNORED_SECTIONS[i]; + const size_t name_len = strlen(ignored_name); + + struct section *sec = NULL; + list_for_each_entry(sec, &uelf->sections, list) { + if (strncmp(sec->name, ignored_name, name_len) == 0) { + sec->status = SAME; + break; + } } } - - /* TODO: handle ignore information from sections or settings */ } - -/* TODO: we do not handle it now */ -static void mark_ignored_functions_same(void) {} -static void mark_ignored_sections_same(void) {} - /* * For a local symbol referenced in the rela list of a changing function, * if it has no section, it will link error in arm. @@ -1053,9 +1055,6 @@ int main(int argc, char*argv[]) mark_file_symbols(&uelf_source); find_debug_symbol(&uelf_source, &relf); - mark_ignored_functions_same(); - mark_ignored_sections_same(); - include_standard_elements(&uelf_patched); num_changed = include_changed_functions(&uelf_patched); diff --git a/upatch-diff/elf-common.h b/upatch-diff/elf-common.h index f5a48da6665603a57a5eb2a57bb81b9979f9ff9a..bc2c1acf550c70297018509ed041da22ab6ae366 100644 --- a/upatch-diff/elf-common.h +++ b/upatch-diff/elf-common.h @@ -35,6 +35,8 @@ #include "list.h" #include "log.h" +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + #define ALLOC_LINK(_new, _list) \ do { \ (_new) = calloc(1, sizeof(*(_new))); \ diff --git a/upatch-diff/elf-debug.c b/upatch-diff/elf-debug.c index 677b8bcedfa19bfab8caa25ab0ce144db1ec7312..9d2641a13488c35c18c54ac415a690e2b4ebb11e 100644 --- a/upatch-diff/elf-debug.c +++ b/upatch-diff/elf-debug.c @@ -33,19 +33,70 @@ void upatch_print_changes(struct upatch_elf *uelf) { - struct symbol *sym; + struct symbol *sym = NULL; + struct section *sec = NULL; + log_normal("------------------------------\n"); + log_normal("New symbol\n"); + log_normal("------------------------------\n"); list_for_each_entry(sym, &uelf->symbols, list) { - if (!sym->include || !sym->sec || - sym->type != STT_FUNC || sym->parent) { - continue; - } if (sym->status == NEW) { - log_normal("New function: %s\n", sym->name); - } else if (sym->status == CHANGED) { - log_normal("Changed function: %s\n", sym->name); + log_normal("idx: %04u, name: '%s'\n", sym->index, sym->name); + } + } + log_normal("------------------------------\n"); + log_normal("\n"); + log_normal("------------------------------\n"); + log_normal("New section\n"); + log_normal("------------------------------\n"); + list_for_each_entry(sec, &uelf->sections, list) { + if (sec->status == NEW) { + log_normal("idx: %04u, name: '%s'\n", sec->index, sec->name); + } + } + log_normal("------------------------------\n"); + log_normal("\n"); + log_normal("------------------------------\n"); + log_normal("Changed symbol\n"); + log_normal("------------------------------\n"); + list_for_each_entry(sym, &uelf->symbols, list) { + if (sym->status == CHANGED) { + log_normal("idx: %04u, name: '%s'\n", sym->index, sym->name); + } + } + log_normal("------------------------------\n"); + log_normal("\n"); + log_normal("------------------------------\n"); + log_normal("Changed section\n"); + log_normal("------------------------------\n"); + list_for_each_entry(sec, &uelf->sections, list) { + if (sec->status == CHANGED) { + log_normal("idx: %04u, name: '%s'\n", sec->index, sec->name); + } + } + log_normal("------------------------------\n"); + log_normal("\n"); + log_normal("------------------------------\n"); + log_normal("Included symbol\n"); + log_normal("------------------------------\n"); + list_for_each_entry(sym, &uelf->symbols, list) { + if (sym->include != 0) { + log_normal("idx: %04u, name: '%s', status: %s\n", + sym->index, sym->name, status_str(sym->status)); + } + } + log_normal("------------------------------\n"); + log_normal("\n"); + log_normal("------------------------------\n"); + log_normal("Included section\n"); + log_normal("------------------------------\n"); + list_for_each_entry(sec, &uelf->sections, list) { + if (sec->include != 0) { + log_normal("idx: %04u, name: '%s', status: %s\n", + sec->index, sec->name, status_str(sec->status)); } } + log_normal("------------------------------\n"); } void upatch_dump_kelf(struct upatch_elf *uelf) diff --git a/upatch-manage/arch/aarch64/insn.c b/upatch-manage/arch/aarch64/insn.c index 63f6227d2744b9501ee770aac47eeb742ed948f7..9a775a5a93d040a648c62565873bc69f45182aea 100644 --- a/upatch-manage/arch/aarch64/insn.c +++ b/upatch-manage/arch/aarch64/insn.c @@ -114,7 +114,7 @@ s64 extract_insn_imm(s64 sval, int len, int lsb) imm_mask = (s64)((BIT(lsb + len) - 1) >> lsb); imm = imm & imm_mask; - log_debug("upatch: extract imm, X=0x%lx, X[%d:%d]=0x%lx\n", + log_debug("imm: insn=0x%lx, insn[%d:%d]=0x%lx\n", sval, (len + lsb - 1), lsb, imm); return imm; } @@ -124,8 +124,7 @@ s32 insert_insn_imm(enum aarch64_insn_imm_type imm_type, void *place, u64 imm) u32 insn = le32_to_cpu(*(__le32 *)place); u32 new_insn = aarch64_insn_encode_immediate(imm_type, insn, imm); - log_debug("upatch: inset imm" - "P=0x%lx, insn=0x%x, imm_type=%d, imm=0x%lx, new_insn=0x%x\n", - (u64)place, insn, imm_type, imm, new_insn); + log_debug("insn: insn=0x%x, imm_type=%d, imm=0x%lx, new_insn=0x%x\n", + insn, imm_type, imm, new_insn); return (s32)new_insn; } diff --git a/upatch-manage/arch/aarch64/relocation.c b/upatch-manage/arch/aarch64/relocation.c index 57e864cc0074b123bb42d0b7418e74e449834300..80a817d8a160c767f207045e355295e198826297 100644 --- a/upatch-manage/arch/aarch64/relocation.c +++ b/upatch-manage/arch/aarch64/relocation.c @@ -54,8 +54,7 @@ static inline s64 calc_reloc(enum aarch64_reloc_op op, void *place, u64 val) break; } - log_debug("upatch: reloc, S+A=0x%lx, P=0x%lx, X=0x%lx\n", - val, (u64)place, sval); + log_debug("reloc: S+A=0x%lx, P=0x%lx, X=0x%lx\n", val, (u64)place, sval); return sval; } @@ -68,6 +67,7 @@ int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, void *loc; void *uloc; u64 val; + u64 got; s64 result; GElf_Shdr *shdrs = (void *)uelf->info.shdrs; GElf_Rela *rel = (void *)shdrs[relsec].sh_addr; @@ -92,7 +92,7 @@ int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, /* val corresponds to (S + A) */ val = (unsigned long)sym->st_value + (unsigned long)rel[i].r_addend; log_debug( - "upatch: reloc symbol, name=%s, k_addr=0x%lx, u_addr=0x%lx, " + "\nsymbol='%s', k_addr=0x%lx, u_addr=0x%lx, " "r_offset=0x%lx, st_value=0x%lx, r_addend=0x%lx\n", sym_name, shdrs[shdrs[relsec].sh_info].sh_addr, shdrs[shdrs[relsec].sh_info].sh_addralign, @@ -155,7 +155,6 @@ int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, if (result < -(s64)BIT(20) || result >= (s64)BIT(20)) { goto overflow; } - result = extract_insn_imm(result, 21, 0); result = insert_insn_imm(AARCH64_INSN_IMM_ADR, loc, (unsigned long)result); @@ -253,7 +252,11 @@ int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, *(__le32 *)loc = cpu_to_le32((__le32)result); break; case R_AARCH64_ADR_GOT_PAGE: - result = calc_reloc(RELOC_OP_PAGE, uloc, val); + got = (u64)setup_got_table(uelf, val, 0); + if (got == 0) { + goto overflow; + } + result = calc_reloc(RELOC_OP_PAGE, uloc, got); if (result < -(s64)BIT(32) || result >= (s64)BIT(32)) { goto overflow; } @@ -263,7 +266,11 @@ int apply_relocate_add(struct upatch_elf *uelf, unsigned int symindex, *(__le32 *)loc = cpu_to_le32((__le32)result); break; case R_AARCH64_LD64_GOT_LO12_NC: - result = calc_reloc(RELOC_OP_ABS, uloc, val); + got = (u64)setup_got_table(uelf, val, 0); + if (got == 0) { + goto overflow; + } + result = calc_reloc(RELOC_OP_ABS, uloc, got); // don't check result & 7 == 0. // sometimes, result & 7 != 0, it works fine. result = extract_insn_imm(result, 9, 3); diff --git a/upatch-manage/arch/aarch64/resolve.c b/upatch-manage/arch/aarch64/resolve.c index 5e0ddeafc54f1b1beae9e85fedf3bb1cb8525fb2..63ebb0fa30af0c680db23e3c3fec466930cf783f 100644 --- a/upatch-manage/arch/aarch64/resolve.c +++ b/upatch-manage/arch/aarch64/resolve.c @@ -65,7 +65,7 @@ static unsigned long setup_jmp_table(struct upatch_elf *uelf, index * sizeof(struct upatch_jmp_table_entry)); } -static unsigned long setup_got_table(struct upatch_elf *uelf, +unsigned long setup_got_table(struct upatch_elf *uelf, unsigned long jmp_addr, unsigned long tls_addr) { struct upatch_jmp_table_entry *table = uelf->core_layout.kbase + @@ -135,7 +135,10 @@ 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); + elf_addr = jmp_addr; + if (r_type != R_AARCH64_GLOB_DAT) { + elf_addr = setup_got_table(uelf, jmp_addr, tls_addr); + } log_debug("0x%lx: jmp_addr=0x%lx, tls_addr=0x%lx\n", elf_addr, jmp_addr, tls_addr); diff --git a/upatch-manage/arch/x86_64/resolve.c b/upatch-manage/arch/x86_64/resolve.c index 71b303a9c78e1bf9ac3da6000bc567281f71cf6b..405c90c8e4b28922bc2dab88e732d10f8926e32b 100644 --- a/upatch-manage/arch/x86_64/resolve.c +++ b/upatch-manage/arch/x86_64/resolve.c @@ -61,7 +61,7 @@ static unsigned long setup_jmp_table(struct upatch_elf *uelf, * GOT only need record address and resolve it by [got_addr]. * To simplify design, use same table for both jmp table and GOT. */ -static unsigned long setup_got_table(struct upatch_elf *uelf, +unsigned long setup_got_table(struct upatch_elf *uelf, unsigned long jmp_addr, unsigned long tls_addr) { struct upatch_jmp_table_entry *table = uelf->core_layout.kbase + diff --git a/upatch-manage/upatch-elf.c b/upatch-manage/upatch-elf.c index 93cb0b20369dc6dd4d2b58b3c2156c89e6eb864e..f3773f90d7a82c9fa9edd99f8c145e58cbed5d41 100644 --- a/upatch-manage/upatch-elf.c +++ b/upatch-manage/upatch-elf.c @@ -49,7 +49,6 @@ static int open_elf(struct elf_info *einfo, const char *name) { int ret = 0; int fd = -1; - char *sec_name; struct stat st; fd = open(name, O_RDONLY); @@ -89,21 +88,6 @@ static int open_elf(struct elf_info *einfo, const char *name) goto out; } - for (unsigned int i = 0; i < einfo->hdr->e_shnum; ++i) { - sec_name = einfo->shstrtab + einfo->shdrs[i].sh_name; - if (streql(sec_name, BUILD_ID_NAME) && - einfo->shdrs[i].sh_type == SHT_NOTE) { - einfo->num_build_id = i; - break; - } - } - - if (einfo->num_build_id == 0) { - ret = -EINVAL; - log_error("Cannot find section '%s'\n", BUILD_ID_NAME); - goto out; - } - ret = 0; out: @@ -220,26 +204,6 @@ int binary_init(struct running_elf *relf, const char *name) return 0; } -bool check_build_id(struct elf_info *uelf, struct elf_info *relf) -{ - GElf_Shdr *uelf_shdr = &uelf->shdrs[uelf->num_build_id]; - GElf_Shdr *relf_shdr = &relf->shdrs[uelf->num_build_id]; - - if (uelf_shdr->sh_size != relf_shdr->sh_size) { - return false; - } - - void* uelf_build_id = (void *)uelf->hdr + uelf_shdr->sh_offset; - void* relf_build_id = (void *)relf->hdr + relf_shdr->sh_offset; - size_t build_id_len = uelf_shdr->sh_size; - - if (memcmp(uelf_build_id, relf_build_id, build_id_len) != 0) { - return false; - } - - return true; -} - void binary_close(struct running_elf *relf) { if (relf->info.patch_buff) { diff --git a/upatch-manage/upatch-elf.h b/upatch-manage/upatch-elf.h index 18e0d2cadb7dd4f9a5e055b6fbbb2f0950b0c1a5..6f62c7df0e108cebd70e8258f86cb9f919a49e9d 100644 --- a/upatch-manage/upatch-elf.h +++ b/upatch-manage/upatch-elf.h @@ -39,7 +39,7 @@ #define TDATA_NAME ".tdata" #define TBSS_NAME ".tbss" -#define JMP_TABLE_MAX_ENTRY 100 +#define JMP_TABLE_MAX_ENTRY 4096 #define UPATCH_HEADER "UPATCH" #define UPATCH_HEADER_LEN 6 #define UPATCH_ID_LEN 40 @@ -156,8 +156,6 @@ int binary_init(struct running_elf *, const char *); void upatch_close(struct upatch_elf *); void binary_close(struct running_elf *); -bool check_build_id(struct elf_info *, struct elf_info *); - bool is_upatch_section(const char *); bool is_note_section(GElf_Word); diff --git a/upatch-manage/upatch-patch.c b/upatch-manage/upatch-patch.c index 819b966eb602bdd3492642739ccd97acb19c5b2d..4a1e5689d280930862d89a8f2a1333c612648430 100644 --- a/upatch-manage/upatch-patch.c +++ b/upatch-manage/upatch-patch.c @@ -259,28 +259,36 @@ static void layout_symtab(struct upatch_elf *uelf) log_debug("\t%s\n", uelf->info.shstrtab + strsect->sh_name); } -static void *upatch_alloc(struct object_file *obj, size_t sz) +static void *upatch_alloc(struct object_file *obj, size_t len) { - struct vm_hole *hole = NULL; + struct upatch_ptrace_ctx *pctx = proc2pctx(obj->proc); + if (pctx == NULL) { + log_error("Failed to find process context\n"); + return NULL; + } - unsigned long addr = object_find_patch_region(obj, sz, &hole); - if (!addr) { + log_debug("Finding patch region for '%s', len=0x%lx\n", obj->name, len); + struct vm_hole *hole = find_patch_region(obj, len); + if (hole == NULL) { + log_error("Failed to find patch region for '%s'\n", obj->name); return NULL; } - addr = upatch_mmap_remote(proc2pctx(obj->proc), addr, sz, + uintptr_t addr = PAGE_ALIGN(hole->start); + log_debug("Found patch region at 0x%lx, size=0x%lx\n", addr, len); + + addr = upatch_mmap_remote(pctx, addr, len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, (unsigned long)-1, 0); if (addr == 0) { + log_error("Failed to map patch region, ret=%d\n", errno); return NULL; } - log_debug("Allocated 0x%lx bytes at 0x%lx of '%s'\n", sz, addr, obj->name); - int ret = vm_hole_split(hole, addr, addr + sz); - if (ret) { - // TODO: clear - log_error("Failed to split vm hole\n"); + int ret = vm_hole_split(hole, addr, (addr + len)); + if (ret != 0) { + log_error("Failed to split vm hole, ret=%d\n", ret); return NULL; } @@ -295,31 +303,21 @@ static void upatch_free(struct object_file *obj, void *base, unsigned long size) } } -static int __alloc_memory(struct object_file *obj_file, - struct upatch_layout *layout) +static int alloc_memory(struct upatch_elf *uelf, struct object_file *obj) { - /* Do the allocs. */ - layout->base = upatch_alloc(obj_file, layout->size); - if (!layout->base) { - return -errno; - } + struct upatch_layout *layout = &uelf->core_layout; - layout->kbase = malloc(layout->size); - if (!layout->kbase) { - upatch_free(obj_file, layout->base, layout->size); - return -errno; + layout->base = upatch_alloc(obj, layout->size); + if (layout->base == NULL) { + log_error("Failed to alloc patch memory\n"); + return ENOMEM; } - memset(layout->kbase, 0, layout->size); - - return 0; -} - -static int alloc_memory(struct upatch_elf *uelf, struct object_file *obj) -{ - int ret = __alloc_memory(obj, &uelf->core_layout); - if (ret) { - return ret; + layout->kbase = calloc(1, layout->size); + if (!layout->kbase) { + log_error("Failed to alloc memory\n"); + upatch_free(obj, layout->base, layout->size); + return ENOMEM; } /* Transfer each section which specifies SHF_ALLOC */ @@ -331,17 +329,17 @@ static int alloc_memory(struct upatch_elf *uelf, struct object_file *obj) continue; } - void *kdest = uelf->core_layout.kbase + shdr->sh_entsize; - void *dest = uelf->core_layout.base + shdr->sh_entsize; + void *dest = layout->base + shdr->sh_entsize; + void *kdest = layout->kbase + shdr->sh_entsize; if (shdr->sh_type != SHT_NOBITS) { memcpy(kdest, (void *)shdr->sh_addr, shdr->sh_size); } - shdr->sh_addr = (unsigned long)kdest; + shdr->sh_addr = (uintptr_t)kdest; /* overuse this attr to record user address */ - shdr->sh_addralign = (unsigned long)dest; - log_debug("\t0x%lx %s <- 0x%lx\n", (long)kdest, - uelf->info.shstrtab + shdr->sh_name, (long)dest); + shdr->sh_addralign = (uintptr_t)dest; + log_debug("\t0x%lx %s <- 0x%lx\n", (uintptr_t)kdest, + uelf->info.shstrtab + shdr->sh_name, (uintptr_t)dest); } return 0; @@ -349,16 +347,15 @@ static int alloc_memory(struct upatch_elf *uelf, struct object_file *obj) static int post_memory(struct upatch_elf *uelf, struct object_file *obj) { - log_debug("Post kbase %lx(%lx) to base %lx\n", - (unsigned long)uelf->core_layout.kbase, - uelf->core_layout.size, - (unsigned long)uelf->core_layout.base); + log_debug("Post memory 0x%lx to 0x%lx, len=0x%lx\n", + (uintptr_t)uelf->core_layout.kbase, (uintptr_t)uelf->core_layout.base, + uelf->core_layout.size); int ret = upatch_process_mem_write(obj->proc, uelf->core_layout.kbase, (unsigned long)uelf->core_layout.base, uelf->core_layout.size); if (ret) { - log_error("Failed to move kbase to base, ret=%d\n", ret); + log_error("Failed to write process memory, ret=%d\n", ret); } return ret; @@ -436,8 +433,8 @@ static struct object_file *upatch_find_obj(struct upatch_elf *uelf, uelf->relf->info.inode, proc->pid); return NULL; } -static int complete_info(struct upatch_elf *uelf, - struct object_file *obj, const char *uuid) +static int complete_info(struct upatch_elf *uelf, struct object_file *obj, + const char *uuid) { int ret = 0; @@ -460,11 +457,20 @@ static int complete_info(struct upatch_elf *uelf, uinfo->func_names = (void *)uinfo + sizeof(*uinfo); uinfo->func_names_size = upatch_string->sh_size; + uinfo->funcs = (void *)uinfo->func_names + uinfo->func_names_size; + memcpy(uinfo->func_names, (void *)upatch_string->sh_addr, upatch_string->sh_size); - log_debug("Changed insn:\n"); - uinfo->funcs = (void *)uinfo->func_names + uinfo->func_names_size; + unsigned long offset = 0; + for (unsigned long i = 0; i < uinfo->changed_func_num; ++i) { + char *name = (char *)uinfo->func_names + offset; + + uinfo->funcs[i].name = name; + offset += strlen(name) + 1; + } + + log_debug("Changed function:\n"); for (unsigned int i = 0; i < uinfo->changed_func_num; ++i) { struct upatch_info_func *upatch_func = &uinfo->funcs[i]; @@ -479,10 +485,10 @@ static int complete_info(struct upatch_elf *uelf, } upatch_func->new_insn = get_new_insn(); - log_debug("\t0x%lx(0x%lx 0x%lx -> 0x%lx 0x%lx)\n", - upatch_func->addr.old_addr, - upatch_func->old_insn[0], upatch_func->old_insn[1], - upatch_func->new_insn, upatch_func->addr.new_addr); + log_debug("\taddr: 0x%lx -> 0x%lx, insn: 0x%lx -> 0x%lx, name: '%s'\n", + upatch_func->addr.old_addr, upatch_func->addr.new_addr, + upatch_func->old_insn[0], upatch_func->new_insn, + upatch_func->name); } out: @@ -492,11 +498,14 @@ out: static int unapply_patch(struct object_file *obj, struct upatch_info_func *funcs, unsigned long changed_func_num) { - log_debug("Changed insn:\n"); + log_debug("Changed function:\n"); for (unsigned int i = 0; i < changed_func_num; ++i) { - log_debug("\t0x%lx(0x%lx -> 0x%lx)\n", funcs[i].addr.old_addr, - funcs[i].new_insn, funcs[i].old_insn[0]); + struct upatch_info_func *upatch_func = &funcs[i]; + log_debug("\taddr: 0x%lx -> 0x%lx, insn: 0x%lx -> 0x%lx, name: '%s'\n", + upatch_func->addr.new_addr, upatch_func->addr.old_addr, + upatch_func->new_insn, upatch_func->old_insn[0], + upatch_func->name); int ret = upatch_process_mem_write(obj->proc, &funcs[i].old_insn, (unsigned long)funcs[i].addr.old_addr, get_origin_insn_len()); if (ret) { @@ -645,13 +654,11 @@ static int upatch_apply_patches(struct object_file *obj, */ 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; } @@ -782,7 +789,7 @@ int process_patch(int pid, struct upatch_elf *uelf, struct running_elf *relf, goto out; } - printf("Patch '%s' to ", uuid); + log_debug("Patch '%s' to ", uuid); upatch_process_print_short(&proc); ret = upatch_process_mem_open(&proc, MEM_READ); @@ -895,7 +902,7 @@ int process_unpatch(int pid, const char *uuid) goto out; } - printf("Unpatch '%s' from ", uuid); + log_debug("Unpatch '%s' from ", uuid); upatch_process_print_short(&proc); ret = upatch_process_mem_open(&proc, MEM_READ); diff --git a/upatch-manage/upatch-process.c b/upatch-manage/upatch-process.c index 924a9c4067ac0988c97620aa812d20bc44213bf6..c3b07ac6183580cc4c2d355e65b64b98d6320dcb 100644 --- a/upatch-manage/upatch-process.c +++ b/upatch-manage/upatch-process.c @@ -127,7 +127,7 @@ int upatch_process_init(struct upatch_process *proc, int pid) INIT_LIST_HEAD(&proc->ptrace.pctxs); INIT_LIST_HEAD(&proc->objs); - INIT_LIST_HEAD(&proc->vmaholes); + INIT_LIST_HEAD(&proc->vma_holes); proc->num_objs = 0; if (upatch_coroutines_init(proc)) { @@ -185,7 +185,7 @@ static void upatch_process_memfree(struct upatch_process *proc) free(p); } - list_for_each_entry_safe(hole, hole_safe, &proc->vmaholes, list) { + list_for_each_entry_safe(hole, hole_safe, &proc->vma_holes, list) { free(hole); } @@ -285,21 +285,19 @@ static unsigned int perms2prot(const char *perms) } static struct vm_hole *process_add_vm_hole(struct upatch_process *proc, - unsigned long hole_start, unsigned long hole_end) + unsigned long start, unsigned long end) { - struct vm_hole *hole; - - hole = malloc(sizeof(*hole)); + struct vm_hole *hole = malloc(sizeof(*hole)); if (hole == NULL) { return NULL; } - memset(hole, 0, sizeof(*hole)); - hole->start = hole_start; - hole->end = hole_end; - - list_add(&hole->list, &proc->vmaholes); + hole->start = start; + hole->end = end; + hole->len = end - start; + list_init(&hole->list); + list_add(&hole->list, &proc->vma_holes); return hole; } @@ -339,8 +337,8 @@ static int object_add_vm_area(struct object_file *o, struct vm_area *vma, { struct obj_vm_area *ovma; - if (o->previous_hole == NULL) { - o->previous_hole = hole; + if (o->prev_hole == NULL) { + o->prev_hole = hole; } list_for_each_entry(ovma, &o->vma, list) { @@ -385,7 +383,7 @@ static struct object_file *process_new_object(struct upatch_process *proc, o->inode = inode; o->is_patch = 0; - o->previous_hole = hole; + o->prev_hole = hole; if (object_add_vm_area(o, vma, hole) < 0) { log_error("Cannot add vm area for %s\n", name); free(o); @@ -488,7 +486,7 @@ static int add_upatch_object(struct upatch_process *proc, struct object_file *o, /** * Returns: 0 if everything is ok, -1 on error. */ -static int process_add_object_vma(struct upatch_process *proc, +static int process_add_vma(struct upatch_process *proc, dev_t dev, ino_t inode, char *name, struct vm_area *vma, struct vm_hole *hole) { @@ -532,13 +530,9 @@ static int process_add_object_vma(struct upatch_process *proc, return 0; } -int upatch_process_parse_proc_maps(struct upatch_process *proc) +int upatch_process_map_object_files(struct upatch_process *proc) { - FILE *f; - int ret; - int is_libc_base_set = 0; - unsigned long hole_start = 0; - struct vm_hole *hole = NULL; + int ret = 0; /* * 1. Create the list of all objects in the process @@ -554,78 +548,81 @@ int upatch_process_parse_proc_maps(struct upatch_process *proc) } lseek(fd, 0, SEEK_SET); - f = fdopen(fd, "r"); - if (f == NULL) { + FILE *file = fdopen(fd, "r"); + if (file == NULL) { log_error("unable to fdopen %d", fd); close(fd); return -1; } - do { + unsigned long hole_start = 0; + + char line[1024]; + while (fgets(line, sizeof(line), file) != NULL) { struct vm_area vma; - char line[1024]; - unsigned long start; - unsigned long end; + unsigned long vma_start; + unsigned long vma_end; unsigned long offset; unsigned int maj; unsigned int min; unsigned int inode; char perms[5]; - char name_[256]; - char *name = name_; - int r; - - if (!fgets(line, sizeof(line), f)) { - break; - } + char name_buf[256]; + char *name = name_buf; - r = sscanf(line, "%lx-%lx %s %lx %x:%x %d %255s", - &start, &end, perms, &offset, &maj, &min, &inode, name_); - if (r == EOF) { + ret = sscanf(line, "%lx-%lx %s %lx %x:%x %u %255s", + &vma_start, &vma_end, perms, &offset, + &maj, &min, &inode, name_buf); + if (ret == EOF) { log_error("Failed to read maps: unexpected EOF"); goto error; } - if (r != 8) { - strcpy(name, "[anonymous]"); + if (ret != 8) { + name = "[anonymous]"; } - vma.start = start; - vma.end = end; + vma.start = vma_start; + vma.end = vma_end; vma.offset = offset; vma.prot = perms2prot(perms); /* Hole must be at least 2 pages for guardians */ - if (start - hole_start > (unsigned long)(2 * PAGE_SIZE)) { - hole = process_add_vm_hole(proc, hole_start + (unsigned long)PAGE_SIZE, - start - (unsigned long)PAGE_SIZE); + struct vm_hole *hole = NULL; + if ((hole_start != 0) && + (vma_start - hole_start > 2 * (uintptr_t)PAGE_SIZE)) { + uintptr_t start = hole_start + (uintptr_t)PAGE_SIZE; + uintptr_t end = vma_start - (uintptr_t)PAGE_SIZE; + + hole = process_add_vm_hole(proc, start, end); if (hole == NULL) { log_error("Failed to add vma hole"); goto error; } + log_debug("vm_hole: start=0x%lx, end=0x%lx, len=0x%lx\n", + hole->start, hole->end, hole->len); } - hole_start = end; - name = name[0] == '/' ? basename(name) : name; + hole_start = vma_end; - ret = process_add_object_vma(proc, makedev(maj, min), inode, - name, &vma, hole); + name = name[0] == '/' ? basename(name) : name; + ret = process_add_vma(proc, makedev(maj, min), inode, name, &vma, hole); if (ret < 0) { log_error("Failed to add object vma"); goto error; } - if (!is_libc_base_set && !strncmp(basename(name), "libc", 4) && - (vma.prot & PROT_EXEC)) { - proc->libc_base = start; - is_libc_base_set = 1; + if ((proc->libc_base == 0) && + (vma.prot & PROT_EXEC) && + !strncmp(basename(name), "libc", 4)) { + proc->libc_base = vma_start; } - } while (1); + } - fclose(f); - close(fd); + (void)fclose(file); + (void)close(fd); log_debug("Found %d object file(s)\n", proc->num_objs); - if (!is_libc_base_set) { - log_error("Can't find libc_base required for manipulations: %d", + if (proc->libc_base == 0) { + log_error("Cannot find libc_base, pid=%d", proc->pid); return -1; } @@ -633,18 +630,11 @@ int upatch_process_parse_proc_maps(struct upatch_process *proc) return 0; error: - fclose(f); - close(fd); + (void)fclose(file); + (void)close(fd); return -1; } -int upatch_process_map_object_files(struct upatch_process *proc) -{ - // we can get plt/got table from mem's elf_segments - // Now we read them from the running file - return upatch_process_parse_proc_maps(proc); -} - static int process_list_threads(struct upatch_process *proc, int **ppids, size_t *npids, size_t *alloc) { @@ -736,7 +726,7 @@ int upatch_process_attach(struct upatch_process *proc) int pid = pids[i]; ret = upatch_ptrace_attach_thread(proc, pid); - if (ret < 0) { + if ((ret != 0) && (ret != ESRCH)) { goto detach; } } @@ -824,48 +814,67 @@ static inline struct vm_hole *prev_hole(struct vm_hole *hole, return list_entry(hole->list.prev, struct vm_hole, list); } -static inline unsigned long hole_size(struct vm_hole *hole) -{ - if (hole == NULL) { - return 0; - } - - return hole->end - hole->start; -} - -int vm_hole_split(struct vm_hole *hole, - unsigned long alloc_start, unsigned long alloc_end) +int vm_hole_split(struct vm_hole *hole, uintptr_t start, uintptr_t end) { - unsigned long page_size = (unsigned long)PAGE_SIZE; - - alloc_start = ROUND_DOWN(alloc_start, page_size) - page_size; - alloc_end = ROUND_UP(alloc_end, page_size) + page_size; + uintptr_t new_start = ROUND_DOWN(start, (uintptr_t)PAGE_SIZE) - + (uintptr_t)PAGE_SIZE; + uintptr_t new_end = ROUND_UP(end, (uintptr_t)PAGE_SIZE) + + (uintptr_t)PAGE_SIZE; - if (alloc_start > hole->start) { + if (new_start > hole->start) { struct vm_hole *left = NULL; left = malloc(sizeof(*hole)); if (left == NULL) { log_error("Failed to malloc for vm hole"); - return -1; + return ENOMEM; } left->start = hole->start; - left->end = alloc_start; + left->end = new_start; list_add(&left->list, &hole->list); } /* Reuse hole pointer as the right hole since it is pointed to by - * the `previous_hole` of some `object_file`. */ - hole->start = alloc_end; - hole->end = hole->end > alloc_end ? hole->end : alloc_end; + * the `prev_hole` of some `object_file`. */ + hole->start = new_end; + hole->end = hole->end > new_end ? hole->end : new_end; return 0; } +static bool is_vm_hole_suitable(struct obj_vm_area *vma, + struct vm_hole *hole, size_t len) +{ + uintptr_t vma_start = vma->inmem.start; + uintptr_t vma_end = vma->inmem.end; + uintptr_t hole_start = PAGE_ALIGN(hole->start); + uintptr_t hole_end = PAGE_ALIGN(hole->start + len); + + log_debug("vma_start=0x%lx, vma_end=0x%lx, " + "hole_start=0x%lx, hole_end=0x%lx, hole_len=0x%lx\n", + vma_start, vma_end, hole->start, hole->end, hole->len); + if (hole->len < len) { + return false; + } + + if (hole_end < vma_start) { + // hole is on the left side of the vma + if ((vma_start - hole_start) <= MAX_DISTANCE) { + return true; + } + } else if (hole_start > vma_end) { + // hole is on the right side of the vma + if ((hole_end - vma_end) <= MAX_DISTANCE) { + return true; + } + } + + return false; +} /* - * Find region for a patch. Take object's `previous_hole` as a left candidate + * Take object's `prev_hole` as a left candidate * and the next hole as a right candidate. Pace through them until there is * enough space in the hole for the patch. * @@ -873,52 +882,30 @@ int vm_hole_split(struct vm_hole *hole, * from the obj. * eg: R_AARCH64_ADR_GOT_PAGE */ -unsigned long object_find_patch_region(struct object_file *obj, - size_t memsize, struct vm_hole **hole) +struct vm_hole *find_patch_region(struct object_file *obj, size_t len) { - struct list_head *head = &obj->proc->vmaholes; - struct vm_hole *left_hole = obj->previous_hole; - struct vm_hole *right_hole = next_hole(left_hole, head); - unsigned long region_start = 0; - struct obj_vm_area *sovma; - unsigned long obj_start; - unsigned long obj_end; - - sovma = list_first_entry(&obj->vma, struct obj_vm_area, list); - obj_start = sovma->inmem.start; - sovma = list_entry(obj->vma.prev, struct obj_vm_area, list); - obj_end = sovma->inmem.end; - - log_debug("Looking for patch region for '%s'...\n", obj->name); - - while (right_hole != NULL || left_hole != NULL) { - if (hole_size(right_hole) > memsize) { - *hole = right_hole; - region_start = right_hole->start; - if (region_start + memsize - obj_start > MAX_DISTANCE) { - continue; + struct list_head *vma_holes = &obj->proc->vma_holes; + + struct obj_vm_area *vma = NULL; + list_for_each_entry(vma, &obj->vma, list) { + struct vm_hole *left_hole = obj->prev_hole; + struct vm_hole *right_hole = next_hole(obj->prev_hole, vma_holes); + + while ((left_hole != NULL) || (right_hole != NULL)) { + if (left_hole != NULL) { + if (is_vm_hole_suitable(vma, left_hole, len)) { + return left_hole; + } + left_hole = prev_hole(left_hole, vma_holes); } - goto found; - } - if (hole_size(left_hole) > memsize) { - *hole = left_hole; - region_start = left_hole->end - memsize; - if (obj_end - region_start > MAX_DISTANCE) { - continue; + if (right_hole != NULL) { + if (is_vm_hole_suitable(vma, right_hole, len)) { + return right_hole; + } + right_hole = next_hole(right_hole, vma_holes); } - goto found; } - right_hole = next_hole(right_hole, head); - left_hole = prev_hole(left_hole, head); } - log_error("Cannot find suitable region for patch '%s'\n", obj->name); - return -1UL; - -found: - region_start = (region_start >> PAGE_SHIFT) << PAGE_SHIFT; - log_debug("Found patch region for '%s' 0xat %lx\n", - obj->name, region_start); - - return region_start; + return NULL; } diff --git a/upatch-manage/upatch-process.h b/upatch-manage/upatch-process.h index 23cbced96d52d343facb6f11826857fd99b741e4..e8d5dee0a733bef5e3962f849a440c3e3433be72 100644 --- a/upatch-manage/upatch-process.h +++ b/upatch-manage/upatch-process.h @@ -57,7 +57,7 @@ struct object_file { struct list_head vma; /* Pointer to the previous hole in the patient's mapping */ - struct vm_hole *previous_hole; + struct vm_hole *prev_hole; /* Pointer to the applied patch list, if any */ struct list_head applied_patch; @@ -81,6 +81,7 @@ struct vm_area { struct vm_hole { unsigned long start; unsigned long end; + unsigned long len; struct list_head list; }; @@ -122,7 +123,7 @@ struct upatch_process { } coro; /* List of free VMA areas */ - struct list_head vmaholes; + struct list_head vma_holes; // TODO: other base? /* libc's base address to use as a worksheet */ @@ -143,9 +144,8 @@ int upatch_process_attach(struct upatch_process *); void upatch_process_detach(struct upatch_process *proc); -int vm_hole_split(struct vm_hole *, unsigned long, unsigned long); +int vm_hole_split(struct vm_hole *, uintptr_t, uintptr_t); -unsigned long object_find_patch_region(struct object_file *, - size_t, struct vm_hole **); +struct vm_hole *find_patch_region(struct object_file *obj, size_t len); #endif diff --git a/upatch-manage/upatch-ptrace.c b/upatch-manage/upatch-ptrace.c index 2d0845c2aa7c6e9cab668953fcdbd6eab6847c1b..ab21891d8e8ae2fa583c0e9734663fa268255760 100644 --- a/upatch-manage/upatch-ptrace.c +++ b/upatch-manage/upatch-ptrace.c @@ -117,7 +117,7 @@ int upatch_ptrace_attach_thread(struct upatch_process *proc, int tid) struct upatch_ptrace_ctx *pctx = upatch_ptrace_ctx_alloc(proc); if (pctx == NULL) { log_error("Failed to alloc ptrace context"); - return -1; + return ENOMEM; } pctx->pid = tid; @@ -126,7 +126,7 @@ int upatch_ptrace_attach_thread(struct upatch_process *proc, int tid) long ret = ptrace(PTRACE_ATTACH, tid, NULL, NULL); if (ret < 0) { log_error("Failed to attach thread, pid=%d, ret=%ld\n", tid, ret); - return -1; + return errno; } do { @@ -135,7 +135,7 @@ int upatch_ptrace_attach_thread(struct upatch_process *proc, int tid) ret = waitpid(tid, &status, __WALL); if (ret < 0) { log_error("Failed to wait thread, tid=%d, ret=%ld\n", tid, ret); - return -1; + return errno; } /* We are expecting SIGSTOP */ @@ -156,7 +156,7 @@ int upatch_ptrace_attach_thread(struct upatch_process *proc, int tid) ret = ptrace(PTRACE_CONT, tid, NULL, (void *)(uintptr_t)status); if (ret < 0) { log_error("Failed to continue thread, tid=%d, ret=%ld\n", tid, ret); - return -1; + return errno; } } while (1); diff --git a/upatch-manage/upatch-relocation.c b/upatch-manage/upatch-relocation.c index 57db9ba751fc3561627323038f1f96943fa4abe0..e9b79dd86173e7c191befafdcd62b1ad0157c7f1 100644 --- a/upatch-manage/upatch-relocation.c +++ b/upatch-manage/upatch-relocation.c @@ -43,12 +43,13 @@ int apply_relocations(struct upatch_elf *uelf) continue; } - log_debug("Relocate '%s'\n", name); + log_debug("Relocate section '%s':\n", name); if (uelf->info.shdrs[i].sh_type == SHT_REL) { return -EPERM; } else if (uelf->info.shdrs[i].sh_type == SHT_RELA) { err = apply_relocate_add(uelf, uelf->index.sym, i); } + log_debug("\n"); if (err < 0) { break; diff --git a/upatch-manage/upatch-resolve.c b/upatch-manage/upatch-resolve.c index b5645784ed196e070fe86a0afa98a84e0cafd672..53debe6018ffba8d037332ae27db1659f8c3d12d 100644 --- a/upatch-manage/upatch-resolve.c +++ b/upatch-manage/upatch-resolve.c @@ -99,8 +99,9 @@ static unsigned long resolve_rela_plt(struct upatch_elf *uelf, for (Elf64_Xword i = 0; i < rela_plt_shdr->sh_size / sizeof(GElf_Rela); i++) { unsigned long sym_idx = GELF_R_SYM(rela_plt[i].r_info); unsigned long sym_type = GELF_ST_TYPE(dynsym[sym_idx].st_info); - - if (sym_type != STT_FUNC && sym_type != STT_TLS) { + if ((sym_type == STT_NOTYPE) && + (sym_type != STT_FUNC) && + (sym_type != STT_TLS)) { continue; } diff --git a/upatch-manage/upatch-resolve.h b/upatch-manage/upatch-resolve.h index 863bcc5c784806eb29ad8d8f2857efcaee6fcf4e..62efc13b1abc01451c84cf461421cfdf50a05f94 100644 --- a/upatch-manage/upatch-resolve.h +++ b/upatch-manage/upatch-resolve.h @@ -36,6 +36,8 @@ unsigned long insert_plt_table(struct upatch_elf *, struct object_file *, unsigned long insert_got_table(struct upatch_elf *, struct object_file *, unsigned long, unsigned long); +unsigned long setup_got_table(struct upatch_elf *uelf, + unsigned long, unsigned long); unsigned long search_insert_plt_table(struct upatch_elf *, unsigned long, unsigned long); diff --git a/upatch-manage/upatch-stack-check.c b/upatch-manage/upatch-stack-check.c index 8cc4867e90b48308cf8a5ab23cb79d66690fdd95..474d857983b2019cf02fc1b2b66099ac65da285d 100644 --- a/upatch-manage/upatch-stack-check.c +++ b/upatch-manage/upatch-stack-check.c @@ -85,7 +85,7 @@ static int stack_check_each_pid(struct upatch_process *proc, } stack_size = read_stack(proc, stack, stack_size, sp); - log_debug("[%d]Stack size %lu, region [0x%lx, 0x%lx]\n", + log_debug("[%d] Stack size %lu, region [0x%lx, 0x%lx]\n", pid, stack_size, sp, sp + stack_size); for (size_t i = 0; i < stack_size / sizeof(*stack); i++) {