mirror of
https://github.com/topjohnwu/Magisk
synced 2024-11-17 01:48:37 +01:00
Refactor sepolicy.rules resolve
We resolve available partitions for sepolicy.rules when patching boot and bind mount the partition by magiskinit. For older devices, the previous logic won't work because the part name is never readable. Co-authored-by: topjohnwu <topjohnwu@gmail.com>
This commit is contained in:
parent
03418ddcbf
commit
9e8c68af12
@ -1,5 +1,9 @@
|
||||
use std::ffi::CStr;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::BufRead;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd};
|
||||
use std::path::Path;
|
||||
|
||||
use libc::{c_char, c_uint, mode_t, EEXIST, ENOENT, O_CLOEXEC, O_PATH};
|
||||
|
||||
@ -131,3 +135,8 @@ pub extern "C" fn mkdirs(path: *const c_char, mode: mode_t) -> i32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_lines<P: AsRef<Path>>(path: P) -> io::Result<io::Lines<io::BufReader<File>>> {
|
||||
let file = File::open(path)?;
|
||||
Ok(io::BufReader::new(file).lines())
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
extern std::string MAGISKTMP;
|
||||
#define INTLROOT ".magisk"
|
||||
#define MIRRDIR INTLROOT "/mirror"
|
||||
#define RULESDIR MIRRDIR "/sepolicy.rules"
|
||||
#define RULESDIR INTLROOT "/sepolicy.rules"
|
||||
#define BLOCKDIR INTLROOT "/block"
|
||||
#define WORKERDIR INTLROOT "/worker"
|
||||
#define MODULEMNT INTLROOT "/modules"
|
||||
|
@ -83,6 +83,9 @@ int main(int argc, char *argv[]) {
|
||||
if (name == "magisk"sv)
|
||||
return magisk_proxy_main(argc, argv);
|
||||
|
||||
if (name == "magiskinit"sv && argc == 2 && argv[1] == "--rules-device"sv)
|
||||
return rust::print_rules_device();
|
||||
|
||||
if (getpid() != 1)
|
||||
return 1;
|
||||
|
||||
|
@ -59,7 +59,6 @@ class MagiskInit : public BaseInit {
|
||||
private:
|
||||
void mount_rules_dir();
|
||||
protected:
|
||||
std::string custom_rules_dir;
|
||||
|
||||
#if ENABLE_AVD_HACK
|
||||
// When this boolean is set, this means we are currently
|
||||
|
@ -1,4 +1,9 @@
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
pub use base;
|
||||
use base::libc::{dev_t, makedev};
|
||||
use base::read_lines;
|
||||
pub use logging::*;
|
||||
|
||||
mod logging;
|
||||
@ -7,5 +12,74 @@ mod logging;
|
||||
pub mod ffi2 {
|
||||
extern "Rust" {
|
||||
fn setup_klog();
|
||||
fn print_rules_device() -> i32;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_rules_device() -> i32 {
|
||||
const UNKNOWN: i32 = 0;
|
||||
const PERSIST: i32 = UNKNOWN + 1;
|
||||
const METADATA: i32 = PERSIST + 1;
|
||||
const CACHE: i32 = METADATA + 1;
|
||||
const UNENCRYPTED: i32 = CACHE + 1;
|
||||
const DATA: i32 = UNENCRYPTED + 1;
|
||||
const EXISTING: i32 = DATA + 1;
|
||||
|
||||
let encrypted = env::var("ISENCRYPTED").map_or(false, |var| var == "true");
|
||||
|
||||
let mut matched = UNKNOWN;
|
||||
let mut rules_dev: dev_t = 0;
|
||||
|
||||
if let Ok(lines) = read_lines("/proc/self/mountinfo") {
|
||||
for line in lines {
|
||||
if let Ok(line) = line {
|
||||
let new_matched;
|
||||
if line.contains("/.magisk/sepolicy.rules ") {
|
||||
new_matched = EXISTING;
|
||||
} else if line.contains(" - ext4 ") && !line.contains("/dm-") {
|
||||
if line.contains(" / /cache ") && matched < CACHE {
|
||||
new_matched = CACHE;
|
||||
} else if line.contains(" / /data ") && matched < DATA {
|
||||
if !encrypted {
|
||||
new_matched = UNENCRYPTED;
|
||||
} else if Path::new("/data/unencrypted").is_dir() {
|
||||
new_matched = DATA;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else if line.contains(" / /metadata ") && matched < METADATA {
|
||||
new_matched = METADATA;
|
||||
} else if (line.contains(" / /persist ")
|
||||
|| line.contains(" / /mnt/vendor/persist "))
|
||||
&& matched < PERSIST
|
||||
{
|
||||
new_matched = PERSIST;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if let Some(device) = line.splitn(4, ' ').nth(2) {
|
||||
device.split_once(':').map(|(a, b)| {
|
||||
a.parse::<i32>().ok().map(|a| {
|
||||
b.parse::<i32>().ok().map(|b| {
|
||||
rules_dev = unsafe { makedev(a, b) };
|
||||
matched = new_matched;
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if matched > UNKNOWN {
|
||||
println!("{rules_dev}");
|
||||
return 0;
|
||||
} else {
|
||||
eprintln!("Failed to find sepolicy rules partition");
|
||||
}
|
||||
} else {
|
||||
eprintln!("Error reading /proc/self/mountinfo");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <sys/mount.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <libgen.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <base.hpp>
|
||||
#include <selinux.hpp>
|
||||
@ -117,99 +118,32 @@ static void switch_root(const string &path) {
|
||||
}
|
||||
|
||||
void MagiskInit::mount_rules_dir() {
|
||||
char path[128];
|
||||
xrealpath(BLOCKDIR, blk_info.block_dev, sizeof(blk_info.block_dev));
|
||||
xrealpath(MIRRDIR, path, sizeof(path));
|
||||
char *b = blk_info.block_dev + strlen(blk_info.block_dev);
|
||||
char *p = path + strlen(path);
|
||||
|
||||
auto do_mount = [&](const char *type) -> bool {
|
||||
xmkdir(path, 0755);
|
||||
bool success = xmount(blk_info.block_dev, path, type, 0, nullptr) == 0;
|
||||
if (success)
|
||||
mount_list.emplace_back(path);
|
||||
return success;
|
||||
};
|
||||
|
||||
// First try userdata
|
||||
strcpy(blk_info.partname, "userdata");
|
||||
strcpy(b, "/data");
|
||||
strcpy(p, "/data");
|
||||
if (setup_block() < 0) {
|
||||
// Try NVIDIA naming scheme
|
||||
strcpy(blk_info.partname, "UDA");
|
||||
if (setup_block() < 0)
|
||||
goto cache;
|
||||
}
|
||||
// WARNING: DO NOT ATTEMPT TO MOUNT F2FS AS IT MAY CRASH THE KERNEL
|
||||
// Failure means either f2fs, FDE, or metadata encryption
|
||||
if (!do_mount("ext4"))
|
||||
goto cache;
|
||||
|
||||
strcpy(p, "/data/unencrypted");
|
||||
if (xaccess(path, F_OK) == 0) {
|
||||
// FBE, need to use an unencrypted path
|
||||
custom_rules_dir = path + "/magisk"s;
|
||||
} else {
|
||||
// Skip if /data/adb does not exist
|
||||
strcpy(p, SECURE_DIR);
|
||||
if (xaccess(path, F_OK) != 0)
|
||||
return;
|
||||
strcpy(p, MODULEROOT);
|
||||
if (xaccess(path, F_OK) != 0) {
|
||||
goto cache;
|
||||
dev_t rules_dev = 0;
|
||||
parse_prop_file(".backup/.magisk", [&rules_dev](auto key, auto value) -> bool {
|
||||
if (key == "RULESDEVICE") {
|
||||
sscanf(value.data(), "%" PRIuPTR, &rules_dev);
|
||||
return false;
|
||||
}
|
||||
// Unencrypted, directly use module paths
|
||||
custom_rules_dir = string(path);
|
||||
}
|
||||
goto success;
|
||||
|
||||
cache:
|
||||
// Fallback to cache
|
||||
strcpy(blk_info.partname, "cache");
|
||||
strcpy(b, "/cache");
|
||||
strcpy(p, "/cache");
|
||||
if (setup_block() < 0) {
|
||||
// Try NVIDIA naming scheme
|
||||
strcpy(blk_info.partname, "CAC");
|
||||
if (setup_block() < 0)
|
||||
goto metadata;
|
||||
}
|
||||
if (!do_mount("ext4"))
|
||||
goto metadata;
|
||||
custom_rules_dir = path + "/magisk"s;
|
||||
goto success;
|
||||
|
||||
metadata:
|
||||
// Fallback to metadata
|
||||
strcpy(blk_info.partname, "metadata");
|
||||
strcpy(b, "/metadata");
|
||||
strcpy(p, "/metadata");
|
||||
if (setup_block() < 0 || !do_mount("ext4"))
|
||||
goto persist;
|
||||
custom_rules_dir = path + "/magisk"s;
|
||||
goto success;
|
||||
|
||||
persist:
|
||||
// Fallback to persist
|
||||
strcpy(blk_info.partname, "persist");
|
||||
strcpy(b, "/persist");
|
||||
strcpy(p, "/persist");
|
||||
if (setup_block() < 0 || !do_mount("ext4"))
|
||||
return;
|
||||
custom_rules_dir = path + "/magisk"s;
|
||||
|
||||
success:
|
||||
// Create symlinks so we don't need to go through this logic again
|
||||
strcpy(p, "/sepolicy.rules");
|
||||
if (char *rel = strstr(custom_rules_dir.data(), MIRRDIR)) {
|
||||
// Create symlink with relative path
|
||||
char s[128];
|
||||
s[0] = '.';
|
||||
strscpy(s + 1, rel + sizeof(MIRRDIR) - 1, sizeof(s) - 1);
|
||||
xsymlink(s, path);
|
||||
} else {
|
||||
xsymlink(custom_rules_dir.data(), path);
|
||||
return true;
|
||||
});
|
||||
if (!rules_dev) return;
|
||||
xmknod(BLOCKDIR "/rules", S_IFBLK | 0600, rules_dev);
|
||||
xmkdir(MIRRDIR "/rules", 0);
|
||||
if (xmount(BLOCKDIR "/rules", MIRRDIR "/rules", "ext4", 0, nullptr) == 0) {
|
||||
string custom_rules_dir = MIRRDIR "/rules";
|
||||
if (access((custom_rules_dir + "/unencrypted").data(), F_OK) == 0) {
|
||||
custom_rules_dir += "/unencrypted/magisk";
|
||||
} else if (access((custom_rules_dir + "/adb").data(), F_OK) == 0) {
|
||||
custom_rules_dir += "/adb/modules";
|
||||
} else {
|
||||
custom_rules_dir += "/magisk";
|
||||
}
|
||||
// Create bind mount
|
||||
xmkdirs(RULESDIR, 0);
|
||||
xmkdirs(custom_rules_dir.data(), 0700);
|
||||
LOGD("sepolicy.rules: %s -> %s\n", custom_rules_dir.data(), RULESDIR);
|
||||
xmount(custom_rules_dir.data(), RULESDIR, nullptr, MS_BIND, nullptr);
|
||||
xumount2(MIRRDIR "/rules", MNT_DETACH);
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,7 +257,7 @@ void MagiskInit::setup_tmp(const char *path) {
|
||||
xsymlink("./magisk", applet_names[i]);
|
||||
xsymlink("./magiskpolicy", "supolicy");
|
||||
|
||||
xmount(".", path, nullptr, MS_BIND, nullptr);
|
||||
xmount(".", path, nullptr, MS_BIND | MS_REC, nullptr);
|
||||
|
||||
chdir("/");
|
||||
}
|
||||
|
@ -267,7 +267,8 @@ void RootFSInit::prepare() {
|
||||
rename(backup_init(), "/init");
|
||||
}
|
||||
|
||||
#define PRE_TMPDIR "/magisk-tmp"
|
||||
#define PRE_TMPSRC "/magisk"
|
||||
#define PRE_TMPDIR PRE_TMPSRC "/tmp"
|
||||
|
||||
void MagiskInit::patch_rw_root() {
|
||||
mount_list.emplace_back("/data");
|
||||
@ -292,6 +293,8 @@ void MagiskInit::patch_rw_root() {
|
||||
treble = init.contains(SPLIT_PLAT_CIL);
|
||||
}
|
||||
|
||||
xmkdir(PRE_TMPSRC, 0);
|
||||
xmount("tmpfs", PRE_TMPSRC, "tmpfs", 0, "mode=755");
|
||||
xmkdir(PRE_TMPDIR, 0);
|
||||
setup_tmp(PRE_TMPDIR);
|
||||
chdir(PRE_TMPDIR);
|
||||
@ -319,10 +322,12 @@ int magisk_proxy_main(int argc, char *argv[]) {
|
||||
unlink("/sbin/magisk");
|
||||
|
||||
// Move tmpfs to /sbin
|
||||
// For some reason MS_MOVE won't work, as a workaround bind mount then unmount
|
||||
xmount(PRE_TMPDIR, "/sbin", nullptr, MS_BIND | MS_REC, nullptr);
|
||||
xumount2(PRE_TMPDIR, MNT_DETACH);
|
||||
// make parent private before MS_MOVE
|
||||
xmount(nullptr, PRE_TMPSRC, nullptr, MS_PRIVATE, nullptr);
|
||||
xmount(PRE_TMPDIR, "/sbin", nullptr, MS_MOVE, nullptr);
|
||||
xumount2(PRE_TMPSRC, MNT_DETACH);
|
||||
rmdir(PRE_TMPDIR);
|
||||
rmdir(PRE_TMPSRC);
|
||||
|
||||
// Create symlinks pointing back to /root
|
||||
recreate_sbin("/root", false);
|
||||
|
@ -15,14 +15,14 @@ void MagiskInit::patch_sepolicy(const char *in, const char *out) {
|
||||
sepol->magisk_rules();
|
||||
|
||||
// Custom rules
|
||||
if (!custom_rules_dir.empty()) {
|
||||
if (auto dir = xopen_dir(custom_rules_dir.data())) {
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
auto rule = custom_rules_dir + "/" + entry->d_name + "/sepolicy.rule";
|
||||
if (xaccess(rule.data(), R_OK) == 0) {
|
||||
LOGD("Loading custom sepolicy patch: [%s]\n", rule.data());
|
||||
sepol->load_rule_file(rule.data());
|
||||
}
|
||||
if (auto dir = xopen_dir(RULESDIR)) {
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
auto rule = RULESDIR "/"s + entry->d_name + "/sepolicy.rule";
|
||||
if (xaccess(rule.data(), R_OK) == 0 &&
|
||||
access((RULESDIR "/"s + entry->d_name + "/disable").data(), F_OK) != 0 &&
|
||||
access((RULESDIR "/"s + entry->d_name + "/remove").data(), F_OK) != 0) {
|
||||
LOGD("Loading custom sepolicy patch: [%s]\n", rule.data());
|
||||
sepol->load_rule_file(rule.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,19 +96,18 @@ bool MagiskInit::hijack_sepolicy() {
|
||||
|
||||
// Read all custom rules into memory
|
||||
string rules;
|
||||
if (!custom_rules_dir.empty()) {
|
||||
if (auto dir = xopen_dir(custom_rules_dir.data())) {
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
auto rule_file = custom_rules_dir + "/" + entry->d_name + "/sepolicy.rule";
|
||||
if (xaccess(rule_file.data(), R_OK) == 0) {
|
||||
LOGD("Load custom sepolicy patch: [%s]\n", rule_file.data());
|
||||
full_read(rule_file.data(), rules);
|
||||
rules += '\n';
|
||||
}
|
||||
if (auto dir = xopen_dir(RULESDIR)) {
|
||||
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
||||
auto rule_file = RULESDIR "/"s + entry->d_name + "/sepolicy.rule";
|
||||
if (xaccess(rule_file.data(), R_OK) == 0 &&
|
||||
access((RULESDIR "/"s + entry->d_name + "/disable").data(), F_OK) != 0 &&
|
||||
access((RULESDIR "/"s + entry->d_name + "/remove").data(), F_OK) != 0) {
|
||||
LOGD("Load custom sepolicy patch: [%s]\n", rule_file.data());
|
||||
full_read(rule_file.data(), rules);
|
||||
rules += '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new process waiting for init operations
|
||||
if (xfork()) {
|
||||
// In parent, return and continue boot process
|
||||
|
@ -59,6 +59,8 @@ cp ramdisk.cpio ramdisk.cpio.orig
|
||||
|
||||
touch config
|
||||
|
||||
echo "RULESDEVICE=$(ISENCRYPTED=true ./magiskinit --rules-device)" >> config
|
||||
|
||||
# For API 28, we also patch advancedFeatures.ini to disable SAR
|
||||
# Manually override skip_initramfs by setting RECOVERYMODE=true
|
||||
[ $API = "28" ] && echo 'RECOVERYMODE=true' >> config
|
||||
|
@ -73,12 +73,16 @@ fi
|
||||
[ -z $KEEPFORCEENCRYPT ] && KEEPFORCEENCRYPT=false
|
||||
[ -z $PATCHVBMETAFLAG ] && PATCHVBMETAFLAG=false
|
||||
[ -z $RECOVERYMODE ] && RECOVERYMODE=false
|
||||
[ -z $ISENCRYPTED ] && ISENCRYPTED=false
|
||||
export KEEPVERITY
|
||||
export KEEPFORCEENCRYPT
|
||||
export PATCHVBMETAFLAG
|
||||
export ISENCRYPTED
|
||||
|
||||
chmod -R 755 .
|
||||
|
||||
RULESDEVICE="$(./magiskinit --rules-device)" || abort "! Unable to find rules partition!"
|
||||
|
||||
#########
|
||||
# Unpack
|
||||
#########
|
||||
@ -152,6 +156,7 @@ echo "KEEPVERITY=$KEEPVERITY" > config
|
||||
echo "KEEPFORCEENCRYPT=$KEEPFORCEENCRYPT" >> config
|
||||
echo "PATCHVBMETAFLAG=$PATCHVBMETAFLAG" >> config
|
||||
echo "RECOVERYMODE=$RECOVERYMODE" >> config
|
||||
echo "RULESDEVICE=$RULESDEVICE" >> config
|
||||
[ ! -z $SHA1 ] && echo "SHA1=$SHA1" >> config
|
||||
|
||||
# Compress to save precious ramdisk space
|
||||
|
@ -637,37 +637,14 @@ run_migrations() {
|
||||
}
|
||||
|
||||
copy_sepolicy_rules() {
|
||||
# Remove all existing rule folders
|
||||
rm -rf /data/unencrypted/magisk /cache/magisk /metadata/magisk /persist/magisk /mnt/vendor/persist/magisk
|
||||
|
||||
# Find current active RULESDIR
|
||||
local RULESDIR
|
||||
local ACTIVEDIR=$(magisk --path)/.magisk/mirror/sepolicy.rules
|
||||
if [ -L $ACTIVEDIR ]; then
|
||||
RULESDIR=$(readlink $ACTIVEDIR)
|
||||
[ "${RULESDIR:0:1}" != "/" ] && RULESDIR="$(magisk --path)/.magisk/mirror/$RULESDIR"
|
||||
elif ! $ISENCRYPTED; then
|
||||
RULESDIR=$NVBASE/modules
|
||||
elif [ -d /data/unencrypted ] && ! grep ' /data ' /proc/mounts | grep -qE 'dm-|f2fs'; then
|
||||
RULESDIR=/data/unencrypted/magisk
|
||||
elif grep ' /cache ' /proc/mounts | grep -q 'ext4' ; then
|
||||
RULESDIR=/cache/magisk
|
||||
elif grep ' /metadata ' /proc/mounts | grep -q 'ext4' ; then
|
||||
RULESDIR=/metadata/magisk
|
||||
elif grep ' /persist ' /proc/mounts | grep -q 'ext4' ; then
|
||||
RULESDIR=/persist/magisk
|
||||
elif grep ' /mnt/vendor/persist ' /proc/mounts | grep -q 'ext4' ; then
|
||||
RULESDIR=/mnt/vendor/persist/magisk
|
||||
else
|
||||
local RULESDIR=$(magisk --path)/.magisk/sepolicy.rules
|
||||
if ! grep -q " $RULESDIR " /proc/mounts; then
|
||||
ui_print "- Unable to find sepolicy rules dir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -d ${RULESDIR%/magisk} ]; then
|
||||
echo "RULESDIR=$RULESDIR" >&2
|
||||
else
|
||||
ui_print "- Unable to find sepolicy rules dir ${RULESDIR%/magisk}"
|
||||
return 1
|
||||
if ! grep -q "/adb/modules $RULESDIR " /proc/self/mountinfo; then
|
||||
rm -rf $RULESDIR/*
|
||||
fi
|
||||
|
||||
# Copy all enabled sepolicy.rule
|
||||
|
Loading…
Reference in New Issue
Block a user