2023-06-06 17:11:42 -07:00
|
|
|
#include <sys/mman.h>
|
2023-04-08 11:56:39 +08:00
|
|
|
#include <sys/syscall.h>
|
2020-04-18 02:00:48 -07:00
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <map>
|
|
|
|
#include <utility>
|
|
|
|
|
2022-05-12 02:03:42 -07:00
|
|
|
#include <base.hpp>
|
2023-11-08 01:46:02 -08:00
|
|
|
#include <consts.hpp>
|
|
|
|
#include <core.hpp>
|
2020-04-18 02:00:48 -07:00
|
|
|
#include <selinux.hpp>
|
|
|
|
|
2023-02-25 18:11:25 -08:00
|
|
|
#include "node.hpp"
|
2021-01-11 02:19:10 -08:00
|
|
|
|
2020-04-18 02:00:48 -07:00
|
|
|
using namespace std;
|
|
|
|
|
2020-06-01 04:22:57 -07:00
|
|
|
#define VLOGD(tag, from, to) LOGD("%-8s: %s <- %s\n", tag, to, from)
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2023-01-20 03:46:35 +08:00
|
|
|
static int bind_mount(const char *reason, const char *from, const char *to) {
|
Refactor magic mount to support overlayfs
Previously, magic mount creates its own mirror devices and mount
mirror mount points. With these mirror mount points, magic mount
can get the original files and directory trees. However, some
devices use overlayfs to modify some mount points, and thus after
magic mount, the overlayed files are missing because the mirror
mount points do not contain the overlayed files. To address this
issue and make magic mount more compatible, this patch refactors
how magic mount works.
The new workflows are as follows:
1. make MAGISKTMP a private mount point so that we can create the
private mount points there
2. for mirror mount points, we instead of creating our own mirror
devices and mount the mirror mount points, we "copy" the
original mount points by recursively mounting /
3. to prevent magic mount affecting the mirror mount points, we
recursively set the mirror mount points private
4. to trace the mount points we created for reverting mounts, we
again make the mirror mount points shared, and by this way we
create a new peer group for each mirror mount points
5. as for tracing the newly created tmpfs mount point by magic
mount, we create a dedicated tmpfs mount point for them, namely
worker mount point, and obviously, it is shared as in a newly
created peer group for tracing
6. when reverting mount points by magic mount, we can then trace
the peer group id and unmount the mount points whose peer group
ids are created by us
The advantages are as follows:
1. it is more compatible, (e.g., with overlayfs, fix #2359)
2. it can mount more partitions for which previous implementation
cannot create mirror mount points (fix #3338)
2022-12-27 04:30:12 +08:00
|
|
|
int ret = xmount(from, to, nullptr, MS_BIND | MS_REC, nullptr);
|
2020-12-30 22:11:24 -08:00
|
|
|
if (ret == 0)
|
2023-01-20 03:46:35 +08:00
|
|
|
VLOGD(reason, from, to);
|
2020-12-30 22:11:24 -08:00
|
|
|
return ret;
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2020-04-24 02:07:46 -07:00
|
|
|
/*************************
|
|
|
|
* Node Tree Construction
|
|
|
|
*************************/
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
tmpfs_node::tmpfs_node(node_entry *node) : dir_node(node, this) {
|
2024-01-05 00:42:33 +08:00
|
|
|
if (!replace()) {
|
|
|
|
if (auto dir = open_dir(node_path().data())) {
|
2022-12-27 04:41:49 +08:00
|
|
|
set_exist(true);
|
|
|
|
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
2024-01-05 00:42:33 +08:00
|
|
|
// create a dummy inter_node to upgrade later
|
|
|
|
emplace<inter_node>(entry->d_name, entry);
|
2022-12-27 04:41:49 +08:00
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto it = children.begin(); it != children.end(); ++it) {
|
2024-01-05 00:42:33 +08:00
|
|
|
// Upgrade resting inter_node children to tmpfs_node
|
2020-12-30 22:11:24 -08:00
|
|
|
if (isa<inter_node>(it->second))
|
2021-08-28 10:27:45 -07:00
|
|
|
it = upgrade<tmpfs_node>(it);
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
2020-04-24 02:07:46 -07:00
|
|
|
}
|
|
|
|
|
2023-02-25 18:11:25 -08:00
|
|
|
bool dir_node::prepare() {
|
2023-02-26 01:14:10 -08:00
|
|
|
// If direct replace or not exist, mount ourselves as tmpfs
|
2024-01-05 00:42:33 +08:00
|
|
|
bool upgrade_to_tmpfs = replace() || !exist();
|
2023-02-26 01:14:10 -08:00
|
|
|
|
2020-12-30 22:11:24 -08:00
|
|
|
for (auto it = children.begin(); it != children.end();) {
|
2023-02-26 01:14:10 -08:00
|
|
|
// We also need to upgrade to tmpfs node if any child:
|
2023-02-25 22:05:50 -08:00
|
|
|
// - Target does not exist
|
|
|
|
// - Source or target is a symlink (since we cannot bind mount symlink)
|
|
|
|
bool cannot_mnt;
|
|
|
|
if (struct stat st{}; lstat(it->second->node_path().data(), &st) != 0) {
|
|
|
|
cannot_mnt = true;
|
|
|
|
} else {
|
|
|
|
it->second->set_exist(true);
|
|
|
|
cannot_mnt = it->second->is_lnk() || S_ISLNK(st.st_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cannot_mnt) {
|
2023-02-25 18:11:25 -08:00
|
|
|
if (_node_type > type_id<tmpfs_node>()) {
|
2020-12-30 22:11:24 -08:00
|
|
|
// Upgrade will fail, remove the unsupported child node
|
2022-03-22 02:43:14 +08:00
|
|
|
LOGW("Unable to add: %s, skipped\n", it->second->node_path().data());
|
2020-12-30 22:11:24 -08:00
|
|
|
delete it->second;
|
|
|
|
it = children.erase(it);
|
|
|
|
continue;
|
|
|
|
}
|
2023-02-26 01:14:10 -08:00
|
|
|
upgrade_to_tmpfs = true;
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
2023-02-25 18:11:25 -08:00
|
|
|
if (auto dn = dyn_cast<dir_node>(it->second)) {
|
2024-01-05 00:42:33 +08:00
|
|
|
if (replace()) {
|
2023-02-26 01:14:10 -08:00
|
|
|
// Propagate skip mirror state to all children
|
2024-01-05 00:42:33 +08:00
|
|
|
dn->set_replace(true);
|
2023-02-25 18:11:25 -08:00
|
|
|
}
|
|
|
|
if (dn->prepare()) {
|
|
|
|
// Upgrade child to tmpfs
|
|
|
|
it = upgrade<tmpfs_node>(it);
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
++it;
|
|
|
|
}
|
2023-02-26 01:14:10 -08:00
|
|
|
return upgrade_to_tmpfs;
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2023-02-25 18:11:25 -08:00
|
|
|
void dir_node::collect_module_files(const char *module, int dfd) {
|
|
|
|
auto dir = xopen_dir(xopenat(dfd, name().data(), O_RDONLY | O_CLOEXEC));
|
2020-12-30 22:11:24 -08:00
|
|
|
if (!dir)
|
2022-12-27 04:41:49 +08:00
|
|
|
return;
|
2020-12-30 22:11:24 -08:00
|
|
|
|
|
|
|
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
|
|
|
if (entry->d_name == ".replace"sv) {
|
2024-01-05 00:42:33 +08:00
|
|
|
set_replace(true);
|
2022-12-27 04:41:49 +08:00
|
|
|
continue;
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (entry->d_type == DT_DIR) {
|
2023-02-26 01:14:10 -08:00
|
|
|
inter_node *node;
|
2022-03-19 12:18:34 +08:00
|
|
|
if (auto it = children.find(entry->d_name); it == children.end()) {
|
2023-02-26 01:14:10 -08:00
|
|
|
node = emplace<inter_node>(entry->d_name, entry->d_name);
|
2022-03-19 12:18:34 +08:00
|
|
|
} else {
|
2023-02-26 01:14:10 -08:00
|
|
|
node = dyn_cast<inter_node>(it->second);
|
2022-03-19 12:18:34 +08:00
|
|
|
}
|
2023-02-26 01:14:10 -08:00
|
|
|
if (node) {
|
|
|
|
node->collect_module_files(module, dirfd(dir.get()));
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
emplace<module_node>(entry->d_name, module, entry);
|
|
|
|
}
|
|
|
|
}
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2020-04-24 02:07:46 -07:00
|
|
|
/************************
|
|
|
|
* Mount Implementations
|
|
|
|
************************/
|
|
|
|
|
2023-12-04 21:11:42 +08:00
|
|
|
void node_entry::create_and_mount(const char *reason, const string &src, bool ro) {
|
|
|
|
const string dest = isa<tmpfs_node>(parent()) ? worker_path() : node_path();
|
2020-12-30 22:11:24 -08:00
|
|
|
if (is_lnk()) {
|
|
|
|
VLOGD("cp_link", src.data(), dest.data());
|
|
|
|
cp_afc(src.data(), dest.data());
|
|
|
|
} else {
|
|
|
|
if (is_dir())
|
|
|
|
xmkdir(dest.data(), 0);
|
|
|
|
else if (is_reg())
|
|
|
|
close(xopen(dest.data(), O_RDONLY | O_CREAT | O_CLOEXEC, 0));
|
|
|
|
else
|
|
|
|
return;
|
2023-01-20 03:46:35 +08:00
|
|
|
bind_mount(reason, src.data(), dest.data());
|
2023-12-04 21:11:42 +08:00
|
|
|
if (ro) {
|
|
|
|
xmount(nullptr, dest.data(), nullptr, MS_REMOUNT | MS_BIND | MS_RDONLY, nullptr);
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
2020-04-24 02:07:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void module_node::mount() {
|
2023-04-10 18:55:30 +08:00
|
|
|
std::string path = module + (parent()->root()->prefix + node_path());
|
|
|
|
string mnt_src = module_mnt + path;
|
|
|
|
{
|
|
|
|
string src = MODULEROOT "/" + path;
|
2024-01-05 00:42:33 +08:00
|
|
|
if (exist()) clone_attr(node_path().data(), src.data());
|
2023-04-10 18:55:30 +08:00
|
|
|
}
|
|
|
|
if (isa<tmpfs_node>(parent())) {
|
|
|
|
create_and_mount("module", mnt_src);
|
|
|
|
} else {
|
|
|
|
bind_mount("module", mnt_src.data(), node_path().data());
|
2023-04-02 17:52:07 +08:00
|
|
|
}
|
2020-04-24 02:07:46 -07:00
|
|
|
}
|
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
void tmpfs_node::mount() {
|
2024-01-05 00:42:33 +08:00
|
|
|
if (!is_dir()) {
|
|
|
|
create_and_mount("mirror", node_path());
|
|
|
|
return;
|
|
|
|
}
|
2021-08-28 10:27:45 -07:00
|
|
|
if (!isa<tmpfs_node>(parent())) {
|
2023-12-04 21:11:42 +08:00
|
|
|
auto worker_dir = worker_path();
|
2023-01-20 03:46:35 +08:00
|
|
|
mkdirs(worker_dir.data(), 0);
|
2024-01-05 00:42:33 +08:00
|
|
|
clone_attr(exist() ? node_path().data() : parent()->node_path().data(), worker_dir.data());
|
2023-12-04 21:11:42 +08:00
|
|
|
dir_node::mount();
|
2024-08-14 21:36:15 +08:00
|
|
|
bind_mount(replace() ? "replace" : "move", worker_dir.data(), node_path().data());
|
2024-02-22 22:19:31 +08:00
|
|
|
xmount(nullptr, node_path().data(), nullptr, MS_REMOUNT | MS_BIND | MS_RDONLY, nullptr);
|
2023-01-20 03:46:35 +08:00
|
|
|
} else {
|
2023-12-04 21:11:42 +08:00
|
|
|
const string dest = worker_path();
|
2022-12-27 04:41:49 +08:00
|
|
|
// We don't need another layer of tmpfs if parent is tmpfs
|
2023-01-20 03:46:35 +08:00
|
|
|
mkdir(dest.data(), 0);
|
2024-01-05 00:42:33 +08:00
|
|
|
clone_attr(exist() ? node_path().data() : parent()->worker_path().data(), dest.data());
|
2023-12-04 21:11:42 +08:00
|
|
|
dir_node::mount();
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
2020-04-24 02:07:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* Magisk Stuffs
|
|
|
|
****************/
|
|
|
|
|
2020-04-18 05:15:59 -07:00
|
|
|
class magisk_node : public node_entry {
|
|
|
|
public:
|
2020-12-30 22:11:24 -08:00
|
|
|
explicit magisk_node(const char *name) : node_entry(name, DT_REG, this) {}
|
2024-12-06 06:27:39 +08:00
|
|
|
explicit magisk_node(const char *name, const char *target)
|
|
|
|
: node_entry(name, DT_LNK, this), target(target) {}
|
2020-12-30 22:11:24 -08:00
|
|
|
|
|
|
|
void mount() override {
|
2024-12-06 06:27:39 +08:00
|
|
|
if (target) {
|
|
|
|
string dest = isa<tmpfs_node>(parent()) ? worker_path() : node_path();
|
|
|
|
VLOGD("create", target, dest.data());
|
|
|
|
xsymlink(target, dest.data());
|
2020-12-30 22:11:24 -08:00
|
|
|
} else {
|
2024-12-06 06:27:39 +08:00
|
|
|
string src = get_magisk_tmp() + "/"s + name();
|
|
|
|
if (access(src.data(), F_OK) == 0)
|
|
|
|
create_and_mount("magisk", src, true);
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
}
|
2024-12-06 06:27:39 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
const char *target = nullptr;
|
2020-04-18 05:15:59 -07:00
|
|
|
};
|
|
|
|
|
2023-11-06 17:19:12 -08:00
|
|
|
class zygisk_node : public node_entry {
|
|
|
|
public:
|
2024-03-31 22:01:22 -07:00
|
|
|
explicit zygisk_node(const char *name, bool is64bit)
|
|
|
|
: node_entry(name, DT_REG, this), is64bit(is64bit) {}
|
2023-11-06 17:19:12 -08:00
|
|
|
|
|
|
|
void mount() override {
|
2024-03-31 22:01:22 -07:00
|
|
|
#if defined(__LP64__)
|
|
|
|
const string src = get_magisk_tmp() + "/magisk"s + (is64bit ? "" : "32");
|
|
|
|
#else
|
|
|
|
const string src = get_magisk_tmp() + "/magisk"s;
|
|
|
|
(void) is64bit;
|
|
|
|
#endif
|
2024-08-21 02:59:33 +08:00
|
|
|
if (access(src.data(), F_OK))
|
|
|
|
return;
|
2023-12-04 21:11:42 +08:00
|
|
|
create_and_mount("zygisk", src, true);
|
2023-11-06 17:19:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool is64bit;
|
|
|
|
};
|
|
|
|
|
2020-04-18 05:15:59 -07:00
|
|
|
static void inject_magisk_bins(root_node *system) {
|
2023-02-25 18:11:25 -08:00
|
|
|
auto bin = system->get_child<inter_node>("bin");
|
2020-12-30 22:11:24 -08:00
|
|
|
if (!bin) {
|
2023-02-25 22:05:50 -08:00
|
|
|
bin = new inter_node("bin");
|
2020-12-30 22:11:24 -08:00
|
|
|
system->insert(bin);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert binaries
|
|
|
|
bin->insert(new magisk_node("magisk"));
|
2022-03-17 03:15:39 -07:00
|
|
|
bin->insert(new magisk_node("magiskpolicy"));
|
2020-12-30 22:11:24 -08:00
|
|
|
|
2024-12-06 06:27:39 +08:00
|
|
|
// Also insert all applets to make sure no one can override it
|
2020-12-30 22:11:24 -08:00
|
|
|
for (int i = 0; applet_names[i]; ++i)
|
2024-12-06 06:27:39 +08:00
|
|
|
bin->insert(new magisk_node(applet_names[i], "./magisk"));
|
|
|
|
bin->insert(new magisk_node("supolicy", "./magiskpolicy"));
|
2020-04-18 05:15:59 -07:00
|
|
|
}
|
|
|
|
|
2023-11-06 17:19:12 -08:00
|
|
|
static void inject_zygisk_libs(root_node *system) {
|
|
|
|
if (access("/system/bin/linker", F_OK) == 0) {
|
|
|
|
auto lib = system->get_child<inter_node>("lib");
|
|
|
|
if (!lib) {
|
|
|
|
lib = new inter_node("lib");
|
|
|
|
system->insert(lib);
|
|
|
|
}
|
|
|
|
lib->insert(new zygisk_node(native_bridge.data(), false));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (access("/system/bin/linker64", F_OK) == 0) {
|
|
|
|
auto lib64 = system->get_child<inter_node>("lib64");
|
|
|
|
if (!lib64) {
|
|
|
|
lib64 = new inter_node("lib64");
|
|
|
|
system->insert(lib64);
|
|
|
|
}
|
|
|
|
lib64->insert(new zygisk_node(native_bridge.data(), true));
|
|
|
|
}
|
2021-09-15 01:59:43 -07:00
|
|
|
}
|
|
|
|
|
2023-11-06 17:19:12 -08:00
|
|
|
vector<module_info> *module_list;
|
|
|
|
|
2023-02-25 18:11:25 -08:00
|
|
|
void load_modules() {
|
2023-11-02 15:50:36 -07:00
|
|
|
node_entry::module_mnt = get_magisk_tmp() + "/"s MODULEMNT "/";
|
2020-12-30 22:11:24 -08:00
|
|
|
|
|
|
|
auto root = make_unique<root_node>("");
|
|
|
|
auto system = new root_node("system");
|
|
|
|
root->insert(system);
|
|
|
|
|
2021-04-13 16:26:58 +08:00
|
|
|
char buf[4096];
|
2020-12-30 22:11:24 -08:00
|
|
|
LOGI("* Loading modules\n");
|
2022-05-06 01:40:19 -07:00
|
|
|
for (const auto &m : *module_list) {
|
|
|
|
const char *module = m.name.data();
|
2023-11-02 15:50:36 -07:00
|
|
|
char *b = buf + ssprintf(buf, sizeof(buf), "%s/" MODULEMNT "/%s/", get_magisk_tmp(), module);
|
2022-05-06 01:40:19 -07:00
|
|
|
|
|
|
|
// Read props
|
|
|
|
strcpy(b, "system.prop");
|
|
|
|
if (access(buf, F_OK) == 0) {
|
|
|
|
LOGI("%s: loading [system.prop]\n", module);
|
2023-05-18 20:26:20 -07:00
|
|
|
// Do NOT go through property service as it could cause boot lock
|
|
|
|
load_prop_file(buf, true);
|
2022-05-06 01:40:19 -07:00
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
|
2022-05-06 01:40:19 -07:00
|
|
|
// Check whether skip mounting
|
|
|
|
strcpy(b, "skip_mount");
|
|
|
|
if (access(buf, F_OK) == 0)
|
|
|
|
continue;
|
2020-12-30 22:11:24 -08:00
|
|
|
|
2022-05-06 01:40:19 -07:00
|
|
|
// Double check whether the system folder exists
|
|
|
|
strcpy(b, "system");
|
|
|
|
if (access(buf, F_OK) != 0)
|
|
|
|
continue;
|
2021-10-26 01:50:29 +08:00
|
|
|
|
2022-05-06 01:40:19 -07:00
|
|
|
LOGI("%s: loading mount files\n", module);
|
|
|
|
b[-1] = '\0';
|
|
|
|
int fd = xopen(buf, O_RDONLY | O_CLOEXEC);
|
2023-02-25 18:11:25 -08:00
|
|
|
system->collect_module_files(module, fd);
|
2022-05-06 01:40:19 -07:00
|
|
|
close(fd);
|
2021-10-26 01:50:29 +08:00
|
|
|
}
|
2023-11-02 15:50:36 -07:00
|
|
|
if (get_magisk_tmp() != "/sbin"sv || !str_contains(getenv("PATH") ?: "", "/sbin")) {
|
2020-12-30 22:11:24 -08:00
|
|
|
// Need to inject our binaries into /system/bin
|
|
|
|
inject_magisk_bins(system);
|
|
|
|
}
|
|
|
|
|
2023-11-06 17:19:12 -08:00
|
|
|
if (zygisk_enabled) {
|
|
|
|
string native_bridge_orig = get_prop(NBPROP);
|
|
|
|
if (native_bridge_orig.empty()) {
|
|
|
|
native_bridge_orig = "0";
|
|
|
|
}
|
|
|
|
native_bridge = native_bridge_orig != "0" ? ZYGISKLDR + native_bridge_orig : ZYGISKLDR;
|
2023-12-17 03:12:08 +08:00
|
|
|
set_prop(NBPROP, native_bridge.data());
|
2023-11-06 17:19:12 -08:00
|
|
|
// Weather Huawei's Maple compiler is enabled.
|
|
|
|
// If so, system server will be created by a special Zygote which ignores the native bridge
|
|
|
|
// and make system server out of our control. Avoid it by disabling.
|
|
|
|
if (get_prop("ro.maple.enable") == "1") {
|
2023-12-17 03:12:08 +08:00
|
|
|
set_prop("ro.maple.enable", "0");
|
2023-11-06 17:19:12 -08:00
|
|
|
}
|
|
|
|
inject_zygisk_libs(system);
|
|
|
|
}
|
|
|
|
|
2021-10-14 01:35:29 -07:00
|
|
|
if (!system->is_empty()) {
|
|
|
|
// Handle special read-only partitions
|
2023-03-04 02:19:51 +08:00
|
|
|
for (const char *part : { "/vendor", "/product", "/system_ext" }) {
|
2022-07-22 16:53:33 +08:00
|
|
|
struct stat st{};
|
2021-10-14 01:35:29 -07:00
|
|
|
if (lstat(part, &st) == 0 && S_ISDIR(st.st_mode)) {
|
|
|
|
if (auto old = system->extract(part + 1)) {
|
|
|
|
auto new_node = new root_node(old);
|
|
|
|
root->insert(new_node);
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
}
|
2021-10-14 01:35:29 -07:00
|
|
|
root->prepare();
|
|
|
|
root->mount();
|
|
|
|
}
|
2021-09-15 01:59:43 -07:00
|
|
|
|
2024-02-22 22:19:31 +08:00
|
|
|
// cleanup mounts
|
2024-08-14 21:36:15 +08:00
|
|
|
clean_mounts();
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2023-02-25 18:11:25 -08:00
|
|
|
/************************
|
|
|
|
* Filesystem operations
|
|
|
|
************************/
|
|
|
|
|
2020-04-18 02:00:48 -07:00
|
|
|
static void prepare_modules() {
|
2020-12-30 22:11:24 -08:00
|
|
|
// Upgrade modules
|
|
|
|
if (auto dir = open_dir(MODULEUPGRADE); dir) {
|
|
|
|
int ufd = dirfd(dir.get());
|
|
|
|
int mfd = xopen(MODULEROOT, O_RDONLY | O_CLOEXEC);
|
|
|
|
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
|
|
|
if (entry->d_type == DT_DIR) {
|
|
|
|
// Cleanup old module if exists
|
|
|
|
if (faccessat(mfd, entry->d_name, F_OK, 0) == 0) {
|
|
|
|
int modfd = xopenat(mfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
|
|
|
if (faccessat(modfd, "disable", F_OK, 0) == 0) {
|
|
|
|
auto disable = entry->d_name + "/disable"s;
|
|
|
|
close(xopenat(ufd, disable.data(), O_RDONLY | O_CREAT | O_CLOEXEC, 0));
|
|
|
|
}
|
|
|
|
frm_rf(modfd);
|
|
|
|
unlinkat(mfd, entry->d_name, AT_REMOVEDIR);
|
|
|
|
}
|
|
|
|
LOGI("Upgrade / New module: %s\n", entry->d_name);
|
|
|
|
renameat(ufd, entry->d_name, mfd, entry->d_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(mfd);
|
|
|
|
rm_rf(MODULEUPGRADE);
|
|
|
|
}
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2020-10-11 18:30:03 -07:00
|
|
|
template<typename Func>
|
2020-10-25 21:41:14 -07:00
|
|
|
static void foreach_module(Func fn) {
|
2020-12-30 22:11:24 -08:00
|
|
|
auto dir = open_dir(MODULEROOT);
|
|
|
|
if (!dir)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int dfd = dirfd(dir.get());
|
|
|
|
for (dirent *entry; (entry = xreaddir(dir.get()));) {
|
|
|
|
if (entry->d_type == DT_DIR && entry->d_name != ".core"sv) {
|
|
|
|
int modfd = xopenat(dfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
|
|
|
fn(dfd, entry, modfd);
|
|
|
|
close(modfd);
|
|
|
|
}
|
|
|
|
}
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2021-10-13 04:52:02 -07:00
|
|
|
static void collect_modules(bool open_zygisk) {
|
|
|
|
foreach_module([=](int dfd, dirent *entry, int modfd) {
|
2020-12-30 22:11:24 -08:00
|
|
|
if (faccessat(modfd, "remove", F_OK, 0) == 0) {
|
|
|
|
LOGI("%s: remove\n", entry->d_name);
|
|
|
|
auto uninstaller = MODULEROOT + "/"s + entry->d_name + "/uninstall.sh";
|
|
|
|
if (access(uninstaller.data(), F_OK) == 0)
|
|
|
|
exec_script(uninstaller.data());
|
|
|
|
frm_rf(xdup(modfd));
|
|
|
|
unlinkat(dfd, entry->d_name, AT_REMOVEDIR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
unlinkat(modfd, "update", 0);
|
2021-09-23 23:54:46 -07:00
|
|
|
if (faccessat(modfd, "disable", F_OK, 0) == 0)
|
|
|
|
return;
|
|
|
|
|
2021-10-13 04:52:02 -07:00
|
|
|
module_info info;
|
2021-11-24 16:51:18 +08:00
|
|
|
if (zygisk_enabled) {
|
|
|
|
// Riru and its modules are not compatible with zygisk
|
|
|
|
if (entry->d_name == "riru-core"sv || faccessat(modfd, "riru", F_OK, 0) == 0) {
|
|
|
|
LOGI("%s: ignore\n", entry->d_name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (open_zygisk) {
|
2021-10-13 04:52:02 -07:00
|
|
|
#if defined(__arm__)
|
|
|
|
info.z32 = openat(modfd, "zygisk/armeabi-v7a.so", O_RDONLY | O_CLOEXEC);
|
|
|
|
#elif defined(__aarch64__)
|
|
|
|
info.z32 = openat(modfd, "zygisk/armeabi-v7a.so", O_RDONLY | O_CLOEXEC);
|
|
|
|
info.z64 = openat(modfd, "zygisk/arm64-v8a.so", O_RDONLY | O_CLOEXEC);
|
|
|
|
#elif defined(__i386__)
|
|
|
|
info.z32 = openat(modfd, "zygisk/x86.so", O_RDONLY | O_CLOEXEC);
|
|
|
|
#elif defined(__x86_64__)
|
|
|
|
info.z32 = openat(modfd, "zygisk/x86.so", O_RDONLY | O_CLOEXEC);
|
|
|
|
info.z64 = openat(modfd, "zygisk/x86_64.so", O_RDONLY | O_CLOEXEC);
|
2024-04-04 22:15:14 +08:00
|
|
|
#elif defined(__riscv)
|
|
|
|
info.z32 = -1;
|
|
|
|
info.z64 = openat(modfd, "zygisk/riscv64.so", O_RDONLY | O_CLOEXEC);
|
2021-10-13 04:52:02 -07:00
|
|
|
#else
|
|
|
|
#error Unsupported ABI
|
|
|
|
#endif
|
2022-01-21 04:43:27 -08:00
|
|
|
unlinkat(modfd, "zygisk/unloaded", 0);
|
2021-11-24 16:51:18 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Ignore zygisk modules when zygisk is not enabled
|
|
|
|
if (faccessat(modfd, "zygisk", F_OK, 0) == 0) {
|
|
|
|
LOGI("%s: ignore\n", entry->d_name);
|
|
|
|
return;
|
2021-11-12 21:11:53 +08:00
|
|
|
}
|
2021-10-13 04:52:02 -07:00
|
|
|
}
|
|
|
|
info.name = entry->d_name;
|
2022-01-14 03:10:02 -08:00
|
|
|
module_list->push_back(info);
|
2020-12-30 22:11:24 -08:00
|
|
|
});
|
2021-11-24 16:51:18 +08:00
|
|
|
if (zygisk_enabled) {
|
2021-10-28 00:26:18 -07:00
|
|
|
bool use_memfd = true;
|
|
|
|
auto convert_to_memfd = [&](int fd) -> int {
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
if (use_memfd) {
|
|
|
|
int memfd = syscall(__NR_memfd_create, "jit-cache", MFD_CLOEXEC);
|
|
|
|
if (memfd >= 0) {
|
|
|
|
xsendfile(memfd, fd, nullptr, INT_MAX);
|
|
|
|
close(fd);
|
|
|
|
return memfd;
|
|
|
|
} else {
|
|
|
|
// memfd_create failed, just use what we had
|
|
|
|
use_memfd = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
};
|
2022-01-14 03:10:02 -08:00
|
|
|
std::for_each(module_list->begin(), module_list->end(), [&](module_info &info) {
|
2021-10-28 00:26:18 -07:00
|
|
|
info.z32 = convert_to_memfd(info.z32);
|
|
|
|
#if defined(__LP64__)
|
|
|
|
info.z64 = convert_to_memfd(info.z64);
|
|
|
|
#endif
|
|
|
|
});
|
|
|
|
}
|
2020-10-11 18:30:03 -07:00
|
|
|
}
|
|
|
|
|
2020-04-18 02:00:48 -07:00
|
|
|
void handle_modules() {
|
2020-12-30 22:11:24 -08:00
|
|
|
prepare_modules();
|
2021-10-13 04:52:02 -07:00
|
|
|
collect_modules(false);
|
2020-12-30 22:11:24 -08:00
|
|
|
exec_module_scripts("post-fs-data");
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2020-12-30 22:11:24 -08:00
|
|
|
// Recollect modules (module scripts could remove itself)
|
2022-01-14 03:10:02 -08:00
|
|
|
module_list->clear();
|
2021-10-13 04:52:02 -07:00
|
|
|
collect_modules(true);
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
2020-04-30 01:26:50 -07:00
|
|
|
|
2023-01-19 04:25:44 +08:00
|
|
|
static int check_rules_dir(char *buf, size_t sz) {
|
2023-11-02 15:50:36 -07:00
|
|
|
int off = ssprintf(buf, sz, "%s/" PREINITMIRR, get_magisk_tmp());
|
2023-01-19 04:25:44 +08:00
|
|
|
struct stat st1{};
|
|
|
|
struct stat st2{};
|
|
|
|
if (xstat(buf, &st1) < 0 || xstat(MODULEROOT, &st2) < 0)
|
|
|
|
return 0;
|
|
|
|
if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
|
|
|
|
return 0;
|
|
|
|
return off;
|
|
|
|
}
|
|
|
|
|
2020-10-11 18:30:03 -07:00
|
|
|
void disable_modules() {
|
2023-01-19 04:25:44 +08:00
|
|
|
char buf[4096];
|
|
|
|
int off = check_rules_dir(buf, sizeof(buf));
|
|
|
|
foreach_module([&](int, dirent *entry, int modfd) {
|
2020-12-30 22:11:24 -08:00
|
|
|
close(xopenat(modfd, "disable", O_RDONLY | O_CREAT | O_CLOEXEC, 0));
|
2023-01-19 04:25:44 +08:00
|
|
|
if (off) {
|
2023-01-20 14:41:22 +08:00
|
|
|
ssprintf(buf + off, sizeof(buf) - off, "/%s/sepolicy.rule", entry->d_name);
|
2023-01-19 04:25:44 +08:00
|
|
|
unlink(buf);
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
});
|
2020-10-11 18:30:03 -07:00
|
|
|
}
|
2020-04-30 01:26:50 -07:00
|
|
|
|
2020-10-11 18:30:03 -07:00
|
|
|
void remove_modules() {
|
2023-01-19 04:25:44 +08:00
|
|
|
char buf[4096];
|
|
|
|
int off = check_rules_dir(buf, sizeof(buf));
|
|
|
|
foreach_module([&](int, dirent *entry, int) {
|
2020-12-30 22:11:24 -08:00
|
|
|
auto uninstaller = MODULEROOT + "/"s + entry->d_name + "/uninstall.sh";
|
|
|
|
if (access(uninstaller.data(), F_OK) == 0)
|
|
|
|
exec_script(uninstaller.data());
|
2023-01-19 04:25:44 +08:00
|
|
|
if (off) {
|
2023-01-20 14:41:22 +08:00
|
|
|
ssprintf(buf + off, sizeof(buf) - off, "/%s/sepolicy.rule", entry->d_name);
|
2023-01-19 04:25:44 +08:00
|
|
|
unlink(buf);
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
});
|
|
|
|
rm_rf(MODULEROOT);
|
2020-04-30 01:26:50 -07:00
|
|
|
}
|
2020-05-18 05:36:02 -07:00
|
|
|
|
|
|
|
void exec_module_scripts(const char *stage) {
|
2021-10-13 04:52:02 -07:00
|
|
|
vector<string_view> module_names;
|
2022-01-14 03:10:02 -08:00
|
|
|
std::transform(module_list->begin(), module_list->end(), std::back_inserter(module_names),
|
2021-10-17 02:02:53 +08:00
|
|
|
[](const module_info &info) -> string_view { return info.name; });
|
2021-10-13 04:52:02 -07:00
|
|
|
exec_module_scripts(stage, module_names);
|
|
|
|
}
|