use crate::ffi::MagiskInit; use base::libc::O_RDONLY; use base::{ cstr_buf, debug, libc, path, BufReadExt, Directory, LibcReturn, LoggedResult, ResultExt, Utf8CStr, Utf8CStrBuf, Utf8CStrBufArr, WalkResult, }; use std::io::BufReader; use std::{ fs::File, io::Write, mem, os::fd::{FromRawFd, RawFd}, sync::OnceLock, }; pub static OVERLAY_ATTRS: OnceLock> = OnceLock::new(); const XATTR_NAME_SELINUX: &[u8] = b"security.selinux\0"; fn get_context(path: &str, con: &mut Utf8CStrBufArr) -> std::io::Result<()> { unsafe { let sz = libc::lgetxattr( path.as_ptr().cast(), XATTR_NAME_SELINUX.as_ptr().cast(), con.as_mut_ptr().cast(), con.capacity(), ) .check_os_err()?; con.set_len((sz - 1) as usize); } Ok(()) } fn set_context(path: &str, con: &str) -> std::io::Result<()> { unsafe { libc::lsetxattr( path.as_ptr().cast(), XATTR_NAME_SELINUX.as_ptr().cast(), con.as_ptr().cast(), con.len() + 1, 0, ) .as_os_err() } } pub fn collect_overlay_contexts(src: &Utf8CStr) { OVERLAY_ATTRS .get_or_try_init(|| -> LoggedResult<_> { let mut contexts = vec![]; let mut con = cstr_buf::default(); let mut path = cstr_buf::default(); let mut src = Directory::open(src)?; src.path(&mut path)?; let src_len = path.len(); src.post_order_walk(|f| { f.path(&mut path)?; let path = &path[src_len..]; if get_context(path, &mut con) .log_with_msg(|w| w.write_fmt(format_args!("collect context {}", path))) .is_ok() { debug!("collect context: {:?} -> {:?}", path, con); contexts.push((path.to_string(), con.to_string())); } Ok(WalkResult::Continue) })?; Ok(contexts) }) .ok(); } pub fn reset_overlay_contexts() { OVERLAY_ATTRS.get().map(|attrs| { for (path, con) in attrs.iter() { debug!("set context: {} -> {}", path, con); set_context(path, con) .log_with_msg(|w| w.write_fmt(format_args!("reset context {}", path))) .ok(); } Some(()) }); } pub fn inject_magisk_rc(fd: RawFd, tmp_dir: &Utf8CStr) { debug!("Injecting magisk rc"); let mut file = unsafe { File::from_raw_fd(fd) }; write!( file, r#" on post-fs-data exec {0} 0 0 -- {1}/magisk --post-fs-data on property:vold.decrypt=trigger_restart_framework exec {0} 0 0 -- {1}/magisk --service on nonencrypted exec {0} 0 0 -- {1}/magisk --service on property:sys.boot_completed=1 exec {0} 0 0 -- {1}/magisk --boot-complete on property:init.svc.zygote=stopped exec {0} 0 0 -- {1}/magisk --zygote-restart "#, "u:r:magisk:s0", tmp_dir ) .ok(); mem::forget(file) } impl MagiskInit { pub(crate) fn parse_config_file(&mut self) { if let Ok(fd) = path!("/data/.backup/.magisk").open(O_RDONLY) { let mut reader = BufReader::new(fd); reader.foreach_props(|key, val| { if key == "PREINITDEVICE" { self.preinit_dev = val.to_string(); return false; } true }) } } }