Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor magic mount #7685

Merged
merged 5 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/src/main/java/com/topjohnwu/magisk/core/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.app.Application
import android.content.Context
import android.content.res.Configuration
import android.os.Bundle
import android.system.Os
import androidx.profileinstaller.ProfileInstaller
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.StubApk
Expand Down Expand Up @@ -46,6 +47,8 @@ open class App() : Application() {
Timber.e(e)
exitProcess(1)
}

Os.setenv("PATH", "${Os.getenv("PATH")}:/debug_ramdisk:/sbin", true)
}

override fun attachBaseContext(context: Context) {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/raw/manager.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ env_check() {
[ -f "$MAGISKBIN/magiskpolicy" ] || return 1
fi
if [ "$2" -ge 25210 ]; then
[ -b "$MAGISKTMP/.magisk/block/preinit" ] || return 2
[ -b "$MAGISKTMP/.magisk/device/preinit" ] || [ -b "$MAGISKTMP/.magisk/block/preinit" ] || return 2
fi
grep -xqF "MAGISK_VER='$1'" "$MAGISKBIN/util_functions.sh" || return 3
grep -xqF "MAGISK_VER_CODE=$2" "$MAGISKBIN/util_functions.sh" || return 3
Expand Down
111 changes: 40 additions & 71 deletions native/src/core/bootstages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,17 @@ bool zygisk_enabled = false;
/*********
* Setup *
*********/

static bool rec_mount(const std::string_view from, const std::string_view to) {
return !xmkdirs(to.data(), 0755) &&
// recursively bind mount to mirror dir, rootfs will fail before 3.12 kernel
// because of MS_NOUSER
!mount(from.data(), to.data(), nullptr, MS_BIND | MS_REC, nullptr);
}

static void mount_mirrors() {
LOGI("* Mounting mirrors\n");
static void setup_mounts() {
LOGI("* Magic mount setup\n");
auto self_mount_info = parse_mount_info("self");
char path[64];
char path[PATH_MAX];

// Bind remount module root to clear nosuid
if (access(SECURE_DIR, F_OK) == 0 || SDK_INT < 24) {
ssprintf(path, sizeof(path), "%s/" MODULEMNT, get_magisk_tmp());
xmkdir(SECURE_DIR, 0700);
xmkdir(MODULEROOT, 0755);
xmkdir(path, 0755);
xmount(MODULEROOT, path, nullptr, MS_BIND, nullptr);
xmount(nullptr, path, nullptr, MS_REMOUNT | MS_BIND | MS_RDONLY, nullptr);
xmount(nullptr, path, nullptr, MS_PRIVATE, nullptr);
chmod(SECURE_DIR, 0700);
}
ssprintf(path, sizeof(path), "%s/" MODULEMNT, get_magisk_tmp());
xmkdir(path, 0755);
xmount(MODULEROOT, path, nullptr, MS_BIND, nullptr);
xmount(nullptr, path, nullptr, MS_REMOUNT | MS_BIND | MS_RDONLY, nullptr);
xmount(nullptr, path, nullptr, MS_PRIVATE, nullptr);

// Check and mount preinit mirror
char dev_path[64];
Expand All @@ -65,8 +52,9 @@ static void mount_mirrors() {
if (!rw) continue;
string preinit_dir = resolve_preinit_dir(info.target.data());
xmkdir(preinit_dir.data(), 0700);
if ((mounted = rec_mount(preinit_dir, path))) {
xmount(nullptr, path, nullptr, MS_UNBINDABLE, nullptr);
xmkdirs(path, 0755);
mounted = xmount(preinit_dir.data(), path, nullptr, MS_BIND, nullptr) == 0;
if (mounted) {
break;
}
}
Expand All @@ -79,29 +67,9 @@ static void mount_mirrors() {

// Prepare worker
ssprintf(path, sizeof(path), "%s/" WORKERDIR, get_magisk_tmp());
xmount("worker", path, "tmpfs", 0, "mode=755");
xmkdir(path, 0);
xmount(path, path, nullptr, MS_BIND, nullptr);
xmount(nullptr, path, nullptr, MS_PRIVATE, nullptr);
// Recursively bind mount / to mirror dir
// Keep mirror shared so that mounting during post-fs-data will be propagated
if (auto mirror_dir = get_magisk_tmp() + "/"s MIRRDIR; !rec_mount("/", mirror_dir)) {
LOGI("fallback to mount subtree\n");
// create new a bind mount for easy make private
xmount(mirror_dir.data(), mirror_dir.data(), nullptr, MS_BIND, nullptr);
// rootfs may fail, fallback to bind mount each mount point
set<string, greater<>> mounted_dirs {{ get_magisk_tmp() }};
for (const auto &info: self_mount_info) {
if (info.type == "rootfs"sv) continue;
// the greatest mount point that less than info.target, which is possibly a parent
if (auto last_mount = mounted_dirs.upper_bound(info.target);
last_mount != mounted_dirs.end() && info.target.starts_with(*last_mount + '/')) {
continue;
}
if (rec_mount(info.target, mirror_dir + info.target)) {
LOGD("%-8s: %s <- %s\n", "rbind", (mirror_dir + info.target).data(), info.target.data());
mounted_dirs.insert(info.target);
}
}
}
}

string find_preinit_device() {
Expand Down Expand Up @@ -208,10 +176,10 @@ static bool magisk_env() {

LOGI("* Initializing Magisk environment\n");

preserve_stub_apk();

// Directories in /data/adb
chmod(SECURE_DIR, 0700);
xmkdir(DATABIN, 0755);
xmkdir(MODULEROOT, 0755);
xmkdir(SECURE_DIR "/post-fs-data.d", 0755);
xmkdir(SECURE_DIR "/service.d", 0755);
restorecon();
Expand Down Expand Up @@ -302,54 +270,55 @@ static bool check_key_combo() {
* Boot Stage Handlers *
***********************/

extern int disable_deny();
static void disable_zygisk() {
char sql[64];
sprintf(sql, "REPLACE INTO settings (key,value) VALUES('%s',%d)",
DB_SETTING_KEYS[ZYGISK_CONFIG], false);
char *err = db_exec(sql);
db_err(err);
}

bool MagiskD::post_fs_data() const {
as_rust().setup_logfile();

LOGI("** post-fs-data mode running\n");

unlock_blocks();
mount_mirrors();
preserve_stub_apk();
prune_su_access();

bool safe_mode = false;

if (access(SECURE_DIR, F_OK) != 0) {
LOGE(SECURE_DIR " is not present, abort\n");
goto early_abort;
if (SDK_INT < 24) {
xmkdir(SECURE_DIR, 0700);
} else {
LOGE(SECURE_DIR " is not present, abort\n");
return safe_mode;
}
}

if (!magisk_env()) {
LOGE("* Magisk environment incomplete, abort\n");
goto early_abort;
return safe_mode;
}

if (get_prop("persist.sys.safemode", true) == "1" ||
get_prop("ro.sys.safemode") == "1" || check_key_combo()) {
safe_mode = true;
// Disable all modules and denylist so next boot will be clean
// Disable all modules and zygisk so next boot will be clean
disable_modules();
disable_deny();
} else {
exec_common_scripts("post-fs-data");
db_settings dbs;
get_db_settings(dbs, ZYGISK_CONFIG);
zygisk_enabled = dbs[ZYGISK_CONFIG];
initialize_denylist();
handle_modules();
disable_zygisk();
return safe_mode;
}

early_abort:
auto mirror_dir = get_magisk_tmp() + "/"s MIRRDIR;
// make mirror dir as a private mount so that it won't be affected by magic mount
LOGD("make %s private\n", mirror_dir.data());
xmount(nullptr, mirror_dir.data(), nullptr, MS_PRIVATE | MS_REC, nullptr);
// We still do magic mount because root itself might need it
exec_common_scripts("post-fs-data");
db_settings dbs;
get_db_settings(dbs, ZYGISK_CONFIG);
zygisk_enabled = dbs[ZYGISK_CONFIG];
initialize_denylist();
setup_mounts();
handle_modules();
load_modules();
// make mirror dir as a shared mount to make magisk --stop work for other ns
xmount(nullptr, mirror_dir.data(), nullptr, MS_SHARED | MS_REC, nullptr);
LOGD("make %s shared\n", mirror_dir.data());
return safe_mode;
}

Expand Down
7 changes: 0 additions & 7 deletions native/src/core/daemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,13 +391,6 @@ static void daemon_entry() {
ssprintf(path, sizeof(path), "%s/" ROOTOVL, tmp);
rm_rf(path);

// Unshare magiskd
xunshare(CLONE_NEWNS);
// Hide magisk internal mount point
xmount(nullptr, tmp, nullptr, MS_PRIVATE | MS_REC, nullptr);
// Fix sdcardfs bug on old kernel
xmount(nullptr, "/mnt", nullptr, MS_SLAVE | MS_REC, nullptr);

// Use isolated devpts if kernel support
if (access("/dev/pts/ptmx", F_OK) == 0) {
ssprintf(path, sizeof(path), "%s/" SHELLPTS, tmp);
Expand Down
2 changes: 1 addition & 1 deletion native/src/core/deny/revert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ void revert_unmount() {
// Unmount dummy skeletons and MAGISKTMP
// since mirror nodes are always mounted under skeleton, we don't have to specifically unmount
for (auto &info: parse_mount_info("self")) {
if (info.source == "magisk" || info.source == "worker" || // magisktmp tmpfs
if (info.source == "magisk" || // magisktmp tmpfs
info.root.starts_with("/adb/modules")) { // bind mount from data partition
targets.insert(info.target);
}
Expand Down
54 changes: 23 additions & 31 deletions native/src/core/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,26 @@ static int bind_mount(const char *reason, const char *from, const char *to) {
*************************/

tmpfs_node::tmpfs_node(node_entry *node) : dir_node(node, this) {
if (!skip_mirror()) {
string mirror = mirror_path();
if (auto dir = open_dir(mirror.data())) {
if (!replace()) {
if (auto dir = open_dir(node_path().data())) {
set_exist(true);
for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (entry->d_type == DT_DIR) {
// create a dummy inter_node to upgrade later
emplace<inter_node>(entry->d_name, entry->d_name);
} else {
// Insert mirror nodes
emplace<mirror_node>(entry->d_name, entry);
}
// create a dummy inter_node to upgrade later
emplace<inter_node>(entry->d_name, entry);
}
}
}

for (auto it = children.begin(); it != children.end(); ++it) {
// Need to upgrade all inter_node children to tmpfs_node
// Upgrade resting inter_node children to tmpfs_node
if (isa<inter_node>(it->second))
it = upgrade<tmpfs_node>(it);
}
}

bool dir_node::prepare() {
// If direct replace or not exist, mount ourselves as tmpfs
bool upgrade_to_tmpfs = skip_mirror() || !exist();
bool upgrade_to_tmpfs = replace() || !exist();

for (auto it = children.begin(); it != children.end();) {
// We also need to upgrade to tmpfs node if any child:
Expand All @@ -77,9 +71,9 @@ bool dir_node::prepare() {
upgrade_to_tmpfs = true;
}
if (auto dn = dyn_cast<dir_node>(it->second)) {
if (skip_mirror()) {
if (replace()) {
// Propagate skip mirror state to all children
dn->set_skip_mirror(true);
dn->set_replace(true);
}
if (dn->prepare()) {
// Upgrade child to tmpfs
Expand All @@ -98,7 +92,7 @@ void dir_node::collect_module_files(const char *module, int dfd) {

for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (entry->d_name == ".replace"sv) {
set_skip_mirror(true);
set_replace(true);
continue;
}

Expand Down Expand Up @@ -141,18 +135,12 @@ void node_entry::create_and_mount(const char *reason, const string &src, bool ro
}
}

void mirror_node::mount() {
create_and_mount("mirror", mirror_path());
}

void module_node::mount() {
std::string path = module + (parent()->root()->prefix + node_path());
string mnt_src = module_mnt + path;
{
string src = MODULEROOT "/" + path;
if (exist()) clone_attr(mirror_path().data(), src.data());
// special case for /system/etc/hosts to ensure it is writable
if (node_path() == "/system/etc/hosts") mnt_src = std::move(src);
if (exist()) clone_attr(node_path().data(), src.data());
}
if (isa<tmpfs_node>(parent())) {
create_and_mount("module", mnt_src);
Expand All @@ -162,22 +150,24 @@ void module_node::mount() {
}

void tmpfs_node::mount() {
string src = mirror_path();
const char *src_path = access(src.data(), F_OK) == 0 ? src.data() : nullptr;
if (!is_dir()) {
create_and_mount("mirror", node_path());
return;
}
if (!isa<tmpfs_node>(parent())) {
const string &dest = node_path();
auto worker_dir = worker_path();
mkdirs(worker_dir.data(), 0);
bind_mount("tmpfs", worker_dir.data(), worker_dir.data());
clone_attr(src_path ?: parent()->node_path().data(), worker_dir.data());
clone_attr(exist() ? node_path().data() : parent()->node_path().data(), worker_dir.data());
dir_node::mount();
VLOGD(skip_mirror() ? "replace" : "move", worker_dir.data(), dest.data());
xmount(worker_dir.data(), dest.data(), nullptr, MS_MOVE, nullptr);
VLOGD(replace() ? "replace" : "move", worker_dir.data(), node_path().data());
xmount(worker_dir.data(), node_path().data(), nullptr, MS_MOVE, nullptr);
xmount(nullptr, node_path().data(), nullptr, MS_REMOUNT | MS_BIND | MS_RDONLY, nullptr);
} else {
const string dest = worker_path();
// We don't need another layer of tmpfs if parent is tmpfs
mkdir(dest.data(), 0);
clone_attr(src_path ?: parent()->worker_path().data(), dest.data());
clone_attr(exist() ? node_path().data() : parent()->worker_path().data(), dest.data());
dir_node::mount();
}
}
Expand Down Expand Up @@ -265,7 +255,6 @@ static void inject_zygisk_libs(root_node *system) {
vector<module_info> *module_list;

void load_modules() {
node_entry::mirror_dir = get_magisk_tmp() + "/"s MIRRDIR;
node_entry::module_mnt = get_magisk_tmp() + "/"s MODULEMNT "/";

auto root = make_unique<root_node>("");
Expand Down Expand Up @@ -338,8 +327,11 @@ void load_modules() {
root->mount();
}

// cleanup mounts
ssprintf(buf, sizeof(buf), "%s/" WORKERDIR, get_magisk_tmp());
xmount(nullptr, buf, nullptr, MS_REMOUNT | MS_RDONLY, nullptr);
xumount2(buf, MNT_DETACH);
ssprintf(buf, sizeof(buf), "%s/" MODULEMNT, get_magisk_tmp());
xumount2(buf, MNT_DETACH);
}

/************************
Expand Down
Loading