diff --git a/native/src/base/files.cpp b/native/src/base/files.cpp index a7147b9ac..7532ea525 100644 --- a/native/src/base/files.cpp +++ b/native/src/base/files.cpp @@ -20,48 +20,6 @@ int fd_pathat(int dirfd, const char *name, char *path, size_t size) { return 0; } -template -static void post_order_walk(int dirfd, const Func &fn) { - auto dir = xopen_dir(dirfd); - if (!dir) return; - - for (dirent *entry; (entry = xreaddir(dir.get()));) { - if (entry->d_type == DT_DIR) - post_order_walk(xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC), fn); - fn(dirfd, entry); - } -} - -enum walk_result { - CONTINUE, SKIP, ABORT -}; - -template -static walk_result pre_order_walk(int dirfd, const Func &fn) { - auto dir = xopen_dir(dirfd); - if (!dir) { - close(dirfd); - return SKIP; - } - - for (dirent *entry; (entry = xreaddir(dir.get()));) { - switch (fn(dirfd, entry)) { - case CONTINUE: - break; - case SKIP: - continue; - case ABORT: - return ABORT; - } - if (entry->d_type == DT_DIR) { - int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); - if (pre_order_walk(fd, fn) == ABORT) - return ABORT; - } - } - return CONTINUE; -} - void mv_path(const char *src, const char *dest) { file_attr attr; getattr(src, &attr); @@ -447,23 +405,6 @@ mmap_data::~mmap_data() { munmap(_buf, _sz); } -string find_apk_path(const char *pkg) { - char buf[PATH_MAX]; - size_t len = strlen(pkg); - pre_order_walk(xopen("/data/app", O_RDONLY), [&](int dfd, dirent *entry) -> walk_result { - if (entry->d_type != DT_DIR) - return SKIP; - if (strncmp(entry->d_name, pkg, len) == 0 && entry->d_name[len] == '-') { - fd_pathat(dfd, entry->d_name, buf, sizeof(buf)); - return ABORT; - } else if (strncmp(entry->d_name, "~~", 2) == 0) { - return CONTINUE; - } else return SKIP; - }); - string path(buf); - return path.append("/base.apk"); -} - string resolve_preinit_dir(const char *base_dir) { string dir = base_dir; if (access((dir + "/unencrypted").data(), F_OK) == 0) { diff --git a/native/src/base/files.hpp b/native/src/base/files.hpp index cd799de2d..01a0130cf 100644 --- a/native/src/base/files.hpp +++ b/native/src/base/files.hpp @@ -92,7 +92,6 @@ void parse_prop_file(const char *file, const std::function &fn); void clone_dir(int src, int dest); std::vector parse_mount_info(const char *pid); -std::string find_apk_path(const char *pkg); std::string resolve_preinit_dir(const char *base_dir); using sFILE = std::unique_ptr; diff --git a/native/src/base/misc.hpp b/native/src/base/misc.hpp index eae95ffb4..125b3a116 100644 --- a/native/src/base/misc.hpp +++ b/native/src/base/misc.hpp @@ -202,6 +202,13 @@ struct byte_data : public byte_view { std::vector patch(byte_view from, byte_view to); }; +template +struct byte_array : public byte_data { + byte_array() : byte_data(arr, N), arr{0} {} +private: + uint8_t arr[N]; +}; + class byte_channel; struct heap_data : public byte_data { diff --git a/native/src/core/daemon.rs b/native/src/core/daemon.rs index 9aac813b5..1d2f0dbe9 100644 --- a/native/src/core/daemon.rs +++ b/native/src/core/daemon.rs @@ -1,8 +1,12 @@ -use crate::logging::{magisk_logging, zygisk_logging}; use std::cell::RefCell; use std::fs::File; +use std::io; use std::sync::{Mutex, OnceLock}; +use base::{copy_str, cstr, Directory, ResultExt, WalkResult}; + +use crate::logging::{magisk_logging, zygisk_logging}; + // Global magiskd singleton pub static MAGISKD: OnceLock = OnceLock::new(); @@ -29,3 +33,30 @@ pub fn get_magiskd() -> &'static MagiskD { } impl MagiskD {} + +pub fn find_apk_path(pkg: &[u8], data: &mut [u8]) -> usize { + use WalkResult::*; + fn inner(pkg: &[u8], data: &mut [u8]) -> io::Result { + let mut len = 0_usize; + Directory::open(cstr!("/data/app"))?.pre_order_walk(|e| { + if !e.is_dir() { + return Ok(Skip); + } + let d_name = e.d_name().to_bytes(); + if d_name.starts_with(pkg) && d_name[pkg.len()] == b'-' { + // Found the APK path, we can abort now + len = e.path(data)?; + return Ok(Abort); + } + if d_name.starts_with(b"~~") { + return Ok(Continue); + } + Ok(Skip) + })?; + if len > 0 { + len += copy_str(&mut data[len..], "/base.apk"); + } + Ok(len) + } + inner(pkg, data).log().unwrap_or(0) +} diff --git a/native/src/core/lib.rs b/native/src/core/lib.rs index 7b5cdf8e4..7a1a0ec26 100644 --- a/native/src/core/lib.rs +++ b/native/src/core/lib.rs @@ -21,6 +21,7 @@ pub mod ffi { fn android_logging(); fn magisk_logging(); fn zygisk_logging(); + fn find_apk_path(pkg: &[u8], data: &mut [u8]) -> usize; } #[namespace = "rust"] diff --git a/native/src/core/package.cpp b/native/src/core/package.cpp index 26a84e373..e944fa3d4 100644 --- a/native/src/core/package.cpp +++ b/native/src/core/package.cpp @@ -169,8 +169,9 @@ int get_manager(int user_id, string *pkg, bool install) { if (stat(app_path, &st) == 0) { int app_id = to_app_id(st.st_uid); - string apk = find_apk_path(str[SU_MANAGER].data()); - int fd = xopen(apk.data(), O_RDONLY | O_CLOEXEC); + byte_array apk; + find_apk_path(byte_view(str[SU_MANAGER]), apk); + int fd = xopen((const char *) apk.buf(), O_RDONLY | O_CLOEXEC); string cert = read_certificate(fd); close(fd); @@ -178,7 +179,7 @@ int get_manager(int user_id, string *pkg, bool install) { if (str[SU_MANAGER] == *mgr_pkg) { if (app_id != mgr_app_id || cert != *mgr_cert) { // app ID or cert should never change - LOGE("pkg: repackaged APK signature invalid: %s\n", apk.data()); + LOGE("pkg: repackaged APK signature invalid: %s\n", apk.buf()); uninstall_pkg(mgr_pkg->data()); invalid = true; install = true;