From b25aa8295afda72db03969bfcecaa2829351026d Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 30 Jan 2025 01:54:07 +0800 Subject: [PATCH] Move bootstage into Rust --- native/src/core/bootstages.cpp | 77 +--------- native/src/core/daemon.rs | 136 +++++++++++------- native/src/core/include/core.hpp | 3 - .../src/core/include/{daemon.hpp => ffi.hpp} | 7 + native/src/core/lib.rs | 14 +- native/src/core/package.rs | 43 +++++- native/src/core/scripting.cpp | 18 +-- native/src/include/consts.rs | 2 +- 8 files changed, 154 insertions(+), 146 deletions(-) rename native/src/core/include/{daemon.hpp => ffi.hpp} (68%) diff --git a/native/src/core/bootstages.cpp b/native/src/core/bootstages.cpp index c21cd1c70..4d8ca336d 100644 --- a/native/src/core/bootstages.cpp +++ b/native/src/core/bootstages.cpp @@ -17,7 +17,7 @@ using namespace std; * Setup * *********/ -static bool magisk_env() { +bool setup_magisk_env() { char buf[4096]; LOGI("* Initializing Magisk environment\n"); @@ -85,7 +85,7 @@ void unlock_blocks() { #define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8))) -static bool check_key_combo() { +bool check_key_combo() { uint8_t bitmask[(KEY_MAX + 1) / 8]; vector events; constexpr char name[] = "/dev/.ev"; @@ -129,76 +129,3 @@ static bool check_key_combo() { LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n"); return true; } - -/*********************** - * Boot Stage Handlers * - ***********************/ - -bool MagiskD::post_fs_data() const noexcept { - setup_logfile(); - - LOGI("** post-fs-data mode running\n"); - - preserve_stub_apk(); - - if (access(SECURE_DIR, F_OK) != 0) { - if (SDK_INT < 24) { - xmkdir(SECURE_DIR, 0700); - } else { - LOGE(SECURE_DIR " is not present, abort\n"); - return true; - } - } - - prune_su_access(); - - if (!magisk_env()) { - LOGE("* Magisk environment incomplete, abort\n"); - return true; - } - - // Check safe mode - int bootloop_cnt = get_db_setting(DbEntryKey::BootloopCount); - // Increment the boot counter - set_db_setting(DbEntryKey::BootloopCount, bootloop_cnt + 1); - bool safe_mode = bootloop_cnt >= 2 || get_prop("persist.sys.safemode", true) == "1" || - get_prop("ro.sys.safemode") == "1" || check_key_combo(); - - if (safe_mode) { - LOGI("* Safe mode triggered\n"); - // Disable all modules and zygisk so next boot will be clean - disable_modules(); - set_db_setting(DbEntryKey::ZygiskConfig, false); - return true; - } - - exec_common_scripts("post-fs-data"); - return false; -} - -void MagiskD::late_start() const noexcept { - setup_logfile(); - - LOGI("** late_start service mode running\n"); - - exec_common_scripts("service"); - exec_module_scripts("service", module_list()); -} - -void MagiskD::boot_complete() const noexcept { - setup_logfile(); - - LOGI("** boot-complete triggered\n"); - - // Reset the bootloop counter once we have boot-complete - set_db_setting(DbEntryKey::BootloopCount, 0); - - // At this point it's safe to create the folder - if (access(SECURE_DIR, F_OK) != 0) - xmkdir(SECURE_DIR, 0700); - - // Ensure manager exists - get_manager(0, nullptr, true); - - zygisk_reset(true); -} diff --git a/native/src/core/daemon.rs b/native/src/core/daemon.rs index f38b02f08..033258ac3 100644 --- a/native/src/core/daemon.rs +++ b/native/src/core/daemon.rs @@ -1,16 +1,18 @@ -use crate::consts::{MAGISK_FULL_VER, MAIN_CONFIG}; +use crate::consts::{MAGISK_FULL_VER, MAIN_CONFIG, SECURE_DIR}; use crate::db::Sqlite3; -use crate::ffi::{get_magisk_tmp, initialize_denylist, DbEntryKey, ModuleInfo, RequestCode}; +use crate::ffi::{ + check_key_combo, disable_modules, exec_common_scripts, exec_module_scripts, get_magisk_tmp, + initialize_denylist, setup_magisk_env, DbEntryKey, ModuleInfo, RequestCode, +}; use crate::get_prop; -use crate::logging::{magisk_logging, start_log_daemon}; +use crate::logging::{magisk_logging, setup_logfile, start_log_daemon}; use crate::mount::setup_mounts; use crate::package::ManagerInfo; use base::libc::{O_CLOEXEC, O_RDONLY}; use base::{ - cstr, info, libc, open_fd, warn, BufReadExt, Directory, FsPath, FsPathBuf, LoggedResult, - ReadExt, ResultExt, Utf8CStr, Utf8CStrBufArr, WriteExt, + cstr, error, info, libc, open_fd, warn, BufReadExt, FsPath, FsPathBuf, ReadExt, ResultExt, + Utf8CStr, Utf8CStrBufArr, WriteExt, }; -use bit_set::BitSet; use bytemuck::{bytes_of, bytes_of_mut, Pod, Zeroable}; use std::fs::File; use std::io; @@ -91,10 +93,6 @@ impl MagiskD { self.module_list.set(module_list).ok(); } - pub fn module_list(&self) -> &Vec { - self.module_list.get().unwrap() - } - pub fn app_data_dir(&self) -> &'static Utf8CStr { if self.sdk_int >= 24 { cstr!("/data/user_de") @@ -103,39 +101,85 @@ impl MagiskD { } } - // app_id = app_no + AID_APP_START - // app_no range: [0, 9999] - pub fn get_app_no_list(&self) -> BitSet { - let mut list = BitSet::new(); - let _: LoggedResult<()> = try { - let mut app_data_dir = Directory::open(self.app_data_dir())?; - // For each user - loop { - let entry = match app_data_dir.read()? { - None => break, - Some(e) => e, - }; - let mut user_dir = match entry.open_as_dir() { - Err(_) => continue, - Ok(dir) => dir, - }; - // For each package - loop { - match user_dir.read()? { - None => break, - Some(e) => { - let attr = e.get_attr()?; - let app_id = to_app_id(attr.st.st_uid as i32); - if (AID_APP_START..=AID_APP_END).contains(&app_id) { - let app_no = app_id - AID_APP_START; - list.insert(app_no as usize); - } - } - } - } + fn post_fs_data(&self) -> bool { + setup_logfile(); + info!("** post-fs-data mode running"); + + self.preserve_stub_apk(); + + // Check secure dir + let secure_dir = FsPath::from(cstr!(SECURE_DIR)); + if !secure_dir.exists() { + if self.sdk_int < 24 { + secure_dir.mkdir(0o700).log().ok(); + } else { + error!("* {} is not present, abort", SECURE_DIR); + return true; } - }; - list + } + + self.prune_su_access(); + + if !setup_magisk_env() { + error!("* Magisk environment incomplete, abort"); + return true; + } + + // Check safe mode + let boot_cnt = self.get_db_setting(DbEntryKey::BootloopCount); + self.set_db_setting(DbEntryKey::BootloopCount, boot_cnt + 1) + .log() + .ok(); + let safe_mode = boot_cnt >= 2 + || get_prop(cstr!("persist.sys.safemode"), true) == "1" + || get_prop(cstr!("ro.sys.safemode"), false) == "1" + || check_key_combo(); + + if safe_mode { + info!("* Safe mode triggered"); + // Disable all modules and zygisk so next boot will be clean + disable_modules(); + self.set_db_setting(DbEntryKey::ZygiskConfig, 0).log().ok(); + return true; + } + + exec_common_scripts(cstr!("post-fs-data")); + self.zygisk_enabled.store( + self.get_db_setting(DbEntryKey::ZygiskConfig) != 0, + Ordering::Release, + ); + initialize_denylist(); + setup_mounts(); + self.handle_modules(); + + false + } + + fn late_start(&self) { + setup_logfile(); + info!("** late_start service mode running"); + + exec_common_scripts(cstr!("service")); + if let Some(module_list) = self.module_list.get() { + exec_module_scripts(cstr!("service"), module_list); + } + } + + fn boot_complete(&self) { + setup_logfile(); + info!("** boot-complete triggered"); + + // Reset the bootloop counter once we have boot-complete + self.set_db_setting(DbEntryKey::BootloopCount, 0).log().ok(); + + // At this point it's safe to create the folder + let secure_dir = FsPath::from(cstr!(SECURE_DIR)); + if !secure_dir.exists() { + secure_dir.mkdir(0o700).log().ok(); + } + + self.ensure_manager(); + self.zygisk_reset(true) } pub fn boot_stage_handler(&self, client: i32, code: i32) { @@ -148,14 +192,6 @@ impl MagiskD { if check_data() && !state.contains(BootState::PostFsDataDone) { if self.post_fs_data() { state.set(BootState::SafeMode); - } else { - self.zygisk_enabled.store( - self.get_db_setting(DbEntryKey::ZygiskConfig) != 0, - Ordering::Release, - ); - initialize_denylist(); - setup_mounts(); - self.handle_modules(); } state.set(BootState::PostFsDataDone); } diff --git a/native/src/core/include/core.hpp b/native/src/core/include/core.hpp index 275ee7f9b..696a7fb12 100644 --- a/native/src/core/include/core.hpp +++ b/native/src/core/include/core.hpp @@ -28,7 +28,6 @@ enum class RespondCode : int { extern std::string native_bridge; -void reset_zygisk(bool restore); int connect_daemon(int req, bool create = false); void unlock_blocks(); @@ -52,8 +51,6 @@ void remove_modules(); // Scripting void exec_script(const char *script); -void exec_common_scripts(const char *stage); -void exec_module_scripts(const char *stage, const rust::Vec &module_list); void clear_pkg(const char *pkg, int user_id); [[noreturn]] void install_module(const char *file); diff --git a/native/src/core/include/daemon.hpp b/native/src/core/include/ffi.hpp similarity index 68% rename from native/src/core/include/daemon.hpp rename to native/src/core/include/ffi.hpp index c47a49106..e319634d0 100644 --- a/native/src/core/include/daemon.hpp +++ b/native/src/core/include/ffi.hpp @@ -2,7 +2,14 @@ #include +struct ModuleInfo; + const char *get_magisk_tmp(); +bool setup_magisk_env(); +bool check_key_combo(); +void disable_modules(); +void exec_common_scripts(rust::Utf8CStr stage); +void exec_module_scripts(rust::Utf8CStr stage, const rust::Vec &module_list); void install_apk(rust::Utf8CStr apk); void uninstall_pkg(rust::Utf8CStr pkg); void update_deny_flags(int uid, rust::Str process, uint32_t &flags); diff --git a/native/src/core/lib.rs b/native/src/core/lib.rs index 39b1b5b3a..e6295c2fa 100644 --- a/native/src/core/lib.rs +++ b/native/src/core/lib.rs @@ -10,7 +10,7 @@ use base::Utf8CStr; use daemon::{daemon_entry, get_magiskd, recv_fd, recv_fds, send_fd, send_fds, MagiskD}; use db::get_default_db_settings; use logging::{android_logging, setup_logfile, zygisk_close_logd, zygisk_get_logd, zygisk_logging}; -use mount::{clean_mounts, find_preinit_device, revert_unmount, setup_mounts}; +use mount::{clean_mounts, find_preinit_device, revert_unmount}; use resetprop::{persist_delete_prop, persist_get_prop, persist_get_props, persist_set_prop}; use su::get_default_root_settings; use zygisk::zygisk_should_load_module; @@ -72,12 +72,17 @@ pub mod ffi { #[cxx_name = "Utf8CStr"] type Utf8CStrRef<'a> = base::ffi::Utf8CStrRef<'a>; - include!("include/daemon.hpp"); + include!("include/ffi.hpp"); #[cxx_name = "get_magisk_tmp_rs"] fn get_magisk_tmp() -> Utf8CStrRef<'static>; #[cxx_name = "resolve_preinit_dir_rs"] fn resolve_preinit_dir(base_dir: Utf8CStrRef) -> String; + fn setup_magisk_env() -> bool; + fn check_key_combo() -> bool; + fn disable_modules(); + fn exec_common_scripts(stage: Utf8CStrRef); + fn exec_module_scripts(state: Utf8CStrRef, modules: &Vec); fn install_apk(apk: Utf8CStrRef); fn uninstall_pkg(apk: Utf8CStrRef); fn update_deny_flags(uid: i32, process: &str, flags: &mut u32); @@ -214,12 +219,10 @@ pub mod ffi { fn boot_stage_handler(&self, client: i32, code: i32); fn zygisk_handler(&self, client: i32); fn zygisk_reset(&self, restore: bool); - fn preserve_stub_apk(&self); fn prune_su_access(&self); #[cxx_name = "get_manager"] unsafe fn get_manager_for_cxx(&self, user: i32, ptr: *mut CxxString, install: bool) -> i32; fn set_module_list(&self, module_list: Vec); - fn module_list(&self) -> &Vec; #[cxx_name = "get_db_settings"] fn get_db_settings_for_cxx(&self, cfg: &mut DbSettings) -> bool; @@ -241,10 +244,7 @@ pub mod ffi { unsafe extern "C++" { #[allow(dead_code)] fn reboot(self: &MagiskD); - fn post_fs_data(self: &MagiskD) -> bool; fn handle_modules(self: &MagiskD); - fn late_start(self: &MagiskD); - fn boot_complete(self: &MagiskD); } } diff --git a/native/src/core/package.rs b/native/src/core/package.rs index 6eef08f9b..5033856b3 100644 --- a/native/src/core/package.rs +++ b/native/src/core/package.rs @@ -1,5 +1,5 @@ use crate::consts::{APP_PACKAGE_NAME, MAGISK_VER_CODE}; -use crate::daemon::{to_app_id, MagiskD, AID_USER_OFFSET}; +use crate::daemon::{to_app_id, MagiskD, AID_APP_END, AID_APP_START, AID_USER_OFFSET}; use crate::ffi::{get_magisk_tmp, install_apk, uninstall_pkg, DbEntryKey}; use base::libc::{O_CLOEXEC, O_CREAT, O_RDONLY, O_TRUNC, O_WRONLY}; use base::WalkResult::{Abort, Continue, Skip}; @@ -7,6 +7,7 @@ use base::{ cstr, error, fd_get_attr, open_fd, warn, BufReadExt, Directory, FsPath, FsPathBuf, LoggedResult, ReadExt, ResultExt, Utf8CStrBuf, Utf8CStrBufArr, }; +use bit_set::BitSet; use cxx::CxxString; use std::collections::BTreeMap; use std::fs::File; @@ -479,6 +480,11 @@ impl MagiskD { uid } + pub fn ensure_manager(&self) { + let mut info = self.manager_info.lock().unwrap(); + let _ = info.get_manager(self, 0, true); + } + pub unsafe fn get_manager_for_cxx(&self, user: i32, ptr: *mut CxxString, install: bool) -> i32 { let mut info = self.manager_info.lock().unwrap(); let (uid, pkg) = info.get_manager(self, user, install); @@ -489,4 +495,39 @@ impl MagiskD { } uid } + + // app_id = app_no + AID_APP_START + // app_no range: [0, 9999] + pub fn get_app_no_list(&self) -> BitSet { + let mut list = BitSet::new(); + let _: LoggedResult<()> = try { + let mut app_data_dir = Directory::open(self.app_data_dir())?; + // For each user + loop { + let entry = match app_data_dir.read()? { + None => break, + Some(e) => e, + }; + let mut user_dir = match entry.open_as_dir() { + Err(_) => continue, + Ok(dir) => dir, + }; + // For each package + loop { + match user_dir.read()? { + None => break, + Some(e) => { + let attr = e.get_attr()?; + let app_id = to_app_id(attr.st.st_uid as i32); + if (AID_APP_START..=AID_APP_END).contains(&app_id) { + let app_no = app_id - AID_APP_START; + list.insert(app_no as usize); + } + } + } + } + } + }; + list + } } diff --git a/native/src/core/scripting.cpp b/native/src/core/scripting.cpp index 5e99c216f..036bfce1a 100644 --- a/native/src/core/scripting.cpp +++ b/native/src/core/scripting.cpp @@ -75,10 +75,10 @@ if (pfs) { \ exit(0); \ } -void exec_common_scripts(const char *stage) { - LOGI("* Running %s.d scripts\n", stage); +void exec_common_scripts(rust::Utf8CStr stage) { + LOGI("* Running %s.d scripts\n", stage.c_str()); char path[4096]; - char *name = path + sprintf(path, SECURE_DIR "/%s.d", stage); + char *name = path + sprintf(path, SECURE_DIR "/%s.d", stage.c_str()); auto dir = xopen_dir(path); if (!dir) return; @@ -97,7 +97,7 @@ void exec_common_scripts(const char *stage) { if (entry->d_type == DT_REG) { if (faccessat(dfd, entry->d_name, X_OK, 0) != 0) continue; - LOGI("%s.d: exec [%s]\n", stage, entry->d_name); + LOGI("%s.d: exec [%s]\n", stage.c_str(), entry->d_name); strcpy(name, entry->d_name); exec_t exec { .pre_exec = set_script_env, @@ -117,12 +117,12 @@ static bool operator>(const timespec &a, const timespec &b) { return a.tv_nsec > b.tv_nsec; } -void exec_module_scripts(const char *stage, const rust::Vec &module_list) { - LOGI("* Running module %s scripts\n", stage); +void exec_module_scripts(rust::Utf8CStr stage, const rust::Vec &module_list) { + LOGI("* Running module %s scripts\n", stage.c_str()); if (module_list.empty()) return; - bool pfs = stage == "post-fs-data"sv; + bool pfs = (string_view) stage == "post-fs-data"; if (pfs) { timespec now{}; clock_gettime(CLOCK_MONOTONIC, &now); @@ -135,10 +135,10 @@ void exec_module_scripts(const char *stage, const rust::Vec &module_ char path[4096]; for (auto &m : module_list) { - sprintf(path, MODULEROOT "/%.*s/%s.sh", (int) m.name.size(), m.name.data(), stage); + sprintf(path, MODULEROOT "/%.*s/%s.sh", (int) m.name.size(), m.name.data(), stage.c_str()); if (access(path, F_OK) == -1) continue; - LOGI("%.*s: exec [%s.sh]\n", (int) m.name.size(), m.name.data(), stage); + LOGI("%.*s: exec [%s.sh]\n", (int) m.name.size(), m.name.data(), stage.c_str()); exec_t exec { .pre_exec = set_script_env, .fork = pfs ? xfork : fork_dont_care diff --git a/native/src/include/consts.rs b/native/src/include/consts.rs index 8c4f31663..7853d06c4 100644 --- a/native/src/include/consts.rs +++ b/native/src/include/consts.rs @@ -13,7 +13,7 @@ pub const APP_PACKAGE_NAME: &str = "com.topjohnwu.magisk"; pub const LOGFILE: &str = "/cache/magisk.log"; // data paths -const SECURE_DIR: &str = "/data/adb"; +pub const SECURE_DIR: &str = "/data/adb"; pub const MODULEROOT: &str = concatcp!(SECURE_DIR, "/modules"); // tmpfs paths