mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-04-29 22:14:27 +02:00
Migrate zygisk handler to Rust
This commit is contained in:
parent
0d8d6290a3
commit
a48a9c858a
@ -268,7 +268,7 @@ impl DirEntry<'_> {
|
||||
}
|
||||
|
||||
unsafe fn open_fd(&self, flags: i32) -> io::Result<RawFd> {
|
||||
self.dir.open_fd(self.d_name(), flags, 0)
|
||||
self.dir.open_raw_fd(self.d_name(), flags, 0)
|
||||
}
|
||||
|
||||
pub fn open_as_dir(&self) -> io::Result<Directory> {
|
||||
@ -353,10 +353,17 @@ impl Directory {
|
||||
unsafe { libc::rewinddir(self.dirp) }
|
||||
}
|
||||
|
||||
unsafe fn open_fd(&self, name: &CStr, flags: i32, mode: i32) -> io::Result<RawFd> {
|
||||
unsafe fn open_raw_fd(&self, name: &CStr, flags: i32, mode: i32) -> io::Result<RawFd> {
|
||||
libc::openat(self.as_raw_fd(), name.as_ptr(), flags | O_CLOEXEC, mode).check_os_err()
|
||||
}
|
||||
|
||||
pub fn open_fd(&self, name: &Utf8CStr, flags: i32, mode: i32) -> io::Result<OwnedFd> {
|
||||
unsafe {
|
||||
self.open_raw_fd(name.as_cstr(), flags, mode)
|
||||
.map(|fd| OwnedFd::from_raw_fd(fd))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_path(&self, path: &CStr) -> bool {
|
||||
// WARNING: Using faccessat is incorrect, because the raw linux kernel syscall
|
||||
// does not support the flag AT_SYMLINK_NOFOLLOW until 5.8 with faccessat2.
|
||||
@ -417,7 +424,7 @@ impl Directory {
|
||||
} else if e.is_file() {
|
||||
let mut src = e.open_as_file(O_RDONLY)?;
|
||||
let mut dest = unsafe {
|
||||
File::from_raw_fd(dir.open_fd(
|
||||
File::from_raw_fd(dir.open_raw_fd(
|
||||
e.d_name(),
|
||||
O_WRONLY | O_CREAT | O_TRUNC,
|
||||
0o777,
|
||||
|
@ -163,7 +163,7 @@ static void handle_request_async(int client, int code, const sock_cred &cred) {
|
||||
break;
|
||||
}
|
||||
case +RequestCode::ZYGISK:
|
||||
zygisk_handler(client, &cred);
|
||||
MagiskD().zygisk_handler(client);
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
|
@ -6,13 +6,16 @@ use crate::logging::{magisk_logging, start_log_daemon};
|
||||
use crate::package::ManagerInfo;
|
||||
use base::libc::{O_CLOEXEC, O_RDONLY};
|
||||
use base::{
|
||||
cstr, info, libc, open_fd, BufReadExt, Directory, FsPath, FsPathBuf, LoggedResult, ReadExt,
|
||||
Utf8CStr, Utf8CStrBufArr, WriteExt,
|
||||
cstr, info, libc, open_fd, warn, BufReadExt, Directory, FsPath, FsPathBuf, LoggedResult,
|
||||
ReadExt, Utf8CStr, Utf8CStrBufArr, WriteExt,
|
||||
};
|
||||
use bit_set::BitSet;
|
||||
use bytemuck::{bytes_of, bytes_of_mut, Pod, Zeroable};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::{BufReader, Read, Write};
|
||||
use std::io::{BufReader, ErrorKind, IoSlice, IoSliceMut, Read, Write};
|
||||
use std::os::fd::{FromRawFd, OwnedFd, RawFd};
|
||||
use std::os::unix::net::{AncillaryData, SocketAncillary, UnixStream};
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
|
||||
// Global magiskd singleton
|
||||
@ -59,7 +62,7 @@ pub struct MagiskD {
|
||||
pub sql_connection: Mutex<Option<Sqlite3>>,
|
||||
pub manager_info: Mutex<ManagerInfo>,
|
||||
boot_stage_lock: Mutex<BootStateFlags>,
|
||||
module_list: OnceLock<Vec<ModuleInfo>>,
|
||||
pub module_list: OnceLock<Vec<ModuleInfo>>,
|
||||
sdk_int: i32,
|
||||
pub is_emulator: bool,
|
||||
is_recovery: bool,
|
||||
@ -254,6 +257,7 @@ pub fn get_magiskd() -> &'static MagiskD {
|
||||
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 {
|
||||
@ -269,6 +273,17 @@ impl<T: Read> IpcRead for T {
|
||||
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 {
|
||||
@ -286,3 +301,88 @@ impl<T: Write> IpcWrite for T {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -429,3 +429,12 @@ bool is_deny_target(int uid, string_view process) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void update_deny_flags(int uid, rust::Str process, uint32_t &flags) {
|
||||
if (is_deny_target(uid, { process.begin(), process.end() })) {
|
||||
flags |= +ZygiskStateFlags::ProcessOnDenyList;
|
||||
}
|
||||
if (denylist_enforced) {
|
||||
flags |= +ZygiskStateFlags::DenyListEnforced;
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,6 @@ void exec_task(std::function<void()> &&task);
|
||||
// Daemon handlers
|
||||
void denylist_handler(int client, const sock_cred *cred);
|
||||
void su_daemon_handler(int client, const sock_cred *cred);
|
||||
void zygisk_handler(int client, const sock_cred *cred);
|
||||
|
||||
// Module stuffs
|
||||
void disable_modules();
|
||||
|
@ -5,6 +5,7 @@
|
||||
const char *get_magisk_tmp();
|
||||
void install_apk(rust::Utf8CStr apk);
|
||||
void uninstall_pkg(rust::Utf8CStr pkg);
|
||||
void update_deny_flags(int uid, rust::Str process, uint32_t &flags);
|
||||
|
||||
// Rust bindings
|
||||
static inline rust::Utf8CStr get_magisk_tmp_rs() { return get_magisk_tmp(); }
|
||||
|
@ -2,6 +2,8 @@
|
||||
#![feature(try_blocks)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(unix_socket_ancillary_data)]
|
||||
#![feature(unix_socket_peek)]
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
|
||||
use base::Utf8CStr;
|
||||
@ -11,6 +13,7 @@ use logging::{android_logging, setup_logfile, zygisk_close_logd, zygisk_get_logd
|
||||
use mount::{clean_mounts, find_preinit_device, revert_unmount, setup_mounts};
|
||||
use resetprop::{persist_delete_prop, persist_get_prop, persist_get_props, persist_set_prop};
|
||||
use su::get_default_root_settings;
|
||||
use zygisk::zygisk_should_load_module;
|
||||
|
||||
#[path = "../include/consts.rs"]
|
||||
mod consts;
|
||||
@ -21,6 +24,7 @@ mod mount;
|
||||
mod package;
|
||||
mod resetprop;
|
||||
mod su;
|
||||
mod zygisk;
|
||||
|
||||
#[cxx::bridge]
|
||||
pub mod ffi {
|
||||
@ -76,7 +80,7 @@ pub mod ffi {
|
||||
fn resolve_preinit_dir(base_dir: Utf8CStrRef) -> String;
|
||||
fn install_apk(apk: Utf8CStrRef);
|
||||
fn uninstall_pkg(apk: Utf8CStrRef);
|
||||
|
||||
fn update_deny_flags(uid: i32, process: &str, flags: &mut u32);
|
||||
fn switch_mnt_ns(pid: i32) -> i32;
|
||||
}
|
||||
|
||||
@ -141,6 +145,21 @@ pub mod ffi {
|
||||
z64: i32,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
enum ZygiskRequest {
|
||||
GetInfo,
|
||||
ConnectCompanion,
|
||||
GetModDir,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
enum ZygiskStateFlags {
|
||||
ProcessGrantedRoot = 0x00000001,
|
||||
ProcessOnDenyList = 0x00000002,
|
||||
DenyListEnforced = 0x40000000,
|
||||
ProcessIsMagiskApp = 0x80000000,
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
include!("include/sqlite.hpp");
|
||||
|
||||
@ -171,6 +190,7 @@ pub mod ffi {
|
||||
fn clean_mounts();
|
||||
fn find_preinit_device() -> String;
|
||||
fn revert_unmount(pid: i32);
|
||||
fn zygisk_should_load_module(flags: u32) -> bool;
|
||||
unsafe fn persist_get_prop(name: Utf8CStrRef, prop_cb: Pin<&mut PropCb>);
|
||||
unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>);
|
||||
unsafe fn persist_delete_prop(name: Utf8CStrRef) -> bool;
|
||||
@ -186,13 +206,14 @@ pub mod ffi {
|
||||
fn is_recovery(&self) -> bool;
|
||||
fn sdk_int(&self) -> i32;
|
||||
fn boot_stage_handler(&self, client: i32, code: i32);
|
||||
fn zygisk_handler(&self, client: i32);
|
||||
fn preserve_stub_apk(&self);
|
||||
fn prune_su_access(&self);
|
||||
fn uid_granted_root(&self, mut uid: i32) -> bool;
|
||||
#[cxx_name = "get_manager"]
|
||||
unsafe fn get_manager_for_cxx(&self, user: i32, ptr: *mut CxxString, install: bool) -> i32;
|
||||
fn set_module_list(&self, module_list: Vec<ModuleInfo>);
|
||||
fn module_list(&self) -> &Vec<ModuleInfo>;
|
||||
fn get_module_fds(&self, is_64_bit: bool) -> Vec<i32>;
|
||||
|
||||
#[cxx_name = "get_db_settings"]
|
||||
fn get_db_settings_for_cxx(&self, cfg: &mut DbSettings) -> bool;
|
||||
@ -219,6 +240,7 @@ pub mod ffi {
|
||||
fn boot_complete(self: &MagiskD);
|
||||
#[allow(dead_code)]
|
||||
fn handle_modules(self: &MagiskD);
|
||||
fn connect_zygiskd(self: &MagiskD, client: i32);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -473,6 +473,12 @@ impl MagiskD {
|
||||
apk.remove().log().ok();
|
||||
}
|
||||
|
||||
pub fn get_manager_uid(&self, user: i32) -> i32 {
|
||||
let mut info = self.manager_info.lock().unwrap();
|
||||
let (uid, _) = info.get_manager(self, user, false);
|
||||
uid
|
||||
}
|
||||
|
||||
pub unsafe fn get_manager_for_cxx(&self, user: i32, ptr: *mut CxxString, install: bool) -> i32 {
|
||||
let mut info = self.manager_info.lock().unwrap();
|
||||
let (uid, pkg) = info.get_manager(self, user, install);
|
||||
|
101
native/src/core/zygisk/daemon.rs
Normal file
101
native/src/core/zygisk/daemon.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use crate::consts::MODULEROOT;
|
||||
use crate::daemon::{to_user_id, IpcRead, MagiskD, UnixSocketExt};
|
||||
use crate::ffi::{update_deny_flags, ZygiskRequest, ZygiskStateFlags};
|
||||
use base::libc::{O_CLOEXEC, O_CREAT, O_RDONLY};
|
||||
use base::{cstr, open_fd, Directory, FsPathBuf, LoggedResult, Utf8CStrBufArr, WriteExt};
|
||||
use std::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::os::unix::net::UnixStream;
|
||||
|
||||
const UNMOUNT_MASK: u32 =
|
||||
ZygiskStateFlags::ProcessOnDenyList.repr | ZygiskStateFlags::DenyListEnforced.repr;
|
||||
|
||||
pub fn zygisk_should_load_module(flags: u32) -> bool {
|
||||
flags & UNMOUNT_MASK != UNMOUNT_MASK && flags & ZygiskStateFlags::ProcessIsMagiskApp.repr == 0
|
||||
}
|
||||
|
||||
impl MagiskD {
|
||||
pub fn zygisk_handler(&self, client: i32) {
|
||||
let mut client = unsafe { UnixStream::from_raw_fd(client) };
|
||||
let _: LoggedResult<()> = try {
|
||||
let code = ZygiskRequest {
|
||||
repr: client.ipc_read_int()?,
|
||||
};
|
||||
match code {
|
||||
ZygiskRequest::GetInfo => self.get_process_info(client)?,
|
||||
ZygiskRequest::ConnectCompanion => self.connect_zygiskd(client.as_raw_fd()),
|
||||
ZygiskRequest::GetModDir => self.get_mod_dir(client)?,
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_module_fds(&self, is_64_bit: bool) -> Vec<RawFd> {
|
||||
if let Some(module_list) = self.module_list.get() {
|
||||
module_list
|
||||
.iter()
|
||||
.map(|m| if is_64_bit { m.z64 } else { m.z32 })
|
||||
.collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_process_info(&self, mut client: UnixStream) -> LoggedResult<()> {
|
||||
let uid = client.ipc_read_int()?;
|
||||
let process = client.ipc_read_string()?;
|
||||
let is_64_bit = client.ipc_read_int()? != 0;
|
||||
let mut flags: u32 = 0;
|
||||
update_deny_flags(uid, &process, &mut flags);
|
||||
if self.get_manager_uid(to_user_id(uid)) == uid {
|
||||
flags |= ZygiskStateFlags::ProcessIsMagiskApp.repr
|
||||
}
|
||||
if self.uid_granted_root(uid) {
|
||||
flags |= ZygiskStateFlags::ProcessGrantedRoot.repr
|
||||
}
|
||||
|
||||
// First send flags
|
||||
client.write_pod(&flags)?;
|
||||
|
||||
// Next send modules
|
||||
if zygisk_should_load_module(flags) {
|
||||
if let Some(module_list) = self.module_list.get() {
|
||||
let module_fds: Vec<RawFd> = module_list
|
||||
.iter()
|
||||
.map(|m| if is_64_bit { m.z64 } else { m.z32 })
|
||||
.collect();
|
||||
client.send_fds(&module_fds)?;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're not in system_server, we are done
|
||||
if uid != 1000 || process != "system_server" {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Read all failed modules
|
||||
let failed_ids: Vec<i32> = client.ipc_read_vec()?;
|
||||
if let Some(module_list) = self.module_list.get() {
|
||||
for id in failed_ids {
|
||||
let mut buf = Utf8CStrBufArr::default();
|
||||
let path = FsPathBuf::new(&mut buf)
|
||||
.join(MODULEROOT)
|
||||
.join(&module_list[id as usize].name)
|
||||
.join("zygisk");
|
||||
// Create the unloaded marker file
|
||||
Directory::open(&path)?.open_fd(cstr!("unloaded"), O_CREAT | O_RDONLY, 0o644)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_mod_dir(&self, mut client: UnixStream) -> LoggedResult<()> {
|
||||
let id = client.ipc_read_int()?;
|
||||
let module = &self.module_list.get().unwrap()[id as usize];
|
||||
let mut buf = Utf8CStrBufArr::default();
|
||||
let dir = FsPathBuf::new(&mut buf).join(MODULEROOT).join(&module.name);
|
||||
let fd = open_fd!(&dir, O_RDONLY | O_CLOEXEC)?;
|
||||
client.send_fds(&[fd.as_raw_fd()])?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -15,8 +15,6 @@ using namespace std;
|
||||
|
||||
string native_bridge = "0";
|
||||
|
||||
using modules_t = const rust::Vec<ModuleInfo>&;
|
||||
|
||||
static bool is_compatible_with(uint32_t) {
|
||||
zygisk_logging();
|
||||
hook_entry();
|
||||
@ -30,56 +28,13 @@ extern "C" [[maybe_unused]] NativeBridgeCallbacks NativeBridgeItf {
|
||||
.isCompatibleWith = &is_compatible_with,
|
||||
};
|
||||
|
||||
// The following code runs in zygote/app process
|
||||
|
||||
static inline bool should_load_modules(uint32_t flags) {
|
||||
return (flags & UNMOUNT_MASK) != UNMOUNT_MASK &&
|
||||
(flags & PROCESS_IS_MAGISK_APP) != PROCESS_IS_MAGISK_APP;
|
||||
}
|
||||
|
||||
int remote_get_info(int uid, const char *process, uint32_t *flags, vector<int> &fds) {
|
||||
if (int fd = zygisk_request(ZygiskRequest::GET_INFO); fd >= 0) {
|
||||
write_int(fd, uid);
|
||||
write_string(fd, process);
|
||||
#ifdef __LP64__
|
||||
write_int(fd, 1);
|
||||
#else
|
||||
write_int(fd, 0);
|
||||
#endif
|
||||
xxread(fd, flags, sizeof(*flags));
|
||||
if (should_load_modules(*flags)) {
|
||||
fds = recv_fds(fd);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// The following code runs in magiskd
|
||||
|
||||
static vector<int> get_module_fds(bool is_64_bit, modules_t module_list) {
|
||||
vector<int> fds;
|
||||
// All fds passed to send_fds have to be valid file descriptors.
|
||||
// To workaround this issue, send over STDOUT_FILENO as an indicator of an
|
||||
// invalid fd as it will always be /dev/null in magiskd
|
||||
#if defined(__LP64__)
|
||||
if (is_64_bit) {
|
||||
std::transform(module_list.begin(), module_list.end(), std::back_inserter(fds),
|
||||
[](const ModuleInfo &info) { return info.z64 < 0 ? STDOUT_FILENO : info.z64; });
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
std::transform(module_list.begin(), module_list.end(), std::back_inserter(fds),
|
||||
[](const ModuleInfo &info) { return info.z32 < 0 ? STDOUT_FILENO : info.z32; });
|
||||
}
|
||||
return fds;
|
||||
}
|
||||
|
||||
static pthread_mutex_t zygiskd_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int zygiskd_sockets[] = { -1, -1 };
|
||||
#define zygiskd_socket zygiskd_sockets[is_64_bit]
|
||||
|
||||
static void connect_companion(int client, modules_t module_list) {
|
||||
void MagiskD::connect_zygiskd(int client) const noexcept {
|
||||
mutex_guard g(zygiskd_lock);
|
||||
|
||||
bool is_64_bit = read_int(client);
|
||||
@ -112,7 +67,7 @@ static void connect_companion(int client, modules_t module_list) {
|
||||
exit(-1);
|
||||
}
|
||||
close(fds[1]);
|
||||
vector<int> module_fds = get_module_fds(is_64_bit, module_list);
|
||||
rust::Vec<int> module_fds = get_module_fds(is_64_bit);
|
||||
send_fds(zygiskd_socket, module_fds.data(), module_fds.size());
|
||||
// Wait for ack
|
||||
if (read_int(zygiskd_socket) != 0) {
|
||||
@ -123,89 +78,6 @@ static void connect_companion(int client, modules_t module_list) {
|
||||
send_fd(zygiskd_socket, client);
|
||||
}
|
||||
|
||||
static void get_process_info(int client, const sock_cred *cred, modules_t module_list) {
|
||||
int uid = read_int(client);
|
||||
string process = read_string(client);
|
||||
int arch = read_int(client);
|
||||
auto &daemon = MagiskD();
|
||||
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (is_deny_target(uid, process)) {
|
||||
flags |= PROCESS_ON_DENYLIST;
|
||||
}
|
||||
if (daemon.get_manager(to_user_id(uid), nullptr, false) == uid) {
|
||||
flags |= PROCESS_IS_MAGISK_APP;
|
||||
}
|
||||
if (denylist_enforced) {
|
||||
flags |= DENYLIST_ENFORCING;
|
||||
}
|
||||
if (daemon.uid_granted_root(uid)) {
|
||||
flags |= PROCESS_GRANTED_ROOT;
|
||||
}
|
||||
|
||||
xwrite(client, &flags, sizeof(flags));
|
||||
|
||||
if (should_load_modules(flags)) {
|
||||
vector<int> fds = get_module_fds(arch, module_list);
|
||||
send_fds(client, fds.data(), fds.size());
|
||||
}
|
||||
|
||||
if (uid != 1000 || process != "system_server")
|
||||
return;
|
||||
|
||||
// Collect module status from system_server
|
||||
int slots = read_int(client);
|
||||
dynamic_bitset bits;
|
||||
for (int i = 0; i < slots; ++i) {
|
||||
dynamic_bitset::slot_type l = 0;
|
||||
xxread(client, &l, sizeof(l));
|
||||
bits.emplace_back(l);
|
||||
}
|
||||
for (int id = 0; id < module_list.size(); ++id) {
|
||||
if (!as_const(bits)[id]) {
|
||||
// Either not a zygisk module, or incompatible
|
||||
char buf[4096];
|
||||
ssprintf(buf, sizeof(buf), MODULEROOT "/%s/zygisk",
|
||||
module_list[id].name.data());
|
||||
if (int dirfd = open(buf, O_RDONLY | O_CLOEXEC); dirfd >= 0) {
|
||||
close(xopenat(dirfd, "unloaded", O_CREAT | O_RDONLY, 0644));
|
||||
close(dirfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void get_moddir(int client, modules_t module_list) {
|
||||
int id = read_int(client);
|
||||
char buf[4096];
|
||||
auto &m = module_list[id];
|
||||
ssprintf(buf, sizeof(buf), MODULEROOT "/%.*s", (int) m.name.size(), m.name.data());
|
||||
int dfd = xopen(buf, O_RDONLY | O_CLOEXEC);
|
||||
send_fd(client, dfd);
|
||||
close(dfd);
|
||||
}
|
||||
|
||||
void zygisk_handler(int client, const sock_cred *cred) {
|
||||
auto &module_list = MagiskD().module_list();
|
||||
int code = read_int(client);
|
||||
switch (code) {
|
||||
case ZygiskRequest::GET_INFO:
|
||||
get_process_info(client, cred, module_list);
|
||||
break;
|
||||
case ZygiskRequest::CONNECT_COMPANION:
|
||||
connect_companion(client, module_list);
|
||||
break;
|
||||
case ZygiskRequest::GET_MODDIR:
|
||||
get_moddir(client, module_list);
|
||||
break;
|
||||
default:
|
||||
// Unknown code
|
||||
break;
|
||||
}
|
||||
close(client);
|
||||
}
|
||||
|
||||
void reset_zygisk(bool restore) {
|
||||
if (!zygisk_enabled) return;
|
||||
static atomic_uint zygote_start_count{1};
|
||||
|
3
native/src/core/zygisk/mod.rs
Normal file
3
native/src/core/zygisk/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
mod daemon;
|
||||
|
||||
pub use daemon::zygisk_should_load_module;
|
@ -77,7 +77,7 @@ bool ZygiskModule::valid() const {
|
||||
}
|
||||
|
||||
int ZygiskModule::connectCompanion() const {
|
||||
if (int fd = zygisk_request(ZygiskRequest::CONNECT_COMPANION); fd >= 0) {
|
||||
if (int fd = zygisk_request(+ZygiskRequest::ConnectCompanion); fd >= 0) {
|
||||
#ifdef __LP64__
|
||||
write_int(fd, 1);
|
||||
#else
|
||||
@ -90,11 +90,9 @@ int ZygiskModule::connectCompanion() const {
|
||||
}
|
||||
|
||||
int ZygiskModule::getModuleDir() const {
|
||||
if (int fd = zygisk_request(ZygiskRequest::GET_MODDIR); fd >= 0) {
|
||||
if (owned_fd fd = zygisk_request(+ZygiskRequest::GetModDir); fd >= 0) {
|
||||
write_int(fd, id);
|
||||
int dfd = recv_fd(fd);
|
||||
close(fd);
|
||||
return dfd;
|
||||
return recv_fd(fd);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -210,6 +208,24 @@ bool ZygiskContext::plt_hook_commit() {
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
int ZygiskContext::get_module_info(int uid, std::vector<int> &fds) {
|
||||
if (int fd = zygisk_request(+ZygiskRequest::GetInfo); fd >= 0) {
|
||||
write_int(fd, uid);
|
||||
write_string(fd, process);
|
||||
#ifdef __LP64__
|
||||
write_int(fd, 1);
|
||||
#else
|
||||
write_int(fd, 0);
|
||||
#endif
|
||||
xxread(fd, &info_flags, sizeof(info_flags));
|
||||
if (zygisk_should_load_module(info_flags)) {
|
||||
fds = recv_fds(fd);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ZygiskContext::sanitize_fds() {
|
||||
zygisk_close_logd();
|
||||
|
||||
@ -315,16 +331,17 @@ void ZygiskContext::fork_post() {
|
||||
sigmask(SIG_UNBLOCK, SIGCHLD);
|
||||
}
|
||||
|
||||
void ZygiskContext::run_modules_pre(const vector<int> &fds) {
|
||||
void ZygiskContext::run_modules_pre(vector<int> &fds) {
|
||||
for (int i = 0; i < fds.size(); ++i) {
|
||||
owned_fd fd = fds[i];
|
||||
struct stat s{};
|
||||
if (fstat(fds[i], &s) != 0 || !S_ISREG(s.st_mode)) {
|
||||
close(fds[i]);
|
||||
if (fstat(fd, &s) != 0 || !S_ISREG(s.st_mode)) {
|
||||
fds[i] = -1;
|
||||
continue;
|
||||
}
|
||||
android_dlextinfo info {
|
||||
.flags = ANDROID_DLEXT_USE_LIBRARY_FD,
|
||||
.library_fd = fds[i],
|
||||
.library_fd = fd,
|
||||
};
|
||||
if (void *h = android_dlopen_ext("/jit-cache", RTLD_LAZY, &info)) {
|
||||
if (void *e = dlsym(h, "zygisk_module_entry")) {
|
||||
@ -332,8 +349,8 @@ void ZygiskContext::run_modules_pre(const vector<int> &fds) {
|
||||
}
|
||||
} else if (flags & SERVER_FORK_AND_SPECIALIZE) {
|
||||
ZLOGW("Failed to dlopen zygisk module: %s\n", dlerror());
|
||||
fds[i] = -1;
|
||||
}
|
||||
close(fds[i]);
|
||||
}
|
||||
|
||||
for (auto it = modules.begin(); it != modules.end();) {
|
||||
@ -370,19 +387,18 @@ void ZygiskContext::app_specialize_pre() {
|
||||
flags |= APP_SPECIALIZE;
|
||||
|
||||
vector<int> module_fds;
|
||||
int fd = remote_get_info(args.app->uid, process, &info_flags, module_fds);
|
||||
owned_fd fd = get_module_info(args.app->uid, module_fds);
|
||||
if ((info_flags & UNMOUNT_MASK) == UNMOUNT_MASK) {
|
||||
ZLOGI("[%s] is on the denylist\n", process);
|
||||
flags |= DO_REVERT_UNMOUNT;
|
||||
} else if (fd >= 0) {
|
||||
run_modules_pre(module_fds);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void ZygiskContext::app_specialize_post() {
|
||||
run_modules_post();
|
||||
if (info_flags & PROCESS_IS_MAGISK_APP) {
|
||||
if (info_flags & +ZygiskStateFlags::ProcessIsMagiskApp) {
|
||||
setenv("ZYGISK_ENABLED", "1", 1);
|
||||
}
|
||||
|
||||
@ -392,24 +408,21 @@ void ZygiskContext::app_specialize_post() {
|
||||
|
||||
void ZygiskContext::server_specialize_pre() {
|
||||
vector<int> module_fds;
|
||||
int fd = remote_get_info(1000, "system_server", &info_flags, module_fds);
|
||||
if (fd >= 0) {
|
||||
if (owned_fd fd = get_module_info(1000, module_fds); fd >= 0) {
|
||||
if (module_fds.empty()) {
|
||||
write_int(fd, 0);
|
||||
} else {
|
||||
run_modules_pre(module_fds);
|
||||
|
||||
// Send the bitset of module status back to magiskd from system_server
|
||||
dynamic_bitset bits;
|
||||
for (const auto &m : modules)
|
||||
bits[m.getId()] = true;
|
||||
write_int(fd, static_cast<int>(bits.slots()));
|
||||
for (int i = 0; i < bits.slots(); ++i) {
|
||||
auto l = bits.get_slot(i);
|
||||
xwrite(fd, &l, sizeof(l));
|
||||
// Find all failed module ids and send it back to magiskd
|
||||
vector<int> failed_ids;
|
||||
for (int i = 0; i < module_fds.size(); ++i) {
|
||||
if (module_fds[i] < 0) {
|
||||
failed_ids.push_back(i);
|
||||
}
|
||||
}
|
||||
write_vector(fd, failed_ids);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,6 +448,7 @@ void ZygiskContext::nativeSpecializeAppProcess_post() {
|
||||
void ZygiskContext::nativeForkSystemServer_pre() {
|
||||
ZLOGV("pre forkSystemServer\n");
|
||||
flags |= SERVER_FORK_AND_SPECIALIZE;
|
||||
process = "system_server";
|
||||
|
||||
fork_pre();
|
||||
if (is_child()) {
|
||||
|
@ -122,15 +122,13 @@ struct module_abi_v1 {
|
||||
void (*postServerSpecialize)(void *, const void *);
|
||||
};
|
||||
|
||||
// Assert the flag values to be the same as the public API
|
||||
static_assert(+ZygiskStateFlags::ProcessGrantedRoot == zygisk::StateFlag::PROCESS_GRANTED_ROOT);
|
||||
static_assert(+ZygiskStateFlags::ProcessOnDenyList == zygisk::StateFlag::PROCESS_ON_DENYLIST);
|
||||
|
||||
enum : uint32_t {
|
||||
PROCESS_GRANTED_ROOT = zygisk::StateFlag::PROCESS_GRANTED_ROOT,
|
||||
PROCESS_ON_DENYLIST = zygisk::StateFlag::PROCESS_ON_DENYLIST,
|
||||
|
||||
DENYLIST_ENFORCING = (1u << 30),
|
||||
PROCESS_IS_MAGISK_APP = (1u << 31),
|
||||
|
||||
UNMOUNT_MASK = (PROCESS_ON_DENYLIST | DENYLIST_ENFORCING),
|
||||
PRIVATE_MASK = (DENYLIST_ENFORCING | PROCESS_IS_MAGISK_APP)
|
||||
UNMOUNT_MASK = (+ZygiskStateFlags::ProcessOnDenyList | +ZygiskStateFlags::DenyListEnforced),
|
||||
PRIVATE_MASK = (+ZygiskStateFlags::DenyListEnforced | +ZygiskStateFlags::ProcessIsMagiskApp)
|
||||
};
|
||||
|
||||
struct api_abi_base {
|
||||
@ -188,7 +186,6 @@ struct ZygiskModule {
|
||||
static uint32_t getFlags();
|
||||
void tryUnload() const;
|
||||
void clearApi() { memset(&api, 0, sizeof(api)); }
|
||||
int getId() const { return id; }
|
||||
|
||||
ZygiskModule(int id, void *handle, void *entry);
|
||||
|
||||
@ -264,7 +261,7 @@ struct ZygiskContext {
|
||||
ZygiskContext(JNIEnv *env, void *args);
|
||||
~ZygiskContext();
|
||||
|
||||
void run_modules_pre(const std::vector<int> &fds);
|
||||
void run_modules_pre(std::vector<int> &fds);
|
||||
void run_modules_post();
|
||||
DCL_PRE_POST(fork)
|
||||
DCL_PRE_POST(app_specialize)
|
||||
@ -273,6 +270,7 @@ struct ZygiskContext {
|
||||
DCL_PRE_POST(nativeSpecializeAppProcess)
|
||||
DCL_PRE_POST(nativeForkSystemServer)
|
||||
|
||||
int get_module_info(int uid, std::vector<int> &fds);
|
||||
void sanitize_fds();
|
||||
bool exempt_fd(int fd);
|
||||
bool can_exempt_fd() const;
|
||||
|
@ -6,15 +6,6 @@
|
||||
#include <vector>
|
||||
#include <core.hpp>
|
||||
|
||||
namespace ZygiskRequest {
|
||||
enum : int {
|
||||
GET_INFO,
|
||||
CONNECT_COMPANION,
|
||||
GET_MODDIR,
|
||||
END
|
||||
};
|
||||
}
|
||||
|
||||
#if defined(__LP64__)
|
||||
#define ZLOGD(...) LOGD("zygisk64: " __VA_ARGS__)
|
||||
#define ZLOGE(...) LOGE("zygisk64: " __VA_ARGS__)
|
||||
@ -34,8 +25,6 @@ enum : int {
|
||||
void hook_entry();
|
||||
void hookJniNativeMethods(JNIEnv *env, const char *clz, JNINativeMethod *methods, int numMethods);
|
||||
|
||||
int remote_get_info(int uid, const char *process, uint32_t *flags, std::vector<int> &fds);
|
||||
|
||||
inline int zygisk_request(int req) {
|
||||
int fd = connect_daemon(+RequestCode::ZYGISK);
|
||||
if (fd < 0) return fd;
|
||||
|
Loading…
x
Reference in New Issue
Block a user