mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-05-01 23:14:26 +02:00
Fix overlay.d context preservation
This commit is contained in:
parent
e55c413261
commit
b6b34f7612
@ -1,14 +1,14 @@
|
|||||||
|
use cxx::{type_id, ExternType};
|
||||||
|
use libc::c_char;
|
||||||
|
use std::borrow::Borrow;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::ffi::{CStr, FromBytesWithNulError, OsStr};
|
use std::ffi::{CStr, FromBytesWithNulError, OsStr};
|
||||||
use std::fmt::{Arguments, Debug, Display, Formatter, Write};
|
use std::fmt::{Debug, Display, Formatter, Write};
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::str::Utf8Error;
|
use std::str::Utf8Error;
|
||||||
use std::{fmt, mem, slice, str};
|
use std::{fmt, mem, slice, str};
|
||||||
|
|
||||||
use cxx::{type_id, ExternType};
|
|
||||||
use libc::c_char;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::slice_from_ptr_mut;
|
use crate::slice_from_ptr_mut;
|
||||||
@ -263,6 +263,12 @@ impl From<String> for Utf8CString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Borrow<Utf8CStr> for Utf8CString {
|
||||||
|
fn borrow(&self) -> &Utf8CStr {
|
||||||
|
self.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UTF-8 validated + null terminated reference to buffer
|
// UTF-8 validated + null terminated reference to buffer
|
||||||
pub struct Utf8CStrBufRef<'a> {
|
pub struct Utf8CStrBufRef<'a> {
|
||||||
used: usize,
|
used: usize,
|
||||||
@ -359,7 +365,7 @@ impl Utf8CStr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn from_bytes_unchecked(buf: &[u8]) -> &Utf8CStr {
|
pub const unsafe fn from_bytes_unchecked(buf: &[u8]) -> &Utf8CStr {
|
||||||
mem::transmute(buf)
|
mem::transmute(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,6 +438,16 @@ impl DerefMut for Utf8CStr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToOwned for Utf8CStr {
|
||||||
|
type Owned = Utf8CString;
|
||||||
|
|
||||||
|
fn to_owned(&self) -> Utf8CString {
|
||||||
|
let mut s = Utf8CString::with_capacity(self.len() + 1);
|
||||||
|
s.push_str(self.as_str());
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Notice that we only implement ExternType on Utf8CStr *reference*
|
// Notice that we only implement ExternType on Utf8CStr *reference*
|
||||||
unsafe impl ExternType for &Utf8CStr {
|
unsafe impl ExternType for &Utf8CStr {
|
||||||
type Id = type_id!("rust::Utf8CStr");
|
type Id = type_id!("rust::Utf8CStr");
|
||||||
@ -535,7 +551,8 @@ impl<const N: usize> FsPathBuf<N> {
|
|||||||
fn inner(buf: &mut dyn Utf8CStrBuf, path: &str) {
|
fn inner(buf: &mut dyn Utf8CStrBuf, path: &str) {
|
||||||
if path.starts_with('/') {
|
if path.starts_with('/') {
|
||||||
buf.clear();
|
buf.clear();
|
||||||
} else {
|
}
|
||||||
|
if !buf.is_empty() && !buf.ends_with('/') {
|
||||||
buf.push_str("/");
|
buf.push_str("/");
|
||||||
}
|
}
|
||||||
buf.push_str(path);
|
buf.push_str(path);
|
||||||
@ -545,10 +562,7 @@ impl<const N: usize> FsPathBuf<N> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn join_fmt<T: Display>(mut self, name: T) -> Self {
|
pub fn join_fmt<T: Display>(mut self, name: T) -> Self {
|
||||||
fn inner(buf: &mut dyn Utf8CStrBuf, path: Arguments) {
|
self.0.write_fmt(format_args!("/{}", name)).ok();
|
||||||
buf.write_fmt(path).ok();
|
|
||||||
}
|
|
||||||
inner(self.0.deref_mut(), format_args!("/{}", name));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
use crate::cxx_extern::readlinkat_for_cxx;
|
use crate::cxx_extern::readlinkat_for_cxx;
|
||||||
use crate::{
|
use crate::{cstr, cstr_buf, errno, error, FsPath, FsPathBuf, LibcReturn, Utf8CStr, Utf8CStrBuf};
|
||||||
cstr, cstr_buf, errno, error, FsPath, FsPathBuf, LibcReturn, Utf8CStr, Utf8CStrBuf,
|
|
||||||
Utf8CStrBufArr,
|
|
||||||
};
|
|
||||||
use bytemuck::{bytes_of, bytes_of_mut, Pod};
|
use bytemuck::{bytes_of, bytes_of_mut, Pod};
|
||||||
use libc::{
|
use libc::{
|
||||||
c_uint, dirent, makedev, mode_t, EEXIST, ENOENT, F_OK, O_CLOEXEC, O_CREAT, O_PATH, O_RDONLY,
|
c_uint, dirent, makedev, mode_t, EEXIST, ENOENT, F_OK, O_CLOEXEC, O_CREAT, O_PATH, O_RDONLY,
|
||||||
@ -142,7 +139,7 @@ impl<T: Write> WriteExt for T {
|
|||||||
pub struct FileAttr {
|
pub struct FileAttr {
|
||||||
pub st: libc::stat,
|
pub st: libc::stat,
|
||||||
#[cfg(feature = "selinux")]
|
#[cfg(feature = "selinux")]
|
||||||
pub con: Utf8CStrBufArr<128>,
|
pub con: crate::Utf8CStrBufArr<128>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileAttr {
|
impl FileAttr {
|
||||||
@ -150,7 +147,7 @@ impl FileAttr {
|
|||||||
FileAttr {
|
FileAttr {
|
||||||
st: unsafe { mem::zeroed() },
|
st: unsafe { mem::zeroed() },
|
||||||
#[cfg(feature = "selinux")]
|
#[cfg(feature = "selinux")]
|
||||||
con: Utf8CStrBufArr::new(),
|
con: crate::Utf8CStrBufArr::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +186,6 @@ impl FileAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "selinux")]
|
|
||||||
const XATTR_NAME_SELINUX: &[u8] = b"security.selinux\0";
|
const XATTR_NAME_SELINUX: &[u8] = b"security.selinux\0";
|
||||||
|
|
||||||
pub struct DirEntry<'a> {
|
pub struct DirEntry<'a> {
|
||||||
@ -199,7 +195,7 @@ pub struct DirEntry<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DirEntry<'_> {
|
impl DirEntry<'_> {
|
||||||
pub fn d_name(&self) -> &CStr {
|
pub fn name(&self) -> &CStr {
|
||||||
unsafe {
|
unsafe {
|
||||||
CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(
|
CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(
|
||||||
self.d_name.as_ptr().cast(),
|
self.d_name.as_ptr().cast(),
|
||||||
@ -211,7 +207,7 @@ impl DirEntry<'_> {
|
|||||||
pub fn path(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
pub fn path(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||||
self.dir.path(buf)?;
|
self.dir.path(buf)?;
|
||||||
buf.push_str("/");
|
buf.push_str("/");
|
||||||
buf.push_lossy(self.d_name().to_bytes());
|
buf.push_lossy(self.name().to_bytes());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,7 +263,7 @@ impl DirEntry<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn open_fd(&self, flags: i32) -> io::Result<RawFd> {
|
unsafe fn open_fd(&self, flags: i32) -> io::Result<RawFd> {
|
||||||
self.dir.open_raw_fd(self.d_name(), flags, 0)
|
self.dir.open_raw_fd(self.name(), flags, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_as_dir(&self) -> io::Result<Directory> {
|
pub fn open_as_dir(&self) -> io::Result<Directory> {
|
||||||
@ -295,6 +291,18 @@ impl DirEntry<'_> {
|
|||||||
self.path(&mut path)?;
|
self.path(&mut path)?;
|
||||||
FsPath::from(&path).set_attr(attr)
|
FsPath::from(&path).set_attr(attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_secontext(&self, con: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||||
|
let mut path = cstr_buf::default();
|
||||||
|
self.path(&mut path)?;
|
||||||
|
FsPath::from(&path).get_secontext(con)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_secontext(&self, con: &Utf8CStr) -> io::Result<()> {
|
||||||
|
let mut path = cstr_buf::default();
|
||||||
|
self.path(&mut path)?;
|
||||||
|
FsPath::from(&path).set_secontext(con)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for DirEntry<'_> {
|
impl Deref for DirEntry<'_> {
|
||||||
@ -424,7 +432,7 @@ impl Directory {
|
|||||||
let mut src = e.open_as_file(O_RDONLY)?;
|
let mut src = e.open_as_file(O_RDONLY)?;
|
||||||
let mut dest = unsafe {
|
let mut dest = unsafe {
|
||||||
File::from_raw_fd(dir.open_raw_fd(
|
File::from_raw_fd(dir.open_raw_fd(
|
||||||
e.d_name(),
|
e.name(),
|
||||||
O_WRONLY | O_CREAT | O_TRUNC,
|
O_WRONLY | O_CREAT | O_TRUNC,
|
||||||
0o777,
|
0o777,
|
||||||
)?)
|
)?)
|
||||||
@ -447,7 +455,7 @@ impl Directory {
|
|||||||
pub fn move_into(&mut self, dir: &Directory) -> io::Result<()> {
|
pub fn move_into(&mut self, dir: &Directory) -> io::Result<()> {
|
||||||
let dir_fd = self.as_raw_fd();
|
let dir_fd = self.as_raw_fd();
|
||||||
while let Some(ref e) = self.read()? {
|
while let Some(ref e) = self.read()? {
|
||||||
if e.is_dir() && dir.contains_path(e.d_name()) {
|
if e.is_dir() && dir.contains_path(e.name()) {
|
||||||
// Destination folder exists, needs recursive move
|
// Destination folder exists, needs recursive move
|
||||||
let mut src = e.open_as_dir()?;
|
let mut src = e.open_as_dir()?;
|
||||||
let new_entry = DirEntry {
|
let new_entry = DirEntry {
|
||||||
@ -621,7 +629,7 @@ impl FsPath {
|
|||||||
pub fn read_link(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
pub fn read_link(&self, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||||
buf.clear();
|
buf.clear();
|
||||||
unsafe {
|
unsafe {
|
||||||
let r = libc::readlink(self.as_ptr(), buf.as_mut_ptr().cast(), buf.capacity() - 1)
|
let r = libc::readlink(self.as_ptr(), buf.as_mut_ptr(), buf.capacity() - 1)
|
||||||
.check_os_err()? as isize;
|
.check_os_err()? as isize;
|
||||||
*(buf.as_mut_ptr().offset(r) as *mut u8) = b'\0';
|
*(buf.as_mut_ptr().offset(r) as *mut u8) = b'\0';
|
||||||
buf.set_len(r as usize);
|
buf.set_len(r as usize);
|
||||||
@ -698,16 +706,7 @@ impl FsPath {
|
|||||||
libc::lstat(self.as_ptr(), &mut attr.st).as_os_err()?;
|
libc::lstat(self.as_ptr(), &mut attr.st).as_os_err()?;
|
||||||
|
|
||||||
#[cfg(feature = "selinux")]
|
#[cfg(feature = "selinux")]
|
||||||
{
|
self.get_secontext(&mut attr.con)?;
|
||||||
let sz = libc::lgetxattr(
|
|
||||||
self.as_ptr(),
|
|
||||||
XATTR_NAME_SELINUX.as_ptr().cast(),
|
|
||||||
attr.con.as_mut_ptr().cast(),
|
|
||||||
attr.con.capacity(),
|
|
||||||
)
|
|
||||||
.check_os_err()?;
|
|
||||||
attr.con.set_len((sz - 1) as usize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(attr)
|
Ok(attr)
|
||||||
}
|
}
|
||||||
@ -721,19 +720,43 @@ impl FsPath {
|
|||||||
|
|
||||||
#[cfg(feature = "selinux")]
|
#[cfg(feature = "selinux")]
|
||||||
if !attr.con.is_empty() {
|
if !attr.con.is_empty() {
|
||||||
libc::lsetxattr(
|
self.set_secontext(&attr.con)?;
|
||||||
self.as_ptr(),
|
|
||||||
XATTR_NAME_SELINUX.as_ptr().cast(),
|
|
||||||
attr.con.as_ptr().cast(),
|
|
||||||
attr.con.len() + 1,
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
.as_os_err()?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_secontext(&self, con: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
||||||
|
unsafe {
|
||||||
|
let sz = libc::lgetxattr(
|
||||||
|
self.as_ptr(),
|
||||||
|
XATTR_NAME_SELINUX.as_ptr().cast(),
|
||||||
|
con.as_mut_ptr().cast(),
|
||||||
|
con.capacity(),
|
||||||
|
)
|
||||||
|
.check_os_err()?;
|
||||||
|
if sz < 1 {
|
||||||
|
con.clear();
|
||||||
|
} else {
|
||||||
|
con.set_len((sz - 1) as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_secontext(&self, con: &Utf8CStr) -> io::Result<()> {
|
||||||
|
unsafe {
|
||||||
|
libc::lsetxattr(
|
||||||
|
self.as_ptr(),
|
||||||
|
XATTR_NAME_SELINUX.as_ptr().cast(),
|
||||||
|
con.as_ptr().cast(),
|
||||||
|
con.len() + 1,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.as_os_err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn copy_to(&self, path: &FsPath) -> io::Result<()> {
|
pub fn copy_to(&self, path: &FsPath) -> io::Result<()> {
|
||||||
let attr = self.get_attr()?;
|
let attr = self.get_attr()?;
|
||||||
if attr.is_dir() {
|
if attr.is_dir() {
|
||||||
|
@ -157,7 +157,7 @@ fn find_apk_path(pkg: &str, buf: &mut dyn Utf8CStrBuf) -> io::Result<()> {
|
|||||||
if !e.is_dir() {
|
if !e.is_dir() {
|
||||||
return Ok(Skip);
|
return Ok(Skip);
|
||||||
}
|
}
|
||||||
let name_bytes = e.d_name().to_bytes();
|
let name_bytes = e.name().to_bytes();
|
||||||
if name_bytes.starts_with(pkg.as_bytes()) && name_bytes[pkg.len()] == b'-' {
|
if name_bytes.starts_with(pkg.as_bytes()) && name_bytes[pkg.len()] == b'-' {
|
||||||
// Found the APK path, we can abort now
|
// Found the APK path, we can abort now
|
||||||
e.path(buf)?;
|
e.path(buf)?;
|
||||||
|
@ -162,7 +162,7 @@ pub fn persist_get_props(mut prop_cb: Pin<&mut PropCb>) {
|
|||||||
let mut dir = Directory::open(cstr!(PERSIST_PROP_DIR))?;
|
let mut dir = Directory::open(cstr!(PERSIST_PROP_DIR))?;
|
||||||
dir.pre_order_walk(|e| {
|
dir.pre_order_walk(|e| {
|
||||||
if e.is_file() {
|
if e.is_file() {
|
||||||
if let Ok(name) = Utf8CStr::from_cstr(e.d_name()) {
|
if let Ok(name) = Utf8CStr::from_cstr(e.name()) {
|
||||||
if let Ok(mut value) = file_get_prop(name) {
|
if let Ok(mut value) = file_get_prop(name) {
|
||||||
prop_cb.exec(name, Utf8CStr::from_string(&mut value));
|
prop_cb.exec(name, Utf8CStr::from_string(&mut value));
|
||||||
}
|
}
|
||||||
|
@ -25,3 +25,5 @@ pub const MODULEMNT: &str = concatcp!(INTERNAL_DIR, "/modules");
|
|||||||
pub const WORKERDIR: &str = concatcp!(INTERNAL_DIR, "/worker");
|
pub const WORKERDIR: &str = concatcp!(INTERNAL_DIR, "/worker");
|
||||||
pub const DEVICEDIR: &str = concatcp!(INTERNAL_DIR, "/device");
|
pub const DEVICEDIR: &str = concatcp!(INTERNAL_DIR, "/device");
|
||||||
pub const PREINITDEV: &str = concatcp!(DEVICEDIR, "/preinit");
|
pub const PREINITDEV: &str = concatcp!(DEVICEDIR, "/preinit");
|
||||||
|
pub const ROOTOVL: &str = concatcp!(INTERNAL_DIR, "/rootdir");
|
||||||
|
pub const ROOTMNT: &str = concatcp!(ROOTOVL, "/.mount_list");
|
||||||
|
@ -18,6 +18,7 @@ impl MagiskInit {
|
|||||||
Self {
|
Self {
|
||||||
preinit_dev: String::new(),
|
preinit_dev: String::new(),
|
||||||
mount_list: Vec::new(),
|
mount_list: Vec::new(),
|
||||||
|
overlay_con: Vec::new(),
|
||||||
argv,
|
argv,
|
||||||
config: BootConfig {
|
config: BootConfig {
|
||||||
skip_initramfs: false,
|
skip_initramfs: false,
|
||||||
|
@ -7,8 +7,10 @@ use logging::setup_klog;
|
|||||||
// Has to be pub so all symbols in that crate is included
|
// Has to be pub so all symbols in that crate is included
|
||||||
pub use magiskpolicy;
|
pub use magiskpolicy;
|
||||||
use mount::{is_device_mounted, switch_root};
|
use mount::{is_device_mounted, switch_root};
|
||||||
use rootdir::{collect_overlay_contexts, inject_magisk_rc, reset_overlay_contexts};
|
use rootdir::{inject_magisk_rc, OverlayAttr};
|
||||||
|
|
||||||
|
#[path = "../include/consts.rs"]
|
||||||
|
mod consts;
|
||||||
mod getinfo;
|
mod getinfo;
|
||||||
mod init;
|
mod init;
|
||||||
mod logging;
|
mod logging;
|
||||||
@ -43,6 +45,7 @@ pub mod ffi {
|
|||||||
mount_list: Vec<String>,
|
mount_list: Vec<String>,
|
||||||
argv: *mut *mut c_char,
|
argv: *mut *mut c_char,
|
||||||
config: BootConfig,
|
config: BootConfig,
|
||||||
|
overlay_con: Vec<OverlayAttr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C++" {
|
unsafe extern "C++" {
|
||||||
@ -62,8 +65,6 @@ pub mod ffi {
|
|||||||
fn inject_magisk_rc(fd: i32, tmp_dir: Utf8CStrRef);
|
fn inject_magisk_rc(fd: i32, tmp_dir: Utf8CStrRef);
|
||||||
fn switch_root(path: Utf8CStrRef);
|
fn switch_root(path: Utf8CStrRef);
|
||||||
fn is_device_mounted(dev: u64, target: Pin<&mut CxxString>) -> bool;
|
fn is_device_mounted(dev: u64, target: Pin<&mut CxxString>) -> bool;
|
||||||
fn collect_overlay_contexts(src: Utf8CStrRef);
|
|
||||||
fn reset_overlay_contexts();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BootConfig
|
// BootConfig
|
||||||
@ -78,8 +79,11 @@ pub mod ffi {
|
|||||||
|
|
||||||
// MagiskInit
|
// MagiskInit
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
|
type OverlayAttr;
|
||||||
fn patch_sepolicy(self: &MagiskInit, src: Utf8CStrRef, out: Utf8CStrRef);
|
fn patch_sepolicy(self: &MagiskInit, src: Utf8CStrRef, out: Utf8CStrRef);
|
||||||
fn parse_config_file(self: &mut MagiskInit);
|
fn parse_config_file(self: &mut MagiskInit);
|
||||||
|
fn mount_overlay(self: &mut MagiskInit, dest: Utf8CStrRef);
|
||||||
|
fn restore_overlay_contexts(self: &MagiskInit);
|
||||||
}
|
}
|
||||||
unsafe extern "C++" {
|
unsafe extern "C++" {
|
||||||
// Used in Rust
|
// Used in Rust
|
||||||
@ -93,5 +97,6 @@ pub mod ffi {
|
|||||||
fn mount_preinit_dir(self: &MagiskInit);
|
fn mount_preinit_dir(self: &MagiskInit);
|
||||||
unsafe fn find_block(self: &MagiskInit, partname: *const c_char) -> u64;
|
unsafe fn find_block(self: &MagiskInit, partname: *const c_char) -> u64;
|
||||||
fn hijack_sepolicy(self: &mut MagiskInit) -> bool;
|
fn hijack_sepolicy(self: &mut MagiskInit) -> bool;
|
||||||
|
unsafe fn patch_fissiond(self: &mut MagiskInit, tmp_path: *const c_char);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
static vector<string> rc_list;
|
static vector<string> rc_list;
|
||||||
static string magic_mount_list;
|
|
||||||
|
|
||||||
#define NEW_INITRC_DIR "/system/etc/init/hw"
|
#define NEW_INITRC_DIR "/system/etc/init/hw"
|
||||||
#define INIT_RC "init.rc"
|
#define INIT_RC "init.rc"
|
||||||
@ -43,33 +42,10 @@ static bool unxz(out_stream &strm, rust::Slice<const uint8_t> bytes) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void magic_mount(const string &sdir, const string &ddir = "") {
|
// When return true, run patch_fissiond
|
||||||
auto dir = xopen_dir(sdir.data());
|
static bool patch_rc_scripts(const char *src_path, const char *tmp_path, bool writable) {
|
||||||
if (!dir) return;
|
|
||||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
|
||||||
string src = sdir + "/" + entry->d_name;
|
|
||||||
string dest = ddir + "/" + entry->d_name;
|
|
||||||
if (access(dest.data(), F_OK) == 0) {
|
|
||||||
if (entry->d_type == DT_DIR) {
|
|
||||||
// Recursive
|
|
||||||
magic_mount(src, dest);
|
|
||||||
} else {
|
|
||||||
LOGD("Mount [%s] -> [%s]\n", src.data(), dest.data());
|
|
||||||
struct stat st;
|
|
||||||
xstat(dest.data(), &st);
|
|
||||||
chmod(src.data(), st.st_mode & 0777);
|
|
||||||
chown(src.data(), st.st_uid, st.st_gid);
|
|
||||||
xmount(src.data(), dest.data(), nullptr, MS_BIND, nullptr);
|
|
||||||
magic_mount_list += dest;
|
|
||||||
magic_mount_list += '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void patch_rc_scripts(const char *src_path, const char *tmp_path, bool writable) {
|
|
||||||
auto src_dir = xopen_dir(src_path);
|
auto src_dir = xopen_dir(src_path);
|
||||||
if (!src_dir) return;
|
if (!src_dir) return false;
|
||||||
int src_fd = dirfd(src_dir.get());
|
int src_fd = dirfd(src_dir.get());
|
||||||
|
|
||||||
// If writable, directly modify the file in src_path, or else add to rootfs overlay
|
// If writable, directly modify the file in src_path, or else add to rootfs overlay
|
||||||
@ -81,17 +57,17 @@ static void patch_rc_scripts(const char *src_path, const char *tmp_path, bool wr
|
|||||||
xmkdirs(buf, 0755);
|
xmkdirs(buf, 0755);
|
||||||
return xopen_dir(buf);
|
return xopen_dir(buf);
|
||||||
}();
|
}();
|
||||||
if (!dest_dir) return;
|
if (!dest_dir) return false;
|
||||||
int dest_fd = dirfd(dest_dir.get());
|
int dest_fd = dirfd(dest_dir.get());
|
||||||
|
|
||||||
// First patch init.rc
|
// First patch init.rc
|
||||||
{
|
{
|
||||||
auto src = xopen_file(xopenat(src_fd, INIT_RC, O_RDONLY | O_CLOEXEC, 0), "re");
|
auto src = xopen_file(xopenat(src_fd, INIT_RC, O_RDONLY | O_CLOEXEC, 0), "re");
|
||||||
if (!src) return;
|
if (!src) return false;
|
||||||
if (writable) unlinkat(src_fd, INIT_RC, 0);
|
if (writable) unlinkat(src_fd, INIT_RC, 0);
|
||||||
auto dest = xopen_file(
|
auto dest = xopen_file(
|
||||||
xopenat(dest_fd, INIT_RC, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0), "we");
|
xopenat(dest_fd, INIT_RC, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0), "we");
|
||||||
if (!dest) return;
|
if (!dest) return false;
|
||||||
LOGD("Patching " INIT_RC " in %s\n", src_path);
|
LOGD("Patching " INIT_RC " in %s\n", src_path);
|
||||||
file_readline(false, src.get(), [&dest](string_view line) -> bool {
|
file_readline(false, src.get(), [&dest](string_view line) -> bool {
|
||||||
// Do not start vaultkeeper
|
// Do not start vaultkeeper
|
||||||
@ -157,12 +133,19 @@ static void patch_rc_scripts(const char *src_path, const char *tmp_path, bool wr
|
|||||||
fclone_attr(fileno(src.get()), fileno(dest.get()));
|
fclone_attr(fileno(src.get()), fileno(dest.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (faccessat(src_fd, "init.fission_host.rc", F_OK, 0) == 0) {
|
return faccessat(src_fd, "init.fission_host.rc", F_OK, 0) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MagiskInit::patch_fissiond(const char *tmp_path) noexcept {
|
||||||
{
|
{
|
||||||
LOGD("Patching fissiond\n");
|
LOGD("Patching fissiond\n");
|
||||||
mmap_data fissiond("/system/bin/fissiond", false);
|
mmap_data fissiond("/system/bin/fissiond", false);
|
||||||
for (size_t off : fissiond.patch("ro.build.system.fission_single_os", "ro.build.system.xxxxxxxxxxxxxxxxx")) {
|
for (size_t off : fissiond.patch(
|
||||||
LOGD("Patch @ %08zX [ro.build.system.fission_single_os] -> [ro.build.system.xxxxxxxxxxxxxxxxx]\n", off);
|
"ro.build.system.fission_single_os",
|
||||||
|
"ro.build.system.xxxxxxxxxxxxxxxxx"))
|
||||||
|
{
|
||||||
|
LOGD("Patch @ %08zX [ro.build.system.fission_single_os] -> "
|
||||||
|
"[ro.build.system.xxxxxxxxxxxxxxxxx]\n", off);
|
||||||
}
|
}
|
||||||
mkdirs(ROOTOVL "/system/bin", 0755);
|
mkdirs(ROOTOVL "/system/bin", 0755);
|
||||||
if (auto target_fissiond = xopen_file(ROOTOVL "/system/bin/fissiond", "we")) {
|
if (auto target_fissiond = xopen_file(ROOTOVL "/system/bin/fissiond", "we")) {
|
||||||
@ -185,15 +168,12 @@ static void patch_rc_scripts(const char *src_path, const char *tmp_path, bool wr
|
|||||||
string target = "/dev/cells/cell2"s + tmp_path;
|
string target = "/dev/cells/cell2"s + tmp_path;
|
||||||
xmkdirs(target.data(), 0);
|
xmkdirs(target.data(), 0);
|
||||||
xmount(tmp_path, target.data(), nullptr, MS_BIND | MS_REC, nullptr);
|
xmount(tmp_path, target.data(), nullptr, MS_BIND | MS_REC, nullptr);
|
||||||
magic_mount(ROOTOVL, "/dev/cells/cell2");
|
mount_overlay("/dev/cells/cell2");
|
||||||
auto mount = xopen_file(ROOTMNT, "w");
|
|
||||||
fwrite(magic_mount_list.data(), 1, magic_mount_list.length(), mount.get());
|
|
||||||
}
|
}
|
||||||
fprintf(dest.get(), "%s", content.data());
|
fprintf(dest.get(), "%s", content.data());
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void load_overlay_rc(const char *overlay) {
|
static void load_overlay_rc(const char *overlay) {
|
||||||
auto dir = open_dir(overlay);
|
auto dir = open_dir(overlay);
|
||||||
@ -337,18 +317,18 @@ void MagiskInit::patch_ro_root() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Patch init.rc
|
// Patch init.rc
|
||||||
|
bool p;
|
||||||
if (access(NEW_INITRC_DIR "/" INIT_RC, F_OK) == 0) {
|
if (access(NEW_INITRC_DIR "/" INIT_RC, F_OK) == 0) {
|
||||||
// Android 11's new init.rc
|
// Android 11's new init.rc
|
||||||
patch_rc_scripts(NEW_INITRC_DIR, tmp_dir.data(), false);
|
p = patch_rc_scripts(NEW_INITRC_DIR, tmp_dir.data(), false);
|
||||||
} else {
|
} else {
|
||||||
patch_rc_scripts("/", tmp_dir.data(), false);
|
p = patch_rc_scripts("/", tmp_dir.data(), false);
|
||||||
}
|
}
|
||||||
|
if (p) patch_fissiond(tmp_dir.data());
|
||||||
|
|
||||||
// Extract overlay archives
|
// Extract overlay archives
|
||||||
extract_files(false);
|
extract_files(false);
|
||||||
|
|
||||||
rust::collect_overlay_contexts(ROOTOVL);
|
|
||||||
|
|
||||||
// Oculus Go will use a special sepolicy if unlocked
|
// Oculus Go will use a special sepolicy if unlocked
|
||||||
if (access("/sepolicy.unlocked", F_OK) == 0) {
|
if (access("/sepolicy.unlocked", F_OK) == 0) {
|
||||||
patch_sepolicy("/sepolicy.unlocked", ROOTOVL "/sepolicy.unlocked");
|
patch_sepolicy("/sepolicy.unlocked", ROOTOVL "/sepolicy.unlocked");
|
||||||
@ -361,10 +341,7 @@ void MagiskInit::patch_ro_root() noexcept {
|
|||||||
unlink("init-ld");
|
unlink("init-ld");
|
||||||
|
|
||||||
// Mount rootdir
|
// Mount rootdir
|
||||||
magic_mount(ROOTOVL);
|
mount_overlay("/");
|
||||||
int dest = xopen(ROOTMNT, O_WRONLY | O_CREAT, 0);
|
|
||||||
write(dest, magic_mount_list.data(), magic_mount_list.length());
|
|
||||||
close(dest);
|
|
||||||
|
|
||||||
chdir("/");
|
chdir("/");
|
||||||
}
|
}
|
||||||
@ -388,7 +365,8 @@ void MagiskInit::patch_rw_root() noexcept {
|
|||||||
rm_rf("/.backup");
|
rm_rf("/.backup");
|
||||||
|
|
||||||
// Patch init.rc
|
// Patch init.rc
|
||||||
patch_rc_scripts("/", "/sbin", true);
|
if (patch_rc_scripts("/", "/sbin", true))
|
||||||
|
patch_fissiond("/sbin");
|
||||||
|
|
||||||
bool treble;
|
bool treble;
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
use crate::consts::{ROOTMNT, ROOTOVL};
|
||||||
use crate::ffi::MagiskInit;
|
use crate::ffi::MagiskInit;
|
||||||
use base::libc::O_RDONLY;
|
use base::libc::{O_CREAT, O_RDONLY, O_WRONLY};
|
||||||
use base::{
|
use base::{
|
||||||
cstr_buf, debug, libc, path, BufReadExt, Directory, LibcReturn, LoggedResult, ResultExt,
|
clone_attr, cstr, cstr_buf, debug, libc, path, BufReadExt, Directory, FsPath, FsPathBuf,
|
||||||
Utf8CStr, Utf8CStrBuf, Utf8CStrBufArr, WalkResult,
|
LibcReturn, LoggedResult, ResultExt, Utf8CStr, Utf8CString,
|
||||||
};
|
};
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::{
|
use std::{
|
||||||
@ -10,80 +11,9 @@ use std::{
|
|||||||
io::Write,
|
io::Write,
|
||||||
mem,
|
mem,
|
||||||
os::fd::{FromRawFd, RawFd},
|
os::fd::{FromRawFd, RawFd},
|
||||||
sync::OnceLock,
|
ptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static OVERLAY_ATTRS: OnceLock<Vec<(String, String)>> = OnceLock::new();
|
|
||||||
|
|
||||||
const XATTR_NAME_SELINUX: &[u8] = b"security.selinux\0";
|
|
||||||
|
|
||||||
fn get_context<const N: usize>(path: &str, con: &mut Utf8CStrBufArr<N>) -> 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) {
|
pub fn inject_magisk_rc(fd: RawFd, tmp_dir: &Utf8CStr) {
|
||||||
debug!("Injecting magisk rc");
|
debug!("Injecting magisk rc");
|
||||||
|
|
||||||
@ -114,6 +44,8 @@ on property:init.svc.zygote=stopped
|
|||||||
mem::forget(file)
|
mem::forget(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct OverlayAttr(Utf8CString, Utf8CString);
|
||||||
|
|
||||||
impl MagiskInit {
|
impl MagiskInit {
|
||||||
pub(crate) fn parse_config_file(&mut self) {
|
pub(crate) fn parse_config_file(&mut self) {
|
||||||
if let Ok(fd) = path!("/data/.backup/.magisk").open(O_RDONLY) {
|
if let Ok(fd) = path!("/data/.backup/.magisk").open(O_RDONLY) {
|
||||||
@ -127,4 +59,64 @@ impl MagiskInit {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mount_impl(
|
||||||
|
&mut self,
|
||||||
|
src_dir: &Utf8CStr,
|
||||||
|
dest_dir: &Utf8CStr,
|
||||||
|
mount_list: &mut String,
|
||||||
|
) -> LoggedResult<()> {
|
||||||
|
let mut dir = Directory::open(src_dir)?;
|
||||||
|
let mut con = cstr_buf::default();
|
||||||
|
loop {
|
||||||
|
match &dir.read()? {
|
||||||
|
None => return Ok(()),
|
||||||
|
Some(e) => {
|
||||||
|
let name = e.name().to_str()?;
|
||||||
|
let src = FsPathBuf::new_dynamic(256).join(src_dir).join(name);
|
||||||
|
let dest = FsPathBuf::new_dynamic(256).join(dest_dir).join(name);
|
||||||
|
if dest.exists() {
|
||||||
|
if e.is_dir() {
|
||||||
|
// Recursive
|
||||||
|
self.mount_impl(&src, &dest, mount_list)?;
|
||||||
|
} else {
|
||||||
|
debug!("Mount [{}] -> [{}]", src, dest);
|
||||||
|
clone_attr(&dest, &src)?;
|
||||||
|
dest.get_secontext(&mut con)?;
|
||||||
|
unsafe {
|
||||||
|
libc::mount(
|
||||||
|
src.as_ptr(),
|
||||||
|
dest.as_ptr(),
|
||||||
|
ptr::null(),
|
||||||
|
libc::MS_BIND,
|
||||||
|
ptr::null(),
|
||||||
|
)
|
||||||
|
.as_os_err()?;
|
||||||
|
};
|
||||||
|
self.overlay_con
|
||||||
|
.push(OverlayAttr(dest.to_owned(), con.to_owned()));
|
||||||
|
mount_list.push_str(dest.as_str());
|
||||||
|
mount_list.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mount_overlay(&mut self, dest: &Utf8CStr) {
|
||||||
|
let mut mount_list = String::new();
|
||||||
|
self.mount_impl(cstr!(ROOTOVL), dest, &mut mount_list)
|
||||||
|
.log_ok();
|
||||||
|
if let Ok(mut fd) = path!(ROOTMNT).create(O_CREAT | O_WRONLY, 0) {
|
||||||
|
fd.write(mount_list.as_bytes()).log_ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn restore_overlay_contexts(&self) {
|
||||||
|
self.overlay_con.iter().for_each(|attr| {
|
||||||
|
let OverlayAttr(path, con) = attr;
|
||||||
|
FsPath::from(path).set_secontext(con).log_ok();
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ bool MagiskInit::hijack_sepolicy() noexcept {
|
|||||||
sepol.to_file(SELINUX_LOAD);
|
sepol.to_file(SELINUX_LOAD);
|
||||||
|
|
||||||
// restore mounted files' context after sepolicy loaded
|
// restore mounted files' context after sepolicy loaded
|
||||||
rust::reset_overlay_contexts();
|
restore_overlay_contexts();
|
||||||
|
|
||||||
// Write to the enforce node ONLY after sepolicy is loaded. We need to make sure
|
// Write to the enforce node ONLY after sepolicy is loaded. We need to make sure
|
||||||
// the actual init process is blocked until sepolicy is loaded, or else
|
// the actual init process is blocked until sepolicy is loaded, or else
|
||||||
|
Loading…
x
Reference in New Issue
Block a user