diff --git a/module/build.gradle.kts b/module/build.gradle.kts index 7558a56..1c9ab17 100644 --- a/module/build.gradle.kts +++ b/module/build.gradle.kts @@ -107,7 +107,6 @@ androidComponents.onVariants { variant -> .putLong(real.length()) .array() sig.update(buffer) - println("sha $path ${real.length()}") real.forEachBlock { bytes, size -> sig.update(bytes, 0, size) } diff --git a/zygiskd/src/companion.rs b/zygiskd/src/companion.rs index 74dc45a..8d158a5 100644 --- a/zygiskd/src/companion.rs +++ b/zygiskd/src/companion.rs @@ -1,13 +1,12 @@ +use crate::dl; +use crate::utils::{check_unix_socket, UnixStreamExt}; +use anyhow::Result; +use passfd::FdPassingExt; +use rustix::fs::fstat; use std::ffi::c_void; use std::os::fd::{AsRawFd, FromRawFd, RawFd}; use std::os::unix::net::UnixStream; use std::thread; -use anyhow::Result; -use passfd::FdPassingExt; -use rustix::fs::fstat; -use tokio::io::AsyncWriteExt; -use crate::utils::{check_unix_socket, UnixStreamExt}; -use crate::dl; type ZygiskCompanionEntryFn = unsafe extern "C" fn(i32); @@ -28,7 +27,7 @@ pub fn entry(fd: i32) { None => { log::debug!("No companion entry for `{name}`"); stream.write_u8(0).expect("reply 0"); - return (); + std::process::exit(0); } }; @@ -43,7 +42,9 @@ pub fn entry(fd: i32) { stream.write_u8(1).expect("reply success"); thread::spawn(move || { let st0 = fstat(&stream).expect("failed to stat stream"); - unsafe { entry(stream.as_raw_fd()); } + unsafe { + entry(stream.as_raw_fd()); + } // Only close client if it is the same file so we don't // accidentally close a re-used file descriptor. // This check is required because the module companion diff --git a/zygiskd/src/constants.rs b/zygiskd/src/constants.rs index c538d4c..747584a 100644 --- a/zygiskd/src/constants.rs +++ b/zygiskd/src/constants.rs @@ -1,32 +1,26 @@ +use crate::lp_select; use bitflags::bitflags; -use const_format::concatcp; use konst::primitive::parse_i32; use konst::unwrap_ctx; use log::LevelFilter; use num_enum::TryFromPrimitive; -use crate::lp_select; pub const MIN_KSU_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MIN_KSU_VERSION"))); pub const MAX_KSU_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MAX_KSU_VERSION"))); pub const MIN_MAGISK_VERSION: i32 = unwrap_ctx!(parse_i32(env!("MIN_MAGISK_VERSION"))); -pub const ZKSU_VERSION: &'static str = env!("ZKSU_VERSION"); +pub const ZKSU_VERSION: &str = env!("ZKSU_VERSION"); #[cfg(debug_assertions)] pub const MAX_LOG_LEVEL: LevelFilter = LevelFilter::Trace; #[cfg(not(debug_assertions))] pub const MAX_LOG_LEVEL: LevelFilter = LevelFilter::Info; - - pub const PATH_MODULES_DIR: &str = ".."; -pub const PATH_MODULE_PROP: &str = "module.prop"; pub const ZYGOTE_INJECTED: i32 = lp_select!(5, 4); pub const DAEMON_SET_INFO: i32 = lp_select!(7, 6); pub const DAEMON_SET_ERROR_INFO: i32 = lp_select!(9, 8); pub const SYSTEM_SERVER_STARTED: i32 = 10; -pub const MAX_RESTART_COUNT: i32 = 5; - #[derive(Debug, Eq, PartialEq, TryFromPrimitive)] #[repr(u8)] pub enum DaemonSocketAction { diff --git a/zygiskd/src/dl.rs b/zygiskd/src/dl.rs index 1b69149..a401fcd 100644 --- a/zygiskd/src/dl.rs +++ b/zygiskd/src/dl.rs @@ -30,13 +30,13 @@ extern "C" { } type AndroidCreateNamespaceFn = unsafe extern "C" fn( - *const c_char, // name - *const c_char, // ld_library_path - *const c_char, // default_library_path - u64, // type - *const c_char, // permitted_when_isolated_path - *mut AndroidNamespace, // parent - *const c_void, // caller_addr + *const c_char, // name + *const c_char, // ld_library_path + *const c_char, // default_library_path + u64, // type + *const c_char, // permitted_when_isolated_path + *mut AndroidNamespace, // parent + *const c_void, // caller_addr ) -> *mut AndroidNamespace; pub unsafe fn dlopen(path: &str, flags: i32) -> Result<*mut c_void> { @@ -57,11 +57,15 @@ pub unsafe fn dlopen(path: &str, flags: i32) -> Result<*mut c_void> { libc::RTLD_DEFAULT, std::ffi::CString::new("__loader_android_create_namespace")?.as_ptr(), ); - let android_create_namespace_fn: AndroidCreateNamespaceFn = std::mem::transmute(android_create_namespace_fn); + let android_create_namespace_fn: AndroidCreateNamespaceFn = + std::mem::transmute(android_create_namespace_fn); let ns = android_create_namespace_fn( - filename, dir, std::ptr::null(), + filename, + dir, + std::ptr::null(), ANDROID_NAMESPACE_TYPE_SHARED, - std::ptr::null(), std::ptr::null_mut(), + std::ptr::null(), + std::ptr::null_mut(), &dlopen as *const _ as *const c_void, ); if ns != std::ptr::null_mut() { diff --git a/zygiskd/src/main.rs b/zygiskd/src/main.rs index 7692a71..c4c1116 100644 --- a/zygiskd/src/main.rs +++ b/zygiskd/src/main.rs @@ -1,11 +1,10 @@ +mod companion; mod constants; mod dl; mod root_impl; mod utils; mod zygiskd; -mod companion; -use std::future::Future; use crate::constants::ZKSU_VERSION; fn init_android_logger(tag: &str) { diff --git a/zygiskd/src/root_impl/kernelsu.rs b/zygiskd/src/root_impl/kernelsu.rs index 18e4dec..da7177e 100644 --- a/zygiskd/src/root_impl/kernelsu.rs +++ b/zygiskd/src/root_impl/kernelsu.rs @@ -71,7 +71,7 @@ pub fn uid_should_umount(uid: i32) -> bool { // TODO: signature pub fn uid_is_manager(uid: i32) -> bool { if let Ok(s) = rustix::fs::stat("/data/user_de/0/me.weishu.kernelsu") { - return s.st_uid == uid as u32 + return s.st_uid == uid as u32; } false } diff --git a/zygiskd/src/root_impl/magisk.rs b/zygiskd/src/root_impl/magisk.rs index b643cef..d815f72 100644 --- a/zygiskd/src/root_impl/magisk.rs +++ b/zygiskd/src/root_impl/magisk.rs @@ -1,5 +1,5 @@ -use std::process::{Command, Stdio}; use crate::constants::MIN_MAGISK_VERSION; +use std::process::{Command, Stdio}; const MAGISK_VANILLA: &str = "com.topjohnwu.magisk"; const MAGISK_ALPHA: &str = "io.github.vvb2060.magisk"; @@ -15,21 +15,25 @@ pub fn get_magisk() -> Option { Command::new("magisk") .arg("-v") .stdout(Stdio::piped()) - .spawn().ok() + .spawn() + .ok() .and_then(|child| child.wait_with_output().ok()) .and_then(|output| String::from_utf8(output.stdout).ok()) .map(|version| { - if (version.contains("alpha")) { + if version.contains("alpha") { MAGISK_ALPHA } else { MAGISK_VANILLA } }) - .map(|variant| { unsafe { VARIANT = variant }; }); + .map(|variant| { + unsafe { VARIANT = variant }; + }); let version: Option = Command::new("magisk") .arg("-V") .stdout(Stdio::piped()) - .spawn().ok() + .spawn() + .ok() .and_then(|child| child.wait_with_output().ok()) .and_then(|output| String::from_utf8(output.stdout).ok()) .and_then(|output| output.trim().parse().ok()); @@ -45,19 +49,24 @@ pub fn get_magisk() -> Option { pub fn uid_granted_root(uid: i32) -> bool { Command::new("magisk") .arg("--sqlite") - .arg(format!("select 1 from policies where uid={uid} and policy=2 limit 1")) + .arg(format!( + "select 1 from policies where uid={uid} and policy=2 limit 1" + )) .stdout(Stdio::piped()) - .spawn().ok() + .spawn() + .ok() .and_then(|child| child.wait_with_output().ok()) .and_then(|output| String::from_utf8(output.stdout).ok()) - .map(|output| output.is_empty()) == Some(false) + .map(|output| output.is_empty()) + == Some(false) } pub fn uid_should_umount(uid: i32) -> bool { let output = Command::new("pm") .args(["list", "packages", "--uid", &uid.to_string()]) .stdout(Stdio::piped()) - .spawn().ok() + .spawn() + .ok() .and_then(|child| child.wait_with_output().ok()) .and_then(|output| String::from_utf8(output.stdout).ok()); let line = match output { @@ -73,12 +82,16 @@ pub fn uid_should_umount(uid: i32) -> bool { }; Command::new("magisk") .arg("--sqlite") - .arg(format!("select 1 from denylist where package_name=\"{pkg}\" limit 1")) + .arg(format!( + "select 1 from denylist where package_name=\"{pkg}\" limit 1" + )) .stdout(Stdio::piped()) - .spawn().ok() + .spawn() + .ok() .and_then(|child| child.wait_with_output().ok()) .and_then(|output| String::from_utf8(output.stdout).ok()) - .map(|output| output.is_empty()) == Some(false) + .map(|output| output.is_empty()) + == Some(false) } // TODO: signature @@ -86,9 +99,12 @@ pub fn uid_should_umount(uid: i32) -> bool { pub fn uid_is_manager(uid: i32) -> bool { let output = Command::new("magisk") .arg("--sqlite") - .arg(format!("select value from strings where key=\"requester\" limit 1")) + .arg(format!( + "select value from strings where key=\"requester\" limit 1" + )) .stdout(Stdio::piped()) - .spawn().ok() + .spawn() + .ok() .and_then(|child| child.wait_with_output().ok()) .and_then(|output| String::from_utf8(output.stdout).ok()) .map(|output| output.trim().to_string()); diff --git a/zygiskd/src/root_impl/mod.rs b/zygiskd/src/root_impl/mod.rs index e5b07b5..2f0bf99 100644 --- a/zygiskd/src/root_impl/mod.rs +++ b/zygiskd/src/root_impl/mod.rs @@ -20,21 +20,19 @@ pub fn setup() { let impl_ = match (ksu_version, magisk_version) { (None, None) => RootImpl::None, (Some(_), Some(_)) => RootImpl::Multiple, - (Some(ksu_version), None) => { - match ksu_version { - kernelsu::Version::Supported => RootImpl::KernelSU, - kernelsu::Version::TooOld => RootImpl::TooOld, - kernelsu::Version::Abnormal => RootImpl::Abnormal, - } - } - (None, Some(magisk_version)) => { - match magisk_version { - magisk::Version::Supported => RootImpl::Magisk, - magisk::Version::TooOld => RootImpl::TooOld, - } - } + (Some(ksu_version), None) => match ksu_version { + kernelsu::Version::Supported => RootImpl::KernelSU, + kernelsu::Version::TooOld => RootImpl::TooOld, + kernelsu::Version::Abnormal => RootImpl::Abnormal, + }, + (None, Some(magisk_version)) => match magisk_version { + magisk::Version::Supported => RootImpl::Magisk, + magisk::Version::TooOld => RootImpl::TooOld, + }, }; - unsafe { ROOT_IMPL = impl_; } + unsafe { + ROOT_IMPL = impl_; + } } pub fn get_impl() -> &'static RootImpl { diff --git a/zygiskd/src/utils.rs b/zygiskd/src/utils.rs index 51b6ee0..e767970 100644 --- a/zygiskd/src/utils.rs +++ b/zygiskd/src/utils.rs @@ -1,35 +1,49 @@ use anyhow::Result; -use std::{fs, io::{Read, Write}, os::unix::net::UnixStream}; -use std::ffi::{c_char, c_void, CStr, CString}; -use std::os::fd::{AsFd, AsRawFd}; -use std::os::unix::net::{UnixDatagram, UnixListener}; -use std::process::Command; -use std::sync::OnceLock; -use bitflags::Flags; -use rustix::net::{AddressFamily, bind_unix, connect_unix, listen, SendFlags, sendto_unix, socket, SocketAddrUnix, SocketType}; +use rustix::net::{ + bind_unix, connect_unix, listen, sendto_unix, socket, AddressFamily, SendFlags, SocketAddrUnix, + SocketType, +}; use rustix::path::Arg; use rustix::thread::gettid; +use std::ffi::{c_char, c_void, CStr, CString}; +use std::os::fd::{AsFd, AsRawFd}; +use std::os::unix::net::{UnixListener}; +use std::process::Command; +use std::sync::OnceLock; +use std::{ + fs, + io::{Read, Write}, + os::unix::net::UnixStream, +}; #[cfg(target_pointer_width = "64")] #[macro_export] macro_rules! lp_select { - ($lp32:expr, $lp64:expr) => { $lp64 }; + ($lp32:expr, $lp64:expr) => { + $lp64 + }; } #[cfg(target_pointer_width = "32")] #[macro_export] macro_rules! lp_select { - ($lp32:expr, $lp64:expr) => { $lp32 }; + ($lp32:expr, $lp64:expr) => { + $lp32 + }; } #[cfg(debug_assertions)] #[macro_export] macro_rules! debug_select { - ($debug:expr, $release:expr) => { $debug }; + ($debug:expr, $release:expr) => { + $debug + }; } #[cfg(not(debug_assertions))] #[macro_export] macro_rules! debug_select { - ($debug:expr, $release:expr) => { $release }; + ($debug:expr, $release:expr) => { + $release + }; } pub struct LateInit { @@ -38,7 +52,9 @@ pub struct LateInit { impl LateInit { pub const fn new() -> Self { - LateInit { cell: OnceLock::new() } + LateInit { + cell: OnceLock::new(), + } } pub fn init(&self, value: T) { @@ -58,7 +74,10 @@ pub fn set_socket_create_context(context: &str) -> Result<()> { match fs::write(path, context) { Ok(_) => Ok(()), Err(_) => { - let path = format!("/proc/self/task/{}/attr/sockcreate", gettid().as_raw_nonzero()); + let path = format!( + "/proc/self/task/{}/attr/sockcreate", + gettid().as_raw_nonzero() + ); fs::write(path, context)?; Ok(()) } @@ -94,6 +113,7 @@ pub fn get_property(name: &str) -> Result { Ok(prop.to_string_lossy().to_string()) } +#[allow(dead_code)] pub fn set_property(name: &str, value: &str) -> Result<()> { let name = CString::new(name)?; let value = CString::new(value)?; @@ -103,11 +123,10 @@ pub fn set_property(name: &str, value: &str) -> Result<()> { Ok(()) } +#[allow(dead_code)] pub fn wait_property(name: &str, serial: u32) -> Result { let name = CString::new(name)?; - let info = unsafe { - __system_property_find(name.as_ptr()) - }; + let info = unsafe { __system_property_find(name.as_ptr()) }; let mut serial = serial; unsafe { __system_property_wait(info, serial, &mut serial, std::ptr::null()); @@ -115,14 +134,11 @@ pub fn wait_property(name: &str, serial: u32) -> Result { Ok(serial) } +#[allow(dead_code)] pub fn get_property_serial(name: &str) -> Result { let name = CString::new(name)?; - let info = unsafe { - __system_property_find(name.as_ptr()) - }; - Ok(unsafe { - __system_property_serial(info) - }) + let info = unsafe { __system_property_find(name.as_ptr()) }; + Ok(unsafe { __system_property_serial(info) }) } pub fn switch_mount_namespace(pid: i32) -> Result<()> { @@ -234,6 +250,11 @@ extern "C" { fn __system_property_get(name: *const c_char, value: *mut c_char) -> u32; fn __system_property_set(name: *const c_char, value: *const c_char) -> u32; fn __system_property_find(name: *const c_char) -> *const c_void; - fn __system_property_wait(info: *const c_void, old_serial: u32, new_serial: *mut u32, timeout: *const libc::timespec) -> bool; + fn __system_property_wait( + info: *const c_void, + old_serial: u32, + new_serial: *mut u32, + timeout: *const libc::timespec, + ) -> bool; fn __system_property_serial(info: *const c_void) -> u32; } diff --git a/zygiskd/src/zygiskd.rs b/zygiskd/src/zygiskd.rs index 560a4d1..71ec467 100644 --- a/zygiskd/src/zygiskd.rs +++ b/zygiskd/src/zygiskd.rs @@ -2,23 +2,22 @@ use crate::constants::{DaemonSocketAction, ProcessFlags}; use crate::utils::{check_unix_socket, LateInit, UnixStreamExt}; use crate::{constants, lp_select, root_impl, utils}; use anyhow::{bail, Result}; +use log::{debug, error, info, trace, warn}; use passfd::FdPassingExt; -use std::sync::{Arc, Mutex}; -use std::thread; +use rustix::fs::{fcntl_setfd, FdFlags}; use std::fs; use std::io::Error; use std::ops::Deref; use std::os::fd::{AsFd, OwnedFd, RawFd}; +use std::os::unix::process::CommandExt; use std::os::unix::{ net::{UnixListener, UnixStream}, prelude::AsRawFd, }; use std::path::PathBuf; -use std::process::{Command, exit}; -use log::{debug, error, info, trace, warn}; -use std::os::unix::process::CommandExt; -use bitflags::Flags; -use rustix::fs::{fcntl_setfd, FdFlags}; +use std::process::{exit, Command}; +use std::sync::{Arc, Mutex}; +use std::thread; struct Module { name: String, @@ -39,7 +38,11 @@ pub fn main() -> Result<()> { TMP_PATH.init(std::env::var("TMP_PATH")?); CONTROLLER_SOCKET.init(format!("{}/init_monitor", TMP_PATH.deref())); - PATH_CP_NAME.init(format!("{}/{}", TMP_PATH.deref(), lp_select!("/cp32.sock", "/cp64.sock"))); + PATH_CP_NAME.init(format!( + "{}/{}", + TMP_PATH.deref(), + lp_select!("/cp32.sock", "/cp64.sock") + )); let arch = get_arch()?; debug!("Daemon architecture: {arch}"); @@ -50,9 +53,13 @@ pub fn main() -> Result<()> { let info = match root_impl::get_impl() { root_impl::RootImpl::KernelSU | root_impl::RootImpl::Magisk => { msg.extend_from_slice(&constants::DAEMON_SET_INFO.to_le_bytes()); - let module_names: Vec<_> = modules.iter() - .map(|m| m.name.as_str()).collect(); - format!("Root: {:?},module({}): {}", root_impl::get_impl(), modules.len(), module_names.join(",")) + let module_names: Vec<_> = modules.iter().map(|m| m.name.as_str()).collect(); + format!( + "Root: {:?},module({}): {}", + root_impl::get_impl(), + modules.len(), + module_names.join(",") + ) } _ => { msg.extend_from_slice(&constants::DAEMON_SET_ERROR_INFO.to_le_bytes()); @@ -62,12 +69,11 @@ pub fn main() -> Result<()> { msg.extend_from_slice(&(info.len() as u32 + 1).to_le_bytes()); msg.extend_from_slice(info.as_bytes()); msg.extend_from_slice(&[0u8]); - utils::unix_datagram_sendto(&CONTROLLER_SOCKET, msg.as_slice()).expect("failed to send info"); + utils::unix_datagram_sendto(&CONTROLLER_SOCKET, msg.as_slice()) + .expect("failed to send info"); } - let context = Context { - modules, - }; + let context = Context { modules }; let context = Arc::new(context); let listener = create_daemon_socket()?; for stream in listener.incoming() { @@ -142,7 +148,11 @@ fn load_modules(arch: &str) -> Result> { } }; let companion = Mutex::new(None); - let module = Module { name, lib_fd, companion }; + let module = Module { + name, + lib_fd, + companion, + }; modules.push(module); } @@ -213,19 +223,21 @@ fn spawn_companion(name: &str, lib_fd: RawFd) -> Result> { exit(0) } -fn handle_daemon_action(action: DaemonSocketAction, mut stream: UnixStream, context: &Context) -> Result<()> { +fn handle_daemon_action( + action: DaemonSocketAction, + mut stream: UnixStream, + context: &Context, +) -> Result<()> { match action { - DaemonSocketAction::RequestLogcatFd => { - loop { - let level = match stream.read_u8() { - Ok(level) => level, - Err(_) => break, - }; - let tag = stream.read_string()?; - let message = stream.read_string()?; - utils::log_raw(level as i32, &tag, &message)?; - } - } + DaemonSocketAction::RequestLogcatFd => loop { + let level = match stream.read_u8() { + Ok(level) => level, + Err(_) => break, + }; + let tag = stream.read_string()?; + let message = stream.read_string()?; + utils::log_raw(level as i32, &tag, &message)?; + }, DaemonSocketAction::GetProcessFlags => { let uid = stream.read_u32()? as i32; let mut flags = ProcessFlags::empty(); @@ -244,8 +256,16 @@ fn handle_daemon_action(action: DaemonSocketAction, mut stream: UnixStream, cont root_impl::RootImpl::Magisk => flags |= ProcessFlags::PROCESS_ROOT_IS_MAGISK, _ => panic!("wrong root impl: {:?}", root_impl::get_impl()), } - trace!("Uid {} granted root: {}", uid, flags.contains(ProcessFlags::PROCESS_GRANTED_ROOT)); - trace!("Uid {} on denylist: {}", uid, flags.contains(ProcessFlags::PROCESS_ON_DENYLIST)); + trace!( + "Uid {} granted root: {}", + uid, + flags.contains(ProcessFlags::PROCESS_GRANTED_ROOT) + ); + trace!( + "Uid {} on denylist: {}", + uid, + flags.contains(ProcessFlags::PROCESS_ON_DENYLIST) + ); stream.write_u32(flags.bits())?; } DaemonSocketAction::ReadModules => { @@ -271,7 +291,10 @@ fn handle_daemon_action(action: DaemonSocketAction, mut stream: UnixStream, cont if c.is_some() { trace!(" Spawned companion for `{}`", module.name); } else { - trace!(" No companion spawned for `{}` because it has not entry", module.name); + trace!( + " No companion spawned for `{}` because it has not entry", + module.name + ); } *companion = Some(c); } @@ -283,7 +306,10 @@ fn handle_daemon_action(action: DaemonSocketAction, mut stream: UnixStream, cont match companion.as_ref() { Some(Some(sock)) => { if let Err(e) = sock.send_fd(stream.as_raw_fd()) { - error!("Failed to send companion fd socket of module `{}`: {}", module.name, e); + error!( + "Failed to send companion fd socket of module `{}`: {}", + module.name, e + ); stream.write_u8(0)?; } // Ok: Send by companion