You've already forked ZygiskNext
mirror of
https://github.com/Dr-TSNG/ZygiskNext.git
synced 2025-08-27 23:46:34 +00:00
Don't spawn new process for companion
This commit is contained in:
@@ -115,6 +115,7 @@ namespace zygiskd {
|
|||||||
if (socket_utils::read_u8(fd) == 1) {
|
if (socket_utils::read_u8(fd) == 1) {
|
||||||
return fd;
|
return fd;
|
||||||
} else {
|
} else {
|
||||||
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
use std::ffi::c_void;
|
|
||||||
use std::os::fd::{FromRawFd, RawFd};
|
|
||||||
use std::os::unix::net::UnixStream;
|
|
||||||
use std::thread;
|
|
||||||
use anyhow::Result;
|
|
||||||
use nix::libc;
|
|
||||||
use passfd::FdPassingExt;
|
|
||||||
use crate::utils::UnixStreamExt;
|
|
||||||
use crate::dl;
|
|
||||||
|
|
||||||
type ZygiskCompanionEntryFn = unsafe extern "C" fn(i32);
|
|
||||||
|
|
||||||
pub fn entry(fd: i32) -> Result<()> {
|
|
||||||
unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL) };
|
|
||||||
let mut stream = unsafe { UnixStream::from_raw_fd(fd) };
|
|
||||||
let name = stream.read_string()?;
|
|
||||||
let library = stream.recv_fd()?;
|
|
||||||
let entry = load_module(library)?;
|
|
||||||
unsafe { libc::close(library) };
|
|
||||||
|
|
||||||
let entry = match entry {
|
|
||||||
Some(entry) => {
|
|
||||||
log::debug!("Companion process created for `{name}`");
|
|
||||||
stream.write_u8(1)?;
|
|
||||||
entry
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
log::debug!("No companion entry for `{name}`");
|
|
||||||
stream.write_u8(0)?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let fd = stream.recv_fd()?;
|
|
||||||
log::trace!("New companion request from module `{name}`");
|
|
||||||
thread::spawn(move || {
|
|
||||||
unsafe {
|
|
||||||
let mut s = UnixStream::from_raw_fd(fd);
|
|
||||||
match s.write_u8(1) { // Ack
|
|
||||||
Ok(_) => entry(fd),
|
|
||||||
Err(_) => log::warn!("Ack failed?"),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_module(fd: RawFd) -> Result<Option<ZygiskCompanionEntryFn>> {
|
|
||||||
unsafe {
|
|
||||||
let path = format!("/proc/self/fd/{fd}");
|
|
||||||
let handle = dl::dlopen(&path, libc::RTLD_NOW)?;
|
|
||||||
let symbol = std::ffi::CString::new("zygisk_companion_entry")?;
|
|
||||||
let entry = libc::dlsym(handle, symbol.as_ptr());
|
|
||||||
if entry.is_null() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let fnptr = std::mem::transmute::<*mut c_void, ZygiskCompanionEntryFn>(entry);
|
|
||||||
Ok(Some(fnptr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
mod companion;
|
|
||||||
mod constants;
|
mod constants;
|
||||||
mod dl;
|
mod dl;
|
||||||
mod magic;
|
mod magic;
|
||||||
|
|||||||
@@ -1,29 +1,28 @@
|
|||||||
|
use std::ffi::c_void;
|
||||||
use crate::constants::DaemonSocketAction;
|
use crate::constants::DaemonSocketAction;
|
||||||
use crate::utils::UnixStreamExt;
|
use crate::utils::UnixStreamExt;
|
||||||
use crate::{constants, lp_select, magic, root_impl, utils};
|
use crate::{constants, dl, lp_select, magic, root_impl, utils};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use nix::{
|
|
||||||
fcntl::{fcntl, FcntlArg, FdFlag},
|
|
||||||
libc::self,
|
|
||||||
};
|
|
||||||
use passfd::FdPassingExt;
|
use passfd::FdPassingExt;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::os::fd::{OwnedFd, RawFd};
|
use std::os::fd::{IntoRawFd, OwnedFd};
|
||||||
use std::os::unix::{
|
use std::os::unix::{
|
||||||
net::{UnixListener, UnixStream},
|
net::{UnixListener, UnixStream},
|
||||||
prelude::AsRawFd,
|
prelude::AsRawFd,
|
||||||
};
|
};
|
||||||
use std::os::unix::process::CommandExt;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use nix::libc;
|
||||||
use nix::poll::{poll, PollFd, PollFlags};
|
use nix::sys::stat::fstat;
|
||||||
|
use nix::unistd::close;
|
||||||
|
|
||||||
|
type ZygiskCompanionEntryFn = unsafe extern "C" fn(i32);
|
||||||
|
|
||||||
struct Module {
|
struct Module {
|
||||||
name: String,
|
name: String,
|
||||||
lib_fd: OwnedFd,
|
lib_fd: OwnedFd,
|
||||||
companion: Mutex<Option<UnixStream>>,
|
entry: Option<ZygiskCompanionEntryFn>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
@@ -83,8 +82,8 @@ fn load_modules(arch: &str) -> Result<Vec<Module>> {
|
|||||||
return Ok(modules);
|
return Ok(modules);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for entry_result in dir.into_iter() {
|
for entry in dir.into_iter() {
|
||||||
let entry = entry_result?;
|
let entry = entry?;
|
||||||
let name = entry.file_name().into_string().unwrap();
|
let name = entry.file_name().into_string().unwrap();
|
||||||
let so_path = entry.path().join(format!("zygisk/{arch}.so"));
|
let so_path = entry.path().join(format!("zygisk/{arch}.so"));
|
||||||
let disabled = entry.path().join("disable");
|
let disabled = entry.path().join("disable");
|
||||||
@@ -92,15 +91,15 @@ fn load_modules(arch: &str) -> Result<Vec<Module>> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
log::info!(" Loading module `{name}`...");
|
log::info!(" Loading module `{name}`...");
|
||||||
let fd = match create_library_fd(&so_path) {
|
let lib_fd = match create_library_fd(&so_path) {
|
||||||
Ok(fd) => fd,
|
Ok(fd) => fd,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!(" Failed to create memfd for `{name}`: {e}");
|
log::warn!(" Failed to create memfd for `{name}`: {e}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let companion = Mutex::new(None);
|
let entry = resolve_module(&so_path.to_string_lossy())?;
|
||||||
let module = Module { name, lib_fd: fd, companion };
|
let module = Module { name, lib_fd, entry };
|
||||||
modules.push(module);
|
modules.push(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,30 +139,16 @@ fn create_daemon_socket() -> Result<UnixListener> {
|
|||||||
Ok(listener)
|
Ok(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_companion(name: &str, fd: RawFd) -> Result<Option<UnixStream>> {
|
fn resolve_module(path: &str) -> Result<Option<ZygiskCompanionEntryFn>> {
|
||||||
let (mut daemon, companion) = UnixStream::pair()?;
|
unsafe {
|
||||||
// Remove FD_CLOEXEC flag
|
let handle = dl::dlopen(path, libc::RTLD_NOW)?;
|
||||||
fcntl(companion.as_raw_fd(), FcntlArg::F_SETFD(FdFlag::empty()))?;
|
let symbol = std::ffi::CString::new("zygisk_companion_entry")?;
|
||||||
|
let entry = libc::dlsym(handle, symbol.as_ptr());
|
||||||
let process = std::env::args().next().unwrap();
|
if entry.is_null() {
|
||||||
let nice_name = process.split('/').last().unwrap();
|
return Ok(None);
|
||||||
|
}
|
||||||
let mut child = Command::new(&process)
|
let fnptr = std::mem::transmute::<*mut c_void, ZygiskCompanionEntryFn>(entry);
|
||||||
.arg0(format!("{}-{}", nice_name, name))
|
Ok(Some(fnptr))
|
||||||
.arg("companion")
|
|
||||||
.arg(format!("{}", companion.as_raw_fd()))
|
|
||||||
.spawn()?;
|
|
||||||
drop(companion);
|
|
||||||
if !child.wait()?.success() {
|
|
||||||
bail!("companion process exited abnormally");
|
|
||||||
}
|
|
||||||
|
|
||||||
daemon.write_string(name)?;
|
|
||||||
daemon.send_fd(fd)?;
|
|
||||||
match daemon.read_u8()? {
|
|
||||||
0 => Ok(None),
|
|
||||||
1 => Ok(Some(daemon)),
|
|
||||||
_ => bail!("Invalid companion response"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,38 +201,25 @@ fn handle_daemon_action(mut stream: UnixStream, context: &Context) -> Result<()>
|
|||||||
DaemonSocketAction::RequestCompanionSocket => {
|
DaemonSocketAction::RequestCompanionSocket => {
|
||||||
let index = stream.read_usize()?;
|
let index = stream.read_usize()?;
|
||||||
let module = &context.modules[index];
|
let module = &context.modules[index];
|
||||||
let mut companion = module.companion.lock().unwrap();
|
match module.entry {
|
||||||
if let Some(sock) = companion.as_ref() {
|
|
||||||
let mut pfds = [PollFd::new(sock.as_raw_fd(), PollFlags::empty())];
|
|
||||||
poll(&mut pfds, 0)?;
|
|
||||||
if !pfds[0].revents().unwrap().is_empty() {
|
|
||||||
log::error!("Poll companion for module `{}` crashed", module.name);
|
|
||||||
companion.take();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if companion.is_none() {
|
|
||||||
match spawn_companion(&module.name, module.lib_fd.as_raw_fd()) {
|
|
||||||
Ok(c) => {
|
|
||||||
if c.is_some() {
|
|
||||||
log::trace!(" Spawned companion for `{}`", module.name);
|
|
||||||
}
|
|
||||||
*companion = c;
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
log::warn!(" Failed to spawn companion for `{}`: {}", module.name, e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
match companion.as_ref() {
|
|
||||||
Some(sock) => {
|
|
||||||
if let Err(_) = sock.send_fd(stream.as_raw_fd()) {
|
|
||||||
log::error!("Failed to send companion fd socket of module `{}`", module.name);
|
|
||||||
stream.write_u8(0)?;
|
|
||||||
}
|
|
||||||
// Ok: Send by companion
|
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
stream.write_u8(0)?;
|
stream.write_u8(0)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Some(companion) => {
|
||||||
|
stream.write_u8(1)?;
|
||||||
|
let fd = stream.into_raw_fd();
|
||||||
|
let st0 = fstat(fd)?;
|
||||||
|
unsafe { companion(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
|
||||||
|
// handler could've closed the file descriptor already.
|
||||||
|
if let Ok(st1) = fstat(fd) {
|
||||||
|
if st0.st_dev == st1.st_dev && st0.st_ino == st1.st_ino {
|
||||||
|
close(fd)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user