mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-04-29 22:14:27 +02:00
Code reorganization
This commit is contained in:
parent
b25aa8295a
commit
7f7f625864
@ -18,7 +18,6 @@ LOCAL_SRC_FILES := \
|
||||
core/applets.cpp \
|
||||
core/magisk.cpp \
|
||||
core/daemon.cpp \
|
||||
core/bootstages.cpp \
|
||||
core/socket.cpp \
|
||||
core/scripting.cpp \
|
||||
core/selinux.cpp \
|
||||
@ -32,7 +31,6 @@ LOCAL_SRC_FILES := \
|
||||
core/su/pts.cpp \
|
||||
core/su/su_daemon.cpp \
|
||||
core/zygisk/entry.cpp \
|
||||
core/zygisk/main.cpp \
|
||||
core/zygisk/module.cpp \
|
||||
core/zygisk/hook.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 <sys/un.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include <consts.hpp>
|
||||
#include <base.hpp>
|
||||
@ -456,3 +458,116 @@ int connect_daemon(int req, bool create) {
|
||||
}
|
||||
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 base::libc::{O_CLOEXEC, O_RDONLY};
|
||||
use base::{
|
||||
cstr, error, info, libc, open_fd, warn, BufReadExt, FsPath, FsPathBuf, ReadExt, ResultExt,
|
||||
Utf8CStr, Utf8CStrBufArr, WriteExt,
|
||||
cstr, error, info, libc, open_fd, BufReadExt, FsPath, FsPathBuf, ResultExt, Utf8CStr,
|
||||
Utf8CStrBufArr,
|
||||
};
|
||||
use bytemuck::{bytes_of, bytes_of_mut, Pod, Zeroable};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::{BufReader, 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};
|
||||
use std::io::BufReader;
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
|
||||
@ -308,162 +304,3 @@ fn check_data() -> bool {
|
||||
pub fn get_magiskd() -> &'static MagiskD {
|
||||
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)]
|
||||
use crate::daemon::{IpcRead, IpcWrite, MagiskD, MAGISKD};
|
||||
use crate::daemon::{MagiskD, MAGISKD};
|
||||
use crate::ffi::{
|
||||
open_and_init_db, sqlite3, sqlite3_errstr, DbEntryKey, DbSettings, DbStatement, DbValues,
|
||||
MntNsMode, MultiuserMode, RootAccess,
|
||||
};
|
||||
use crate::socket::{IpcRead, IpcWrite};
|
||||
use base::{LoggedResult, ResultExt, Utf8CStr};
|
||||
use std::ffi::c_void;
|
||||
use std::fs::File;
|
||||
|
@ -7,11 +7,12 @@
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
|
||||
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 logging::{android_logging, setup_logfile, zygisk_close_logd, zygisk_get_logd, zygisk_logging};
|
||||
use mount::{clean_mounts, find_preinit_device, revert_unmount};
|
||||
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 zygisk::zygisk_should_load_module;
|
||||
|
||||
@ -23,6 +24,7 @@ mod logging;
|
||||
mod mount;
|
||||
mod package;
|
||||
mod resetprop;
|
||||
mod socket;
|
||||
mod su;
|
||||
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::daemon::{to_user_id, IpcRead, MagiskD, UnixSocketExt};
|
||||
use crate::daemon::{to_user_id, MagiskD};
|
||||
use crate::ffi::{
|
||||
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::{
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
pub fn zygisk_handler(&self, client: i32) {
|
||||
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) {
|
||||
let mut zygiskd_sockets = self.zygiskd_sockets.lock().unwrap();
|
||||
let result: LoggedResult<()> = try {
|
||||
@ -127,7 +128,7 @@ impl MagiskD {
|
||||
// Create a new socket pair and fork zygiskd process
|
||||
let (local, remote) = UnixStream::pair()?;
|
||||
if fork_dont_care() == 0 {
|
||||
Self::exec_zygiskd(is_64_bit, remote);
|
||||
exec_zygiskd(is_64_bit, remote);
|
||||
}
|
||||
*socket = Some(local);
|
||||
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 <android/log.h>
|
||||
#include <android/dlext.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <base.hpp>
|
||||
#include <consts.hpp>
|
||||
#include <base.hpp>
|
||||
#include <core.hpp>
|
||||
#include <selinux.hpp>
|
||||
|
||||
#include "zygisk.hpp"
|
||||
#include "module.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
string native_bridge = "0";
|
||||
|
||||
static bool is_compatible_with(uint32_t) {
|
||||
zygisk_logging();
|
||||
hook_entry();
|
||||
ZLOGD("load success\n");
|
||||
return false;
|
||||
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 = &is_compatible_with,
|
||||
.isCompatibleWith = [](auto) {
|
||||
zygisk_logging();
|
||||
hook_entry();
|
||||
ZLOGD("load success\n");
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
// The following code runs in magiskd
|
||||
|
||||
void restore_zygisk_prop() {
|
||||
string native_bridge_orig = "0";
|
||||
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