Compare commits

...

7 Commits

Author SHA1 Message Date
Nullptr
bea5ed47b8 Bump to 0.7.0 2023-06-04 11:16:03 +08:00
Nullptr
954a712089 Use app profile 2023-06-04 01:31:12 +08:00
Nullptr
f6195ddb43 Don't spawn new process for companion 2023-05-21 20:14:36 +08:00
Nullptr
8b5e9db347 Make watchdog async 2023-05-21 19:38:24 +08:00
Nullptr
a04f636ac4 Refine code 2023-05-19 19:14:54 +08:00
5ec1cff
00f0a6e3fa several changes (#21)
* umount for ksu 10763

Signed-off-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>

* Add crashdump sepolicy

Signed-off-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>

* Add more information about debug

Signed-off-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>

* daemonize zygiskd companion

Signed-off-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>

* create zygiskd if crash

Signed-off-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>

* injector: use ANDROID_DLEXT_USE_LIBRARY_FD to load module

Signed-off-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>

* zygiskd: use file as module fd instead of memfd on debug build

Signed-off-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>

* use OwnedFd

Signed-off-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>

* dlopen: no need to create ns

Signed-off-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>

---------

Signed-off-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>
2023-05-19 18:28:56 +08:00
Nullptr
f5bf82fa93 Set memfd name to module name on debug 2023-04-23 09:15:53 +08:00
17 changed files with 210 additions and 235 deletions

View File

@@ -2,7 +2,7 @@
Zygisk loader for KernelSU, allowing Zygisk modules to run without Magisk environment.
Also works as standalone loader for Magisk on purpose of getting rid of LD_PRELOAD.
Also works as standalone loader for Magisk.
## Requirements
@@ -12,8 +12,8 @@ Also works as standalone loader for Magisk on purpose of getting rid of LD_PRELO
### KernelSU
+ Minimal KernelSU version: 10654
+ Minimal ksud version: 10670
+ Minimal KernelSU version: 10940
+ Minimal ksud version: 10942
+ Kernel has full SELinux patch support
### Magisk

View File

@@ -31,10 +31,10 @@ val gitCommitHash = "git rev-parse --verify --short HEAD".execute()
val moduleId by extra("zygisksu")
val moduleName by extra("Zygisk on KernelSU")
val verName by extra("v4-0.6.5")
val verName by extra("v4-0.7.0")
val verCode by extra(gitCommitCount)
val minKsuVersion by extra(10818)
val minKsudVersion by extra(10818)
val minKsuVersion by extra(10940)
val minKsudVersion by extra(10942)
val maxKsuVersion by extra(20000)
val minMagiskVersion by extra(25208)

View File

@@ -115,6 +115,7 @@ namespace zygiskd {
if (socket_utils::read_u8(fd) == 1) {
return fd;
} else {
close(fd);
return -1;
}
}

View File

@@ -44,8 +44,17 @@ void* DlopenExt(const char* path, int flags) {
return handle;
}
void* DlopenMem(int memfd, int flags) {
char path[PATH_MAX];
sprintf(path, "/proc/self/fd/%d", memfd);
return DlopenExt(path, flags);
void* DlopenMem(int fd, int flags) {
auto info = android_dlextinfo{
.flags = ANDROID_DLEXT_USE_LIBRARY_FD,
.library_fd = fd
};
auto* handle = android_dlopen_ext("/jit-cache", flags, &info);
if (handle) {
LOGD("dlopen fd %d: %p", fd, handle);
} else {
LOGE("dlopen fd %d: %s", fd, dlerror());
}
return handle;
}

View File

@@ -20,7 +20,7 @@ public:
UniqueFd(Fd fd) : fd_(fd) {}
~UniqueFd() { close(fd_); }
~UniqueFd() { if (fd_ >= 0) close(fd_); }
// Disallow copy
UniqueFd(const UniqueFd&) = delete;

View File

@@ -46,7 +46,7 @@ androidComponents.onVariants { variant ->
expand(
"moduleId" to moduleId,
"moduleName" to moduleName,
"versionName" to "$verName ($verCode)",
"versionName" to "$verName ($verCode-$variantLowered)",
"versionCode" to verCode,
)
}

View File

@@ -80,6 +80,11 @@ extract "$ZIPFILE" 'customize.sh' "$TMPDIR/.vunzip"
extract "$ZIPFILE" 'verify.sh' "$TMPDIR/.vunzip"
extract "$ZIPFILE" 'sepolicy.rule' "$TMPDIR"
if [ "$DEBUG" = true ]; then
ui_print "- Add debug SELinux policy"
echo "allow crash_dump adb_data_file dir search" >> "$TMPDIR/sepolicy.rule"
fi
if [ "$KSU" ]; then
ui_print "- Checking SELinux patches"
if ! check_sepolicy "$TMPDIR/sepolicy.rule"; then

View File

@@ -3,22 +3,25 @@ name = "zygiskd"
authors = ["Nullptr"]
version = "1.0.0"
edition = "2021"
rust-version = "1.67"
rust-version = "1.69"
[dependencies]
android_logger = "0.13.0"
anyhow = { version = "1.0.68", features = ["backtrace"] }
clap = { version = "4.1.4", features = ["derive"] }
const_format = "0.2.5"
konst = "0.3.4"
lazy_static = "1.4.0"
log = "0.4.17"
memfd = "0.6.2"
nix = "0.26.2"
num_enum = "0.5.9"
once_cell = "1.17.1"
passfd = "0.1.5"
rand = "0.8.5"
android_logger = "0.13"
anyhow = { version = "1.0", features = ["backtrace"] }
bitflags = { version = "2.3" }
clap = { version = "4", features = ["derive"] }
const_format = "0.2"
futures = "0.3"
konst = "0.3"
lazy_static = "1.4"
log = "0.4"
memfd = "0.6"
nix = { version = "0.26", features = ["process","poll"] }
num_enum = "0.5"
once_cell = "1.17"
passfd = "0.1"
rand = "0.8"
tokio = { version = "1.28", features = ["full"] }
binder = { git = "https://github.com/Kernel-SU/binder_rs" }

View File

@@ -1,61 +0,0 @@
use std::ffi::c_void;
use std::os::fd::{FromRawFd, RawFd};
use std::os::unix::net::UnixStream;
use std::thread;
use anyhow::Result;
use nix::libc;
use passfd::FdPassingExt;
use crate::utils::UnixStreamExt;
use crate::dl;
type ZygiskCompanionEntryFn = unsafe extern "C" fn(i32);
pub fn entry(fd: i32) -> Result<()> {
unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL) };
let mut stream = unsafe { UnixStream::from_raw_fd(fd) };
let name = stream.read_string()?;
let library = stream.recv_fd()?;
let entry = load_module(library)?;
unsafe { libc::close(library) };
let entry = match entry {
Some(entry) => {
log::debug!("Companion process created for `{name}`");
stream.write_u8(1)?;
entry
}
None => {
log::debug!("No companion entry for `{name}`");
stream.write_u8(0)?;
return Ok(());
}
};
loop {
let fd = stream.recv_fd()?;
log::trace!("New companion request from module `{name}`");
thread::spawn(move || {
unsafe {
let mut s = UnixStream::from_raw_fd(fd);
match s.write_u8(1) { // Ack
Ok(_) => entry(fd),
Err(_) => log::warn!("Ack failed?"),
}
};
});
}
}
fn load_module(fd: RawFd) -> Result<Option<ZygiskCompanionEntryFn>> {
unsafe {
let path = format!("/proc/self/fd/{fd}");
let handle = dl::dlopen(&path, libc::RTLD_NOW)?;
let symbol = std::ffi::CString::new("zygisk_companion_entry")?;
let entry = libc::dlsym(handle, symbol.as_ptr());
if entry.is_null() {
return Ok(None);
}
let fnptr = std::mem::transmute::<*mut c_void, ZygiskCompanionEntryFn>(entry);
Ok(Some(fnptr))
}
}

