You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
150be54ff0 | ||
|
|
ab9ce993eb | ||
|
|
209036ad66 | ||
|
|
820d59e285 | ||
|
|
291599ffc8 | ||
|
|
f75d15c6f6 | ||
|
|
fb1ba93db8 | ||
|
|
814476ea7a |
16
README.md
16
README.md
@@ -6,24 +6,22 @@ Warning: The current version of Zygisksu is UNSTABLE. You may suffer boot loop o
|
||||
|
||||
## Requirements
|
||||
|
||||
+ Minimal KernelSU version: 15
|
||||
+ Minimal ksud version: 7b32c0e
|
||||
+ Minimal KernelSU version: 10575
|
||||
+ Minimal ksud version: 10200
|
||||
+ Full SELinux patch support (If non-gki kernel)
|
||||
|
||||
## Compatibility
|
||||
|
||||
- [x] LSPosed
|
||||
- [x] Storage Isolation
|
||||
- [ ] IFW Enhance
|
||||
- [ ] Universal SafetyNet Fix
|
||||
- [ ] Shamiko
|
||||
Should work with everything except those rely on Magisk internal behaviors.
|
||||
|
||||
## Development road map
|
||||
|
||||
- [x] [Inject] Basic Zygisk loader
|
||||
- [x] [Inject] Stabilize injector
|
||||
- [x] [Inject] Unload
|
||||
- [ ] [Daemon] Separate zygiskd process
|
||||
- [ ] [Daemon] Handle 64 bit only devices
|
||||
- [x] [Daemon] Linker namespace
|
||||
- [x] [Daemon] Separate zygiskd process
|
||||
- [x] [Daemon] Handle 64 bit only devices
|
||||
- [ ] [Daemon] Handle zygote death
|
||||
|
||||
## Running on Magisk
|
||||
|
||||
@@ -31,7 +31,7 @@ val gitCommitHash = "git rev-parse --verify --short HEAD".execute()
|
||||
|
||||
val moduleId by extra("zygisksu")
|
||||
val moduleName by extra("Zygisk on KernelSU")
|
||||
val verName by extra("v4-0.1.0")
|
||||
val verName by extra("v4-0.3.0")
|
||||
val verCode by extra(gitCommitCount)
|
||||
|
||||
val androidMinSdkVersion by extra(29)
|
||||
|
||||
@@ -29,7 +29,6 @@ namespace zygiskd {
|
||||
}
|
||||
|
||||
bool PingHeartbeat() {
|
||||
LOGD("Daemon socket: %s", kZygiskSocket.data());
|
||||
UniqueFd fd = Connect(5);
|
||||
if (fd == -1) {
|
||||
PLOGE("Connect to zygiskd");
|
||||
@@ -39,6 +38,16 @@ namespace zygiskd {
|
||||
return true;
|
||||
}
|
||||
|
||||
int RequestLogcatFd() {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("RequestLogcatFd");
|
||||
return -1;
|
||||
}
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::RequestLogcatFd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
std::string ReadNativeBridge() {
|
||||
UniqueFd fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
@@ -89,10 +98,6 @@ namespace zygiskd {
|
||||
}
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetModuleDir);
|
||||
socket_utils::write_usize(fd, index);
|
||||
if (socket_utils::read_u8(fd) == 1) {
|
||||
return fd;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return socket_utils::recv_fd(fd);
|
||||
}
|
||||
}
|
||||
|
||||
36
loader/src/common/logging.cpp
Normal file
36
loader/src/common/logging.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <android/log.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "logging.h"
|
||||
#include "socket_utils.h"
|
||||
|
||||
namespace logging {
|
||||
static int logfd = -1;
|
||||
|
||||
void setfd(int fd) {
|
||||
close(logfd);
|
||||
logfd = fd;
|
||||
}
|
||||
|
||||
int getfd() {
|
||||
return logfd;
|
||||
}
|
||||
|
||||
void log(int prio, const char* tag, const char* fmt, ...) {
|
||||
if (logfd == -1) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
__android_log_vprint(prio, tag, fmt, ap);
|
||||
va_end(ap);
|
||||
} else {
|
||||
char buf[BUFSIZ];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
socket_utils::write_u8(logfd, prio);
|
||||
socket_utils::write_string(logfd, tag);
|
||||
socket_utils::write_string(logfd, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,6 +110,10 @@ namespace socket_utils {
|
||||
return write_exact<uint8_t>(fd, val);
|
||||
}
|
||||
|
||||
bool write_string(int fd, std::string_view str) {
|
||||
return write_usize(fd, str.size()) && str.size() == xwrite(fd, str.data(), str.size());
|
||||
}
|
||||
|
||||
int recv_fd(int sockfd) {
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace zygiskd {
|
||||
|
||||
enum class SocketAction {
|
||||
PingHeartBeat,
|
||||
RequestLogcatFd,
|
||||
ReadNativeBridge,
|
||||
ReadModules,
|
||||
RequestCompanionSocket,
|
||||
@@ -60,6 +61,8 @@ namespace zygiskd {
|
||||
|
||||
bool PingHeartbeat();
|
||||
|
||||
int RequestLogcatFd();
|
||||
|
||||
std::string ReadNativeBridge();
|
||||
|
||||
std::vector<Module> ReadModules();
|
||||
|
||||
@@ -20,15 +20,24 @@
|
||||
#define LOGE(...)
|
||||
#else
|
||||
#ifndef NDEBUG
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGD(...) logging::log(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGV(...) logging::log(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
|
||||
#else
|
||||
#define LOGD(...)
|
||||
#define LOGV(...)
|
||||
#endif
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGI(...) logging::log(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGW(...) logging::log(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) logging::log(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGF(...) logging::log(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__)
|
||||
#define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno))
|
||||
#endif
|
||||
|
||||
namespace logging {
|
||||
void setfd(int fd);
|
||||
|
||||
int getfd();
|
||||
|
||||
[[gnu::format(printf, 3, 4)]]
|
||||
void log(int prio, const char* tag, const char* fmt, ...);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
@@ -21,4 +22,6 @@ namespace socket_utils {
|
||||
int recv_fd(int fd);
|
||||
|
||||
bool write_usize(int fd, size_t val);
|
||||
|
||||
bool write_string(int fd, std::string_view str);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "daemon.h"
|
||||
#include "logging.h"
|
||||
#include "zygisk.hpp"
|
||||
#include "module.hpp"
|
||||
@@ -17,8 +18,10 @@ static void zygisk_cleanup_wait() {
|
||||
|
||||
extern "C" [[gnu::visibility("default")]]
|
||||
void entry(void *handle) {
|
||||
LOGD("Load injector successfully");
|
||||
logging::setfd(zygiskd::RequestLogcatFd());
|
||||
self_handle = handle;
|
||||
|
||||
LOGD("Load injector successfully");
|
||||
hook_functions();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,10 @@ static void lazy_unmount(const char* mountpoint) {
|
||||
LOGD("Unmounted (%s)", mountpoint);
|
||||
}
|
||||
|
||||
#define OVERLAY_MNT(dir) (mentry->mnt_type == "overlay"sv && std::string_view(mentry->mnt_dir).starts_with("/" #dir))
|
||||
|
||||
void revert_unmount() {
|
||||
parse_mnt("/proc/self/mounts", [](mntent* mentry) {
|
||||
if (OVERLAY_MNT("system") || OVERLAY_MNT("vendor") || OVERLAY_MNT("product") || OVERLAY_MNT("system_ext")) {
|
||||
if (mentry->mnt_fsname == "/data/adb/ksu/modules"sv ||
|
||||
std::string_view(mentry->mnt_opts).find("/data/adb/ksu/modules") != std::string_view::npos) {
|
||||
lazy_unmount(mentry->mnt_fsname);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -204,7 +204,17 @@ DCL_HOOK_FUNC(int, unshare, int flags) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Zygisksu changed: No android_log_close hook */
|
||||
// Close logd_fd if necessary to prevent crashing
|
||||
// For more info, check comments in zygisk_log_write
|
||||
DCL_HOOK_FUNC(void, android_log_close) {
|
||||
if (g_ctx == nullptr) {
|
||||
// Happens during un-managed fork like nativeForkApp, nativeForkUsap
|
||||
logging::setfd(-1);
|
||||
} else if (!g_ctx->flags[SKIP_FD_SANITIZATION]) {
|
||||
logging::setfd(-1);
|
||||
}
|
||||
old_android_log_close();
|
||||
}
|
||||
|
||||
// Last point before process secontext changes
|
||||
DCL_HOOK_FUNC(int, selinux_android_setcontext,
|
||||
@@ -595,7 +605,7 @@ void HookContext::app_specialize_post() {
|
||||
// Cleanups
|
||||
env->ReleaseStringUTFChars(args.app->nice_name, process);
|
||||
g_ctx = nullptr;
|
||||
/* Zygisksu changed: No android_log_close */
|
||||
logging::setfd(-1);
|
||||
}
|
||||
|
||||
void HookContext::unload_zygisk() {
|
||||
@@ -668,7 +678,9 @@ void HookContext::nativeForkAndSpecialize_pre() {
|
||||
|
||||
flags[APP_FORK_AND_SPECIALIZE] = true;
|
||||
/* Zygisksu changed: No args.app->fds_to_ignore check since we are Android 10+ */
|
||||
flags[SKIP_FD_SANITIZATION] = true;
|
||||
if (logging::getfd() != -1) {
|
||||
exempted_fds.push_back(logging::getfd());
|
||||
}
|
||||
|
||||
fork_pre();
|
||||
if (pid == 0) {
|
||||
@@ -729,7 +741,7 @@ void hook_functions() {
|
||||
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, unshare);
|
||||
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, jniRegisterNativeMethods);
|
||||
PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, selinux_android_setcontext);
|
||||
/* Zygisksu changed: No android_log_close hook */
|
||||
PLT_HOOK_REGISTER_SYM(android_runtime_dev, android_runtime_inode, "__android_log_close", android_log_close);
|
||||
hook_commit();
|
||||
|
||||
// Remove unhooked methods
|
||||
|
||||
@@ -42,9 +42,10 @@ void Constructor() {
|
||||
|
||||
std::string native_bridge;
|
||||
do {
|
||||
LOGD("Ping heartbeat");
|
||||
if (!zygiskd::PingHeartbeat()) break;
|
||||
|
||||
logging::setfd(zygiskd::RequestLogcatFd());
|
||||
|
||||
LOGI("Read native bridge");
|
||||
native_bridge = zygiskd::ReadNativeBridge();
|
||||
|
||||
@@ -63,32 +64,37 @@ void Constructor() {
|
||||
reinterpret_cast<void (*)(void*)>(entry)(handle);
|
||||
} while (false);
|
||||
|
||||
if (native_bridge.empty() || native_bridge == "0") return;
|
||||
LOGI("Load original native bridge: %s", native_bridge.data());
|
||||
sOriginalBridge = dlopen(native_bridge.data(), RTLD_NOW);
|
||||
if (sOriginalBridge == nullptr) {
|
||||
LOGE("dlopen failed: %s", dlerror());
|
||||
return;
|
||||
}
|
||||
do {
|
||||
if (native_bridge.empty() || native_bridge == "0") break;
|
||||
|
||||
auto* original_native_bridge_itf = dlsym(sOriginalBridge, "NativeBridgeItf");
|
||||
if (original_native_bridge_itf == nullptr) {
|
||||
LOGE("dlsym failed: %s", dlerror());
|
||||
return;
|
||||
}
|
||||
LOGI("Load original native bridge: %s", native_bridge.data());
|
||||
sOriginalBridge = dlopen(native_bridge.data(), RTLD_NOW);
|
||||
if (sOriginalBridge == nullptr) {
|
||||
LOGE("dlopen failed: %s", dlerror());
|
||||
break;
|
||||
}
|
||||
|
||||
long sdk = 0;
|
||||
char value[PROP_VALUE_MAX + 1];
|
||||
if (__system_property_get("ro.build.version.sdk", value) > 0) {
|
||||
sdk = strtol(value, nullptr, 10);
|
||||
}
|
||||
auto* original_native_bridge_itf = dlsym(sOriginalBridge, "NativeBridgeItf");
|
||||
if (original_native_bridge_itf == nullptr) {
|
||||
LOGE("dlsym failed: %s", dlerror());
|
||||
break;
|
||||
}
|
||||
|
||||
auto callbacks_size = 0;
|
||||
if (sdk >= __ANDROID_API_R__) {
|
||||
callbacks_size = sizeof(NativeBridgeCallbacks<__ANDROID_API_R__>);
|
||||
} else if (sdk == __ANDROID_API_Q__) {
|
||||
callbacks_size = sizeof(NativeBridgeCallbacks<__ANDROID_API_Q__>);
|
||||
}
|
||||
long sdk = 0;
|
||||
char value[PROP_VALUE_MAX + 1];
|
||||
if (__system_property_get("ro.build.version.sdk", value) > 0) {
|
||||
sdk = strtol(value, nullptr, 10);
|
||||
}
|
||||
|
||||
memcpy(NativeBridgeItf, original_native_bridge_itf, callbacks_size);
|
||||
auto callbacks_size = 0;
|
||||
if (sdk >= __ANDROID_API_R__) {
|
||||
callbacks_size = sizeof(NativeBridgeCallbacks<__ANDROID_API_R__>);
|
||||
} else if (sdk == __ANDROID_API_Q__) {
|
||||
callbacks_size = sizeof(NativeBridgeCallbacks<__ANDROID_API_Q__>);
|
||||
}
|
||||
|
||||
memcpy(NativeBridgeItf, original_native_bridge_itf, callbacks_size);
|
||||
} while (false);
|
||||
|
||||
logging::setfd(-1);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ androidComponents.onVariants { variant ->
|
||||
from("$projectDir/src") {
|
||||
include("customize.sh", "daemon.sh")
|
||||
val tokens = mapOf(
|
||||
"ZYGISK_API" to (verCode / 1000).toString(),
|
||||
"DEBUG" to if (buildTypeLowered == "debug") "true" else "false"
|
||||
)
|
||||
filter<ReplaceTokens>("tokens" to tokens)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# shellcheck disable=SC2034
|
||||
SKIPUNZIP=1
|
||||
|
||||
ZYGISK_API="@ZYGISK_API@"
|
||||
|
||||
if [ $BOOTMODE ] && [ "$KSU" == "true" ]; then
|
||||
ui_print "- Installing from KernelSU app"
|
||||
else
|
||||
@@ -13,10 +11,16 @@ else
|
||||
fi
|
||||
|
||||
VERSION=$(grep_prop version "${TMPDIR}/module.prop")
|
||||
ui_print "- Installing Zygisksu $VERSION (ZYGISK API $ZYGISK_API)"
|
||||
ui_print "- Installing Zygisksu $VERSION"
|
||||
|
||||
# check KernelSU
|
||||
# ui_print "- KernelSU version: $KSU_VER ($KSU_VER_CODE)"
|
||||
ui_print "- KernelSU version: $KSU_VER ($KSU_VER_CODE)"
|
||||
if [ "$KSU_VER_CODE" -lt 10200 ]; then
|
||||
ui_print "*********************************************************"
|
||||
ui_print "! KernelSU version is too old!"
|
||||
ui_print "! Please update KernelSU to latest version"
|
||||
abort "*********************************************************"
|
||||
fi
|
||||
|
||||
# check android
|
||||
if [ "$API" -lt 29 ]; then
|
||||
@@ -39,11 +43,20 @@ if [ ! -f "$TMPDIR/verify.sh" ]; then
|
||||
ui_print "*********************************************************"
|
||||
ui_print "! Unable to extract verify.sh!"
|
||||
ui_print "! This zip may be corrupted, please try downloading again"
|
||||
abort "*********************************************************"
|
||||
abort "*********************************************************"
|
||||
fi
|
||||
. "$TMPDIR/verify.sh"
|
||||
extract "$ZIPFILE" 'customize.sh' "$TMPDIR/.vunzip"
|
||||
extract "$ZIPFILE" 'verify.sh' "$TMPDIR/.vunzip"
|
||||
extract "$ZIPFILE" 'customize.sh' "$TMPDIR/.vunzip"
|
||||
extract "$ZIPFILE" 'verify.sh' "$TMPDIR/.vunzip"
|
||||
extract "$ZIPFILE" 'sepolicy.rule' "$TMPDIR"
|
||||
|
||||
ui_print "- Checking SELinux patches"
|
||||
if ! /data/adb/ksud sepolicy check "$TMPDIR/sepolicy.rule"; then
|
||||
ui_print "*********************************************************"
|
||||
ui_print "! Unable to apply SELinux patches!"
|
||||
ui_print "! Your kernel may not support SELinux patch fully"
|
||||
abort "*********************************************************"
|
||||
fi
|
||||
|
||||
ui_print "- Extracting module files"
|
||||
extract "$ZIPFILE" 'daemon.sh' "$MODPATH"
|
||||
|
||||
@@ -9,4 +9,4 @@ export NATIVE_BRIDGE=$(getprop ro.dalvik.vm.native.bridge)
|
||||
|
||||
log -p i -t "zygisksu" "Start watchdog"
|
||||
resetprop ro.dalvik.vm.native.bridge libzygiskloader.so
|
||||
exec "$MODDIR/bin/zygiskwd" >/dev/null 2>&1
|
||||
exec "$MODDIR/bin/zygiskwd" "watchdog" >/dev/null 2>&1
|
||||
|
||||
@@ -8,6 +8,7 @@ rust-version = "1.67"
|
||||
[dependencies]
|
||||
android_logger = "0.12.0"
|
||||
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
||||
clap = { version = "4.1.4", features = ["derive"] }
|
||||
const_format = "0.2.5"
|
||||
log = "0.4.17"
|
||||
memfd = "0.6.2"
|
||||
|
||||
@@ -3,6 +3,9 @@ plugins {
|
||||
id("org.mozilla.rust-android-gradle.rust-android")
|
||||
}
|
||||
|
||||
val verName: String by rootProject.extra
|
||||
val verCode: Int by rootProject.extra
|
||||
|
||||
android.buildFeatures {
|
||||
androidResources = false
|
||||
buildConfig = false
|
||||
@@ -16,4 +19,8 @@ cargo {
|
||||
targetDirectory = "build/intermediates/rust"
|
||||
val isDebug = gradle.startParameter.taskNames.any { it.toLowerCase().contains("debug") }
|
||||
profile = if (isDebug) "debug" else "release"
|
||||
exec = { spec, _ ->
|
||||
spec.environment("VERSION_CODE", verCode)
|
||||
spec.environment("VERSION_NAME", verName)
|
||||
}
|
||||
}
|
||||
|
||||
61
zygiskd/src/companion.rs
Normal file
61
zygiskd/src/companion.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
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,27 @@
|
||||
use const_format::concatcp;
|
||||
use log::LevelFilter;
|
||||
use num_enum::TryFromPrimitive;
|
||||
|
||||
pub const VERSION_NAME: &str = env!("VERSION_NAME");
|
||||
pub const VERSION_CODE: &str = env!("VERSION_CODE");
|
||||
pub const VERSION_FULL: &str = concatcp!(VERSION_NAME, " (", VERSION_CODE, ")");
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
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 SOCKET_PLACEHOLDER: &str = "socket_placeholder";
|
||||
@@ -15,6 +36,7 @@ pub const PATH_DAEMON_LOCK: &str = concatcp!(PATH_ZYGISKSU_DIR, "/zygiskd.lock")
|
||||
#[repr(u8)]
|
||||
pub enum DaemonSocketAction {
|
||||
PingHeartbeat,
|
||||
RequestLogcatFd,
|
||||
ReadNativeBridge,
|
||||
ReadModules,
|
||||
RequestCompanionSocket,
|
||||
|
||||
82
zygiskd/src/dl.rs
Normal file
82
zygiskd/src/dl.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
use anyhow::{bail, Result};
|
||||
use std::ffi::{c_char, c_void};
|
||||
use nix::libc;
|
||||
|
||||
const ANDROID_NAMESPACE_TYPE_SHARED: u64 = 0x2;
|
||||
const ANDROID_DLEXT_USE_NAMESPACE: u64 = 0x200;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct AndroidNamespace {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct AndroidDlextinfo {
|
||||
pub flags: u64,
|
||||
pub reserved_addr: *mut c_void,
|
||||
pub reserved_size: libc::size_t,
|
||||
pub relro_fd: libc::c_int,
|
||||
pub library_fd: libc::c_int,
|
||||
pub library_fd_offset: libc::off64_t,
|
||||
pub library_namespace: *mut AndroidNamespace,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn android_dlopen_ext(
|
||||
filename: *const c_char,
|
||||
flags: libc::c_int,
|
||||
extinfo: *const AndroidDlextinfo,
|
||||
) -> *mut c_void;
|
||||
}
|
||||
|
||||
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
|
||||
) -> *mut AndroidNamespace;
|
||||
|
||||
pub unsafe fn dlopen(path: &str, flags: i32) -> Result<*mut c_void> {
|
||||
let filename = std::ffi::CString::new(path)?;
|
||||
let filename = filename.as_ptr() as *mut _;
|
||||
let dir = libc::dirname(filename);
|
||||
let mut info = AndroidDlextinfo {
|
||||
flags: 0,
|
||||
reserved_addr: std::ptr::null_mut(),
|
||||
reserved_size: 0,
|
||||
relro_fd: 0,
|
||||
library_fd: 0,
|
||||
library_fd_offset: 0,
|
||||
library_namespace: std::ptr::null_mut(),
|
||||
};
|
||||
|
||||
let android_create_namespace_fn = libc::dlsym(
|
||||
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 ns = android_create_namespace_fn(
|
||||
filename, dir, std::ptr::null(),
|
||||
ANDROID_NAMESPACE_TYPE_SHARED,
|
||||
std::ptr::null(), std::ptr::null_mut(),
|
||||
&dlopen as *const _ as *const c_void,
|
||||
);
|
||||
if ns != std::ptr::null_mut() {
|
||||
info.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
info.library_namespace = ns;
|
||||
log::debug!("Open {} with namespace {:p}", path, ns);
|
||||
} else {
|
||||
log::debug!("Cannot create namespace for {}", path);
|
||||
};
|
||||
|
||||
let result = android_dlopen_ext(filename, flags, &info);
|
||||
if result.is_null() {
|
||||
let e = std::ffi::CStr::from_ptr(libc::dlerror()).to_string_lossy();
|
||||
bail!("dlopen failed: {}", e);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
@@ -1,51 +1,53 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
mod companion;
|
||||
mod constants;
|
||||
mod dl;
|
||||
mod utils;
|
||||
mod watchdog;
|
||||
mod zygisk;
|
||||
mod zygiskd;
|
||||
|
||||
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,
|
||||
/// Start zygisk companion
|
||||
Companion { fd: i32 },
|
||||
}
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use log::LevelFilter;
|
||||
use nix::libc;
|
||||
|
||||
fn init_android_logger(tag: &str) {
|
||||
android_logger::init_once(
|
||||
android_logger::Config::default()
|
||||
.with_max_level(LevelFilter::Trace)
|
||||
.with_max_level(constants::MAX_LOG_LEVEL)
|
||||
.with_tag(tag),
|
||||
);
|
||||
}
|
||||
|
||||
fn entry() -> Result<()> {
|
||||
let process = std::env::args().next().unwrap();
|
||||
let process = process.split('/').last().unwrap();
|
||||
init_android_logger(process);
|
||||
match process {
|
||||
"zygiskwd" => {
|
||||
log::info!("Start zygisksu watchdog");
|
||||
watchdog::check_permission()?;
|
||||
watchdog::ensure_single_instance()?;
|
||||
watchdog::spawn_daemon()?;
|
||||
}
|
||||
"zygiskd32" => {
|
||||
log::info!("Start zygiskd32");
|
||||
unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL); }
|
||||
zygisk::start(false)?;
|
||||
loop {}
|
||||
}
|
||||
"zygiskd64" => {
|
||||
log::info!("Start zygiskd64");
|
||||
unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL); }
|
||||
zygisk::start(true)?;
|
||||
}
|
||||
_ => bail!("Unexpected process name: {process}")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if let Err(e) = entry() {
|
||||
let process = std::env::args().next().unwrap();
|
||||
let nice_name = process.split('/').last().unwrap();
|
||||
init_android_logger(nice_name);
|
||||
|
||||
let cli = Args::parse();
|
||||
let result = match cli.command {
|
||||
Commands::Watchdog => watchdog::entry(),
|
||||
Commands::Daemon => zygiskd::entry(),
|
||||
Commands::Companion { fd } => companion::entry(fd),
|
||||
};
|
||||
|
||||
if let Err(e) = &result {
|
||||
log::error!("Crashed: {}\n{}", e, e.backtrace());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,8 +39,10 @@ pub trait UnixStreamExt {
|
||||
fn read_u8(&mut self) -> Result<u8>;
|
||||
fn read_u32(&mut self) -> Result<u32>;
|
||||
fn read_usize(&mut self) -> Result<usize>;
|
||||
fn read_string(&mut self) -> Result<String>;
|
||||
fn write_u8(&mut self, value: u8) -> Result<()>;
|
||||
fn write_usize(&mut self, value: usize) -> Result<()>;
|
||||
fn write_string(&mut self, value: &str) -> Result<()>;
|
||||
}
|
||||
|
||||
impl UnixStreamExt for UnixStream {
|
||||
@@ -62,6 +64,13 @@ impl UnixStreamExt for UnixStream {
|
||||
Ok(usize::from_ne_bytes(buf))
|
||||
}
|
||||
|
||||
fn read_string(&mut self) -> Result<String> {
|
||||
let len = self.read_usize()?;
|
||||
let mut buf = vec![0u8; len];
|
||||
self.read_exact(&mut buf)?;
|
||||
Ok(String::from_utf8(buf)?)
|
||||
}
|
||||
|
||||
fn write_u8(&mut self, value: u8) -> Result<()> {
|
||||
self.write_all(&value.to_ne_bytes())?;
|
||||
Ok(())
|
||||
@@ -71,6 +80,12 @@ impl UnixStreamExt for UnixStream {
|
||||
self.write_all(&value.to_ne_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_string(&mut self, value: &str) -> Result<()> {
|
||||
self.write_usize(value.len())?;
|
||||
self.write_all(value.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Replace with SockAddrExt::from_abstract_name when it's stable
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::constants;
|
||||
use crate::{constants, utils};
|
||||
use anyhow::{bail, Result};
|
||||
use nix::fcntl::{flock, FlockArg};
|
||||
use nix::unistd::{getgid, getuid};
|
||||
@@ -6,10 +6,19 @@ use std::os::unix::prelude::AsRawFd;
|
||||
use std::process::{Child, Command};
|
||||
use std::sync::mpsc;
|
||||
use std::{fs, thread};
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
|
||||
static mut LOCK_FILE: Option<fs::File> = None;
|
||||
|
||||
pub fn check_permission() -> Result<()> {
|
||||
pub fn entry() -> Result<()> {
|
||||
log::info!("Start zygisksu watchdog");
|
||||
check_permission()?;
|
||||
ensure_single_instance()?;
|
||||
spawn_daemon()
|
||||
}
|
||||
|
||||
fn check_permission() -> Result<()> {
|
||||
log::info!("Check permission");
|
||||
let uid = getuid();
|
||||
if uid.as_raw() != 0 {
|
||||
@@ -31,7 +40,7 @@ pub fn check_permission() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn ensure_single_instance() -> Result<()> {
|
||||
fn ensure_single_instance() -> Result<()> {
|
||||
log::info!("Ensure single instance");
|
||||
let metadata = fs::metadata(constants::PATH_ZYGISKSU_DIR);
|
||||
if metadata.is_err() || !metadata.unwrap().is_dir() {
|
||||
@@ -50,11 +59,13 @@ pub fn ensure_single_instance() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn spawn_daemon() -> Result<()> {
|
||||
let daemon32 = Command::new(constants::PATH_ZYGISKD32).spawn()?;
|
||||
let daemon64 = Command::new(constants::PATH_ZYGISKD64).spawn()?;
|
||||
fn spawn_daemon() -> Result<()> {
|
||||
let daemon32 = Command::new(constants::PATH_ZYGISKD32).arg("daemon").spawn();
|
||||
let daemon64 = Command::new(constants::PATH_ZYGISKD64).arg("daemon").spawn();
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
let spawn = |mut daemon: Child| {
|
||||
let mut waiting = vec![];
|
||||
let mut spawn = |mut daemon: Child, socket: &'static str| {
|
||||
waiting.push(socket);
|
||||
let sender = sender.clone();
|
||||
thread::spawn(move || {
|
||||
let result = daemon.wait().unwrap();
|
||||
@@ -63,8 +74,22 @@ pub fn spawn_daemon() -> Result<()> {
|
||||
sender.send(()).unwrap();
|
||||
});
|
||||
};
|
||||
spawn(daemon32);
|
||||
spawn(daemon64);
|
||||
if let Ok(it) = daemon32 { spawn(it, "/dev/socket/zygote_secondary") }
|
||||
if let Ok(it) = daemon64 { spawn(it, "/dev/socket/zygote") }
|
||||
|
||||
waiting.into_iter().for_each(|socket| wait_zygote(socket));
|
||||
log::info!("Zygote ready, restore native bridge");
|
||||
utils::restore_native_bridge()?;
|
||||
|
||||
let _ = receiver.recv();
|
||||
bail!("Daemon process died");
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
use crate::constants::DaemonSocketAction;
|
||||
use crate::utils::{restore_native_bridge, UnixStreamExt};
|
||||
use crate::{constants, utils};
|
||||
use crate::utils::UnixStreamExt;
|
||||
use crate::{constants, lp_select, utils};
|
||||
use anyhow::{bail, Result};
|
||||
use memfd::Memfd;
|
||||
use nix::{
|
||||
libc::{self, dlsym},
|
||||
unistd::getppid,
|
||||
fcntl::{fcntl, FcntlArg, FdFlag},
|
||||
libc::self,
|
||||
};
|
||||
use passfd::FdPassingExt;
|
||||
use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::ffi::c_void;
|
||||
use std::ffi::c_char;
|
||||
use std::fs;
|
||||
use std::os::unix::{
|
||||
net::{UnixListener, UnixStream},
|
||||
prelude::AsRawFd,
|
||||
};
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
type ZygiskCompanionEntryFn = unsafe extern "C" fn(i32);
|
||||
|
||||
struct Module {
|
||||
name: String,
|
||||
memfd: Memfd,
|
||||
companion_entry: Option<ZygiskCompanionEntryFn>,
|
||||
companion: Mutex<Option<UnixStream>>,
|
||||
}
|
||||
|
||||
struct Context {
|
||||
@@ -33,9 +31,10 @@ struct Context {
|
||||
modules: Vec<Module>,
|
||||
}
|
||||
|
||||
pub fn start(is64: bool) -> Result<()> {
|
||||
check_parent()?;
|
||||
let arch = get_arch(is64)?;
|
||||
pub fn entry() -> Result<()> {
|
||||
unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL) };
|
||||
|
||||
let arch = get_arch()?;
|
||||
log::debug!("Daemon architecture: {arch}");
|
||||
|
||||
log::info!("Load modules");
|
||||
@@ -48,7 +47,7 @@ pub fn start(is64: bool) -> Result<()> {
|
||||
let context = Arc::new(context);
|
||||
|
||||
log::info!("Create socket");
|
||||
let listener = create_daemon_socket(is64)?;
|
||||
let listener = create_daemon_socket()?;
|
||||
|
||||
log::info!("Handle zygote connections");
|
||||
for stream in listener.incoming() {
|
||||
@@ -64,27 +63,16 @@ pub fn start(is64: bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_parent() -> Result<()> {
|
||||
let parent = fs::read_to_string(format!("/proc/{}/cmdline", getppid().as_raw()))?;
|
||||
let parent = parent.split('/').last().unwrap().trim_end_matches('\0');
|
||||
if parent != "zygiskwd" {
|
||||
bail!("Daemon is not started by watchdog: {parent}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_arch(is64: bool) -> Result<&'static str> {
|
||||
fn get_arch() -> Result<&'static str> {
|
||||
let output = Command::new("getprop").arg("ro.product.cpu.abi").output()?;
|
||||
let system_arch = String::from_utf8(output.stdout)?;
|
||||
let is_arm = system_arch.contains("arm");
|
||||
let is_x86 = system_arch.contains("x86");
|
||||
match (is_arm, is_x86, is64) {
|
||||
(true, _, false) => Ok("armeabi-v7a"),
|
||||
(true, _, true) => Ok("arm64-v8a"),
|
||||
(_, true, false) => Ok("x86"),
|
||||
(_, true, true) => Ok("x86_64"),
|
||||
_ => bail!("Unsupported system architecture: {}", system_arch),
|
||||
if system_arch.contains("arm") {
|
||||
return Ok(lp_select!("armeabi-v7a", "arm64-v8a"))
|
||||
}
|
||||
if system_arch.contains("x86") {
|
||||
return Ok(lp_select!("x86", "x86_64"))
|
||||
}
|
||||
bail!("Unsupported system architecture: {}", system_arch);
|
||||
}
|
||||
|
||||
fn load_modules(arch: &str) -> Result<Vec<Module>> {
|
||||
@@ -112,18 +100,16 @@ fn load_modules(arch: &str) -> Result<Vec<Module>> {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let companion_entry = match preload_module(&memfd) {
|
||||
Ok(entry) => entry,
|
||||
let companion = match spawn_companion(&name, &memfd) {
|
||||
Ok(companion) => companion,
|
||||
Err(e) => {
|
||||
log::warn!(" Failed to preload `{name}`: {e}");
|
||||
log::warn!(" Failed to spawn companion for `{name}`: {e}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let module = Module {
|
||||
name,
|
||||
memfd,
|
||||
companion_entry,
|
||||
};
|
||||
|
||||
let companion = Mutex::new(companion);
|
||||
let module = Module { name, memfd, companion };
|
||||
modules.push(module);
|
||||
}
|
||||
|
||||
@@ -149,66 +135,83 @@ fn create_memfd(name: &str, so_path: &PathBuf) -> Result<Memfd> {
|
||||
Ok(memfd)
|
||||
}
|
||||
|
||||
fn preload_module(memfd: &Memfd) -> Result<Option<ZygiskCompanionEntryFn>> {
|
||||
unsafe {
|
||||
let path = format!("/proc/self/fd/{}", memfd.as_raw_fd());
|
||||
let filename = std::ffi::CString::new(path)?;
|
||||
let handle = libc::dlopen(filename.as_ptr(), libc::RTLD_LAZY);
|
||||
if handle.is_null() {
|
||||
let e = std::ffi::CStr::from_ptr(libc::dlerror())
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
bail!("dlopen failed: {}", e);
|
||||
}
|
||||
let symbol = std::ffi::CString::new("zygisk_companion_entry")?;
|
||||
let entry = 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))
|
||||
}
|
||||
}
|
||||
|
||||
fn create_daemon_socket(is64: bool) -> Result<UnixListener> {
|
||||
fn create_daemon_socket() -> Result<UnixListener> {
|
||||
utils::set_socket_create_context("u:r:zygote:s0")?;
|
||||
let suffix = if is64 { "zygiskd64" } else { "zygiskd32" };
|
||||
let suffix = lp_select!("zygiskd32", "zygiskd64");
|
||||
let name = String::from(suffix) + constants::SOCKET_PLACEHOLDER;
|
||||
let listener = utils::abstract_namespace_socket(&name)?;
|
||||
log::debug!("Daemon socket: {name}");
|
||||
Ok(listener)
|
||||
}
|
||||
|
||||
fn spawn_companion(name: &str, memfd: &Memfd) -> Result<Option<UnixStream>> {
|
||||
let (mut daemon, companion) = UnixStream::pair()?;
|
||||
// Remove FD_CLOEXEC flag
|
||||
fcntl(companion.as_raw_fd(), FcntlArg::F_SETFD(FdFlag::empty()))?;
|
||||
|
||||
let process = std::env::args().next().unwrap();
|
||||
let nice_name = process.split('/').last().unwrap();
|
||||
Command::new(&process)
|
||||
.arg0(format!("{}-{}", nice_name, name))
|
||||
.arg("companion")
|
||||
.arg(format!("{}", companion.as_raw_fd()))
|
||||
.spawn()?;
|
||||
drop(companion);
|
||||
|
||||
daemon.write_string(name)?;
|
||||
daemon.send_fd(memfd.as_raw_fd())?;
|
||||
match daemon.read_u8()? {
|
||||
0 => Ok(None),
|
||||
1 => Ok(Some(daemon)),
|
||||
_ => bail!("Invalid companion response"),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_daemon_action(mut stream: UnixStream, context: &Context) -> Result<()> {
|
||||
let action = stream.read_u8()?;
|
||||
let action = DaemonSocketAction::try_from(action)?;
|
||||
log::trace!("New daemon action {:?}", action);
|
||||
match action {
|
||||
DaemonSocketAction::PingHeartbeat => {
|
||||
restore_native_bridge()?;
|
||||
// Do nothing
|
||||
}
|
||||
DaemonSocketAction::RequestLogcatFd => {
|
||||
loop {
|
||||
let level = match stream.read_u8() {
|
||||
Ok(level) => level,
|
||||
Err(_) => break,
|
||||
};
|
||||
let tag = stream.read_string()?;
|
||||
let tag = std::ffi::CString::new(tag)?;
|
||||
let message = stream.read_string()?;
|
||||
let message = std::ffi::CString::new(message)?;
|
||||
unsafe {
|
||||
__android_log_print(level as i32, tag.as_ptr(), message.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
DaemonSocketAction::ReadNativeBridge => {
|
||||
stream.write_usize(context.native_bridge.len())?;
|
||||
stream.write_all(context.native_bridge.as_bytes())?;
|
||||
stream.write_string(&context.native_bridge)?;
|
||||
}
|
||||
DaemonSocketAction::ReadModules => {
|
||||
stream.write_usize(context.modules.len())?;
|
||||
for module in context.modules.iter() {
|
||||
stream.write_usize(module.name.len())?;
|
||||
stream.write_all(module.name.as_bytes())?;
|
||||
stream.write_string(&module.name)?;
|
||||
stream.send_fd(module.memfd.as_raw_fd())?;
|
||||
}
|
||||
}
|
||||
DaemonSocketAction::RequestCompanionSocket => {
|
||||
let index = stream.read_usize()?;
|
||||
let module = &context.modules[index];
|
||||
log::debug!("New companion request from module {}", module.name);
|
||||
|
||||
// FIXME: Spawn a new process
|
||||
match module.companion_entry {
|
||||
Some(entry) => {
|
||||
stream.write_u8(1)?;
|
||||
unsafe { entry(stream.as_raw_fd()); }
|
||||
let mut companion = module.companion.lock().unwrap();
|
||||
match companion.as_ref() {
|
||||
Some(sock) => {
|
||||
if let Err(_) = sock.send_fd(stream.as_raw_fd()) {
|
||||
log::error!("Companion of module `{}` crashed", module.name);
|
||||
companion.take();
|
||||
stream.write_u8(0)?;
|
||||
}
|
||||
// Ok: Send by companion
|
||||
}
|
||||
None => {
|
||||
stream.write_u8(0)?;
|
||||
@@ -225,3 +228,7 @@ fn handle_daemon_action(mut stream: UnixStream, context: &Context) -> Result<()>
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn __android_log_print(prio: i32, tag: *const c_char, fmt: *const c_char, ...) -> i32;
|
||||
}
|
||||
Reference in New Issue
Block a user