Replace native bridge with fuse + ptrace

This commit is contained in:
Nullptr
2023-10-20 13:49:03 +08:00
parent 77cb323506
commit 5f2dd50703
18 changed files with 452 additions and 301 deletions

View File

@@ -9,7 +9,6 @@ rust-version = "1.69"
android_logger = "0.13"
anyhow = { version = "1.0", features = ["backtrace"] }
bitflags = { version = "2.3" }
clap = { version = "4", features = ["derive"] }
const_format = "0.2"
futures = "0.3"
konst = "0.3"
@@ -19,11 +18,13 @@ log = "0.4"
memfd = "0.6"
num_enum = "0.5"
passfd = "0.1"
rand = "0.8"
proc-maps = "0.3"
ptrace-do = "0.1"
rustix = { version = "0.38", features = [ "fs", "process", "mount", "net", "thread"] }
tokio = { version = "1.28", features = ["full"] }
binder = { git = "https://github.com/Kernel-SU/binder_rs", rev = "c9f2b62d6a744fd2264056c638c1b061a6a2932d" }
fuser = { git = "https://github.com/Dr-TSNG/fuser", default-features = false }
[profile.release]
strip = true

View File

@@ -17,15 +17,25 @@ pub const MAX_LOG_LEVEL: LevelFilter = LevelFilter::Trace;
#[cfg(not(debug_assertions))]
pub const MAX_LOG_LEVEL: LevelFilter = LevelFilter::Info;
pub const PROP_NATIVE_BRIDGE: &str = "ro.dalvik.vm.native.bridge";
pub const PROP_CTL_RESTART: &str = "ctl.restart";
pub const ZYGISK_LOADER: &str = "libzygisk_loader.so";
pub const ZYGISK_MAGIC: &str = "/system/zygisk_magic";
pub const ZYGISK_LIBRARY: &str = "libzygisk.so";
pub const PATH_PCL: &str = "/system/etc/preloaded-classes";
pub const PATH_SYSTEM_LIB32: &str = "/system/lib";
pub const PATH_SYSTEM_LIB64: &str = "/system/lib64";
pub const PATH_WORK_DIR: &str = "/dev/zygisk"; // TODO: Replace with /debug_ramdisk/zygisk
pub const PATH_PROP_OVERLAY: &str = concatcp!(PATH_WORK_DIR, "/module.prop");
#[cfg(target_pointer_width = "64")]
pub const PATH_CP_SOCKET: &str = concatcp!(PATH_WORK_DIR, "/cp64.sock");
#[cfg(target_pointer_width = "32")]
pub const PATH_CP_SOCKET: &str = concatcp!(PATH_WORK_DIR, "/cp32.sock");
pub const PATH_FUSE_DIR: &str = concatcp!(PATH_WORK_DIR, "/fuse");
pub const PATH_FUSE_PCL: &str = concatcp!(PATH_FUSE_DIR, "/preloaded-classes");
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_CP32_BIN: &str = "bin/zygisk-cp32";
pub const PATH_CP64_BIN: &str = "bin/zygisk-cp64";
pub const STATUS_LOADED: &str = "😋 Zygisksu is loaded";
pub const STATUS_CRASHED: &str = "❌ Zygiskd has crashed";
@@ -39,7 +49,6 @@ pub const STATUS_ROOT_IMPL_MULTIPLE: &str = "❌ Multiple root implementations i
pub enum DaemonSocketAction {
PingHeartbeat,
RequestLogcatFd,
ReadNativeBridge,
GetProcessFlags,
ReadModules,
RequestCompanionSocket,

View File

@@ -1,17 +1,17 @@
use anyhow::{bail, Result};
use std::ffi::{c_char, c_void};
const ANDROID_NAMESPACE_TYPE_SHARED: u64 = 0x2;
const ANDROID_DLEXT_USE_NAMESPACE: u64 = 0x200;
pub const ANDROID_NAMESPACE_TYPE_SHARED: u64 = 0x2;
pub const ANDROID_DLEXT_USE_NAMESPACE: u64 = 0x200;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct AndroidNamespace {
pub struct AndroidNamespace {
_unused: [u8; 0],
}
#[repr(C)]
struct AndroidDlextinfo {
pub struct AndroidDlextinfo {
pub flags: u64,
pub reserved_addr: *mut c_void,
pub reserved_size: libc::size_t,
@@ -22,7 +22,7 @@ struct AndroidDlextinfo {
}
extern "C" {
fn android_dlopen_ext(
pub fn android_dlopen_ext(
filename: *const c_char,
flags: libc::c_int,
extinfo: *const AndroidDlextinfo,

335
zygiskd/src/fuse.rs Normal file
View File

@@ -0,0 +1,335 @@
use std::cmp::min;
use anyhow::{bail, Result};
use std::ffi::{CString, OsStr};
use std::{fs, thread};
use std::sync::{mpsc, Mutex};
use std::time::{Duration, SystemTime};
use fuser::{FileAttr, Filesystem, FileType, ReplyAttr, ReplyData, ReplyDirectory, ReplyEntry, ReplyOpen, Request};
use libc::ENOENT;
use log::{debug, error, info};
use proc_maps::{get_process_maps, MapRange, Pid};
use ptrace_do::{RawProcess, TracedProcess};
use rustix::mount::mount_bind;
use rustix::path::Arg;
use rustix::process::getpid;
use crate::{constants, dl};
use crate::utils::LateInit;
pub struct DelegateFilesystem;
const fn attr(inode: u64, size: u64, kind: FileType) -> FileAttr {
FileAttr {
ino: inode,
size,
blocks: 0,
atime: SystemTime::UNIX_EPOCH,
mtime: SystemTime::UNIX_EPOCH,
ctime: SystemTime::UNIX_EPOCH,
crtime: SystemTime::UNIX_EPOCH,
kind,
perm: 0o644,
nlink: 0,
uid: 0,
gid: 0,
rdev: 0,
blksize: 0,
flags: 0,
}
}
const ANDROID_LIBC: &str = "bionic/libc.so";
const ANDROID_LIBDL: &str = "bionic/libdl.so";
const INO_DIR: u64 = 1;
const INO_PCL: u64 = 2;
static ATTR_DIR: FileAttr = attr(INO_DIR, 0, FileType::Directory);
static ATTR_PCL: LateInit<FileAttr> = LateInit::new();
static PCL_CONTENT: LateInit<Vec<u8>> = LateInit::new();
const ENTRIES: &[(u64, FileType, &str)] = &[
(INO_DIR, FileType::Directory, "."),
(INO_DIR, FileType::Directory, ".."),
(INO_PCL, FileType::RegularFile, "preloaded-classes"),
];
const TTL: Duration = Duration::from_secs(1);
impl Filesystem for DelegateFilesystem {
fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) {
if parent != INO_DIR {
reply.error(ENOENT);
return;
}
match name.as_str().unwrap() {
"preloaded-classes" => reply.entry(&TTL, &ATTR_PCL, 0),
_ => reply.error(ENOENT),
}
}
fn getattr(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyAttr) {
match ino {
INO_DIR => reply.attr(&TTL, &ATTR_DIR),
INO_PCL => reply.attr(&TTL, &ATTR_PCL),
_ => reply.error(ENOENT),
}
}
fn open(&mut self, req: &Request<'_>, ino: u64, _flags: i32, reply: ReplyOpen) {
if ino == INO_PCL {
let pid = req.pid();
let process = format!("/proc/{}/cmdline", pid);
let process = fs::read_to_string(process).unwrap();
let process = &process[..process.find('\0').unwrap()];
info!("Process {} is reading preloaded-classes", process);
match process {
// "zygote" => ptrace_zygote(pid, false).unwrap(),
"zygote64" => ptrace_zygote(pid, true).unwrap(),
_ => (),
}
}
reply.opened(0, 0);
}
fn read(&mut self, _req: &Request<'_>, ino: u64, _fh: u64, offset: i64, size: u32, _flags: i32, _lock_owner: Option<u64>, reply: ReplyData) {
let offset = offset as usize;
let size = size as usize;
if ino == INO_PCL {
let len = PCL_CONTENT.len();
if offset >= len {
reply.data(&[]);
} else {
let end = min(offset + size, len);
reply.data(&PCL_CONTENT[offset..end]);
}
} else {
reply.error(ENOENT);
}
}
fn readdir(&mut self, _req: &Request<'_>, ino: u64, _fh: u64, offset: i64, mut reply: ReplyDirectory) {
if ino != INO_DIR {
reply.error(ENOENT);
return;
}
for (i, entry) in ENTRIES.iter().enumerate().skip(offset as usize) {
if reply.add(entry.0, (i + 1) as i64, entry.1, entry.2) {
break;
}
}
reply.ok();
}
}
fn find_module_for_pid(pid: Pid, library: &str) -> Result<MapRange> {
let maps = get_process_maps(pid)?;
for map in maps.into_iter() {
if let Some(p) = map.filename() {
if p.as_str()?.contains(library) {
return Ok(map);
}
}
}
bail!("Cannot find module {library} for pid {pid}");
}
fn find_remote_procedure(
pid: Pid,
library: &str,
local_addr: usize,
) -> Result<usize> {
let local_module = find_module_for_pid(getpid().as_raw_nonzero().get(), library)?;
debug!(
"Identifed local range {library} ({:?}) at {:x}",
local_module.filename(),
local_module.start()
);
let remote_module = find_module_for_pid(pid, library)?;
debug!(
"Identifed remote range {library} ({:?}) at {:x}",
remote_module.filename(),
remote_module.start()
);
Ok(local_addr - local_module.start() + remote_module.start())
}
fn ptrace_zygote(pid: u32, is64: bool) -> Result<()> {
static LAST_32: Mutex<u32> = Mutex::new(0);
static LAST_64: Mutex<u32> = Mutex::new(0);
let mut last = match is64 {
true => LAST_64.lock().unwrap(),
false => LAST_32.lock().unwrap(),
};
if *last == pid {
return Ok(());
}
*last = pid;
let (sender, receiver) = mpsc::channel::<()>();
let worker = move || -> Result<()> {
info!("Injecting into pid {}, is64 = {}", pid, is64);
let lib_dir = match is64 {
true => constants::PATH_SYSTEM_LIB64,
false => constants::PATH_SYSTEM_LIB32,
};
let zygisk_lib = format!("{}/{}", lib_dir, constants::ZYGISK_LIBRARY);
let lib_dir = CString::new(lib_dir)?;
let zygisk_lib = CString::new(zygisk_lib)?;
let libc_base = find_module_for_pid(pid as i32, ANDROID_LIBC)?.start();
let mmap_remote = find_remote_procedure(
pid as i32,
ANDROID_LIBC,
libc::mmap as usize,
)?;
let munmap_remote = find_remote_procedure(
pid as i32,
ANDROID_LIBC,
libc::munmap as usize,
)?;
let dlopen_remote = find_remote_procedure(
pid as i32,
ANDROID_LIBDL,
dl::android_dlopen_ext as usize,
)?;
let dlsym_remote = find_remote_procedure(
pid as i32,
ANDROID_LIBDL,
libc::dlsym as usize,
)?;
let tracer = TracedProcess::attach(RawProcess::new(pid as i32))?;
sender.send(())?;
let frame = tracer.next_frame()?;
debug!("Waited for a frame");
// Map a buffer in the remote process
let mmap_params: [usize; 6] = [
0,
0x1000,
(libc::PROT_READ | libc::PROT_WRITE) as usize,
(libc::MAP_ANONYMOUS | libc::MAP_PRIVATE) as usize,
0,
0,
];
let (regs, mut frame) = frame.invoke_remote(
mmap_remote,
libc_base,
&mmap_params,
)?;
let buf_addr = regs.return_value();
debug!("Buffer addr: {:x}", buf_addr);
// Find the address of __loader_android_create_namespace
let sym = CString::new("__loader_android_create_namespace")?;
frame.write_memory(buf_addr, sym.as_bytes_with_nul())?;
let (regs, mut frame) = frame.invoke_remote(
dlsym_remote,
libc_base,
&[libc::RTLD_DEFAULT as usize, buf_addr],
)?;
let android_create_namespace_remote = regs.return_value();
debug!("__loader_android_create_namespace addr: {:x}", android_create_namespace_remote);
// Create a linker namespace for remote process
frame.write_memory(buf_addr, zygisk_lib.as_bytes_with_nul())?;
frame.write_memory(buf_addr + 0x100, lib_dir.as_bytes_with_nul())?;
let ns_params: [usize; 7] = [
buf_addr, // name
buf_addr + 0x100, // ld_library_path
0, // default_library_path
dl::ANDROID_NAMESPACE_TYPE_SHARED as usize, // type
0, // permitted_when_isolated_path
0, // parent
dlopen_remote, // caller_addr
];
let (regs, mut frame) = frame.invoke_remote(
android_create_namespace_remote,
libc_base,
&ns_params,
)?;
let ns_addr = regs.return_value();
debug!("Linker namespace addr: {:x}", ns_addr);
// Load zygisk into remote process
let info = dl::AndroidDlextinfo {
flags: dl::ANDROID_DLEXT_USE_NAMESPACE,
reserved_addr: std::ptr::null_mut(),
reserved_size: 0,
relro_fd: 0,
library_fd: 0,
library_fd_offset: 0,
library_namespace: ns_addr as *mut _,
};
let info = unsafe {
std::slice::from_raw_parts(
&info as *const _ as *const u8,
std::mem::size_of::<dl::AndroidDlextinfo>(),
)
};
frame.write_memory(buf_addr + 0x200, info)?;
let (regs, mut frame) = frame.invoke_remote(
dlopen_remote,
libc_base,
&[buf_addr, libc::RTLD_NOW as usize, buf_addr + 0x200],
)?;
let handle = regs.return_value();
debug!("Load zygisk into remote process: {:x}", handle);
let entry = CString::new("entry")?;
frame.write_memory(buf_addr, entry.as_bytes_with_nul())?;
let (regs, frame) = frame.invoke_remote(
dlsym_remote,
libc_base,
&[handle, buf_addr],
)?;
let entry = regs.return_value();
debug!("Call zygisk entry: {:x}", entry);
let (_, frame) = frame.invoke_remote(
entry,
libc_base,
&[handle],
)?;
// Cleanup
let _ = frame.invoke_remote(
munmap_remote,
libc_base,
&[buf_addr],
)?;
debug!("Cleaned up");
Ok(())
};
thread::spawn(move || {
if let Err(e) = worker() {
error!("Crashed: {:?}", e);
}
});
receiver.recv()?;
Ok(())
}
pub fn main() -> Result<()> {
fs::create_dir(constants::PATH_WORK_DIR)?;
fs::create_dir(constants::PATH_FUSE_DIR)?;
PCL_CONTENT.init(fs::read(constants::PATH_PCL)?);
ATTR_PCL.init(attr(INO_PCL, PCL_CONTENT.len() as u64, FileType::RegularFile));
let options = [
fuser::MountOption::FSName(String::from("zygisk")),
fuser::MountOption::AllowOther,
fuser::MountOption::RO,
];
let session = fuser::spawn_mount2(
DelegateFilesystem,
constants::PATH_FUSE_DIR,
&options,
)?;
mount_bind(constants::PATH_FUSE_PCL, constants::PATH_PCL)?;
session.join();
bail!("Fuse mount exited unexpectedly");
}

View File

@@ -1,19 +0,0 @@
use std::fs;
use anyhow::Result;
use crate::constants;
use crate::utils::LateInit;
pub static MAGIC: LateInit<String> = LateInit::new();
pub static PATH_TMP_DIR: LateInit<String> = LateInit::new();
pub static PATH_TMP_PROP: LateInit<String> = LateInit::new();
pub fn setup() -> Result<()> {
let name = fs::read_to_string(constants::ZYGISK_MAGIC)?;
let path_tmp_dir = format!("/dev/{}", name);
let path_tmp_prop = format!("{}/module.prop", path_tmp_dir);
MAGIC.init(name);
PATH_TMP_DIR.init(path_tmp_dir);
PATH_TMP_PROP.init(path_tmp_prop);
Ok(())
}

View File

@@ -3,29 +3,13 @@
mod constants;
mod dl;
mod magic;
mod fuse;
mod root_impl;
mod utils;
mod watchdog;
mod zygiskd;
use anyhow::Result;
use clap::{Subcommand, Parser};
#[derive(Parser, Debug)]
#[command(author, version = constants::VERSION_FULL, about, long_about = None)]
struct Args {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
/// Start zygisk watchdog
Watchdog,
/// Start zygisk daemon
Daemon,
}
fn init_android_logger(tag: &str) {
@@ -36,14 +20,15 @@ fn init_android_logger(tag: &str) {
);
}
async fn start() -> Result<()> {
async fn start(name: &str) -> Result<()> {
root_impl::setup();
magic::setup()?;
let cli = Args::parse();
match cli.command {
Commands::Watchdog => watchdog::entry().await?,
Commands::Daemon => zygiskd::entry()?,
};
match name.trim_start_matches("zygisk-") {
"wd" => watchdog::main().await?,
"fuse" => fuse::main()?,
"cp32" => zygiskd::main()?,
"cp64" => zygiskd::main()?,
_ => println!("Available commands: wd, fuse, cp"),
}
Ok(())
}
@@ -53,7 +38,7 @@ async fn main() {
let nice_name = process.split('/').last().unwrap();
init_android_logger(nice_name);
if let Err(e) = start().await {
if let Err(e) = start(nice_name).await {
log::error!("Crashed: {}\n{}", e, e.backtrace());
}
}

View File

@@ -1,9 +1,9 @@
use anyhow::Result;
use std::{fs, io::{Read, Write}, os::unix::net::UnixStream, process::Command};
use std::{fs, io::{Read, Write}, os::unix::net::UnixStream};
use std::ffi::c_char;
use std::os::unix::net::UnixListener;
use std::process::Command;
use std::sync::OnceLock;
use rand::distributions::{Alphanumeric, DistString};
use rustix::net::{AddressFamily, bind_unix, listen, socket, SocketAddrUnix, SocketType};
use rustix::thread::gettid;
@@ -50,10 +50,6 @@ impl<T> std::ops::Deref for LateInit<T> {
}
}
pub fn random_string() -> String {
Alphanumeric.sample_string(&mut rand::thread_rng(), 8)
}
pub fn set_socket_create_context(context: &str) -> Result<()> {
let path = "/proc/thread-self/attr/sockcreate";
match fs::write(path, context) {
@@ -66,15 +62,16 @@ pub fn set_socket_create_context(context: &str) -> Result<()> {
}
}
pub fn get_native_bridge() -> String {
std::env::var("NATIVE_BRIDGE").unwrap_or_default()
pub fn chcon(path: &str, context: &str) -> Result<()> {
Command::new("chcon").arg(context).arg(path).status()?;
Ok(())
}
pub fn log_raw(level: i32, tag: &str, message: &str) -> Result<()> {
let tag = std::ffi::CString::new(tag)?;
let message = std::ffi::CString::new(message)?;
unsafe {
__android_log_print(level as i32, tag.as_ptr(), message.as_ptr());
__android_log_print(level, tag.as_ptr(), message.as_ptr());
}
Ok(())
}
@@ -89,10 +86,11 @@ pub fn get_property(name: &str) -> Result<String> {
}
pub fn set_property(name: &str, value: &str) -> Result<()> {
Command::new("resetprop")
.arg(name)
.arg(value)
.spawn()?.wait()?;
let name = std::ffi::CString::new(name)?;
let value = std::ffi::CString::new(value)?;
unsafe {
__system_property_set(name.as_ptr(), value.as_ptr());
}
Ok(())
}
@@ -155,15 +153,18 @@ impl UnixStreamExt for UnixStream {
}
}
pub fn abstract_namespace_socket(name: &str) -> Result<UnixListener> {
let addr = SocketAddrUnix::new_abstract_name(name.as_bytes())?;
pub fn unix_listener_from_path(path: &str) -> Result<UnixListener> {
let _ = fs::remove_file(path);
let addr = SocketAddrUnix::new(path)?;
let socket = socket(AddressFamily::UNIX, SocketType::STREAM, None)?;
bind_unix(&socket, &addr)?;
listen(&socket, 2)?;
chcon(path, "u:object_r:magisk_file:s0")?;
Ok(UnixListener::from(socket))
}
extern "C" {
fn __android_log_print(prio: i32, tag: *const c_char, fmt: *const c_char, ...) -> i32;
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;
}

View File

@@ -1,39 +1,46 @@
use crate::{constants, magic, root_impl, utils};
use crate::{constants, root_impl, utils};
use anyhow::{bail, Result};
use std::fs;
use std::future::Future;
use std::io::{BufRead, BufReader, Write};
use std::os::unix::net::UnixListener;
use std::pin::Pin;
use std::time::Duration;
use binder::IBinder;
use futures::stream::FuturesUnordered;
use futures::StreamExt;
use log::info;
use rustix::mount::mount_bind;
use rustix::process::{getgid, getuid, kill_process, Pid, Signal};
use tokio::process::{Child, Command};
use crate::utils::LateInit;
static LOCK: LateInit<UnixListener> = LateInit::new();
static PROP_SECTIONS: LateInit<[String; 2]> = LateInit::new();
pub async fn entry() -> Result<()> {
log::info!("Start zygisksu watchdog");
pub async fn main() -> Result<()> {
let result = run().await;
set_prop_hint(constants::STATUS_CRASHED)?;
result
}
async fn run() -> Result<()> {
info!("Start zygisksu watchdog");
check_permission()?;
ensure_single_instance()?;
mount_prop().await?;
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().await;
set_prop_hint(constants::STATUS_CRASHED)?;
end
spawn_daemon().await?;
Ok(())
}
fn spawn_fuse() -> Result<()> {
Command::new("bin/zygisk-fuse").spawn()?;
Ok(())
}
fn check_permission() -> Result<()> {
log::info!("Check permission");
info!("Check permission");
let uid = getuid();
if !uid.is_root() {
bail!("UID is not 0");
@@ -53,16 +60,6 @@ fn check_permission() -> Result<()> {
Ok(())
}
fn ensure_single_instance() -> Result<()> {
log::info!("Ensure single instance");
let name = format!("zygiskwd{}", magic::MAGIC.as_str());
match utils::abstract_namespace_socket(&name) {
Ok(socket) => LOCK.init(socket),
Err(e) => bail!("Failed to acquire lock: {e}. Maybe another instance is running?")
}
Ok(())
}
async fn mount_prop() -> Result<()> {
let module_prop = if let root_impl::RootImpl::Magisk = root_impl::get_impl() {
let magisk_path = Command::new("magisk").arg("--path").output().await?;
@@ -74,7 +71,7 @@ async fn mount_prop() -> Result<()> {
} else {
constants::PATH_MODULE_PROP.to_string()
};
log::info!("Mount {module_prop}");
info!("Mount {module_prop}");
let module_prop_file = fs::File::open(&module_prop)?;
let mut section = 0;
let mut sections: [String; 2] = [String::new(), String::new()];
@@ -93,15 +90,13 @@ async fn mount_prop() -> Result<()> {
}
PROP_SECTIONS.init(sections);
fs::create_dir(magic::PATH_TMP_DIR.as_str())?;
fs::File::create(magic::PATH_TMP_PROP.as_str())?;
mount_bind(magic::PATH_TMP_PROP.as_str(), &module_prop)?;
fs::File::create(constants::PATH_PROP_OVERLAY)?;
mount_bind(constants::PATH_PROP_OVERLAY, &module_prop)?;
Ok(())
}
fn set_prop_hint(hint: &str) -> Result<()> {
let mut file = fs::File::create(magic::PATH_TMP_PROP.as_str())?;
let mut file = fs::File::create(constants::PATH_PROP_OVERLAY)?;
file.write_all(PROP_SECTIONS[0].as_bytes())?;
file.write_all(b"[")?;
file.write_all(hint.as_bytes())?;
@@ -131,8 +126,8 @@ async fn spawn_daemon() -> Result<()> {
let mut futures = FuturesUnordered::<Pin<Box<dyn Future<Output=Result<()>>>>>::new();
let mut child_ids = vec![];
let daemon32 = Command::new(constants::PATH_ZYGISKD32).arg("daemon").spawn();
let daemon64 = Command::new(constants::PATH_ZYGISKD64).arg("daemon").spawn();
let daemon32 = Command::new(constants::PATH_CP32_BIN).spawn();
let daemon64 = Command::new(constants::PATH_CP64_BIN).spawn();
async fn spawn_daemon(mut daemon: Child) -> Result<()> {
let result = daemon.wait().await?;
log::error!("Daemon process {} died: {}", daemon.id().unwrap(), result);
@@ -158,8 +153,7 @@ async fn spawn_daemon() -> Result<()> {
};
};
log::info!("System server ready, restore native bridge");
utils::set_property(constants::PROP_NATIVE_BRIDGE, &utils::get_native_bridge())?;
info!("System server ready");
loop {
if binder.ping_binder().is_err() { break; }
@@ -185,7 +179,6 @@ async fn spawn_daemon() -> Result<()> {
}
log::error!("Restarting zygote...");
utils::set_property(constants::PROP_NATIVE_BRIDGE, constants::ZYGISK_LOADER)?;
utils::set_property(constants::PROP_CTL_RESTART, "zygote")?;
}
}

View File

@@ -1,7 +1,7 @@
use std::ffi::c_void;
use crate::constants::{DaemonSocketAction, ProcessFlags};
use crate::utils::UnixStreamExt;
use crate::{constants, dl, lp_select, magic, root_impl, utils};
use crate::{constants, dl, lp_select, root_impl, utils};
use anyhow::{bail, Result};
use passfd::FdPassingExt;
use std::sync::Arc;
@@ -14,7 +14,7 @@ use std::os::unix::{
};
use std::path::PathBuf;
use rustix::fs::fstat;
use rustix::process::Signal;
use rustix::process::{set_parent_process_death_signal, Signal};
type ZygiskCompanionEntryFn = unsafe extern "C" fn(i32);
@@ -25,12 +25,11 @@ struct Module {
}
struct Context {
native_bridge: String,
modules: Vec<Module>,
}
pub fn entry() -> Result<()> {
rustix::process::set_parent_process_death_signal(Some(Signal::Kill))?;
pub fn main() -> Result<()> {
set_parent_process_death_signal(Some(Signal::Kill))?;
let arch = get_arch()?;
log::debug!("Daemon architecture: {arch}");
@@ -39,7 +38,6 @@ pub fn entry() -> Result<()> {
let modules = load_modules(arch)?;
let context = Context {
native_bridge: utils::get_native_bridge(),
modules,
};
let context = Arc::new(context);
@@ -131,10 +129,8 @@ fn create_library_fd(so_path: &PathBuf) -> Result<OwnedFd> {
fn create_daemon_socket() -> Result<UnixListener> {
utils::set_socket_create_context("u:r:zygote:s0")?;
let prefix = lp_select!("zygiskd32", "zygiskd64");
let name = format!("{}{}", prefix, magic::MAGIC.as_str());
let listener = utils::abstract_namespace_socket(&name)?;
log::debug!("Daemon socket: {name}");
log::debug!("Daemon socket: {}", constants::PATH_CP_SOCKET);
let listener = utils::unix_listener_from_path(constants::PATH_CP_SOCKET)?;
Ok(listener)
}
@@ -170,9 +166,6 @@ fn handle_daemon_action(mut stream: UnixStream, context: &Context) -> Result<()>
utils::log_raw(level as i32, &tag, &message)?;
}
}
DaemonSocketAction::ReadNativeBridge => {
stream.write_string(&context.native_bridge)?;
}
DaemonSocketAction::GetProcessFlags => {
let uid = stream.read_u32()? as i32;
let mut flags = ProcessFlags::empty();