Move more daemon_start code into Rust

This commit is contained in:
topjohnwu 2025-04-28 16:03:14 -07:00 committed by John Wu
parent 73840f8721
commit d1829308e9
7 changed files with 97 additions and 77 deletions

View File

@ -16,7 +16,7 @@ impl Utf8CStr {
}
}
pub fn remount_with_flags(&self, flags: c_ulong) -> OsResult<()> {
pub fn remount_mount_point_flags(&self, flags: c_ulong) -> OsResult<()> {
unsafe {
libc::mount(
ptr::null(),
@ -29,6 +29,19 @@ impl Utf8CStr {
}
}
pub fn remount_mount_flags(&self, flags: c_ulong) -> OsResult<()> {
unsafe {
libc::mount(
ptr::null(),
self.as_ptr(),
ptr::null(),
libc::MS_REMOUNT | flags,
ptr::null(),
)
.check_os_err("remount", Some(self), None)
}
}
pub fn remount_with_data(&self, data: &Utf8CStr) -> OsResult<()> {
unsafe {
libc::mount(

View File

@ -325,29 +325,6 @@ static void handle_request(pollfd *pfd) {
}
}
static void switch_cgroup(const char *cgroup, int pid) {
char buf[32];
ssprintf(buf, sizeof(buf), "%s/cgroup.procs", cgroup);
if (access(buf, F_OK) != 0)
return;
int fd = xopen(buf, O_WRONLY | O_APPEND | O_CLOEXEC);
if (fd == -1)
return;
ssprintf(buf, sizeof(buf), "%d\n", pid);
xwrite(fd, buf, strlen(buf));
close(fd);
}
static int setcon(const char *con) {
int fd = open("/proc/self/attr/current", O_WRONLY | O_CLOEXEC);
if (fd < 0)
return fd;
size_t len = strlen(con) + 1;
int rc = write(fd, con, len);
close(fd);
return rc != len;
}
static void daemon_entry() {
android_logging();
@ -369,49 +346,15 @@ static void daemon_entry() {
if (fd > STDERR_FILENO)
close(fd);
setsid();
setcon(MAGISK_PROC_CON);
rust::daemon_entry();
SDK_INT = MagiskD::Get().sdk_int();
// Escape from cgroup
int pid = getpid();
switch_cgroup("/acct", pid);
switch_cgroup("/dev/cg2_bpf", pid);
switch_cgroup("/sys/fs/cgroup", pid);
if (get_prop("ro.config.per_app_memcg") != "false") {
switch_cgroup("/dev/memcg/apps", pid);
}
// Get self stat
xstat("/proc/self/exe", &self_st);
// Samsung workaround #7887
if (access("/system_ext/app/mediatek-res/mediatek-res.apk", F_OK) == 0) {
set_prop("ro.vendor.mtk_model", "0");
}
// Cleanups
const char *tmp = get_magisk_tmp();
char path[64];
ssprintf(path, sizeof(path), "%s/" ROOTMNT, tmp);
if (access(path, F_OK) == 0) {
file_readline(true, path, [](string_view line) -> bool {
umount2(line.data(), MNT_DETACH);
return true;
});
}
if (getenv("REMOUNT_ROOT")) {
xmount(nullptr, "/", nullptr, MS_REMOUNT | MS_RDONLY, nullptr);
unsetenv("REMOUNT_ROOT");
}
ssprintf(path, sizeof(path), "%s/" ROOTOVL, tmp);
rm_rf(path);
fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
sockaddr_un addr = {.sun_family = AF_LOCAL};
ssprintf(addr.sun_path, sizeof(addr.sun_path), "%s/" MAIN_SOCKET, tmp);
ssprintf(addr.sun_path, sizeof(addr.sun_path), "%s/" MAIN_SOCKET, get_magisk_tmp());
unlink(addr.sun_path);
if (xbind(fd, (sockaddr *) &addr, sizeof(addr)))
exit(1);

View File

@ -1,18 +1,21 @@
use crate::consts::{MAGISK_FULL_VER, MAIN_CONFIG, SECURE_DIR};
use crate::consts::{MAGISK_FULL_VER, MAGISK_PROC_CON, MAIN_CONFIG, ROOTMNT, ROOTOVL, SECURE_DIR};
use crate::db::Sqlite3;
use crate::ffi::{
DbEntryKey, ModuleInfo, RequestCode, check_key_combo, disable_modules, exec_common_scripts,
exec_module_scripts, get_magisk_tmp, initialize_denylist, setup_magisk_env,
};
use crate::get_prop;
use crate::logging::{magisk_logging, setup_logfile, start_log_daemon};
use crate::mount::{clean_mounts, setup_mounts};
use crate::package::ManagerInfo;
use crate::selinux::restore_tmpcon;
use crate::su::SuInfo;
use base::libc::{O_CLOEXEC, O_RDONLY};
use base::{AtomicArc, BufReadExt, FsPathBuilder, ResultExt, Utf8CStr, cstr, error, info, libc};
use std::io::BufReader;
use crate::{get_prop, set_prop};
use base::libc::{O_APPEND, O_CLOEXEC, O_RDONLY, O_WRONLY};
use base::{
AtomicArc, BufReadExt, FsPathBuilder, ResultExt, Utf8CStr, Utf8CStrBuf, cstr, error, info, libc,
};
use std::fmt::Write as FmtWrite;
use std::io::{BufReader, Write};
use std::os::unix::net::UnixStream;
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use std::sync::{Mutex, OnceLock};
@ -217,6 +220,14 @@ impl MagiskD {
}
pub fn daemon_entry() {
unsafe { libc::setsid() };
// Make sure the current context is magisk
if let Ok(mut current) = cstr!("/proc/self/attr/current").open(O_WRONLY | O_CLOEXEC) {
let con = cstr!(MAGISK_PROC_CON);
current.write_all(con.as_bytes_with_nul()).log_ok();
}
start_log_daemon();
magisk_logging();
info!("Magisk {} daemon started", MAGISK_FULL_VER);
@ -226,13 +237,13 @@ pub fn daemon_entry() {
|| get_prop(cstr!("ro.product.device"), false).contains("vsoc");
// Load config status
let path = cstr::buf::new::<64>()
.join_path(get_magisk_tmp())
let magisk_tmp = get_magisk_tmp();
let mut tmp_path = cstr::buf::new::<64>()
.join_path(magisk_tmp)
.join_path(MAIN_CONFIG);
let mut is_recovery = false;
if let Ok(file) = path.open(O_RDONLY | O_CLOEXEC) {
let mut file = BufReader::new(file);
file.foreach_props(|key, val| {
if let Ok(main_config) = tmp_path.open(O_RDONLY | O_CLOEXEC) {
BufReader::new(main_config).foreach_props(|key, val| {
if key == "RECOVERYMODE" {
is_recovery = val == "true";
return false;
@ -240,11 +251,11 @@ pub fn daemon_entry() {
true
});
}
tmp_path.truncate(magisk_tmp.len());
let mut sdk_int = -1;
if let Ok(file) = cstr!("/system/build.prop").open(O_RDONLY | O_CLOEXEC) {
let mut file = BufReader::new(file);
file.foreach_props(|key, val| {
if let Ok(build_prop) = cstr!("/system/build.prop").open(O_RDONLY | O_CLOEXEC) {
BufReader::new(build_prop).foreach_props(|key, val| {
if key == "ro.build.version.sdk" {
sdk_int = val.parse::<i32>().unwrap_or(-1);
return false;
@ -262,6 +273,42 @@ pub fn daemon_entry() {
restore_tmpcon().log_ok();
// Escape from cgroup
let pid = unsafe { libc::getpid() };
switch_cgroup("/acct", pid);
switch_cgroup("/dev/cg2_bpf", pid);
switch_cgroup("/sys/fs/cgroup", pid);
if get_prop(cstr!("ro.config.per_app_memcg"), false) != "false" {
switch_cgroup("/dev/memcg/apps", pid);
}
// Samsung workaround #7887
if cstr!("/system_ext/app/mediatek-res/mediatek-res.apk").exists() {
set_prop(cstr!("ro.vendor.mtk_model"), cstr!("0"), false);
}
// Cleanup pre-init mounts
tmp_path.append_path(ROOTMNT);
if let Ok(mount_list) = tmp_path.open(O_RDONLY | O_CLOEXEC) {
BufReader::new(mount_list).foreach_lines(|line| {
let item = Utf8CStr::from_string(line);
item.unmount().log_ok();
true
})
}
tmp_path.truncate(magisk_tmp.len());
// Remount rootfs as read-only if requested
if std::env::var_os("REMOUNT_ROOT").is_some() {
cstr!("/").remount_mount_flags(libc::MS_RDONLY).log_ok();
unsafe { std::env::remove_var("REMOUNT_ROOT") };
}
// Remove all pre-init overlay files to free-up memory
tmp_path.append_path(ROOTOVL);
tmp_path.remove_all().log_ok();
tmp_path.truncate(magisk_tmp.len());
let magiskd = MagiskD {
sdk_int,
is_emulator,
@ -272,6 +319,20 @@ pub fn daemon_entry() {
MAGISKD.set(magiskd).ok();
}
fn switch_cgroup(cgroup: &str, pid: i32) {
let mut buf = cstr::buf::new::<64>()
.join_path(cgroup)
.join_path("cgroup.procs");
if !buf.exists() {
return;
}
if let Ok(mut file) = buf.open(O_WRONLY | O_APPEND | O_CLOEXEC) {
buf.clear();
buf.write_fmt(format_args!("{}", pid)).ok();
file.write_all(buf.as_bytes()).log_ok();
}
}
fn check_data() -> bool {
if let Ok(file) = cstr!("/proc/mounts").open(O_RDONLY | O_CLOEXEC) {
let mut mnt = false;

View File

@ -137,6 +137,8 @@ pub mod ffi {
#[cxx_name = "prop_cb"]
type PropCb;
unsafe fn get_prop_rs(name: *const c_char, persist: bool) -> String;
#[cxx_name = "set_prop"]
unsafe fn set_prop_rs(name: *const c_char, value: *const c_char, skip_svc: bool) -> i32;
unsafe fn prop_cb_exec(
cb: Pin<&mut PropCb>,
name: *const c_char,
@ -277,3 +279,7 @@ impl SuRequest {
pub fn get_prop(name: &Utf8CStr, persist: bool) -> String {
unsafe { ffi::get_prop_rs(name.as_ptr(), persist) }
}
pub fn set_prop(name: &Utf8CStr, value: &Utf8CStr, skip_svc: bool) -> bool {
unsafe { ffi::set_prop_rs(name.as_ptr(), value.as_ptr(), skip_svc) == 0 }
}

View File

@ -74,7 +74,7 @@ pub fn setup_mounts() {
let _: LoggedResult<()> = try {
module_mnt.mkdir(0o755)?;
cstr!(MODULEROOT).bind_mount_to(&module_mnt)?;
module_mnt.remount_with_flags(libc::MS_RDONLY)?;
module_mnt.remount_mount_point_flags(libc::MS_RDONLY)?;
};
}

View File

@ -20,11 +20,8 @@
#define BBPATH INTLROOT "/busybox"
#define ROOTOVL INTLROOT "/rootdir"
#define SHELLPTS INTLROOT "/pts"
#define ROOTMNT ROOTOVL "/.mount_list"
#define SELINUXMOCK INTLROOT "/selinux"
#define MAIN_CONFIG INTLROOT "/config"
#define MAIN_SOCKET DEVICEDIR "/socket"
#define LOG_PIPE DEVICEDIR "/log"
constexpr const char *applet_names[] = { "su", "resetprop", nullptr };
@ -39,7 +36,6 @@ constexpr const char *applet_names[] = { "su", "resetprop", nullptr };
#define MAGISK_FILE_CON "u:object_r:" SEPOL_FILE_TYPE ":s0"
// Log pipe that only root and zygote can open
#define SEPOL_LOG_TYPE "magisk_log_file"
#define MAGISK_LOG_CON "u:object_r:" SEPOL_LOG_TYPE ":s0"
extern int SDK_INT;
#define APP_DATA_DIR (SDK_INT >= 24 ? "/data/user_de" : "/data/user")

View File

@ -32,6 +32,7 @@ pub const SELINUXMOCK: &str = concatcp!(INTERNAL_DIR, "/selinux");
// Unconstrained domain the daemon and root processes run in
pub const SEPOL_PROC_DOMAIN: &str = "magisk";
pub const MAGISK_PROC_CON: &str = concatcp!("u:r:", SEPOL_PROC_DOMAIN, ":s0");
// Unconstrained file type that anyone can access
pub const SEPOL_FILE_TYPE: &str = "magisk_file";
// Log pipe that only root and zygote can open