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 *
*********/
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<int> 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);
}

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::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<ModuleInfo> {
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);
}

View File

@ -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<ModuleInfo> &module_list);
void clear_pkg(const char *pkg, int user_id);
[[noreturn]] void install_module(const char *file);

View File

@ -2,7 +2,14 @@
#include <base.hpp>
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<ModuleInfo> &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);

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 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<ModuleInfo>);
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<ModuleInfo>);
fn module_list(&self) -> &Vec<ModuleInfo>;
#[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);
}
}

View File

@ -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
}
}

View File

@ -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<ModuleInfo> &module_list) {
LOGI("* Running module %s scripts\n", stage);
void exec_module_scripts(rust::Utf8CStr stage, const rust::Vec<ModuleInfo> &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<ModuleInfo> &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

View File

@ -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