Migrate zygisk handler to Rust

This commit is contained in:
topjohnwu 2025-01-29 20:16:48 +08:00 committed by John Wu
parent 0d8d6290a3
commit a48a9c858a
14 changed files with 307 additions and 186 deletions

View File

@ -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,

View File

@ -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();

View File

@ -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)
}
}

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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(); }

View File

@ -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);
}
}

View File

@ -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);

View 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(())
}
}

View File

@ -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};

View File

@ -0,0 +1,3 @@
mod daemon;
pub use daemon::zygisk_should_load_module;

View File

@ -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()) {

View File

@ -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;

View File

@ -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;