View File

@@ -1,3 +1,4 @@
use bitflags::bitflags;
use const_format::concatcp;
use konst::primitive::parse_i32;
use konst::unwrap_ctx;
@@ -46,8 +47,13 @@ pub enum DaemonSocketAction {
}
// Zygisk process flags
pub const PROCESS_GRANTED_ROOT: u32 = 1 << 0;
pub const PROCESS_ON_DENYLIST: u32 = 1 << 1;
pub const PROCESS_ROOT_IS_KSU: u32 = 1 << 29;
pub const PROCESS_ROOT_IS_MAGISK: u32 = 1 << 30;
pub const PROCESS_IS_SYSUI: u32 = 1 << 31;
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ProcessFlags: u32 {
const PROCESS_GRANTED_ROOT = 1 << 0;
const PROCESS_ON_DENYLIST = 1 << 1;
const PROCESS_ROOT_IS_KSU = 1 << 29;
const PROCESS_ROOT_IS_MAGISK = 1 << 30;
const PROCESS_IS_SYSUI = 1 << 31;
}
}

View File

@@ -1,6 +1,5 @@
#![allow(dead_code)]
mod companion;
mod constants;
mod dl;
mod magic;
@@ -25,8 +24,6 @@ enum Commands {
Watchdog,
/// Start zygisk daemon
Daemon,
/// Start zygisk companion
Companion { fd: i32 },
}
@@ -38,24 +35,24 @@ fn init_android_logger(tag: &str) {
);
}
fn start() -> Result<()> {
async fn start() -> Result<()> {
root_impl::setup();
magic::setup()?;
let cli = Args::parse();
match cli.command {
Commands::Watchdog => watchdog::entry()?,
Commands::Watchdog => watchdog::entry().await?,
Commands::Daemon => zygiskd::entry()?,
Commands::Companion { fd } => companion::entry(fd)?,
};
Ok(())
}
fn main() {
#[tokio::main]
async fn main() {
let process = std::env::args().next().unwrap();
let nice_name = process.split('/').last().unwrap();
init_android_logger(nice_name);
if let Err(e) = start() {
if let Err(e) = start().await {
log::error!("Crashed: {}\n{}", e, e.backtrace());
}
}

View File

@@ -4,7 +4,8 @@ use crate::constants::{MIN_KSU_VERSION, MAX_KSU_VERSION};
const KERNEL_SU_OPTION: i32 = 0xdeadbeefu32 as i32;
const CMD_GET_VERSION: usize = 2;
const CMD_GET_ALLOW_LIST: usize = 5;
const CMD_UID_GRANTED_ROOT: usize = 12;
const CMD_UID_SHOULD_UMOUNT: usize = 13;
pub enum Version {
Supported,
@@ -23,16 +24,14 @@ pub fn get_kernel_su() -> Option<Version> {
}
}
#[inline(never)]
pub fn uid_on_allowlist(uid: i32) -> bool {
let mut size = 1024u32;
let mut uids = vec![0; size as usize];
unsafe { prctl(KERNEL_SU_OPTION, CMD_GET_ALLOW_LIST, uids.as_mut_ptr(), &mut size as *mut u32) };
uids.resize(size as usize, 0);
uids.contains(&uid)
pub fn uid_granted_root(uid: i32) -> bool {
let mut granted = false;
unsafe { prctl(KERNEL_SU_OPTION, CMD_UID_GRANTED_ROOT, uid, &mut granted as *mut bool) };
granted
}
#[inline(never)]
pub fn uid_on_denylist(uid: i32) -> bool {
false
pub fn uid_should_umount(uid: i32) -> bool {
let mut umount = false;
unsafe { prctl(KERNEL_SU_OPTION, CMD_UID_SHOULD_UMOUNT, uid, &mut umount as *mut bool) };
umount
}

View File

@@ -23,8 +23,7 @@ pub fn get_magisk() -> Option<Version> {
})
}
#[inline(never)]
pub fn uid_on_allowlist(uid: i32) -> bool {
pub fn uid_granted_root(uid: i32) -> bool {
let output: Option<String> = Command::new("magisk")
.arg("--sqlite")
.arg("select uid from policies where policy=2")
@@ -41,8 +40,7 @@ pub fn uid_on_allowlist(uid: i32) -> bool {
})
}
#[inline(never)]
pub fn uid_on_denylist(uid: i32) -> bool {
// TODO: uid_on_denylist
pub fn uid_should_umount(uid: i32) -> bool {
// TODO: uid_should_umount
return false;
}

View File

@@ -41,21 +41,18 @@ pub fn get_impl() -> &'static RootImpl {
unsafe { &ROOT_IMPL }
}
// FIXME: Without #[inline(never)], this function will lag forever
#[inline(never)]
pub fn uid_on_allowlist(uid: i32) -> bool {
pub fn uid_granted_root(uid: i32) -> bool {
match get_impl() {
RootImpl::KernelSU => kernelsu::uid_on_allowlist(uid),
RootImpl::Magisk => magisk::uid_on_allowlist(uid),
RootImpl::KernelSU => kernelsu::uid_granted_root(uid),
RootImpl::Magisk => magisk::uid_granted_root(uid),
_ => unreachable!(),
}
}
#[inline(never)]
pub fn uid_on_denylist(uid: i32) -> bool {
pub fn uid_should_umount(uid: i32) -> bool {
match get_impl() {
RootImpl::KernelSU => kernelsu::uid_on_denylist(uid),
RootImpl::Magisk => magisk::uid_on_denylist(uid),
RootImpl::KernelSU => kernelsu::uid_should_umount(uid),
RootImpl::Magisk => magisk::uid_should_umount(uid),
_ => unreachable!(),
}
}

View File

@@ -19,6 +19,17 @@ macro_rules! lp_select {
($lp32:expr, $lp64:expr) => { $lp32 };
}
#[cfg(debug_assertions)]
#[macro_export]
macro_rules! debug_select {
($debug:expr, $release:expr) => { $debug };
}
#[cfg(not(debug_assertions))]
#[macro_export]
macro_rules! debug_select {
($debug:expr, $release:expr) => { $release };
}
pub struct LateInit<T> {
cell: OnceCell<T>,
}

View File

@@ -1,33 +1,36 @@
use crate::{constants, magic, root_impl, utils};
use anyhow::{bail, Result};
use nix::unistd::{getgid, getuid, Pid};
use std::process::{Child, Command};
use std::sync::mpsc;
use std::{fs, io, thread};
use std::{fs, io};
use std::ffi::CString;
use std::future::Future;
use std::io::{BufRead, Write};
use std::os::unix::net::UnixListener;
use std::pin::Pin;
use std::time::Duration;
use binder::IBinder;
use futures::stream::FuturesUnordered;
use futures::StreamExt;
use nix::errno::Errno;
use nix::libc;
use nix::sys::signal::{kill, Signal};
use tokio::process::{Child, Command};
use crate::utils::LateInit;
static LOCK: LateInit<UnixListener> = LateInit::new();
static PROP_SECTIONS: LateInit<[String; 2]> = LateInit::new();
pub fn entry() -> Result<()> {
pub async fn entry() -> Result<()> {
log::info!("Start zygisksu watchdog");
check_permission()?;
ensure_single_instance()?;
mount_prop()?;
mount_prop().await?;
if check_and_set_hint()? == false {
log::warn!("Requirements not met, exiting");
utils::set_property(constants::PROP_NATIVE_BRIDGE, &utils::get_native_bridge())?;
return Ok(());
}
let end = spawn_daemon();
let end = spawn_daemon().await;
set_prop_hint(constants::STATUS_CRASHED)?;
end
}
@@ -63,9 +66,9 @@ fn ensure_single_instance() -> Result<()> {
Ok(())
}
fn mount_prop() -> Result<()> {
async fn mount_prop() -> Result<()> {
let module_prop = if let root_impl::RootImpl::Magisk = root_impl::get_impl() {
let magisk_path = Command::new("magisk").arg("--path").output()?;
let magisk_path = Command::new("magisk").arg("--path").output().await?;
let mut magisk_path = String::from_utf8(magisk_path.stdout)?;
magisk_path.pop(); // Removing '\n'
let cwd = std::env::current_dir()?;
@@ -136,46 +139,57 @@ fn check_and_set_hint() -> Result<bool> {
Ok(false)
}
fn spawn_daemon() -> Result<()> {
async fn spawn_daemon() -> Result<()> {
let mut lives = 5;
loop {
let mut futures = FuturesUnordered::<Pin<Box<dyn Future<Output=Result<()>>>>>::new();
let mut child_ids = vec![];
let daemon32 = Command::new(constants::PATH_ZYGISKD32).arg("daemon").spawn();
let daemon64 = Command::new(constants::PATH_ZYGISKD64).arg("daemon").spawn();
let mut child_ids = vec![];
let (sender, receiver) = mpsc::channel();
let mut spawn = |mut daemon: Child| {
child_ids.push(daemon.id());
let sender = sender.clone();
thread::spawn(move || {
let result = daemon.wait().unwrap();
log::error!("Daemon process {} died: {}", daemon.id(), result);
drop(daemon);
let _ = sender.send(());
});
};
if let Ok(it) = daemon32 { spawn(it) }
if let Ok(it) = daemon64 { spawn(it) }
let mut binder = loop {
if receiver.try_recv().is_ok() {
bail!("Daemon died before system server ready");
}
match binder::get_service("activity") {
Some(binder) => break binder,
None => {
log::trace!("System server not ready, wait for 1s...");
thread::sleep(Duration::from_secs(1));
}
};
};
log::info!("System server ready, restore native bridge");
utils::set_property(constants::PROP_NATIVE_BRIDGE, &utils::get_native_bridge())?;
loop {
if receiver.try_recv().is_ok() || binder.ping_binder().is_err() { break; }
thread::sleep(Duration::from_secs(1))
async fn spawn_daemon(mut daemon: Child) -> Result<()> {
let result = daemon.wait().await?;
log::error!("Daemon process {} died: {}", daemon.id().unwrap(), result);
Ok(())
}
if let Ok(it) = daemon32 {
child_ids.push(it.id().unwrap());
futures.push(Box::pin(spawn_daemon(it)));
}
if let Ok(it) = daemon64 {
child_ids.push(it.id().unwrap());
futures.push(Box::pin(spawn_daemon(it)));
}
async fn binder_listener() -> Result<()> {
let mut binder = loop {
match binder::get_service("activity") {
Some(binder) => break binder,
None => {
log::trace!("System server not ready, wait for 1s...");
tokio::time::sleep(Duration::from_secs(1)).await;
}
};
};
log::info!("System server ready, restore native bridge");
utils::set_property(constants::PROP_NATIVE_BRIDGE, &utils::get_native_bridge())?;
loop {
if binder.ping_binder().is_err() { break; }
tokio::time::sleep(Duration::from_secs(1)).await;
}
log::error!("System server died");
Ok(())
}
futures.push(Box::pin(binder_listener()));
if let Err(e) = futures.next().await.unwrap() {
log::error!("{}", e);
}
for child in child_ids {
log::debug!("Killing child process {}", child);
let _ = kill(Pid::from_raw(child as i32), Signal::SIGKILL);
}

View File

@@ -1,28 +1,28 @@
use crate::constants::DaemonSocketAction;
use std::ffi::c_void;
use crate::constants::{DaemonSocketAction, ProcessFlags};
use crate::utils::UnixStreamExt;
use crate::{constants, lp_select, magic, root_impl, utils};
use crate::{constants, dl, lp_select, magic, root_impl, utils};
use anyhow::{bail, Result};
use memfd::Memfd;
use nix::{
fcntl::{fcntl, FcntlArg, FdFlag},
libc::self,
};
use passfd::FdPassingExt;
use std::sync::{Arc, Mutex};
use std::sync::Arc;
use std::thread;
use std::fs;
use std::os::fd::{IntoRawFd, OwnedFd};
use std::os::unix::{
net::{UnixListener, UnixStream},
prelude::AsRawFd,
};
use std::os::unix::process::CommandExt;
use std::path::PathBuf;
use std::process::Command;
use nix::libc;
use nix::sys::stat::fstat;
use nix::unistd::close;
type ZygiskCompanionEntryFn = unsafe extern "C" fn(i32);
struct Module {
name: String,
memfd: Memfd,
companion: Mutex<Option<UnixStream>>,
lib_fd: OwnedFd,
entry: Option<ZygiskCompanionEntryFn>,
}
struct Context {
@@ -82,8 +82,8 @@ fn load_modules(arch: &str) -> Result<Vec<Module>> {
return Ok(modules);
}
};
for entry_result in dir.into_iter() {
let entry = entry_result?;
for entry in dir.into_iter() {
let entry = entry?;
let name = entry.file_name().into_string().unwrap();
let so_path = entry.path().join(format!("zygisk/{arch}.so"));
let disabled = entry.path().join("disable");
@@ -91,30 +91,28 @@ fn load_modules(arch: &str) -> Result<Vec<Module>> {
continue;
}
log::info!(" Loading module `{name}`...");
let memfd = match create_memfd(&so_path) {
Ok(memfd) => memfd,
let lib_fd = match create_library_fd(&so_path) {
Ok(fd) => fd,
Err(e) => {
log::warn!(" Failed to create memfd for `{name}`: {e}");
continue;
}
};
let companion = match spawn_companion(&name, &memfd) {
Ok(companion) => companion,
Err(e) => {
log::warn!(" Failed to spawn companion for `{name}`: {e}");
continue;
}
};
let companion = Mutex::new(companion);
let module = Module { name, memfd, companion };
let entry = resolve_module(&so_path.to_string_lossy())?;
let module = Module { name, lib_fd, entry };
modules.push(module);
}
Ok(modules)
}
fn create_memfd(so_path: &PathBuf) -> Result<Memfd> {
#[cfg(debug_assertions)]
fn create_library_fd(so_path: &PathBuf) -> Result<OwnedFd> {
Ok(OwnedFd::from(fs::File::open(so_path)?))
}
#[cfg(not(debug_assertions))]
fn create_library_fd(so_path: &PathBuf) -> Result<OwnedFd> {
let opts = memfd::MemfdOptions::default().allow_sealing(true);
let memfd = opts.create("jit-cache")?;
let file = fs::File::open(so_path)?;
@@ -129,7 +127,7 @@ fn create_memfd(so_path: &PathBuf) -> Result<Memfd> {
seals.insert(memfd::FileSeal::SealSeal);
memfd.add_seals(&seals)?;
Ok(memfd)
Ok(OwnedFd::from(memfd.into_file()))
}
fn create_daemon_socket() -> Result<UnixListener> {
@@ -141,26 +139,16 @@ fn create_daemon_socket() -> Result<UnixListener> {
Ok(listener)
}
fn spawn_companion(name: &str, memfd: &Memfd) -> Result<Option<UnixStream>> {
let (mut daemon, companion) = UnixStream::pair()?;
// Remove FD_CLOEXEC flag
fcntl(companion.as_raw_fd(), FcntlArg::F_SETFD(FdFlag::empty()))?;
let process = std::env::args().next().unwrap();
let nice_name = process.split('/').last().unwrap();
Command::new(&process)
.arg0(format!("{}-{}", nice_name, name))
.arg("companion")
.arg(format!("{}", companion.as_raw_fd()))
.spawn()?;
drop(companion);
daemon.write_string(name)?;
daemon.send_fd(memfd.as_raw_fd())?;
match daemon.read_u8()? {
0 => Ok(None),
1 => Ok(Some(daemon)),
_ => bail!("Invalid companion response"),
fn resolve_module(path: &str) -> Result<Option<ZygiskCompanionEntryFn>> {
unsafe {
let handle = dl::dlopen(path, libc::RTLD_NOW)?;
let symbol = std::ffi::CString::new("zygisk_companion_entry")?;
let entry = libc::dlsym(handle, symbol.as_ptr());
if entry.is_null() {
return Ok(None);
}
let fnptr = std::mem::transmute::<*mut c_void, ZygiskCompanionEntryFn>(entry);
Ok(Some(fnptr))
}
}
@@ -188,43 +176,51 @@ fn handle_daemon_action(mut stream: UnixStream, context: &Context) -> Result<()>
}
DaemonSocketAction::GetProcessFlags => {
let uid = stream.read_u32()? as i32;
let mut flags = 0u32;
if root_impl::uid_on_allowlist(uid) {
flags |= constants::PROCESS_GRANTED_ROOT;
let mut flags = ProcessFlags::empty();
if root_impl::uid_granted_root(uid) {
flags |= ProcessFlags::PROCESS_GRANTED_ROOT;
}
if root_impl::uid_on_denylist(uid) {
flags |= constants::PROCESS_ON_DENYLIST;
if root_impl::uid_should_umount(uid) {
flags |= ProcessFlags::PROCESS_ON_DENYLIST;
}
match root_impl::get_impl() {
root_impl::RootImpl::KernelSU => flags |= constants::PROCESS_ROOT_IS_KSU,
root_impl::RootImpl::Magisk => flags |= constants::PROCESS_ROOT_IS_MAGISK,
root_impl::RootImpl::KernelSU => flags |= ProcessFlags::PROCESS_ROOT_IS_KSU,
root_impl::RootImpl::Magisk => flags |= ProcessFlags::PROCESS_ROOT_IS_MAGISK,
_ => unreachable!(),
}
// TODO: PROCESS_IS_SYSUI?
stream.write_u32(flags)?;
log::trace!("Uid {} granted root: {}", uid, flags.contains(ProcessFlags::PROCESS_GRANTED_ROOT));
log::trace!("Uid {} on denylist: {}", uid, flags.contains(ProcessFlags::PROCESS_ON_DENYLIST));
stream.write_u32(flags.bits())?;
}
DaemonSocketAction::ReadModules => {
stream.write_usize(context.modules.len())?;
for module in context.modules.iter() {
stream.write_string(&module.name)?;
stream.send_fd(module.memfd.as_raw_fd())?;
stream.send_fd(module.lib_fd.as_raw_fd())?;
}
}
DaemonSocketAction::RequestCompanionSocket => {
let index = stream.read_usize()?;
let module = &context.modules[index];
let mut companion = module.companion.lock().unwrap();
match companion.as_ref() {
Some(sock) => {
if let Err(_) = sock.send_fd(stream.as_raw_fd()) {
log::error!("Companion of module `{}` crashed", module.name);
companion.take();
stream.write_u8(0)?;
}
// Ok: Send by companion
}
match module.entry {
None => {
stream.write_u8(0)?;
return Ok(());
}
Some(companion) => {
stream.write_u8(1)?;
let fd = stream.into_raw_fd();
let st0 = fstat(fd)?;
unsafe { companion(fd); }
// 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 let Ok(st1) = fstat(fd) {
if st0.st_dev == st1.st_dev && st0.st_ino == st1.st_ino {
close(fd)?;
}
}
}
}
}