You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
Handle zygote death
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -4,3 +4,6 @@
|
|||||||
[submodule "loader/src/external/parallel-hashmap"]
|
[submodule "loader/src/external/parallel-hashmap"]
|
||||||
path = loader/src/external/parallel-hashmap
|
path = loader/src/external/parallel-hashmap
|
||||||
url = https://github.com/greg7mdp/parallel-hashmap
|
url = https://github.com/greg7mdp/parallel-hashmap
|
||||||
|
[submodule "zygiskd/src/external/binder_rs"]
|
||||||
|
path = zygiskd/src/external/binder_rs
|
||||||
|
url = https://github.com/Kernel-SU/binder_rs
|
||||||
|
|||||||
14
README.md
14
README.md
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
Zygisk loader for KernelSU, allowing Zygisk modules to run without Magisk environment.
|
Zygisk loader for KernelSU, allowing Zygisk modules to run without Magisk environment.
|
||||||
|
|
||||||
Warning: The current version of Zygisksu is UNSTABLE. You may suffer boot loop or even data loss so use with caution.
|
Also works as standalone loader for Magisk on purpose of getting rid of LD_PRELOAD. (Coming soon)
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
+ Minimal KernelSU version: 10575
|
+ Minimal KernelSU version: 10575
|
||||||
+ Minimal ksud version: 10200
|
+ Minimal ksud version: 10616
|
||||||
+ Full SELinux patch support (If non-gki kernel)
|
+ Full SELinux patch support (If non-gki kernel)
|
||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
@@ -22,11 +22,5 @@ Should work with everything except those rely on Magisk internal behaviors.
|
|||||||
- [x] [Daemon] Linker namespace
|
- [x] [Daemon] Linker namespace
|
||||||
- [x] [Daemon] Separate zygiskd process
|
- [x] [Daemon] Separate zygiskd process
|
||||||
- [x] [Daemon] Handle 64 bit only devices
|
- [x] [Daemon] Handle 64 bit only devices
|
||||||
- [ ] [Daemon] Handle zygote death
|
- [x] [Daemon] Handle zygote death
|
||||||
|
- [ ] [ Misc ] Support Magisk out of box
|
||||||
## Running on Magisk
|
|
||||||
|
|
||||||
It is possible to run Zygisksu on Magisk with a few steps:
|
|
||||||
|
|
||||||
1. `mkdir /data/adb/ksu`
|
|
||||||
2. `ln -s /data/adb/modules /data/adb/ksu/`
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
SKIPUNZIP=1
|
SKIPUNZIP=1
|
||||||
|
|
||||||
|
DEBUG=@DEBUG@
|
||||||
|
|
||||||
if [ $BOOTMODE ] && [ "$KSU" == "true" ]; then
|
if [ $BOOTMODE ] && [ "$KSU" == "true" ]; then
|
||||||
ui_print "- Installing from KernelSU app"
|
ui_print "- Installing from KernelSU app"
|
||||||
else
|
else
|
||||||
@@ -14,8 +16,8 @@ VERSION=$(grep_prop version "${TMPDIR}/module.prop")
|
|||||||
ui_print "- Installing Zygisksu $VERSION"
|
ui_print "- Installing Zygisksu $VERSION"
|
||||||
|
|
||||||
# check KernelSU
|
# check KernelSU
|
||||||
ui_print "- KernelSU version: $KSU_VER ($KSU_VER_CODE)"
|
ui_print "- KernelSU version: $KSU_KERNEL_VER_CODE (kernel) + $KSU_VER_CODE (ksud)"
|
||||||
if [ "$KSU_VER_CODE" -lt 10200 ]; then
|
if [ "$KSU_KERNEL_VER_CODE" -lt 10575 ]; then
|
||||||
ui_print "*********************************************************"
|
ui_print "*********************************************************"
|
||||||
ui_print "! KernelSU version is too old!"
|
ui_print "! KernelSU version is too old!"
|
||||||
ui_print "! Please update KernelSU to latest version"
|
ui_print "! Please update KernelSU to latest version"
|
||||||
@@ -25,7 +27,7 @@ fi
|
|||||||
# check android
|
# check android
|
||||||
if [ "$API" -lt 29 ]; then
|
if [ "$API" -lt 29 ]; then
|
||||||
ui_print "! Unsupported sdk: $API"
|
ui_print "! Unsupported sdk: $API"
|
||||||
abort "! Minimal supported sdk is 29 (Android 10.0)"
|
abort "! Minimal supported sdk is 29 (Android 10)"
|
||||||
else
|
else
|
||||||
ui_print "- Device sdk: $API"
|
ui_print "- Device sdk: $API"
|
||||||
fi
|
fi
|
||||||
@@ -51,7 +53,7 @@ extract "$ZIPFILE" 'verify.sh' "$TMPDIR/.vunzip"
|
|||||||
extract "$ZIPFILE" 'sepolicy.rule' "$TMPDIR"
|
extract "$ZIPFILE" 'sepolicy.rule' "$TMPDIR"
|
||||||
|
|
||||||
ui_print "- Checking SELinux patches"
|
ui_print "- Checking SELinux patches"
|
||||||
if ! /data/adb/ksud sepolicy check "$TMPDIR/sepolicy.rule"; then
|
if ! check_sepolicy "$TMPDIR/sepolicy.rule"; then
|
||||||
ui_print "*********************************************************"
|
ui_print "*********************************************************"
|
||||||
ui_print "! Unable to apply SELinux patches!"
|
ui_print "! Unable to apply SELinux patches!"
|
||||||
ui_print "! Your kernel may not support SELinux patch fully"
|
ui_print "! Your kernel may not support SELinux patch fully"
|
||||||
@@ -110,17 +112,19 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ui_print "- Hex patching"
|
if [ $DEBUG = false ]; then
|
||||||
SOCKET_PATCH=$(tr -dc 'a-f0-9' </dev/urandom | head -c 18)
|
ui_print "- Hex patching"
|
||||||
if [ "$HAS32BIT" = true ]; then
|
SOCKET_PATCH=$(tr -dc 'a-f0-9' </dev/urandom | head -c 18)
|
||||||
|
if [ "$HAS32BIT" = true ]; then
|
||||||
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/bin/zygiskd32"
|
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/bin/zygiskd32"
|
||||||
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/system/lib/libinjector.so"
|
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/system/lib/libinjector.so"
|
||||||
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/system/lib/libzygiskloader.so"
|
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/system/lib/libzygiskloader.so"
|
||||||
fi
|
fi
|
||||||
if [ "$HAS64BIT" = true ]; then
|
if [ "$HAS64BIT" = true ]; then
|
||||||
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/bin/zygiskd64"
|
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/bin/zygiskd64"
|
||||||
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/system/lib64/libinjector.so"
|
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/system/lib64/libinjector.so"
|
||||||
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/system/lib64/libzygiskloader.so"
|
sed -i "s/socket_placeholder/$SOCKET_PATCH/g" "$MODPATH/system/lib64/libzygiskloader.so"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ui_print "- Setting permissions"
|
ui_print "- Setting permissions"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ android_logger = "0.12.0"
|
|||||||
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
||||||
clap = { version = "4.1.4", features = ["derive"] }
|
clap = { version = "4.1.4", features = ["derive"] }
|
||||||
const_format = "0.2.5"
|
const_format = "0.2.5"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
memfd = "0.6.2"
|
memfd = "0.6.2"
|
||||||
nix = "0.26.2"
|
nix = "0.26.2"
|
||||||
@@ -17,6 +18,8 @@ num_enum = "0.5.9"
|
|||||||
passfd = "0.1.5"
|
passfd = "0.1.5"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
|
||||||
|
binder = { path = "src/external/binder_rs/binder" }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
strip = true
|
strip = true
|
||||||
opt-level = "z"
|
opt-level = "z"
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ cargo {
|
|||||||
val isDebug = gradle.startParameter.taskNames.any { it.toLowerCase().contains("debug") }
|
val isDebug = gradle.startParameter.taskNames.any { it.toLowerCase().contains("debug") }
|
||||||
profile = if (isDebug) "debug" else "release"
|
profile = if (isDebug) "debug" else "release"
|
||||||
exec = { spec, _ ->
|
exec = { spec, _ ->
|
||||||
|
spec.environment("ANDROID_NDK_HOME", android.ndkDirectory.path)
|
||||||
spec.environment("VERSION_CODE", verCode)
|
spec.environment("VERSION_CODE", verCode)
|
||||||
spec.environment("VERSION_NAME", verName)
|
spec.environment("VERSION_NAME", verName)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ macro_rules! lp_select {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const PROP_NATIVE_BRIDGE: &str = "ro.dalvik.vm.native.bridge";
|
pub const PROP_NATIVE_BRIDGE: &str = "ro.dalvik.vm.native.bridge";
|
||||||
|
pub const PROP_SVC_ZYGOTE: &str = "init.svc.zygote";
|
||||||
|
pub const ZYGISK_LOADER: &str = "libzygiskloader.so";
|
||||||
|
|
||||||
pub const SOCKET_PLACEHOLDER: &str = "socket_placeholder";
|
pub const SOCKET_PLACEHOLDER: &str = "socket_placeholder";
|
||||||
|
|
||||||
|
|||||||
1
zygiskd/src/external/binder_rs
vendored
Submodule
1
zygiskd/src/external/binder_rs
vendored
Submodule
Submodule zygiskd/src/external/binder_rs added at 6d958bb94a
@@ -1,4 +1,3 @@
|
|||||||
use crate::constants;
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use nix::unistd::gettid;
|
use nix::unistd::gettid;
|
||||||
use std::{fs, io::{Read, Write}, os::unix::net::UnixStream, process::Command};
|
use std::{fs, io::{Read, Write}, os::unix::net::UnixStream, process::Command};
|
||||||
@@ -27,10 +26,10 @@ pub fn get_native_bridge() -> String {
|
|||||||
std::env::var("NATIVE_BRIDGE").unwrap_or_default()
|
std::env::var("NATIVE_BRIDGE").unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn restore_native_bridge() -> Result<()> {
|
pub fn set_property(name: &str, value: &str) -> Result<()> {
|
||||||
Command::new("resetprop")
|
Command::new("resetprop")
|
||||||
.arg(constants::PROP_NATIVE_BRIDGE)
|
.arg(name)
|
||||||
.arg(get_native_bridge())
|
.arg(value)
|
||||||
.spawn()?.wait()?;
|
.spawn()?.wait()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
use crate::{constants, utils};
|
use crate::{constants, utils};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use nix::unistd::{getgid, getuid};
|
use nix::unistd::{getgid, getuid, Pid};
|
||||||
use std::process::{Child, Command};
|
use std::process::{Child, Command};
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::{fs, thread};
|
use std::{fs, thread};
|
||||||
use std::os::unix::net::UnixListener;
|
use std::os::unix::net::UnixListener;
|
||||||
use std::path::Path;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use binder::IBinder;
|
||||||
|
use nix::sys::signal::{kill, Signal};
|
||||||
|
|
||||||
static mut LOCK: Option<UnixListener> = None;
|
static mut LOCK: Option<UnixListener> = None;
|
||||||
|
|
||||||
@@ -49,36 +50,56 @@ fn ensure_single_instance() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_daemon() -> Result<()> {
|
fn spawn_daemon() -> Result<()> {
|
||||||
|
let mut lives = 5;
|
||||||
|
loop {
|
||||||
let daemon32 = Command::new(constants::PATH_ZYGISKD32).arg("daemon").spawn();
|
let daemon32 = Command::new(constants::PATH_ZYGISKD32).arg("daemon").spawn();
|
||||||
let daemon64 = Command::new(constants::PATH_ZYGISKD64).arg("daemon").spawn();
|
let daemon64 = Command::new(constants::PATH_ZYGISKD64).arg("daemon").spawn();
|
||||||
|
let mut child_ids = vec![];
|
||||||
let (sender, receiver) = mpsc::channel();
|
let (sender, receiver) = mpsc::channel();
|
||||||
let mut waiting = vec![];
|
let mut spawn = |mut daemon: Child| {
|
||||||
let mut spawn = |mut daemon: Child, socket: &'static str| {
|
child_ids.push(daemon.id());
|
||||||
waiting.push(socket);
|
|
||||||
let sender = sender.clone();
|
let sender = sender.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let result = daemon.wait().unwrap();
|
let result = daemon.wait().unwrap();
|
||||||
log::error!("Daemon process {} died: {}", daemon.id(), result);
|
log::error!("Daemon process {} died: {}", daemon.id(), result);
|
||||||
drop(daemon);
|
drop(daemon);
|
||||||
sender.send(()).unwrap();
|
let _ = sender.send(());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
if let Ok(it) = daemon32 { spawn(it, "/dev/socket/zygote_secondary") }
|
if let Ok(it) = daemon32 { spawn(it) }
|
||||||
if let Ok(it) = daemon64 { spawn(it, "/dev/socket/zygote") }
|
if let Ok(it) = daemon64 { spawn(it) }
|
||||||
|
|
||||||
waiting.into_iter().for_each(|socket| wait_zygote(socket));
|
let mut binder = loop {
|
||||||
log::info!("Zygote ready, restore native bridge");
|
if receiver.try_recv().is_ok() {
|
||||||
utils::restore_native_bridge()?;
|
bail!("Daemon died before system server ready");
|
||||||
|
}
|
||||||
let _ = receiver.recv();
|
match binder::get_service("activity") {
|
||||||
bail!("Daemon process died");
|
Some(binder) => break binder,
|
||||||
}
|
None => {
|
||||||
|
log::trace!("System server not ready, wait for 1s...");
|
||||||
fn wait_zygote(socket: &str) -> () {
|
|
||||||
let path = Path::new(socket);
|
|
||||||
loop {
|
|
||||||
if path.exists() { return; }
|
|
||||||
log::debug!("{socket} not exists, wait for 1s...");
|
|
||||||
thread::sleep(Duration::from_secs(1));
|
thread::sleep(Duration::from_secs(1));
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
log::info!("System server ready, restore native bridge");
|
||||||
|
utils::set_property(constants::PROP_NATIVE_BRIDGE, &utils::get_native_bridge())?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if receiver.try_recv().is_ok() || binder.ping_binder().is_err() { break; }
|
||||||
|
thread::sleep(Duration::from_secs(1))
|
||||||
|
}
|
||||||
|
for child in child_ids {
|
||||||
|
let _ = kill(Pid::from_raw(child as i32), Signal::SIGKILL);
|
||||||
|
}
|
||||||
|
|
||||||
|
lives -= 1;
|
||||||
|
if lives == 0 {
|
||||||
|
bail!("Too many crashes, abort");
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user