mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-02-22 10:48:36 +00:00
Fully implement daemon side of Zygisk in Rust
This commit is contained in:
parent
b575c95710
commit
15a605765c
@ -8,6 +8,7 @@ use num_traits::FromPrimitive;
|
||||
|
||||
pub use cstr::*;
|
||||
use cxx_extern::*;
|
||||
pub use ffi::fork_dont_care;
|
||||
pub use files::*;
|
||||
pub use logging::*;
|
||||
pub use misc::*;
|
||||
@ -42,6 +43,7 @@ pub mod ffi {
|
||||
type Utf8CStrRef<'a> = &'a crate::cstr::Utf8CStr;
|
||||
|
||||
fn mut_u8_patch(buf: &mut [u8], from: &[u8], to: &[u8]) -> Vec<usize>;
|
||||
fn fork_dont_care() -> i32;
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
|
@ -13,8 +13,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool zygisk_enabled = false;
|
||||
|
||||
/*********
|
||||
* Setup *
|
||||
*********/
|
||||
@ -175,10 +173,6 @@ bool MagiskD::post_fs_data() const noexcept {
|
||||
}
|
||||
|
||||
exec_common_scripts("post-fs-data");
|
||||
zygisk_enabled = get_db_setting(DbEntryKey::ZygiskConfig);
|
||||
initialize_denylist();
|
||||
setup_mounts();
|
||||
handle_modules();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -206,5 +200,5 @@ void MagiskD::boot_complete() const noexcept {
|
||||
// Ensure manager exists
|
||||
get_manager(0, nullptr, true);
|
||||
|
||||
reset_zygisk(true);
|
||||
zygisk_reset(true);
|
||||
}
|
||||
|
@ -142,13 +142,15 @@ static void handle_request_async(int client, int code, const sock_cred &cred) {
|
||||
case +RequestCode::SUPERUSER:
|
||||
su_daemon_handler(client, &cred);
|
||||
break;
|
||||
case +RequestCode::ZYGOTE_RESTART:
|
||||
case +RequestCode::ZYGOTE_RESTART: {
|
||||
LOGI("** zygote restarted\n");
|
||||
MagiskD().prune_su_access();
|
||||
auto &daemon = MagiskD();
|
||||
daemon.prune_su_access();
|
||||
scan_deny_apps();
|
||||
reset_zygisk(false);
|
||||
daemon.zygisk_reset(false);
|
||||
close(client);
|
||||
break;
|
||||
}
|
||||
case +RequestCode::SQLITE_CMD:
|
||||
MagiskD().db_exec(client);
|
||||
break;
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::consts::{MAGISK_FULL_VER, MAIN_CONFIG};
|
||||
use crate::db::Sqlite3;
|
||||
use crate::ffi::{get_magisk_tmp, ModuleInfo, RequestCode};
|
||||
use crate::ffi::{get_magisk_tmp, initialize_denylist, DbEntryKey, ModuleInfo, RequestCode};
|
||||
use crate::get_prop;
|
||||
use crate::logging::{magisk_logging, start_log_daemon};
|
||||
use crate::mount::setup_mounts;
|
||||
use crate::package::ManagerInfo;
|
||||
use base::libc::{O_CLOEXEC, O_RDONLY};
|
||||
use base::{
|
||||
@ -17,6 +18,7 @@ use std::io::{BufReader, ErrorKind, IoSlice, IoSliceMut, Read, Write};
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::os::fd::{FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
use std::os::unix::net::{AncillaryData, SocketAncillary, UnixStream};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
|
||||
// Global magiskd singleton
|
||||
@ -64,6 +66,9 @@ pub struct MagiskD {
|
||||
pub manager_info: Mutex<ManagerInfo>,
|
||||
boot_stage_lock: Mutex<BootStateFlags>,
|
||||
pub module_list: OnceLock<Vec<ModuleInfo>>,
|
||||
pub zygiskd_sockets: Mutex<(Option<UnixStream>, Option<UnixStream>)>,
|
||||
pub zygisk_enabled: AtomicBool,
|
||||
pub zygote_start_count: AtomicU32,
|
||||
sdk_int: i32,
|
||||
pub is_emulator: bool,
|
||||
is_recovery: bool,
|
||||
@ -74,6 +79,10 @@ impl MagiskD {
|
||||
self.is_recovery
|
||||
}
|
||||
|
||||
pub fn zygisk_enabled(&self) -> bool {
|
||||
self.zygisk_enabled.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
pub fn sdk_int(&self) -> i32 {
|
||||
self.sdk_int
|
||||
}
|
||||
@ -139,6 +148,14 @@ 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);
|
||||
}
|
||||
@ -215,6 +232,7 @@ pub fn daemon_entry() {
|
||||
sdk_int,
|
||||
is_emulator,
|
||||
is_recovery,
|
||||
zygote_start_count: AtomicU32::new(1),
|
||||
..Default::default()
|
||||
};
|
||||
MAGISKD.set(magiskd).ok();
|
||||
|
@ -370,7 +370,7 @@ int enable_deny() {
|
||||
|
||||
denylist_enforced = true;
|
||||
|
||||
if (!zygisk_enabled) {
|
||||
if (!MagiskD().zygisk_enabled()) {
|
||||
if (new_daemon_thread(&logcat)) {
|
||||
denylist_enforced = false;
|
||||
return DenyResponse::ERROR;
|
||||
|
@ -26,7 +26,6 @@ enum class RespondCode : int {
|
||||
END
|
||||
};
|
||||
|
||||
extern bool zygisk_enabled;
|
||||
extern std::string native_bridge;
|
||||
|
||||
void reset_zygisk(bool restore);
|
||||
|
@ -6,6 +6,8 @@ const char *get_magisk_tmp();
|
||||
void install_apk(rust::Utf8CStr apk);
|
||||
void uninstall_pkg(rust::Utf8CStr pkg);
|
||||
void update_deny_flags(int uid, rust::Str process, uint32_t &flags);
|
||||
void initialize_denylist();
|
||||
void restore_zygisk_prop();
|
||||
|
||||
// Rust bindings
|
||||
static inline rust::Utf8CStr get_magisk_tmp_rs() { return get_magisk_tmp(); }
|
||||
|
@ -81,6 +81,8 @@ pub mod ffi {
|
||||
fn install_apk(apk: Utf8CStrRef);
|
||||
fn uninstall_pkg(apk: Utf8CStrRef);
|
||||
fn update_deny_flags(uid: i32, process: &str, flags: &mut u32);
|
||||
fn initialize_denylist();
|
||||
fn restore_zygisk_prop();
|
||||
fn switch_mnt_ns(pid: i32) -> i32;
|
||||
}
|
||||
|
||||
@ -186,7 +188,6 @@ pub mod ffi {
|
||||
fn zygisk_close_logd();
|
||||
fn zygisk_get_logd() -> i32;
|
||||
fn setup_logfile();
|
||||
fn setup_mounts();
|
||||
fn clean_mounts();
|
||||
fn find_preinit_device() -> String;
|
||||
fn revert_unmount(pid: i32);
|
||||
@ -209,15 +210,16 @@ pub mod ffi {
|
||||
type MagiskD;
|
||||
fn is_recovery(&self) -> bool;
|
||||
fn sdk_int(&self) -> i32;
|
||||
fn zygisk_enabled(&self) -> bool;
|
||||
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>;
|
||||
fn get_module_fds(&self, is_64_bit: bool) -> Vec<i32>;
|
||||
|
||||
#[cxx_name = "get_db_settings"]
|
||||
fn get_db_settings_for_cxx(&self, cfg: &mut DbSettings) -> bool;
|
||||
@ -240,11 +242,9 @@ pub mod ffi {
|
||||
#[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);
|
||||
#[allow(dead_code)]
|
||||
fn handle_modules(self: &MagiskD);
|
||||
fn connect_zygiskd(self: &MagiskD, client: i32);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,7 +269,7 @@ static void inject_zygisk_libs(root_node *system) {
|
||||
}
|
||||
}
|
||||
|
||||
static void load_modules(const rust::Vec<ModuleInfo> &module_list) {
|
||||
static void load_modules(bool zygisk_enabled, const rust::Vec<ModuleInfo> &module_list) {
|
||||
node_entry::module_mnt = get_magisk_tmp() + "/"s MODULEMNT "/";
|
||||
|
||||
auto root = make_unique<root_node>("");
|
||||
@ -392,7 +392,7 @@ static void foreach_module(Func fn) {
|
||||
}
|
||||
}
|
||||
|
||||
static rust::Vec<ModuleInfo> collect_modules(bool open_zygisk) {
|
||||
static rust::Vec<ModuleInfo> collect_modules(bool zygisk_enabled, bool open_zygisk) {
|
||||
rust::Vec<ModuleInfo> modules;
|
||||
foreach_module([&](int dfd, dirent *entry, int modfd) {
|
||||
if (faccessat(modfd, "remove", F_OK, 0) == 0) {
|
||||
@ -475,11 +475,12 @@ static rust::Vec<ModuleInfo> collect_modules(bool open_zygisk) {
|
||||
}
|
||||
|
||||
void MagiskD::handle_modules() const noexcept {
|
||||
bool zygisk = zygisk_enabled();
|
||||
prepare_modules();
|
||||
exec_module_scripts("post-fs-data", collect_modules(false));
|
||||
exec_module_scripts("post-fs-data", collect_modules(zygisk, false));
|
||||
// Recollect modules (module scripts could remove itself)
|
||||
auto list = collect_modules(true);
|
||||
load_modules(list);
|
||||
auto list = collect_modules(zygisk, true);
|
||||
load_modules(zygisk, list);
|
||||
set_module_list(std::move(list));
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ static void set_script_env() {
|
||||
char new_path[4096];
|
||||
ssprintf(new_path, sizeof(new_path), "%s:%s", getenv("PATH"), get_magisk_tmp());
|
||||
setenv("PATH", new_path, 1);
|
||||
if (zygisk_enabled)
|
||||
if (MagiskD().zygisk_enabled())
|
||||
setenv("ZYGISK_ENABLED", "1", 1);
|
||||
};
|
||||
|
||||
|
@ -1,10 +1,18 @@
|
||||
use crate::consts::MODULEROOT;
|
||||
use crate::daemon::{to_user_id, IpcRead, MagiskD, UnixSocketExt};
|
||||
use crate::ffi::{update_deny_flags, ZygiskRequest, ZygiskStateFlags};
|
||||
use crate::ffi::{
|
||||
get_magisk_tmp, restore_zygisk_prop, update_deny_flags, ZygiskRequest, ZygiskStateFlags,
|
||||
};
|
||||
use base::libc::{O_CLOEXEC, O_CREAT, O_RDONLY};
|
||||
use base::{cstr, open_fd, Directory, FsPathBuf, LoggedResult, Utf8CStrBufArr, WriteExt};
|
||||
use base::{
|
||||
cstr, error, fork_dont_care, libc, open_fd, raw_cstr, warn, Directory, FsPathBuf, LoggedError,
|
||||
LoggedResult, Utf8CStrBufArr, WriteExt,
|
||||
};
|
||||
use std::fmt::Write;
|
||||
use std::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::ptr;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
const UNMOUNT_MASK: u32 =
|
||||
ZygiskStateFlags::ProcessOnDenyList.repr | ZygiskStateFlags::DenyListEnforced.repr;
|
||||
@ -22,21 +30,119 @@ impl MagiskD {
|
||||
};
|
||||
match code {
|
||||
ZygiskRequest::GetInfo => self.get_process_info(client)?,
|
||||
ZygiskRequest::ConnectCompanion => self.connect_zygiskd(client.as_raw_fd()),
|
||||
ZygiskRequest::ConnectCompanion => self.connect_zygiskd(client),
|
||||
ZygiskRequest::GetModDir => self.get_mod_dir(client)?,
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_module_fds(&self, is_64_bit: bool) -> Vec<RawFd> {
|
||||
if let Some(module_list) = self.module_list.get() {
|
||||
pub fn zygisk_reset(&self, mut restore: bool) {
|
||||
if !self.zygisk_enabled.load(Ordering::Acquire) {
|
||||
return;
|
||||
}
|
||||
|
||||
if restore {
|
||||
self.zygote_start_count.store(1, Ordering::Release);
|
||||
} else {
|
||||
*self.zygiskd_sockets.lock().unwrap() = (None, None);
|
||||
if self.zygote_start_count.fetch_add(1, Ordering::AcqRel) > 3 {
|
||||
warn!("zygote crashes too many times, rolling-back");
|
||||
restore = true;
|
||||
}
|
||||
}
|
||||
|
||||
if restore {
|
||||
restore_zygisk_prop();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_module_fds(&self, is_64_bit: bool) -> Option<Vec<RawFd>> {
|
||||
self.module_list.get().map(|module_list| {
|
||||
module_list
|
||||
.iter()
|
||||
.map(|m| if is_64_bit { m.z64 } else { m.z32 })
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
fn exec_zygiskd(is_64_bit: bool, remote: UnixStream) {
|
||||
// This fd has to survive exec
|
||||
unsafe {
|
||||
libc::fcntl(remote.as_raw_fd(), libc::F_SETFD, 0);
|
||||
}
|
||||
|
||||
// Start building the exec arguments
|
||||
let mut exe = Utf8CStrBufArr::<64>::new();
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
let magisk = if is_64_bit { "magisk" } else { "magisk32" };
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
let magisk = "magisk";
|
||||
|
||||
let exe = FsPathBuf::new(&mut exe).join(get_magisk_tmp()).join(magisk);
|
||||
|
||||
let mut fd_str = Utf8CStrBufArr::<16>::new();
|
||||
write!(fd_str, "{}", remote.as_raw_fd()).ok();
|
||||
unsafe {
|
||||
libc::execl(
|
||||
exe.as_ptr(),
|
||||
raw_cstr!(""),
|
||||
raw_cstr!("zygisk"),
|
||||
raw_cstr!("companion"),
|
||||
fd_str.as_ptr(),
|
||||
ptr::null() as *const libc::c_char,
|
||||
);
|
||||
libc::exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
fn connect_zygiskd(&self, mut client: UnixStream) {
|
||||
let mut zygiskd_sockets = self.zygiskd_sockets.lock().unwrap();
|
||||
let result: LoggedResult<()> = try {
|
||||
let is_64_bit = client.ipc_read_int()? != 0;
|
||||
let socket = if is_64_bit {
|
||||
&mut zygiskd_sockets.1
|
||||
} else {
|
||||
Vec::new()
|
||||
&mut zygiskd_sockets.0
|
||||
};
|
||||
|
||||
if let Some(fd) = socket {
|
||||
// Make sure the socket is still valid
|
||||
let mut pfd = libc::pollfd {
|
||||
fd: fd.as_raw_fd(),
|
||||
events: 0,
|
||||
revents: 0,
|
||||
};
|
||||
if unsafe { libc::poll(&mut pfd, 1, 0) } != 0 || pfd.revents != 0 {
|
||||
// Any revent means error
|
||||
*socket = None;
|
||||
}
|
||||
}
|
||||
|
||||
let socket = if let Some(fd) = socket {
|
||||
fd
|
||||
} else {
|
||||
// Create a new socket pair and fork zygiskd process
|
||||
let (local, remote) = UnixStream::pair()?;
|
||||
if fork_dont_care() == 0 {
|
||||
Self::exec_zygiskd(is_64_bit, remote);
|
||||
}
|
||||
*socket = Some(local);
|
||||
let local = socket.as_mut().unwrap();
|
||||
if let Some(module_fds) = self.get_module_fds(is_64_bit) {
|
||||
local.send_fds(&module_fds)?;
|
||||
}
|
||||
if local.ipc_read_int()? != 0 {
|
||||
Err(LoggedError::default())?;
|
||||
}
|
||||
local
|
||||
};
|
||||
socket.send_fds(&[client.as_raw_fd()])?;
|
||||
};
|
||||
if result.is_err() {
|
||||
error!("zygiskd startup error");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,75 +30,10 @@ extern "C" [[maybe_unused]] NativeBridgeCallbacks NativeBridgeItf {
|
||||
|
||||
// The following code runs in magiskd
|
||||
|
||||
static pthread_mutex_t zygiskd_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int zygiskd_sockets[] = { -1, -1 };
|
||||
#define zygiskd_socket zygiskd_sockets[is_64_bit]
|
||||
|
||||
void MagiskD::connect_zygiskd(int client) const noexcept {
|
||||
mutex_guard g(zygiskd_lock);
|
||||
|
||||
bool is_64_bit = read_int(client);
|
||||
if (zygiskd_socket >= 0) {
|
||||
// Make sure the socket is still valid
|
||||
pollfd pfd = { zygiskd_socket, 0, 0 };
|
||||
poll(&pfd, 1, 0);
|
||||
if (pfd.revents) {
|
||||
// Any revent means error
|
||||
close(zygiskd_socket);
|
||||
zygiskd_socket = -1;
|
||||
}
|
||||
}
|
||||
if (zygiskd_socket < 0) {
|
||||
int fds[2];
|
||||
socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds);
|
||||
zygiskd_socket = fds[0];
|
||||
if (fork_dont_care() == 0) {
|
||||
char exe[64];
|
||||
#if defined(__LP64__)
|
||||
ssprintf(exe, sizeof(exe), "%s/magisk%s", get_magisk_tmp(), (is_64_bit ? "" : "32"));
|
||||
#else
|
||||
ssprintf(exe, sizeof(exe), "%s/magisk", get_magisk_tmp());
|
||||
#endif
|
||||
// This fd has to survive exec
|
||||
fcntl(fds[1], F_SETFD, 0);
|
||||
char buf[16];
|
||||
ssprintf(buf, sizeof(buf), "%d", fds[1]);
|
||||
execl(exe, "", "zygisk", "companion", buf, (char *) nullptr);
|
||||
exit(-1);
|
||||
}
|
||||
close(fds[1]);
|
||||
rust::Vec<int> module_fds = get_module_fds(is_64_bit);
|
||||
send_fds(zygiskd_socket, rust::Slice<const int>(module_fds));
|
||||
// Wait for ack
|
||||
if (read_int(zygiskd_socket) != 0) {
|
||||
LOGE("zygiskd startup error\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
send_fd(zygiskd_socket, client);
|
||||
}
|
||||
|
||||
void reset_zygisk(bool restore) {
|
||||
if (!zygisk_enabled) return;
|
||||
static atomic_uint zygote_start_count{1};
|
||||
if (!restore) {
|
||||
close(zygiskd_sockets[0]);
|
||||
close(zygiskd_sockets[1]);
|
||||
zygiskd_sockets[0] = zygiskd_sockets[1] = -1;
|
||||
}
|
||||
if (restore) {
|
||||
zygote_start_count = 1;
|
||||
} else if (zygote_start_count.fetch_add(1) > 3) {
|
||||
LOGW("zygote crashes too many times, rolling-back\n");
|
||||
restore = true;
|
||||
}
|
||||
if (restore) {
|
||||
void restore_zygisk_prop() {
|
||||
string native_bridge_orig = "0";
|
||||
if (native_bridge.length() > strlen(ZYGISKLDR)) {
|
||||
native_bridge_orig = native_bridge.substr(strlen(ZYGISKLDR));
|
||||
}
|
||||
set_prop(NBPROP, native_bridge_orig.data());
|
||||
} else {
|
||||
set_prop(NBPROP, native_bridge.data());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user