Move bootstage into Rust

This commit is contained in:
topjohnwu 2025-01-30 01:54:07 +08:00 committed by John Wu
parent 15a605765c
commit b25aa8295a
8 changed files with 154 additions and 146 deletions

View File

@ -17,7 +17,7 @@ using namespace std;
* Setup * * Setup *
*********/ *********/
static bool magisk_env() { bool setup_magisk_env() {
char buf[4096]; char buf[4096];
LOGI("* Initializing Magisk environment\n"); LOGI("* Initializing Magisk environment\n");
@ -85,7 +85,7 @@ void unlock_blocks() {
#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8))) #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]; uint8_t bitmask[(KEY_MAX + 1) / 8];
vector<int> events; vector<int> events;
constexpr char name[] = "/dev/.ev"; constexpr char name[] = "/dev/.ev";
@ -129,76 +129,3 @@ static bool check_key_combo() {
LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n"); LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n");
return true; 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);
}

View File

@ -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::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::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::mount::setup_mounts;
use crate::package::ManagerInfo; use crate::package::ManagerInfo;
use base::libc::{O_CLOEXEC, O_RDONLY}; use base::libc::{O_CLOEXEC, O_RDONLY};
use base::{ use base::{
cstr, info, libc, open_fd, warn, BufReadExt, Directory, FsPath, FsPathBuf, LoggedResult, cstr, error, info, libc, open_fd, warn, BufReadExt, FsPath, FsPathBuf, ReadExt, ResultExt,
ReadExt, ResultExt, Utf8CStr, Utf8CStrBufArr, WriteExt, Utf8CStr, Utf8CStrBufArr, WriteExt,
}; };
use bit_set::BitSet;
use bytemuck::{bytes_of, bytes_of_mut, Pod, Zeroable}; use bytemuck::{bytes_of, bytes_of_mut, Pod, Zeroable};
use std::fs::File; use std::fs::File;
use std::io; use std::io;
@ -91,10 +93,6 @@ impl MagiskD {
self.module_list.set(module_list).ok(); self.module_list.set(module_list).ok();
} }
pub fn module_list(&self) -> &Vec<ModuleInfo> {
self.module_list.get().unwrap()
}
pub fn app_data_dir(&self) -> &'static Utf8CStr { pub fn app_data_dir(&self) -> &'static Utf8CStr {
if self.sdk_int >= 24 { if self.sdk_int >= 24 {
cstr!("/data/user_de") cstr!("/data/user_de")
@ -103,39 +101,85 @@ impl MagiskD {
} }
} }
// app_id = app_no + AID_APP_START fn post_fs_data(&self) -> bool {
// app_no range: [0, 9999] setup_logfile();
pub fn get_app_no_list(&self) -> BitSet { info!("** post-fs-data mode running");
let mut list = BitSet::new();
let _: LoggedResult<()> = try { self.preserve_stub_apk();
let mut app_data_dir = Directory::open(self.app_data_dir())?;
// For each user // Check secure dir
loop { let secure_dir = FsPath::from(cstr!(SECURE_DIR));
let entry = match app_data_dir.read()? { if !secure_dir.exists() {
None => break, if self.sdk_int < 24 {
Some(e) => e, secure_dir.mkdir(0o700).log().ok();
}; } else {
let mut user_dir = match entry.open_as_dir() { error!("* {} is not present, abort", SECURE_DIR);
Err(_) => continue, return true;
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
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) { pub fn boot_stage_handler(&self, client: i32, code: i32) {
@ -148,14 +192,6 @@ impl MagiskD {
if check_data() && !state.contains(BootState::PostFsDataDone) { if check_data() && !state.contains(BootState::PostFsDataDone) {
if self.post_fs_data() { if self.post_fs_data() {
state.set(BootState::SafeMode); 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); state.set(BootState::PostFsDataDone);
} }

View File

@ -28,7 +28,6 @@ enum class RespondCode : int {
extern std::string native_bridge; extern std::string native_bridge;
void reset_zygisk(bool restore);
int connect_daemon(int req, bool create = false); int connect_daemon(int req, bool create = false);
void unlock_blocks(); void unlock_blocks();
@ -52,8 +51,6 @@ void remove_modules();
// Scripting // Scripting
void exec_script(const char *script); void exec_script(const char *script);
void exec_common_scripts(const char *stage);
void exec_module_scripts(const char *stage, const rust::Vec<ModuleInfo> &module_list);
void clear_pkg(const char *pkg, int user_id); void clear_pkg(const char *pkg, int user_id);
[[noreturn]] void install_module(const char *file); [[noreturn]] void install_module(const char *file);

View File

@ -2,7 +2,14 @@
#include <base.hpp> #include <base.hpp>
struct ModuleInfo;
const char *get_magisk_tmp(); 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<ModuleInfo> &module_list);
void install_apk(rust::Utf8CStr apk); void install_apk(rust::Utf8CStr apk);
void uninstall_pkg(rust::Utf8CStr pkg); void uninstall_pkg(rust::Utf8CStr pkg);
void update_deny_flags(int uid, rust::Str process, uint32_t &flags); void update_deny_flags(int uid, rust::Str process, uint32_t &flags);

View File

@ -10,7 +10,7 @@ use base::Utf8CStr;
use daemon::{daemon_entry, get_magiskd, recv_fd, recv_fds, send_fd, send_fds, MagiskD}; use daemon::{daemon_entry, get_magiskd, recv_fd, recv_fds, send_fd, send_fds, MagiskD};
use db::get_default_db_settings; use db::get_default_db_settings;
use logging::{android_logging, setup_logfile, zygisk_close_logd, zygisk_get_logd, zygisk_logging}; 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 resetprop::{persist_delete_prop, persist_get_prop, persist_get_props, persist_set_prop};
use su::get_default_root_settings; use su::get_default_root_settings;
use zygisk::zygisk_should_load_module; use zygisk::zygisk_should_load_module;
@ -72,12 +72,17 @@ pub mod ffi {
#[cxx_name = "Utf8CStr"] #[cxx_name = "Utf8CStr"]
type Utf8CStrRef<'a> = base::ffi::Utf8CStrRef<'a>; type Utf8CStrRef<'a> = base::ffi::Utf8CStrRef<'a>;
include!("include/daemon.hpp"); include!("include/ffi.hpp");
#[cxx_name = "get_magisk_tmp_rs"] #[cxx_name = "get_magisk_tmp_rs"]
fn get_magisk_tmp() -> Utf8CStrRef<'static>; fn get_magisk_tmp() -> Utf8CStrRef<'static>;
#[cxx_name = "resolve_preinit_dir_rs"] #[cxx_name = "resolve_preinit_dir_rs"]
fn resolve_preinit_dir(base_dir: Utf8CStrRef) -> String; 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<ModuleInfo>);
fn install_apk(apk: Utf8CStrRef); fn install_apk(apk: Utf8CStrRef);
fn uninstall_pkg(apk: Utf8CStrRef); fn uninstall_pkg(apk: Utf8CStrRef);
fn update_deny_flags(uid: i32, process: &str, flags: &mut u32); 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 boot_stage_handler(&self, client: i32, code: i32);
fn zygisk_handler(&self, client: i32); fn zygisk_handler(&self, client: i32);
fn zygisk_reset(&self, restore: bool); fn zygisk_reset(&self, restore: bool);
fn preserve_stub_apk(&self);
fn prune_su_access(&self); fn prune_su_access(&self);
#[cxx_name = "get_manager"] #[cxx_name = "get_manager"]
unsafe fn get_manager_for_cxx(&self, user: i32, ptr: *mut CxxString, install: bool) -> i32; unsafe fn get_manager_for_cxx(&self, user: i32, ptr: *mut CxxString, install: bool) -> i32;
fn set_module_list(&self, module_list: Vec<ModuleInfo>); fn set_module_list(&self, module_list: Vec<ModuleInfo>);
fn module_list(&self) -> &Vec<ModuleInfo>;
#[cxx_name = "get_db_settings"] #[cxx_name = "get_db_settings"]
fn get_db_settings_for_cxx(&self, cfg: &mut DbSettings) -> bool; fn get_db_settings_for_cxx(&self, cfg: &mut DbSettings) -> bool;
@ -241,10 +244,7 @@ pub mod ffi {
unsafe extern "C++" { unsafe extern "C++" {
#[allow(dead_code)] #[allow(dead_code)]
fn reboot(self: &MagiskD); fn reboot(self: &MagiskD);
fn post_fs_data(self: &MagiskD) -> bool;
fn handle_modules(self: &MagiskD); fn handle_modules(self: &MagiskD);
fn late_start(self: &MagiskD);
fn boot_complete(self: &MagiskD);
} }
} }

View File

@ -1,5 +1,5 @@
use crate::consts::{APP_PACKAGE_NAME, MAGISK_VER_CODE}; 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 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::libc::{O_CLOEXEC, O_CREAT, O_RDONLY, O_TRUNC, O_WRONLY};
use base::WalkResult::{Abort, Continue, Skip}; use base::WalkResult::{Abort, Continue, Skip};
@ -7,6 +7,7 @@ use base::{
cstr, error, fd_get_attr, open_fd, warn, BufReadExt, Directory, FsPath, FsPathBuf, cstr, error, fd_get_attr, open_fd, warn, BufReadExt, Directory, FsPath, FsPathBuf,
LoggedResult, ReadExt, ResultExt, Utf8CStrBuf, Utf8CStrBufArr, LoggedResult, ReadExt, ResultExt, Utf8CStrBuf, Utf8CStrBufArr,
}; };
use bit_set::BitSet;
use cxx::CxxString; use cxx::CxxString;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fs::File; use std::fs::File;
@ -479,6 +480,11 @@ impl MagiskD {
uid 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 { 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 mut info = self.manager_info.lock().unwrap();
let (uid, pkg) = info.get_manager(self, user, install); let (uid, pkg) = info.get_manager(self, user, install);
@ -489,4 +495,39 @@ impl MagiskD {
} }
uid 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
}
} }

View File

@ -75,10 +75,10 @@ if (pfs) { \
exit(0); \ exit(0); \
} }
void exec_common_scripts(const char *stage) { void exec_common_scripts(rust::Utf8CStr stage) {
LOGI("* Running %s.d scripts\n", stage); LOGI("* Running %s.d scripts\n", stage.c_str());
char path[4096]; 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); auto dir = xopen_dir(path);
if (!dir) return; if (!dir) return;
@ -97,7 +97,7 @@ void exec_common_scripts(const char *stage) {
if (entry->d_type == DT_REG) { if (entry->d_type == DT_REG) {
if (faccessat(dfd, entry->d_name, X_OK, 0) != 0) if (faccessat(dfd, entry->d_name, X_OK, 0) != 0)
continue; 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); strcpy(name, entry->d_name);
exec_t exec { exec_t exec {
.pre_exec = set_script_env, .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; return a.tv_nsec > b.tv_nsec;
} }
void exec_module_scripts(const char *stage, const rust::Vec<ModuleInfo> &module_list) { void exec_module_scripts(rust::Utf8CStr stage, const rust::Vec<ModuleInfo> &module_list) {
LOGI("* Running module %s scripts\n", stage); LOGI("* Running module %s scripts\n", stage.c_str());
if (module_list.empty()) if (module_list.empty())
return; return;
bool pfs = stage == "post-fs-data"sv; bool pfs = (string_view) stage == "post-fs-data";
if (pfs) { if (pfs) {
timespec now{}; timespec now{};
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
@ -135,10 +135,10 @@ void exec_module_scripts(const char *stage, const rust::Vec<ModuleInfo> &module_
char path[4096]; char path[4096];
for (auto &m : module_list) { 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) if (access(path, F_OK) == -1)
continue; 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 { exec_t exec {
.pre_exec = set_script_env, .pre_exec = set_script_env,
.fork = pfs ? xfork : fork_dont_care .fork = pfs ? xfork : fork_dont_care

View File

@ -13,7 +13,7 @@ pub const APP_PACKAGE_NAME: &str = "com.topjohnwu.magisk";
pub const LOGFILE: &str = "/cache/magisk.log"; pub const LOGFILE: &str = "/cache/magisk.log";
// data paths // data paths
const SECURE_DIR: &str = "/data/adb"; pub const SECURE_DIR: &str = "/data/adb";
pub const MODULEROOT: &str = concatcp!(SECURE_DIR, "/modules"); pub const MODULEROOT: &str = concatcp!(SECURE_DIR, "/modules");
// tmpfs paths // tmpfs paths