mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-04-30 22:44:25 +02:00
Code reorganization
This commit is contained in:
parent
b25aa8295a
commit
7f7f625864
@ -18,7 +18,6 @@ LOCAL_SRC_FILES := \
|
|||||||
core/applets.cpp \
|
core/applets.cpp \
|
||||||
core/magisk.cpp \
|
core/magisk.cpp \
|
||||||
core/daemon.cpp \
|
core/daemon.cpp \
|
||||||
core/bootstages.cpp \
|
|
||||||
core/socket.cpp \
|
core/socket.cpp \
|
||||||
core/scripting.cpp \
|
core/scripting.cpp \
|
||||||
core/selinux.cpp \
|
core/selinux.cpp \
|
||||||
@ -32,7 +31,6 @@ LOCAL_SRC_FILES := \
|
|||||||
core/su/pts.cpp \
|
core/su/pts.cpp \
|
||||||
core/su/su_daemon.cpp \
|
core/su/su_daemon.cpp \
|
||||||
core/zygisk/entry.cpp \
|
core/zygisk/entry.cpp \
|
||||||
core/zygisk/main.cpp \
|
|
||||||
core/zygisk/module.cpp \
|
core/zygisk/module.cpp \
|
||||||
core/zygisk/hook.cpp \
|
core/zygisk/hook.cpp \
|
||||||
core/deny/cli.cpp \
|
core/deny/cli.cpp \
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
#include <sys/mount.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/sysmacros.h>
|
|
||||||
#include <linux/input.h>
|
|
||||||
#include <libgen.h>
|
|
||||||
#include <set>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <consts.hpp>
|
|
||||||
#include <base.hpp>
|
|
||||||
#include <core.hpp>
|
|
||||||
#include <selinux.hpp>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
/*********
|
|
||||||
* Setup *
|
|
||||||
*********/
|
|
||||||
|
|
||||||
bool setup_magisk_env() {
|
|
||||||
char buf[4096];
|
|
||||||
|
|
||||||
LOGI("* Initializing Magisk environment\n");
|
|
||||||
|
|
||||||
ssprintf(buf, sizeof(buf), "%s/0/%s/install", APP_DATA_DIR, JAVA_PACKAGE_NAME);
|
|
||||||
// Alternative binaries paths
|
|
||||||
const char *alt_bin[] = { "/cache/data_adb/magisk", "/data/magisk", buf };
|
|
||||||
for (auto alt : alt_bin) {
|
|
||||||
if (access(alt, F_OK) == 0) {
|
|
||||||
rm_rf(DATABIN);
|
|
||||||
cp_afc(alt, DATABIN);
|
|
||||||
rm_rf(alt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rm_rf("/cache/data_adb");
|
|
||||||
|
|
||||||
// Directories in /data/adb
|
|
||||||
chmod(SECURE_DIR, 0700);
|
|
||||||
xmkdir(DATABIN, 0755);
|
|
||||||
xmkdir(MODULEROOT, 0755);
|
|
||||||
xmkdir(SECURE_DIR "/post-fs-data.d", 0755);
|
|
||||||
xmkdir(SECURE_DIR "/service.d", 0755);
|
|
||||||
restorecon();
|
|
||||||
|
|
||||||
if (access(DATABIN "/busybox", X_OK))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ssprintf(buf, sizeof(buf), "%s/" BBPATH "/busybox", get_magisk_tmp());
|
|
||||||
mkdir(dirname(buf), 0755);
|
|
||||||
cp_afc(DATABIN "/busybox", buf);
|
|
||||||
exec_command_async(buf, "--install", "-s", dirname(buf));
|
|
||||||
|
|
||||||
// magisk32 and magiskpolicy are not installed into ramdisk and has to be copied
|
|
||||||
// from data to magisk tmp
|
|
||||||
if (access(DATABIN "/magisk32", X_OK) == 0) {
|
|
||||||
ssprintf(buf, sizeof(buf), "%s/magisk32", get_magisk_tmp());
|
|
||||||
cp_afc(DATABIN "/magisk32", buf);
|
|
||||||
}
|
|
||||||
if (access(DATABIN "/magiskpolicy", X_OK) == 0) {
|
|
||||||
ssprintf(buf, sizeof(buf), "%s/magiskpolicy", get_magisk_tmp());
|
|
||||||
cp_afc(DATABIN "/magiskpolicy", buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock_blocks() {
|
|
||||||
int fd, dev, OFF = 0;
|
|
||||||
|
|
||||||
auto dir = xopen_dir("/dev/block");
|
|
||||||
if (!dir)
|
|
||||||
return;
|
|
||||||
dev = dirfd(dir.get());
|
|
||||||
|
|
||||||
for (dirent *entry; (entry = readdir(dir.get()));) {
|
|
||||||
if (entry->d_type == DT_BLK) {
|
|
||||||
if ((fd = openat(dev, entry->d_name, O_RDONLY | O_CLOEXEC)) < 0)
|
|
||||||
continue;
|
|
||||||
if (ioctl(fd, BLKROSET, &OFF) < 0)
|
|
||||||
PLOGE("unlock %s", entry->d_name);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8)))
|
|
||||||
|
|
||||||
bool check_key_combo() {
|
|
||||||
uint8_t bitmask[(KEY_MAX + 1) / 8];
|
|
||||||
vector<int> events;
|
|
||||||
constexpr char name[] = "/dev/.ev";
|
|
||||||
|
|
||||||
// First collect candidate events that accepts volume down
|
|
||||||
for (int minor = 64; minor < 96; ++minor) {
|
|
||||||
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
|
|
||||||
continue;
|
|
||||||
int fd = open(name, O_RDONLY | O_CLOEXEC);
|
|
||||||
unlink(name);
|
|
||||||
if (fd < 0)
|
|
||||||
continue;
|
|
||||||
memset(bitmask, 0, sizeof(bitmask));
|
|
||||||
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
|
|
||||||
if (test_bit(KEY_VOLUMEDOWN, bitmask))
|
|
||||||
events.push_back(fd);
|
|
||||||
else
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
if (events.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
run_finally fin([&]{ std::for_each(events.begin(), events.end(), close); });
|
|
||||||
|
|
||||||
// Check if volume down key is held continuously for more than 3 seconds
|
|
||||||
for (int i = 0; i < 300; ++i) {
|
|
||||||
bool pressed = false;
|
|
||||||
for (const int &fd : events) {
|
|
||||||
memset(bitmask, 0, sizeof(bitmask));
|
|
||||||
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
|
|
||||||
if (test_bit(KEY_VOLUMEDOWN, bitmask)) {
|
|
||||||
pressed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!pressed)
|
|
||||||
return false;
|
|
||||||
// Check every 10ms
|
|
||||||
usleep(10000);
|
|
||||||
}
|
|
||||||
LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -2,6 +2,8 @@
|
|||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
|
#include <sys/sysmacros.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
|
||||||
#include <consts.hpp>
|
#include <consts.hpp>
|
||||||
#include <base.hpp>
|
#include <base.hpp>
|
||||||
@ -456,3 +458,116 @@ int connect_daemon(int req, bool create) {
|
|||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool setup_magisk_env() {
|
||||||
|
char buf[4096];
|
||||||
|
|
||||||
|
LOGI("* Initializing Magisk environment\n");
|
||||||
|
|
||||||
|
ssprintf(buf, sizeof(buf), "%s/0/%s/install", APP_DATA_DIR, JAVA_PACKAGE_NAME);
|
||||||
|
// Alternative binaries paths
|
||||||
|
const char *alt_bin[] = { "/cache/data_adb/magisk", "/data/magisk", buf };
|
||||||
|
for (auto alt : alt_bin) {
|
||||||
|
if (access(alt, F_OK) == 0) {
|
||||||
|
rm_rf(DATABIN);
|
||||||
|
cp_afc(alt, DATABIN);
|
||||||
|
rm_rf(alt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rm_rf("/cache/data_adb");
|
||||||
|
|
||||||
|
// Directories in /data/adb
|
||||||
|
chmod(SECURE_DIR, 0700);
|
||||||
|
xmkdir(DATABIN, 0755);
|
||||||
|
xmkdir(MODULEROOT, 0755);
|
||||||
|
xmkdir(SECURE_DIR "/post-fs-data.d", 0755);
|
||||||
|
xmkdir(SECURE_DIR "/service.d", 0755);
|
||||||
|
restorecon();
|
||||||
|
|
||||||
|
if (access(DATABIN "/busybox", X_OK))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ssprintf(buf, sizeof(buf), "%s/" BBPATH "/busybox", get_magisk_tmp());
|
||||||
|
mkdir(dirname(buf), 0755);
|
||||||
|
cp_afc(DATABIN "/busybox", buf);
|
||||||
|
exec_command_async(buf, "--install", "-s", dirname(buf));
|
||||||
|
|
||||||
|
// magisk32 and magiskpolicy are not installed into ramdisk and has to be copied
|
||||||
|
// from data to magisk tmp
|
||||||
|
if (access(DATABIN "/magisk32", X_OK) == 0) {
|
||||||
|
ssprintf(buf, sizeof(buf), "%s/magisk32", get_magisk_tmp());
|
||||||
|
cp_afc(DATABIN "/magisk32", buf);
|
||||||
|
}
|
||||||
|
if (access(DATABIN "/magiskpolicy", X_OK) == 0) {
|
||||||
|
ssprintf(buf, sizeof(buf), "%s/magiskpolicy", get_magisk_tmp());
|
||||||
|
cp_afc(DATABIN "/magiskpolicy", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock_blocks() {
|
||||||
|
int fd, dev, OFF = 0;
|
||||||
|
|
||||||
|
auto dir = xopen_dir("/dev/block");
|
||||||
|
if (!dir)
|
||||||
|
return;
|
||||||
|
dev = dirfd(dir.get());
|
||||||
|
|
||||||
|
for (dirent *entry; (entry = readdir(dir.get()));) {
|
||||||
|
if (entry->d_type == DT_BLK) {
|
||||||
|
if ((fd = openat(dev, entry->d_name, O_RDONLY | O_CLOEXEC)) < 0)
|
||||||
|
continue;
|
||||||
|
if (ioctl(fd, BLKROSET, &OFF) < 0)
|
||||||
|
PLOGE("unlock %s", entry->d_name);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8)))
|
||||||
|
|
||||||
|
bool check_key_combo() {
|
||||||
|
uint8_t bitmask[(KEY_MAX + 1) / 8];
|
||||||
|
vector<int> events;
|
||||||
|
constexpr char name[] = "/dev/.ev";
|
||||||
|
|
||||||
|
// First collect candidate events that accepts volume down
|
||||||
|
for (int minor = 64; minor < 96; ++minor) {
|
||||||
|
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
|
||||||
|
continue;
|
||||||
|
int fd = open(name, O_RDONLY | O_CLOEXEC);
|
||||||
|
unlink(name);
|
||||||
|
if (fd < 0)
|
||||||
|
continue;
|
||||||
|
memset(bitmask, 0, sizeof(bitmask));
|
||||||
|
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
|
||||||
|
if (test_bit(KEY_VOLUMEDOWN, bitmask))
|
||||||
|
events.push_back(fd);
|
||||||
|
else
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
if (events.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
run_finally fin([&]{ std::for_each(events.begin(), events.end(), close); });
|
||||||
|
|
||||||
|
// Check if volume down key is held continuously for more than 3 seconds
|
||||||
|
for (int i = 0; i < 300; ++i) {
|
||||||
|
bool pressed = false;
|
||||||
|
for (const int &fd : events) {
|
||||||
|
memset(bitmask, 0, sizeof(bitmask));
|
||||||
|
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
|
||||||
|
if (test_bit(KEY_VOLUMEDOWN, bitmask)) {
|
||||||
|
pressed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pressed)
|
||||||
|
return false;
|
||||||
|
// Check every 10ms
|
||||||
|
usleep(10000);
|
||||||
|
}
|
||||||
|
LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -10,16 +10,12 @@ use crate::mount::setup_mounts;
|
|||||||
use crate::package::ManagerInfo;
|
use crate::package::ManagerInfo;
|
||||||
use base::libc::{O_CLOEXEC, O_RDONLY};
|
use base::libc::{O_CLOEXEC, O_RDONLY};
|
||||||
use base::{
|
use base::{
|
||||||
cstr, error, info, libc, open_fd, warn, BufReadExt, FsPath, FsPathBuf, ReadExt, ResultExt,
|
cstr, error, info, libc, open_fd, BufReadExt, FsPath, FsPathBuf, ResultExt, Utf8CStr,
|
||||||
Utf8CStr, Utf8CStrBufArr, WriteExt,
|
Utf8CStrBufArr,
|
||||||
};
|
};
|
||||||
use bytemuck::{bytes_of, bytes_of_mut, Pod, Zeroable};
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io::BufReader;
|
||||||
use std::io::{BufReader, ErrorKind, IoSlice, IoSliceMut, Read, Write};
|
use std::os::unix::net::UnixStream;
|
||||||
use std::mem::ManuallyDrop;
|
|
||||||
use std::os::fd::{FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
|
||||||
use std::os::unix::net::{AncillaryData, SocketAncillary, UnixStream};
|
|
||||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||||
use std::sync::{Mutex, OnceLock};
|
use std::sync::{Mutex, OnceLock};
|
||||||
|
|
||||||
@ -308,162 +304,3 @@ fn check_data() -> bool {
|
|||||||
pub fn get_magiskd() -> &'static MagiskD {
|
pub fn get_magiskd() -> &'static MagiskD {
|
||||||
unsafe { MAGISKD.get().unwrap_unchecked() }
|
unsafe { MAGISKD.get().unwrap_unchecked() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IpcRead {
|
|
||||||
fn ipc_read_int(&mut self) -> io::Result<i32>;
|
|
||||||
fn ipc_read_string(&mut self) -> io::Result<String>;
|
|
||||||
fn ipc_read_vec<E: Pod>(&mut self) -> io::Result<Vec<E>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Read> IpcRead for T {
|
|
||||||
fn ipc_read_int(&mut self) -> io::Result<i32> {
|
|
||||||
let mut val: i32 = 0;
|
|
||||||
self.read_pod(&mut val)?;
|
|
||||||
Ok(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ipc_read_string(&mut self) -> io::Result<String> {
|
|
||||||
let len = self.ipc_read_int()?;
|
|
||||||
let mut val = "".to_string();
|
|
||||||
self.take(len as u64).read_to_string(&mut val)?;
|
|
||||||
Ok(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ipc_read_vec<E: Pod>(&mut self) -> io::Result<Vec<E>> {
|
|
||||||
let len = self.ipc_read_int()? as usize;
|
|
||||||
let mut vec = Vec::new();
|
|
||||||
let mut val: E = Zeroable::zeroed();
|
|
||||||
for _ in 0..len {
|
|
||||||
self.read_pod(&mut val)?;
|
|
||||||
vec.push(val.clone());
|
|
||||||
}
|
|
||||||
Ok(vec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait IpcWrite {
|
|
||||||
fn ipc_write_int(&mut self, val: i32) -> io::Result<()>;
|
|
||||||
fn ipc_write_string(&mut self, val: &str) -> io::Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Write> IpcWrite for T {
|
|
||||||
fn ipc_write_int(&mut self, val: i32) -> io::Result<()> {
|
|
||||||
self.write_pod(&val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ipc_write_string(&mut self, val: &str) -> io::Result<()> {
|
|
||||||
self.ipc_write_int(val.len() as i32)?;
|
|
||||||
self.write_all(val.as_bytes())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait UnixSocketExt {
|
|
||||||
fn send_fds(&mut self, fd: &[RawFd]) -> io::Result<()>;
|
|
||||||
fn recv_fd(&mut self) -> io::Result<Option<OwnedFd>>;
|
|
||||||
fn recv_fds(&mut self) -> io::Result<Vec<OwnedFd>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UnixSocketExt for UnixStream {
|
|
||||||
fn send_fds(&mut self, fds: &[RawFd]) -> io::Result<()> {
|
|
||||||
match fds.len() {
|
|
||||||
0 => self.ipc_write_int(-1)?,
|
|
||||||
len => {
|
|
||||||
// 4k buffer is reasonable enough
|
|
||||||
let mut buf = [0u8; 4096];
|
|
||||||
let mut ancillary = SocketAncillary::new(&mut buf);
|
|
||||||
if !ancillary.add_fds(fds) {
|
|
||||||
return Err(ErrorKind::OutOfMemory.into());
|
|
||||||
}
|
|
||||||
let fd_count = len as i32;
|
|
||||||
let iov = IoSlice::new(bytes_of(&fd_count));
|
|
||||||
self.send_vectored_with_ancillary(&[iov], &mut ancillary)?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recv_fd(&mut self) -> io::Result<Option<OwnedFd>> {
|
|
||||||
let mut fd_count = 0;
|
|
||||||
self.peek(bytes_of_mut(&mut fd_count))?;
|
|
||||||
if fd_count < 1 {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4k buffer is reasonable enough
|
|
||||||
let mut buf = [0u8; 4096];
|
|
||||||
let mut ancillary = SocketAncillary::new(&mut buf);
|
|
||||||
let iov = IoSliceMut::new(bytes_of_mut(&mut fd_count));
|
|
||||||
self.recv_vectored_with_ancillary(&mut [iov], &mut ancillary)?;
|
|
||||||
for msg in ancillary.messages() {
|
|
||||||
if let Ok(msg) = msg {
|
|
||||||
if let AncillaryData::ScmRights(mut scm_rights) = msg {
|
|
||||||
// We only want the first one
|
|
||||||
let fd = if let Some(fd) = scm_rights.next() {
|
|
||||||
unsafe { OwnedFd::from_raw_fd(fd) }
|
|
||||||
} else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
// Close all others
|
|
||||||
for fd in scm_rights {
|
|
||||||
unsafe { libc::close(fd) };
|
|
||||||
}
|
|
||||||
return Ok(Some(fd));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recv_fds(&mut self) -> io::Result<Vec<OwnedFd>> {
|
|
||||||
let mut fd_count = 0;
|
|
||||||
// 4k buffer is reasonable enough
|
|
||||||
let mut buf = [0u8; 4096];
|
|
||||||
let mut ancillary = SocketAncillary::new(&mut buf);
|
|
||||||
let iov = IoSliceMut::new(bytes_of_mut(&mut fd_count));
|
|
||||||
self.recv_vectored_with_ancillary(&mut [iov], &mut ancillary)?;
|
|
||||||
let mut fds: Vec<OwnedFd> = Vec::new();
|
|
||||||
for msg in ancillary.messages() {
|
|
||||||
if let Ok(msg) = msg {
|
|
||||||
if let AncillaryData::ScmRights(scm_rights) = msg {
|
|
||||||
fds = scm_rights
|
|
||||||
.map(|fd| unsafe { OwnedFd::from_raw_fd(fd) })
|
|
||||||
.collect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if fd_count as usize != fds.len() {
|
|
||||||
warn!(
|
|
||||||
"Received unexpected number of fds: expected={} actual={}",
|
|
||||||
fd_count,
|
|
||||||
fds.len()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok(fds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_fd(socket: RawFd, fd: RawFd) -> bool {
|
|
||||||
let mut socket = ManuallyDrop::new(unsafe { UnixStream::from_raw_fd(socket) });
|
|
||||||
socket.send_fds(&[fd]).log().is_ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_fds(socket: RawFd, fds: &[RawFd]) -> bool {
|
|
||||||
let mut socket = ManuallyDrop::new(unsafe { UnixStream::from_raw_fd(socket) });
|
|
||||||
socket.send_fds(fds).log().is_ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recv_fd(socket: RawFd) -> RawFd {
|
|
||||||
let mut socket = ManuallyDrop::new(unsafe { UnixStream::from_raw_fd(socket) });
|
|
||||||
socket
|
|
||||||
.recv_fd()
|
|
||||||
.log()
|
|
||||||
.unwrap_or(None)
|
|
||||||
.map_or(-1, IntoRawFd::into_raw_fd)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recv_fds(socket: RawFd) -> Vec<RawFd> {
|
|
||||||
let mut socket = ManuallyDrop::new(unsafe { UnixStream::from_raw_fd(socket) });
|
|
||||||
let fds = socket.recv_fds().log().unwrap_or(Vec::new());
|
|
||||||
// SAFETY: OwnedFd and RawFd has the same layout
|
|
||||||
unsafe { std::mem::transmute(fds) }
|
|
||||||
}
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#![allow(improper_ctypes, improper_ctypes_definitions)]
|
#![allow(improper_ctypes, improper_ctypes_definitions)]
|
||||||
use crate::daemon::{IpcRead, IpcWrite, MagiskD, MAGISKD};
|
use crate::daemon::{MagiskD, MAGISKD};
|
||||||
use crate::ffi::{
|
use crate::ffi::{
|
||||||
open_and_init_db, sqlite3, sqlite3_errstr, DbEntryKey, DbSettings, DbStatement, DbValues,
|
open_and_init_db, sqlite3, sqlite3_errstr, DbEntryKey, DbSettings, DbStatement, DbValues,
|
||||||
MntNsMode, MultiuserMode, RootAccess,
|
MntNsMode, MultiuserMode, RootAccess,
|
||||||
};
|
};
|
||||||
|
use crate::socket::{IpcRead, IpcWrite};
|
||||||
use base::{LoggedResult, ResultExt, Utf8CStr};
|
use base::{LoggedResult, ResultExt, Utf8CStr};
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
@ -7,11 +7,12 @@
|
|||||||
#![allow(clippy::missing_safety_doc)]
|
#![allow(clippy::missing_safety_doc)]
|
||||||
|
|
||||||
use base::Utf8CStr;
|
use base::Utf8CStr;
|
||||||
use daemon::{daemon_entry, get_magiskd, recv_fd, recv_fds, send_fd, send_fds, MagiskD};
|
use daemon::{daemon_entry, get_magiskd, MagiskD};
|
||||||
use db::get_default_db_settings;
|
use db::get_default_db_settings;
|
||||||
use logging::{android_logging, setup_logfile, zygisk_close_logd, zygisk_get_logd, zygisk_logging};
|
use logging::{android_logging, setup_logfile, zygisk_close_logd, zygisk_get_logd, zygisk_logging};
|
||||||
use mount::{clean_mounts, find_preinit_device, revert_unmount};
|
use mount::{clean_mounts, find_preinit_device, revert_unmount};
|
||||||
use resetprop::{persist_delete_prop, persist_get_prop, persist_get_props, persist_set_prop};
|
use resetprop::{persist_delete_prop, persist_get_prop, persist_get_props, persist_set_prop};
|
||||||
|
use socket::{recv_fd, recv_fds, send_fd, send_fds};
|
||||||
use su::get_default_root_settings;
|
use su::get_default_root_settings;
|
||||||
use zygisk::zygisk_should_load_module;
|
use zygisk::zygisk_should_load_module;
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ mod logging;
|
|||||||
mod mount;
|
mod mount;
|
||||||
mod package;
|
mod package;
|
||||||
mod resetprop;
|
mod resetprop;
|
||||||
|
mod socket;
|
||||||
mod su;
|
mod su;
|
||||||
mod zygisk;
|
mod zygisk;
|
||||||
|
|
||||||
|
166
native/src/core/socket.rs
Normal file
166
native/src/core/socket.rs
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
use base::{libc, warn, ReadExt, ResultExt, WriteExt};
|
||||||
|
use bytemuck::{bytes_of, bytes_of_mut, Pod, Zeroable};
|
||||||
|
use std::io;
|
||||||
|
use std::io::{ErrorKind, IoSlice, IoSliceMut, Read, Write};
|
||||||
|
use std::mem::ManuallyDrop;
|
||||||
|
use std::os::fd::{FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||||
|
use std::os::unix::net::{AncillaryData, SocketAncillary, UnixStream};
|
||||||
|
|
||||||
|
pub trait IpcRead {
|
||||||
|
fn ipc_read_int(&mut self) -> io::Result<i32>;
|
||||||
|
fn ipc_read_string(&mut self) -> io::Result<String>;
|
||||||
|
fn ipc_read_vec<E: Pod>(&mut self) -> io::Result<Vec<E>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Read> IpcRead for T {
|
||||||
|
fn ipc_read_int(&mut self) -> io::Result<i32> {
|
||||||
|
let mut val: i32 = 0;
|
||||||
|
self.read_pod(&mut val)?;
|
||||||
|
Ok(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ipc_read_string(&mut self) -> io::Result<String> {
|
||||||
|
let len = self.ipc_read_int()?;
|
||||||
|
let mut val = "".to_string();
|
||||||
|
self.take(len as u64).read_to_string(&mut val)?;
|
||||||
|
Ok(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ipc_read_vec<E: Pod>(&mut self) -> io::Result<Vec<E>> {
|
||||||
|
let len = self.ipc_read_int()? as usize;
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
let mut val: E = Zeroable::zeroed();
|
||||||
|
for _ in 0..len {
|
||||||
|
self.read_pod(&mut val)?;
|
||||||
|
vec.push(val.clone());
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IpcWrite {
|
||||||
|
fn ipc_write_int(&mut self, val: i32) -> io::Result<()>;
|
||||||
|
fn ipc_write_string(&mut self, val: &str) -> io::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Write> IpcWrite for T {
|
||||||
|
fn ipc_write_int(&mut self, val: i32) -> io::Result<()> {
|
||||||
|
self.write_pod(&val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ipc_write_string(&mut self, val: &str) -> io::Result<()> {
|
||||||
|
self.ipc_write_int(val.len() as i32)?;
|
||||||
|
self.write_all(val.as_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait UnixSocketExt {
|
||||||
|
fn send_fds(&mut self, fd: &[RawFd]) -> io::Result<()>;
|
||||||
|
fn recv_fd(&mut self) -> io::Result<Option<OwnedFd>>;
|
||||||
|
fn recv_fds(&mut self) -> io::Result<Vec<OwnedFd>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnixSocketExt for UnixStream {
|
||||||
|
fn send_fds(&mut self, fds: &[RawFd]) -> io::Result<()> {
|
||||||
|
match fds.len() {
|
||||||
|
0 => self.ipc_write_int(-1)?,
|
||||||
|
len => {
|
||||||
|
// 4k buffer is reasonable enough
|
||||||
|
let mut buf = [0u8; 4096];
|
||||||
|
let mut ancillary = SocketAncillary::new(&mut buf);
|
||||||
|
if !ancillary.add_fds(fds) {
|
||||||
|
return Err(ErrorKind::OutOfMemory.into());
|
||||||
|
}
|
||||||
|
let fd_count = len as i32;
|
||||||
|
let iov = IoSlice::new(bytes_of(&fd_count));
|
||||||
|
self.send_vectored_with_ancillary(&[iov], &mut ancillary)?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recv_fd(&mut self) -> io::Result<Option<OwnedFd>> {
|
||||||
|
let mut fd_count = 0;
|
||||||
|
self.peek(bytes_of_mut(&mut fd_count))?;
|
||||||
|
if fd_count < 1 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4k buffer is reasonable enough
|
||||||
|
let mut buf = [0u8; 4096];
|
||||||
|
let mut ancillary = SocketAncillary::new(&mut buf);
|
||||||
|
let iov = IoSliceMut::new(bytes_of_mut(&mut fd_count));
|
||||||
|
self.recv_vectored_with_ancillary(&mut [iov], &mut ancillary)?;
|
||||||
|
for msg in ancillary.messages() {
|
||||||
|
if let Ok(msg) = msg {
|
||||||
|
if let AncillaryData::ScmRights(mut scm_rights) = msg {
|
||||||
|
// We only want the first one
|
||||||
|
let fd = if let Some(fd) = scm_rights.next() {
|
||||||
|
unsafe { OwnedFd::from_raw_fd(fd) }
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
// Close all others
|
||||||
|
for fd in scm_rights {
|
||||||
|
unsafe { libc::close(fd) };
|
||||||
|
}
|
||||||
|
return Ok(Some(fd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recv_fds(&mut self) -> io::Result<Vec<OwnedFd>> {
|
||||||
|
let mut fd_count = 0;
|
||||||
|
// 4k buffer is reasonable enough
|
||||||
|
let mut buf = [0u8; 4096];
|
||||||
|
let mut ancillary = SocketAncillary::new(&mut buf);
|
||||||
|
let iov = IoSliceMut::new(bytes_of_mut(&mut fd_count));
|
||||||
|
self.recv_vectored_with_ancillary(&mut [iov], &mut ancillary)?;
|
||||||
|
let mut fds: Vec<OwnedFd> = Vec::new();
|
||||||
|
for msg in ancillary.messages() {
|
||||||
|
if let Ok(msg) = msg {
|
||||||
|
if let AncillaryData::ScmRights(scm_rights) = msg {
|
||||||
|
fds = scm_rights
|
||||||
|
.map(|fd| unsafe { OwnedFd::from_raw_fd(fd) })
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fd_count as usize != fds.len() {
|
||||||
|
warn!(
|
||||||
|
"Received unexpected number of fds: expected={} actual={}",
|
||||||
|
fd_count,
|
||||||
|
fds.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(fds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_fd(socket: RawFd, fd: RawFd) -> bool {
|
||||||
|
let mut socket = ManuallyDrop::new(unsafe { UnixStream::from_raw_fd(socket) });
|
||||||
|
socket.send_fds(&[fd]).log().is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_fds(socket: RawFd, fds: &[RawFd]) -> bool {
|
||||||
|
let mut socket = ManuallyDrop::new(unsafe { UnixStream::from_raw_fd(socket) });
|
||||||
|
socket.send_fds(fds).log().is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recv_fd(socket: RawFd) -> RawFd {
|
||||||
|
let mut socket = ManuallyDrop::new(unsafe { UnixStream::from_raw_fd(socket) });
|
||||||
|
socket
|
||||||
|
.recv_fd()
|
||||||
|
.log()
|
||||||
|
.unwrap_or(None)
|
||||||
|
.map_or(-1, IntoRawFd::into_raw_fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recv_fds(socket: RawFd) -> Vec<RawFd> {
|
||||||
|
let mut socket = ManuallyDrop::new(unsafe { UnixStream::from_raw_fd(socket) });
|
||||||
|
let fds = socket.recv_fds().log().unwrap_or(Vec::new());
|
||||||
|
// SAFETY: OwnedFd and RawFd has the same layout
|
||||||
|
unsafe { std::mem::transmute(fds) }
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
use crate::consts::MODULEROOT;
|
use crate::consts::MODULEROOT;
|
||||||
use crate::daemon::{to_user_id, IpcRead, MagiskD, UnixSocketExt};
|
use crate::daemon::{to_user_id, MagiskD};
|
||||||
use crate::ffi::{
|
use crate::ffi::{
|
||||||
get_magisk_tmp, restore_zygisk_prop, update_deny_flags, ZygiskRequest, ZygiskStateFlags,
|
get_magisk_tmp, restore_zygisk_prop, update_deny_flags, ZygiskRequest, ZygiskStateFlags,
|
||||||
};
|
};
|
||||||
|
use crate::socket::{IpcRead, UnixSocketExt};
|
||||||
use base::libc::{O_CLOEXEC, O_CREAT, O_RDONLY};
|
use base::libc::{O_CLOEXEC, O_CREAT, O_RDONLY};
|
||||||
use base::{
|
use base::{
|
||||||
cstr, error, fork_dont_care, libc, open_fd, raw_cstr, warn, Directory, FsPathBuf, LoggedError,
|
cstr, error, fork_dont_care, libc, open_fd, raw_cstr, warn, Directory, FsPathBuf, LoggedError,
|
||||||
@ -21,6 +22,38 @@ pub fn zygisk_should_load_module(flags: u32) -> bool {
|
|||||||
flags & UNMOUNT_MASK != UNMOUNT_MASK && flags & ZygiskStateFlags::ProcessIsMagiskApp.repr == 0
|
flags & UNMOUNT_MASK != UNMOUNT_MASK && flags & ZygiskStateFlags::ProcessIsMagiskApp.repr == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exec_zygiskd(is_64_bit: bool, remote: UnixStream) {
|
||||||
|
// This fd has to survive exec
|
||||||
|
unsafe {
|
||||||
|
libc::fcntl(remote.as_raw_fd(), libc::F_SETFD, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start building the exec arguments
|
||||||
|
let mut exe = Utf8CStrBufArr::<64>::new();
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
let magisk = if is_64_bit { "magisk" } else { "magisk32" };
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
let magisk = "magisk";
|
||||||
|
|
||||||
|
let exe = FsPathBuf::new(&mut exe).join(get_magisk_tmp()).join(magisk);
|
||||||
|
|
||||||
|
let mut fd_str = Utf8CStrBufArr::<16>::new();
|
||||||
|
write!(fd_str, "{}", remote.as_raw_fd()).ok();
|
||||||
|
unsafe {
|
||||||
|
libc::execl(
|
||||||
|
exe.as_ptr(),
|
||||||
|
raw_cstr!(""),
|
||||||
|
raw_cstr!("zygisk"),
|
||||||
|
raw_cstr!("companion"),
|
||||||
|
fd_str.as_ptr(),
|
||||||
|
ptr::null() as *const libc::c_char,
|
||||||
|
);
|
||||||
|
libc::exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MagiskD {
|
impl MagiskD {
|
||||||
pub fn zygisk_handler(&self, client: i32) {
|
pub fn zygisk_handler(&self, client: i32) {
|
||||||
let mut client = unsafe { UnixStream::from_raw_fd(client) };
|
let mut client = unsafe { UnixStream::from_raw_fd(client) };
|
||||||
@ -66,38 +99,6 @@ impl MagiskD {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_zygiskd(is_64_bit: bool, remote: UnixStream) {
|
|
||||||
// This fd has to survive exec
|
|
||||||
unsafe {
|
|
||||||
libc::fcntl(remote.as_raw_fd(), libc::F_SETFD, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start building the exec arguments
|
|
||||||
let mut exe = Utf8CStrBufArr::<64>::new();
|
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
|
||||||
let magisk = if is_64_bit { "magisk" } else { "magisk32" };
|
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
|
||||||
let magisk = "magisk";
|
|
||||||
|
|
||||||
let exe = FsPathBuf::new(&mut exe).join(get_magisk_tmp()).join(magisk);
|
|
||||||
|
|
||||||
let mut fd_str = Utf8CStrBufArr::<16>::new();
|
|
||||||
write!(fd_str, "{}", remote.as_raw_fd()).ok();
|
|
||||||
unsafe {
|
|
||||||
libc::execl(
|
|
||||||
exe.as_ptr(),
|
|
||||||
raw_cstr!(""),
|
|
||||||
raw_cstr!("zygisk"),
|
|
||||||
raw_cstr!("companion"),
|
|
||||||
fd_str.as_ptr(),
|
|
||||||
ptr::null() as *const libc::c_char,
|
|
||||||
);
|
|
||||||
libc::exit(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn connect_zygiskd(&self, mut client: UnixStream) {
|
fn connect_zygiskd(&self, mut client: UnixStream) {
|
||||||
let mut zygiskd_sockets = self.zygiskd_sockets.lock().unwrap();
|
let mut zygiskd_sockets = self.zygiskd_sockets.lock().unwrap();
|
||||||
let result: LoggedResult<()> = try {
|
let result: LoggedResult<()> = try {
|
||||||
@ -127,7 +128,7 @@ impl MagiskD {
|
|||||||
// Create a new socket pair and fork zygiskd process
|
// Create a new socket pair and fork zygiskd process
|
||||||
let (local, remote) = UnixStream::pair()?;
|
let (local, remote) = UnixStream::pair()?;
|
||||||
if fork_dont_care() == 0 {
|
if fork_dont_care() == 0 {
|
||||||
Self::exec_zygiskd(is_64_bit, remote);
|
exec_zygiskd(is_64_bit, remote);
|
||||||
}
|
}
|
||||||
*socket = Some(local);
|
*socket = Some(local);
|
||||||
let local = socket.as_mut().unwrap();
|
let local = socket.as_mut().unwrap();
|
||||||
|
@ -1,35 +1,116 @@
|
|||||||
#include <libgen.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <sys/prctl.h>
|
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <android/log.h>
|
|
||||||
#include <android/dlext.h>
|
#include <android/dlext.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#include <base.hpp>
|
|
||||||
#include <consts.hpp>
|
#include <consts.hpp>
|
||||||
|
#include <base.hpp>
|
||||||
|
#include <core.hpp>
|
||||||
|
#include <selinux.hpp>
|
||||||
|
|
||||||
#include "zygisk.hpp"
|
#include "zygisk.hpp"
|
||||||
#include "module.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
string native_bridge = "0";
|
string native_bridge = "0";
|
||||||
|
|
||||||
static bool is_compatible_with(uint32_t) {
|
static void zygiskd(int socket) {
|
||||||
|
if (getuid() != 0 || fcntl(socket, F_GETFD) < 0)
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
init_thread_pool();
|
||||||
|
|
||||||
|
#if defined(__LP64__)
|
||||||
|
set_nice_name("zygiskd64");
|
||||||
|
LOGI("* Launching zygiskd64\n");
|
||||||
|
#else
|
||||||
|
set_nice_name("zygiskd32");
|
||||||
|
LOGI("* Launching zygiskd32\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Load modules
|
||||||
|
using comp_entry = void(*)(int);
|
||||||
|
vector<comp_entry> modules;
|
||||||
|
{
|
||||||
|
auto module_fds = recv_fds(socket);
|
||||||
|
for (int fd : module_fds) {
|
||||||
|
comp_entry entry = nullptr;
|
||||||
|
struct stat s{};
|
||||||
|
if (fstat(fd, &s) == 0 && S_ISREG(s.st_mode)) {
|
||||||
|
android_dlextinfo info {
|
||||||
|
.flags = ANDROID_DLEXT_USE_LIBRARY_FD,
|
||||||
|
.library_fd = fd,
|
||||||
|
};
|
||||||
|
if (void *h = android_dlopen_ext("/jit-cache", RTLD_LAZY, &info)) {
|
||||||
|
*(void **) &entry = dlsym(h, "zygisk_companion_entry");
|
||||||
|
} else {
|
||||||
|
LOGW("Failed to dlopen zygisk module: %s\n", dlerror());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modules.push_back(entry);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ack
|
||||||
|
write_int(socket, 0);
|
||||||
|
|
||||||
|
// Start accepting requests
|
||||||
|
pollfd pfd = { socket, POLLIN, 0 };
|
||||||
|
for (;;) {
|
||||||
|
poll(&pfd, 1, -1);
|
||||||
|
if (pfd.revents && !(pfd.revents & POLLIN)) {
|
||||||
|
// Something bad happened in magiskd, terminate zygiskd
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
int client = recv_fd(socket);
|
||||||
|
if (client < 0) {
|
||||||
|
// Something bad happened in magiskd, terminate zygiskd
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
int module_id = read_int(client);
|
||||||
|
if (module_id >= 0 && module_id < modules.size() && modules[module_id]) {
|
||||||
|
exec_task([=, entry = modules[module_id]] {
|
||||||
|
struct stat s1;
|
||||||
|
fstat(client, &s1);
|
||||||
|
entry(client);
|
||||||
|
// 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 (struct stat s2; fstat(client, &s2) == 0) {
|
||||||
|
if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) {
|
||||||
|
close(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
close(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entrypoint where we need to re-exec ourselves
|
||||||
|
// This should only ever be called internally
|
||||||
|
int zygisk_main(int argc, char *argv[]) {
|
||||||
|
android_logging();
|
||||||
|
if (argc == 3 && argv[1] == "companion"sv) {
|
||||||
|
zygiskd(parse_int(argv[2]));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entrypoint of code injection
|
||||||
|
extern "C" [[maybe_unused]] NativeBridgeCallbacks NativeBridgeItf {
|
||||||
|
.version = 2,
|
||||||
|
.padding = {},
|
||||||
|
.isCompatibleWith = [](auto) {
|
||||||
zygisk_logging();
|
zygisk_logging();
|
||||||
hook_entry();
|
hook_entry();
|
||||||
ZLOGD("load success\n");
|
ZLOGD("load success\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
},
|
||||||
|
|
||||||
extern "C" [[maybe_unused]] NativeBridgeCallbacks NativeBridgeItf {
|
|
||||||
.version = 2,
|
|
||||||
.padding = {},
|
|
||||||
.isCompatibleWith = &is_compatible_with,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// The following code runs in magiskd
|
|
||||||
|
|
||||||
void restore_zygisk_prop() {
|
void restore_zygisk_prop() {
|
||||||
string native_bridge_orig = "0";
|
string native_bridge_orig = "0";
|
||||||
if (native_bridge.length() > strlen(ZYGISKLDR)) {
|
if (native_bridge.length() > strlen(ZYGISKLDR)) {
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
#include <sys/mount.h>
|
|
||||||
#include <android/dlext.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
|
|
||||||
#include <consts.hpp>
|
|
||||||
#include <base.hpp>
|
|
||||||
#include <core.hpp>
|
|
||||||
#include <selinux.hpp>
|
|
||||||
|
|
||||||
#include "zygisk.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
static void zygiskd(int socket) {
|
|
||||||
if (getuid() != 0 || fcntl(socket, F_GETFD) < 0)
|
|
||||||
exit(-1);
|
|
||||||
|
|
||||||
init_thread_pool();
|
|
||||||
|
|
||||||
#if defined(__LP64__)
|
|
||||||
set_nice_name("zygiskd64");
|
|
||||||
LOGI("* Launching zygiskd64\n");
|
|
||||||
#else
|
|
||||||
set_nice_name("zygiskd32");
|
|
||||||
LOGI("* Launching zygiskd32\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Load modules
|
|
||||||
using comp_entry = void(*)(int);
|
|
||||||
vector<comp_entry> modules;
|
|
||||||
{
|
|
||||||
auto module_fds = recv_fds(socket);
|
|
||||||
for (int fd : module_fds) {
|
|
||||||
comp_entry entry = nullptr;
|
|
||||||
struct stat s{};
|
|
||||||
if (fstat(fd, &s) == 0 && S_ISREG(s.st_mode)) {
|
|
||||||
android_dlextinfo info {
|
|
||||||
.flags = ANDROID_DLEXT_USE_LIBRARY_FD,
|
|
||||||
.library_fd = fd,
|
|
||||||
};
|
|
||||||
if (void *h = android_dlopen_ext("/jit-cache", RTLD_LAZY, &info)) {
|
|
||||||
*(void **) &entry = dlsym(h, "zygisk_companion_entry");
|
|
||||||
} else {
|
|
||||||
LOGW("Failed to dlopen zygisk module: %s\n", dlerror());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
modules.push_back(entry);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ack
|
|
||||||
write_int(socket, 0);
|
|
||||||
|
|
||||||
// Start accepting requests
|
|
||||||
pollfd pfd = { socket, POLLIN, 0 };
|
|
||||||
for (;;) {
|
|
||||||
poll(&pfd, 1, -1);
|
|
||||||
if (pfd.revents && !(pfd.revents & POLLIN)) {
|
|
||||||
// Something bad happened in magiskd, terminate zygiskd
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
int client = recv_fd(socket);
|
|
||||||
if (client < 0) {
|
|
||||||
// Something bad happened in magiskd, terminate zygiskd
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
int module_id = read_int(client);
|
|
||||||
if (module_id >= 0 && module_id < modules.size() && modules[module_id]) {
|
|
||||||
exec_task([=, entry = modules[module_id]] {
|
|
||||||
struct stat s1;
|
|
||||||
fstat(client, &s1);
|
|
||||||
entry(client);
|
|
||||||
// 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 (struct stat s2; fstat(client, &s2) == 0) {
|
|
||||||
if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) {
|
|
||||||
close(client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
close(client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entrypoint where we need to re-exec ourselves
|
|
||||||
// This should only ever be called internally
|
|
||||||
int zygisk_main(int argc, char *argv[]) {
|
|
||||||
android_logging();
|
|
||||||
if (argc == 3 && argv[1] == "companion"sv) {
|
|
||||||
zygiskd(parse_int(argv[2]));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user