You've already forked ZygiskNext
mirror of
https://github.com/Dr-TSNG/ZygiskNext.git
synced 2025-08-27 23:46:34 +00:00
Fix zygote restart & Show zygisksu status on module.prop
This commit is contained in:
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
rust-version = "1.67"
|
||||
|
||||
[dependencies]
|
||||
android_logger = "0.12.0"
|
||||
android_logger = "0.13.0"
|
||||
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
||||
clap = { version = "4.1.4", features = ["derive"] }
|
||||
const_format = "0.2.5"
|
||||
|
||||
@@ -16,26 +16,25 @@ pub const MAX_LOG_LEVEL: LevelFilter = LevelFilter::Trace;
|
||||
#[cfg(not(debug_assertions))]
|
||||
pub const MAX_LOG_LEVEL: LevelFilter = LevelFilter::Info;
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[macro_export]
|
||||
macro_rules! lp_select {
|
||||
($lp32:expr, $lp64:expr) => { $lp64 };
|
||||
}
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
#[macro_export]
|
||||
macro_rules! lp_select {
|
||||
($lp32:expr, $lp64:expr) => { $lp32 };
|
||||
}
|
||||
|
||||
pub const PROP_NATIVE_BRIDGE: &str = "ro.dalvik.vm.native.bridge";
|
||||
pub const PROP_SVC_ZYGOTE: &str = "init.svc.zygote";
|
||||
pub const PROP_CTL_RESTART: &str = "ctl.restart";
|
||||
pub const ZYGISK_LOADER: &str = "libzygiskloader.so";
|
||||
|
||||
pub const SOCKET_PLACEHOLDER: &str = "socket_placeholder";
|
||||
|
||||
pub const PATH_MODULE_DIR: &str = "..";
|
||||
pub const PATH_MODULES_DIR: &str = "..";
|
||||
pub const PATH_MODULE_PROP: &str = "module.prop";
|
||||
pub const PATH_ZYGISKD32: &str = "bin/zygiskd32";
|
||||
pub const PATH_ZYGISKD64: &str = "bin/zygiskd64";
|
||||
pub const PATH_TMP_DIR: &str = concatcp!("/dev/", SOCKET_PLACEHOLDER);
|
||||
pub const PATH_TMP_PROP: &str = concatcp!("/dev/", SOCKET_PLACEHOLDER, "/module.prop");
|
||||
|
||||
pub const STATUS_LOADED: &str = "😋 Zygisksu is loaded";
|
||||
pub const STATUS_CRASHED: &str = "❌ Zygiskd has crashed";
|
||||
pub const STATUS_ROOT_IMPL_NONE: &str = "❌ Unknown root implementation";
|
||||
pub const STATUS_ROOT_IMPL_TOO_OLD: &str = "❌ Root implementation version too old";
|
||||
pub const STATUS_ROOT_IMPL_ABNORMAL: &str = "❌ Abnormal root implementation version";
|
||||
pub const STATUS_ROOT_IMPL_MULTIPLE: &str = "❌ Multiple root implementations installed";
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
|
||||
#[repr(u8)]
|
||||
|
||||
@@ -38,7 +38,7 @@ fn init_android_logger(tag: &str) {
|
||||
}
|
||||
|
||||
fn start() -> Result<()> {
|
||||
root_impl::setup()?;
|
||||
root_impl::setup();
|
||||
let cli = Args::parse();
|
||||
match cli.command {
|
||||
Commands::Watchdog => watchdog::entry()?,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use anyhow::{bail, Result};
|
||||
use nix::libc::prctl;
|
||||
use crate::constants::{MIN_KSU_VERSION, MAX_KSU_VERSION};
|
||||
|
||||
@@ -8,14 +7,20 @@ const CMD_GET_VERSION: usize = 2;
|
||||
const CMD_GET_ALLOW_LIST: usize = 5;
|
||||
const CMD_GET_DENY_LIST: usize = 6;
|
||||
|
||||
pub fn is_kernel_su() -> Result<bool> {
|
||||
pub enum Version {
|
||||
Supported,
|
||||
TooOld,
|
||||
Abnormal,
|
||||
}
|
||||
|
||||
pub fn get_kernel_su() -> Option<Version> {
|
||||
let mut version = 0;
|
||||
unsafe { prctl(KERNEL_SU_OPTION, CMD_GET_VERSION, &mut version as *mut i32) };
|
||||
return match version {
|
||||
0 => Ok(false),
|
||||
MIN_KSU_VERSION..=MAX_KSU_VERSION => Ok(true),
|
||||
1..=MIN_KSU_VERSION => bail!("KernelSU version too old: {}", version),
|
||||
_ => bail!("KernelSU version abnormal: {}", version)
|
||||
match version {
|
||||
0 => None,
|
||||
MIN_KSU_VERSION..=MAX_KSU_VERSION => Some(Version::Supported),
|
||||
1..=MIN_KSU_VERSION => Some(Version::TooOld),
|
||||
_ => Some(Version::Abnormal)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
use anyhow::{bail, Result};
|
||||
use std::process::{Command, Stdio};
|
||||
use crate::constants::MIN_MAGISK_VERSION;
|
||||
|
||||
pub fn is_magisk() -> Result<bool> {
|
||||
pub enum Version {
|
||||
Supported,
|
||||
TooOld,
|
||||
}
|
||||
|
||||
pub fn get_magisk() -> Option<Version> {
|
||||
let version: Option<i32> = Command::new("magisk")
|
||||
.arg("-V")
|
||||
.stdout(Stdio::piped())
|
||||
@@ -10,13 +14,13 @@ pub fn is_magisk() -> Result<bool> {
|
||||
.and_then(|child| child.wait_with_output().ok())
|
||||
.and_then(|output| String::from_utf8(output.stdout).ok())
|
||||
.and_then(|output| output.trim().parse().ok());
|
||||
if let Some(version) = version {
|
||||
if version < MIN_MAGISK_VERSION {
|
||||
bail!("Magisk version too old: {}", version);
|
||||
version.map(|version| {
|
||||
if version >= MIN_MAGISK_VERSION {
|
||||
Version::Supported
|
||||
} else {
|
||||
Version::TooOld
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(false)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn uid_on_allowlist(uid: i32) -> bool {
|
||||
|
||||
@@ -2,33 +2,52 @@ mod kernelsu;
|
||||
mod magisk;
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
enum RootImpl {
|
||||
pub enum RootImpl {
|
||||
None,
|
||||
TooOld,
|
||||
Abnormal,
|
||||
Multiple,
|
||||
KernelSU,
|
||||
Magisk,
|
||||
}
|
||||
|
||||
static ROOT_IMPL: OnceCell<RootImpl> = OnceCell::new();
|
||||
|
||||
pub fn setup() -> Result<()> {
|
||||
if kernelsu::is_kernel_su()? {
|
||||
if let Ok(true) = magisk::is_magisk() {
|
||||
bail!("Multiple root implementation");
|
||||
pub fn setup() {
|
||||
let ksu_version = kernelsu::get_kernel_su();
|
||||
let magisk_version = magisk::get_magisk();
|
||||
|
||||
let _ = match (ksu_version, magisk_version) {
|
||||
(None, None) => ROOT_IMPL.set(RootImpl::None),
|
||||
(Some(_), Some(_)) => ROOT_IMPL.set(RootImpl::Multiple),
|
||||
(Some(ksu_version), None) => {
|
||||
let val = match ksu_version {
|
||||
kernelsu::Version::Supported => RootImpl::KernelSU,
|
||||
kernelsu::Version::TooOld => RootImpl::TooOld,
|
||||
kernelsu::Version::Abnormal => RootImpl::Abnormal,
|
||||
};
|
||||
ROOT_IMPL.set(val)
|
||||
}
|
||||
let _ = ROOT_IMPL.set(RootImpl::KernelSU);
|
||||
} else if magisk::is_magisk()? {
|
||||
let _ = ROOT_IMPL.set(RootImpl::Magisk);
|
||||
} else {
|
||||
bail!("Unknown root implementation");
|
||||
}
|
||||
Ok(())
|
||||
(None, Some(magisk_version)) => {
|
||||
let val = match magisk_version {
|
||||
magisk::Version::Supported => RootImpl::Magisk,
|
||||
magisk::Version::TooOld => RootImpl::TooOld,
|
||||
};
|
||||
ROOT_IMPL.set(val)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_impl() -> &'static RootImpl {
|
||||
ROOT_IMPL.get().unwrap()
|
||||
}
|
||||
|
||||
pub fn uid_on_allowlist(uid: i32) -> bool {
|
||||
match ROOT_IMPL.get().unwrap() {
|
||||
RootImpl::KernelSU => kernelsu::uid_on_allowlist(uid),
|
||||
RootImpl::Magisk => magisk::uid_on_allowlist(uid),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,5 +55,6 @@ pub fn uid_on_denylist(uid: i32) -> bool {
|
||||
match ROOT_IMPL.get().unwrap() {
|
||||
RootImpl::KernelSU => kernelsu::uid_on_denylist(uid),
|
||||
RootImpl::Magisk => magisk::uid_on_denylist(uid),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,17 @@ use std::os::unix::net::UnixListener;
|
||||
use nix::sys::socket::{AddressFamily, SockFlag, SockType, UnixAddr};
|
||||
use rand::distributions::{Alphanumeric, DistString};
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[macro_export]
|
||||
macro_rules! lp_select {
|
||||
($lp32:expr, $lp64:expr) => { $lp64 };
|
||||
}
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
#[macro_export]
|
||||
macro_rules! lp_select {
|
||||
($lp32:expr, $lp64:expr) => { $lp32 };
|
||||
}
|
||||
|
||||
pub fn random_string() -> String {
|
||||
Alphanumeric.sample_string(&mut rand::thread_rng(), 8)
|
||||
}
|
||||
|
||||
@@ -1,21 +1,35 @@
|
||||
use crate::{constants, utils};
|
||||
use crate::{constants, root_impl, utils};
|
||||
use anyhow::{bail, Result};
|
||||
use nix::unistd::{getgid, getuid, Pid};
|
||||
use std::process::{Child, Command};
|
||||
use std::sync::mpsc;
|
||||
use std::{fs, thread};
|
||||
use std::{fs, io, thread};
|
||||
use std::ffi::CString;
|
||||
use std::io::{BufRead, Write};
|
||||
use std::os::unix::net::UnixListener;
|
||||
use std::time::Duration;
|
||||
use binder::IBinder;
|
||||
use nix::errno::Errno;
|
||||
use nix::libc;
|
||||
use nix::sys::signal::{kill, Signal};
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
static mut LOCK: Option<UnixListener> = None;
|
||||
static LOCK: OnceCell<UnixListener> = OnceCell::new();
|
||||
static PROP_SECTIONS: OnceCell<[String; 2]> = OnceCell::new();
|
||||
|
||||
pub fn entry() -> Result<()> {
|
||||
log::info!("Start zygisksu watchdog");
|
||||
check_permission()?;
|
||||
ensure_single_instance()?;
|
||||
spawn_daemon()
|
||||
mount_prop()?;
|
||||
if check_and_set_hint()? == false {
|
||||
log::warn!("Requirements not met, exiting");
|
||||
utils::set_property(constants::PROP_NATIVE_BRIDGE, &utils::get_native_bridge())?;
|
||||
return Ok(())
|
||||
}
|
||||
let end = spawn_daemon();
|
||||
set_prop_hint(constants::STATUS_CRASHED)?;
|
||||
end
|
||||
}
|
||||
|
||||
fn check_permission() -> Result<()> {
|
||||
@@ -43,12 +57,83 @@ fn ensure_single_instance() -> Result<()> {
|
||||
log::info!("Ensure single instance");
|
||||
let name = String::from("zygiskwd") + constants::SOCKET_PLACEHOLDER;
|
||||
match utils::abstract_namespace_socket(&name) {
|
||||
Ok(socket) => unsafe { LOCK = Some(socket) },
|
||||
Ok(socket) => { let _ = LOCK.set(socket); }
|
||||
Err(e) => bail!("Failed to acquire lock: {e}. Maybe another instance is running?")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mount_prop() -> Result<()> {
|
||||
let module_prop = fs::File::open(constants::PATH_MODULE_PROP)?;
|
||||
let mut section = 0;
|
||||
let mut sections: [String; 2] = [String::new(), String::new()];
|
||||
let lines = io::BufReader::new(module_prop).lines();
|
||||
for line in lines {
|
||||
let line = line?;
|
||||
if line.starts_with("description=") {
|
||||
sections[0].push_str("description=");
|
||||
sections[1].push_str(line.trim_start_matches("description="));
|
||||
sections[1].push('\n');
|
||||
section = 1;
|
||||
} else {
|
||||
sections[section].push_str(&line);
|
||||
sections[section].push('\n');
|
||||
}
|
||||
}
|
||||
let _ = PROP_SECTIONS.set(sections);
|
||||
|
||||
fs::create_dir(constants::PATH_TMP_DIR)?;
|
||||
|
||||
// FIXME: sys_mount cannot be compiled on 32 bit
|
||||
unsafe {
|
||||
let r = libc::mount(
|
||||
CString::new("tmpfs")?.as_ptr(),
|
||||
CString::new(constants::PATH_TMP_DIR)?.as_ptr(),
|
||||
CString::new("tmpfs")?.as_ptr(),
|
||||
0,
|
||||
CString::new("mode=755")?.as_ptr() as *const libc::c_void,
|
||||
);
|
||||
Errno::result(r)?;
|
||||
let _file = fs::File::create(constants::PATH_TMP_PROP)?;
|
||||
let r = libc::mount(
|
||||
CString::new(constants::PATH_TMP_PROP)?.as_ptr(),
|
||||
CString::new(constants::PATH_MODULE_PROP)?.as_ptr(),
|
||||
std::ptr::null(),
|
||||
libc::MS_BIND,
|
||||
std::ptr::null(),
|
||||
);
|
||||
Errno::result(r)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_prop_hint(hint: &str) -> Result<()> {
|
||||
let mut file = fs::File::create(constants::PATH_TMP_PROP)?;
|
||||
let sections = PROP_SECTIONS.get().unwrap();
|
||||
file.write_all(sections[0].as_bytes())?;
|
||||
file.write_all(b"[")?;
|
||||
file.write_all(hint.as_bytes())?;
|
||||
file.write_all(b"] ")?;
|
||||
file.write_all(sections[1].as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_and_set_hint() -> Result<bool> {
|
||||
let root_impl = root_impl::get_impl();
|
||||
match root_impl {
|
||||
root_impl::RootImpl::None => set_prop_hint(constants::STATUS_ROOT_IMPL_NONE)?,
|
||||
root_impl::RootImpl::TooOld => set_prop_hint(constants::STATUS_ROOT_IMPL_TOO_OLD)?,
|
||||
root_impl::RootImpl::Abnormal => set_prop_hint(constants::STATUS_ROOT_IMPL_ABNORMAL)?,
|
||||
root_impl::RootImpl::Multiple => set_prop_hint(constants::STATUS_ROOT_IMPL_MULTIPLE)?,
|
||||
_ => {
|
||||
set_prop_hint(constants::STATUS_LOADED)?;
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn spawn_daemon() -> Result<()> {
|
||||
let mut lives = 5;
|
||||
loop {
|
||||
@@ -99,7 +184,6 @@ fn spawn_daemon() -> Result<()> {
|
||||
|
||||
log::error!("Restarting zygote...");
|
||||
utils::set_property(constants::PROP_NATIVE_BRIDGE, constants::ZYGISK_LOADER)?;
|
||||
utils::set_property(constants::PROP_SVC_ZYGOTE, "restart")?;
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
utils::set_property(constants::PROP_CTL_RESTART, "zygote")?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ fn get_arch() -> Result<&'static str> {
|
||||
|
||||
fn load_modules(arch: &str) -> Result<Vec<Module>> {
|
||||
let mut modules = Vec::new();
|
||||
let dir = match fs::read_dir(constants::PATH_MODULE_DIR) {
|
||||
let dir = match fs::read_dir(constants::PATH_MODULES_DIR) {
|
||||
Ok(dir) => dir,
|
||||
Err(e) => {
|
||||
log::warn!("Failed reading modules directory: {}", e);
|
||||
@@ -232,7 +232,7 @@ fn handle_daemon_action(mut stream: UnixStream, context: &Context) -> Result<()>
|
||||
DaemonSocketAction::GetModuleDir => {
|
||||
let index = stream.read_usize()?;
|
||||
let module = &context.modules[index];
|
||||
let dir = format!("{}/{}", constants::PATH_MODULE_DIR, module.name);
|
||||
let dir = format!("{}/{}", constants::PATH_MODULES_DIR, module.name);
|
||||
let dir = fs::File::open(dir)?;
|
||||
stream.send_fd(dir.as_raw_fd())?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user