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>
|
2020-04-18 02:00:48 -07:00
|
|
|
#include <magisk.hpp>
|
2021-09-16 05:27:34 -07:00
|
|
|
#include <daemon.hpp>
|
2020-04-18 02:00:48 -07:00
|
|
|
#include <selinux.hpp>
|
|
|
|
#include <resetprop.hpp>
|
|
|
|
|
2021-01-11 02:19:10 -08:00
|
|
|
#include "core.hpp"
|
|
|
|
|
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
|
|
|
|
2020-04-24 02:07:46 -07:00
|
|
|
#define TYPE_MIRROR (1 << 0) /* mount from mirror */
|
|
|
|
#define TYPE_INTER (1 << 1) /* intermediate node */
|
2021-08-28 10:27:45 -07:00
|
|
|
#define TYPE_TMPFS (1 << 2) /* replace with tmpfs */
|
2020-04-18 02:00:48 -07:00
|
|
|
#define TYPE_MODULE (1 << 3) /* mount from module */
|
|
|
|
#define TYPE_ROOT (1 << 4) /* partition root */
|
2020-04-18 05:15:59 -07:00
|
|
|
#define TYPE_CUSTOM (1 << 5) /* custom node type overrides all */
|
2021-08-28 10:27:45 -07:00
|
|
|
#define TYPE_DIR (TYPE_INTER|TYPE_TMPFS|TYPE_ROOT)
|
2020-04-18 02:00:48 -07:00
|
|
|
|
|
|
|
class node_entry;
|
|
|
|
class dir_node;
|
|
|
|
class inter_node;
|
|
|
|
class mirror_node;
|
2021-08-28 10:27:45 -07:00
|
|
|
class tmpfs_node;
|
2020-04-18 02:00:48 -07:00
|
|
|
class module_node;
|
|
|
|
class root_node;
|
|
|
|
|
|
|
|
template<class T> static bool isa(node_entry *node);
|
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-18 05:15:59 -07:00
|
|
|
template<class T> uint8_t type_id() { return TYPE_CUSTOM; }
|
2020-04-18 02:00:48 -07:00
|
|
|
template<> uint8_t type_id<dir_node>() { return TYPE_DIR; }
|
|
|
|
template<> uint8_t type_id<inter_node>() { return TYPE_INTER; }
|
|
|
|
template<> uint8_t type_id<mirror_node>() { return TYPE_MIRROR; }
|
2021-08-28 10:27:45 -07:00
|
|
|
template<> uint8_t type_id<tmpfs_node>() { return TYPE_TMPFS; }
|
2020-04-18 02:00:48 -07:00
|
|
|
template<> uint8_t type_id<module_node>() { return TYPE_MODULE; }
|
|
|
|
template<> uint8_t type_id<root_node>() { return TYPE_ROOT; }
|
|
|
|
|
|
|
|
class node_entry {
|
|
|
|
public:
|
2020-12-30 22:11:24 -08:00
|
|
|
virtual ~node_entry() = default;
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
// Node info
|
2020-12-30 22:11:24 -08:00
|
|
|
bool is_dir() { return file_type() == DT_DIR; }
|
|
|
|
bool is_lnk() { return file_type() == DT_LNK; }
|
|
|
|
bool is_reg() { return file_type() == DT_REG; }
|
|
|
|
uint8_t type() { return node_type; }
|
|
|
|
const string &name() { return _name; }
|
2022-03-22 02:43:14 +08:00
|
|
|
|
|
|
|
// Don't call the following two functions before prepare
|
2020-12-30 22:11:24 -08:00
|
|
|
const string &node_path();
|
|
|
|
string mirror_path() { return mirror_dir + node_path(); }
|
2020-04-18 05:15:59 -07:00
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
// Tree methods
|
2020-12-30 22:11:24 -08:00
|
|
|
dir_node *parent() { return _parent; }
|
2021-08-28 10:27:45 -07:00
|
|
|
void merge(node_entry *other);
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2020-12-30 22:11:24 -08:00
|
|
|
virtual void mount() = 0;
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2020-12-30 22:11:24 -08:00
|
|
|
static string module_mnt;
|
|
|
|
static string mirror_dir;
|
2020-04-18 02:00:48 -07:00
|
|
|
|
|
|
|
protected:
|
2020-12-30 22:11:24 -08:00
|
|
|
template<class T>
|
|
|
|
node_entry(const char *name, uint8_t file_type, T*)
|
|
|
|
: _name(name), _file_type(file_type), node_type(type_id<T>()) {}
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2020-12-30 22:11:24 -08:00
|
|
|
template<class T>
|
2021-08-28 10:27:45 -07:00
|
|
|
explicit node_entry(T*) : _file_type(0), node_type(type_id<T>()) {}
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2023-01-20 03:46:35 +08:00
|
|
|
void create_and_mount(const char *reason, const string &src);
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
// Use top bit of _file_type for node exist status
|
2020-12-30 22:11:24 -08:00
|
|
|
bool exist() { return static_cast<bool>(_file_type & (1 << 7)); }
|
|
|
|
void set_exist(bool b) { if (b) _file_type |= (1 << 7); else _file_type &= ~(1 << 7); }
|
|
|
|
uint8_t file_type() { return static_cast<uint8_t>(_file_type & ~(1 << 7)); }
|
2020-04-18 02:00:48 -07:00
|
|
|
|
|
|
|
private:
|
2020-12-30 22:11:24 -08:00
|
|
|
friend class dir_node;
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
static bool should_be_tmpfs(node_entry *child);
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2020-12-30 22:11:24 -08:00
|
|
|
// Node properties
|
|
|
|
string _name;
|
|
|
|
uint8_t _file_type;
|
|
|
|
uint8_t node_type;
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2020-12-30 22:11:24 -08:00
|
|
|
dir_node *_parent = nullptr;
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2022-03-22 02:43:14 +08:00
|
|
|
// Cache, it should only be used within prepare
|
2020-12-30 22:11:24 -08:00
|
|
|
string _node_path;
|
2020-04-18 02:00:48 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
class dir_node : public node_entry {
|
|
|
|
public:
|
2021-08-28 10:27:45 -07:00
|
|
|
friend void node_entry::merge(node_entry *other);
|
2020-12-30 22:11:24 -08:00
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
using map_type = map<string_view, node_entry *>;
|
|
|
|
using iterator = map_type::iterator;
|
2020-12-30 22:11:24 -08:00
|
|
|
|
|
|
|
~dir_node() override {
|
|
|
|
for (auto &it : children)
|
|
|
|
delete it.second;
|
|
|
|
children.clear();
|
|
|
|
}
|
|
|
|
|
2022-12-27 04:41:49 +08:00
|
|
|
void collect_files(const char *module, int dfd);
|
2020-12-30 22:11:24 -08:00
|
|
|
|
2022-12-27 00:57:41 +08:00
|
|
|
// Return true to indicate need to upgrade to skeleton
|
2022-12-27 04:41:49 +08:00
|
|
|
bool prepare(bool should_skip_mirror=false);
|
2020-12-30 22:11:24 -08:00
|
|
|
|
|
|
|
// Default directory mount logic
|
|
|
|
void mount() override {
|
|
|
|
for (auto &pair : children)
|
|
|
|
pair.second->mount();
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************
|
|
|
|
* Tree Methods
|
|
|
|
***************/
|
|
|
|
|
|
|
|
bool is_empty() { return children.empty(); }
|
|
|
|
|
|
|
|
template<class T>
|
2021-08-28 10:27:45 -07:00
|
|
|
T *child(string_view name) { return iterator_to_node<T>(children.find(name)); }
|
2020-12-30 22:11:24 -08:00
|
|
|
|
|
|
|
// Lazy val
|
|
|
|
root_node *root() {
|
|
|
|
if (!_root)
|
|
|
|
_root = _parent->root();
|
|
|
|
return _root;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return child with name or nullptr
|
|
|
|
node_entry *extract(string_view name);
|
|
|
|
|
|
|
|
// Return false if rejected
|
|
|
|
bool insert(node_entry *node) {
|
2021-08-28 10:27:45 -07:00
|
|
|
auto fn = [=](auto) { return node; };
|
|
|
|
return node && iterator_to_node(insert(node->_name, node->node_type, fn));
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return inserted node or null if rejected
|
|
|
|
template<class T, class ...Args>
|
2021-04-13 06:15:42 +08:00
|
|
|
T *emplace(string_view name, Args &&...args) {
|
2021-08-28 10:27:45 -07:00
|
|
|
auto fn = [&](auto) { return new T(std::forward<Args>(args)...); };
|
|
|
|
return iterator_to_node<T>(insert(name, type_id<T>(), fn));
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
// Return inserted node, existing node with same rank, or null if rejected
|
2020-12-30 22:11:24 -08:00
|
|
|
template<class T, class ...Args>
|
2021-04-13 06:15:42 +08:00
|
|
|
T *emplace_or_get(string_view name, Args &&...args) {
|
2021-08-28 10:27:45 -07:00
|
|
|
auto fn = [&](auto) { return new T(std::forward<Args>(args)...); };
|
|
|
|
return iterator_to_node<T>(insert(name, type_id<T>(), fn, true));
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return upgraded node or null if rejected
|
|
|
|
template<class T, class ...Args>
|
|
|
|
T *upgrade(string_view name, Args &...args) {
|
2021-08-28 10:27:45 -07:00
|
|
|
return iterator_to_node<T>(upgrade<T>(children.find(name), args...));
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2022-12-27 04:41:49 +08:00
|
|
|
bool skip_mirror() const { return _skip_mirror; }
|
|
|
|
void set_skip_mirror(bool b) { _skip_mirror = b; }
|
|
|
|
|
2020-04-18 02:00:48 -07:00
|
|
|
protected:
|
2020-12-30 22:11:24 -08:00
|
|
|
template<class T>
|
|
|
|
dir_node(const char *name, uint8_t file_type, T *self) : node_entry(name, file_type, self) {
|
|
|
|
if constexpr (std::is_same_v<T, root_node>)
|
|
|
|
_root = self;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
dir_node(node_entry *node, T *self) : node_entry(self) {
|
2021-08-28 10:27:45 -07:00
|
|
|
merge(node);
|
2020-12-30 22:11:24 -08:00
|
|
|
if constexpr (std::is_same_v<T, root_node>)
|
|
|
|
_root = self;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
dir_node(const char *name, T *self) : dir_node(name, DT_DIR, self) {}
|
|
|
|
|
|
|
|
template<class T = node_entry>
|
2021-08-28 10:27:45 -07:00
|
|
|
T *iterator_to_node(iterator it) {
|
|
|
|
return static_cast<T*>(it == children.end() ? nullptr : it->second);
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
// Emplace insert a new node, or upgrade if the requested type has a higher rank.
|
|
|
|
// Return iterator to new node or end() if insertion is rejected.
|
|
|
|
// If get_same is true and a node with the same rank exists, it will return that node instead.
|
|
|
|
// fn is the node construction callback. Signature: (node_ent *&) -> node_ent *
|
|
|
|
// fn gets a reference to the existing node pointer and returns a new node object.
|
|
|
|
// Input is null when there is no existing node. If returns null, the insertion is rejected.
|
|
|
|
// If fn consumes the input, it should set the reference to null.
|
|
|
|
template<typename Func>
|
|
|
|
iterator insert(iterator it, uint8_t type, const Func &fn, bool get_same);
|
2020-12-30 22:11:24 -08:00
|
|
|
|
|
|
|
template<typename Func>
|
2021-08-28 10:27:45 -07:00
|
|
|
iterator insert(string_view name, uint8_t type, const Func &fn, bool get_same = false) {
|
|
|
|
return insert(children.find(name), type, fn, get_same);
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
|
|
|
|
template<class To, class From = node_entry, class ...Args>
|
2021-08-28 10:27:45 -07:00
|
|
|
iterator upgrade(iterator it, Args &&...args);
|
2020-12-30 22:11:24 -08:00
|
|
|
|
|
|
|
// dir nodes host children
|
|
|
|
map_type children;
|
|
|
|
|
|
|
|
// Root node lookup cache
|
2021-04-13 06:12:02 +08:00
|
|
|
root_node *_root = nullptr;
|
2022-12-27 04:41:49 +08:00
|
|
|
|
|
|
|
// Skip binding mirror for this directory
|
|
|
|
bool _skip_mirror = false;
|
2020-04-18 02:00:48 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
class root_node : public dir_node {
|
|
|
|
public:
|
2022-12-27 04:41:49 +08:00
|
|
|
explicit root_node(const char *name) : dir_node(name, this), prefix("") {
|
|
|
|
set_exist(true);
|
|
|
|
}
|
|
|
|
explicit root_node(node_entry *node) : dir_node(node, this), prefix("/system") {
|
|
|
|
set_exist(true);
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
const char * const prefix;
|
2020-04-18 02:00:48 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
class inter_node : public dir_node {
|
|
|
|
public:
|
2020-12-30 22:11:24 -08:00
|
|
|
inter_node(const char *name, const char *module) : dir_node(name, this), module(module) {}
|
2020-04-18 02:00:48 -07:00
|
|
|
private:
|
2020-12-30 22:11:24 -08:00
|
|
|
const char *module;
|
|
|
|
friend class module_node;
|
2020-04-18 02:00:48 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
class module_node : public node_entry {
|
|
|
|
public:
|
2020-12-30 22:11:24 -08:00
|
|
|
module_node(const char *module, dirent *entry)
|
|
|
|
: node_entry(entry->d_name, entry->d_type, this), module(module) {}
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2020-12-30 22:11:24 -08:00
|
|
|
module_node(node_entry *node, const char *module) : node_entry(this), module(module) {
|
2021-08-28 10:27:45 -07:00
|
|
|
merge(node);
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2020-12-30 22:11:24 -08:00
|
|
|
explicit module_node(inter_node *node) : module_node(node, node->module) {}
|
2020-04-18 02:00:48 -07:00
|
|
|
|
2020-12-30 22:11:24 -08:00
|
|
|
void mount() override;
|
2020-04-18 02:00:48 -07:00
|
|
|
private:
|
2020-12-30 22:11:24 -08:00
|
|
|
const char *module;
|
2020-04-18 02:00:48 -07:00
|
|
|
};
|
|
|
|
|
2022-03-22 02:43:14 +08:00
|
|
|
// Don't create the following two nodes before prepare
|
2020-04-24 02:07:46 -07:00
|
|
|
class mirror_node : public node_entry {
|
2020-04-18 02:00:48 -07:00
|
|
|
public:
|
2020-12-30 22:11:24 -08:00
|
|
|
explicit mirror_node(dirent *entry) : node_entry(entry->d_name, entry->d_type, this) {}
|
|
|
|
void mount() override {
|
2023-01-20 03:46:35 +08:00
|
|
|
create_and_mount("mirror", mirror_path());
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
2020-04-18 02:00:48 -07:00
|
|
|
};
|
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
class tmpfs_node : public dir_node {
|
2020-04-18 02:00:48 -07:00
|
|
|
public:
|
2021-08-28 10:27:45 -07:00
|
|
|
explicit tmpfs_node(node_entry *node);
|
2020-12-30 22:11:24 -08:00
|
|
|
void mount() override;
|
2020-04-18 02:00:48 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// Poor man's dynamic cast without RTTI
|
|
|
|
template<class T>
|
|
|
|
static bool isa(node_entry *node) {
|
2020-12-30 22:11:24 -08:00
|
|
|
return node && (node->type() & type_id<T>());
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
template<class T>
|
|
|
|
static T *dyn_cast(node_entry *node) {
|
2021-08-28 10:27:45 -07:00
|
|
|
return isa<T>(node) ? static_cast<T*>(node) : nullptr;
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
string node_entry::module_mnt;
|
|
|
|
string node_entry::mirror_dir;
|
|
|
|
|
|
|
|
// other will be deleted
|
|
|
|
void node_entry::merge(node_entry *other) {
|
|
|
|
_name.swap(other->_name);
|
|
|
|
_file_type = other->_file_type;
|
|
|
|
_parent = other->_parent;
|
2020-12-30 22:11:24 -08:00
|
|
|
|
|
|
|
// Merge children if both is dir
|
2021-08-28 10:27:45 -07:00
|
|
|
if (auto a = dyn_cast<dir_node>(this)) {
|
|
|
|
if (auto b = dyn_cast<dir_node>(other)) {
|
2022-12-27 04:41:49 +08:00
|
|
|
a->_skip_mirror = b->_skip_mirror;
|
2021-08-28 10:27:45 -07:00
|
|
|
a->children.merge(b->children);
|
|
|
|
for (auto &pair : a->children)
|
|
|
|
pair.second->_parent = a;
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
}
|
2021-08-28 10:27:45 -07:00
|
|
|
delete other;
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const string &node_entry::node_path() {
|
2020-12-30 22:11:24 -08:00
|
|
|
if (_parent && _node_path.empty())
|
|
|
|
_node_path = _parent->node_path() + '/' + _name;
|
|
|
|
return _node_path;
|
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
|
|
|
|
|
|
|
template<typename Func>
|
2021-08-28 10:27:45 -07:00
|
|
|
dir_node::iterator dir_node::insert(iterator it, uint8_t type, const Func &fn, bool get_same) {
|
2020-12-30 22:11:24 -08:00
|
|
|
node_entry *node = nullptr;
|
|
|
|
if (it != children.end()) {
|
2021-08-28 10:27:45 -07:00
|
|
|
// Upgrade existing node only if higher rank
|
2020-12-30 22:11:24 -08:00
|
|
|
if (it->second->node_type < type) {
|
|
|
|
node = fn(it->second);
|
|
|
|
if (!node)
|
|
|
|
return children.end();
|
|
|
|
if (it->second)
|
2021-08-28 10:27:45 -07:00
|
|
|
node->merge(it->second);
|
2020-12-30 22:11:24 -08:00
|
|
|
it = children.erase(it);
|
|
|
|
// Minor optimization to make insert O(1) by using hint
|
|
|
|
if (it == children.begin())
|
|
|
|
it = children.emplace(node->_name, node).first;
|
|
|
|
else
|
|
|
|
it = children.emplace_hint(--it, node->_name, node);
|
|
|
|
} else {
|
2022-03-19 12:18:34 +08:00
|
|
|
if (get_same && it->second->node_type != type)
|
|
|
|
return children.end();
|
|
|
|
return it;
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
node = fn(node);
|
|
|
|
if (!node)
|
2021-08-28 10:27:45 -07:00
|
|
|
return children.end();
|
2020-12-30 22:11:24 -08:00
|
|
|
node->_parent = this;
|
|
|
|
it = children.emplace(node->_name, node).first;
|
|
|
|
}
|
|
|
|
return it;
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
template<class To, class From, class... Args>
|
|
|
|
dir_node::iterator dir_node::upgrade(iterator it, Args &&... args) {
|
|
|
|
return insert(it, type_id<To>(), [&](node_entry *&ex) -> node_entry * {
|
|
|
|
if (!ex)
|
|
|
|
return nullptr;
|
|
|
|
if constexpr (!std::is_same_v<From, node_entry>) {
|
|
|
|
// Type check if type is specified
|
|
|
|
if (!isa<From>(ex))
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
auto node = new To(static_cast<From *>(ex), std::forward<Args>(args)...);
|
|
|
|
ex = nullptr;
|
|
|
|
return node;
|
|
|
|
}, false);
|
|
|
|
}
|
|
|
|
|
2020-04-18 02:00:48 -07:00
|
|
|
node_entry* dir_node::extract(string_view name) {
|
2020-12-30 22:11:24 -08:00
|
|
|
auto it = children.find(name);
|
|
|
|
if (it != children.end()) {
|
|
|
|
auto ret = it->second;
|
|
|
|
children.erase(it);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return nullptr;
|
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) {
|
2020-12-30 22:11:24 -08:00
|
|
|
string mirror = mirror_path();
|
2022-12-27 04:41:49 +08:00
|
|
|
if (!skip_mirror()) {
|
|
|
|
if (auto dir = open_dir(mirror.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, "mirror");
|
|
|
|
} else {
|
|
|
|
// Insert mirror nodes
|
|
|
|
emplace<mirror_node>(entry->d_name, entry);
|
|
|
|
}
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto it = children.begin(); it != children.end(); ++it) {
|
2021-08-28 10:27:45 -07:00
|
|
|
// Need to upgrade all 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
|
|
|
}
|
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
// We need to upgrade to tmpfs node if any child:
|
|
|
|
// - Target does not exist
|
2022-12-27 04:41:49 +08:00
|
|
|
// - Source or target is a symlink (since we cannot bind mount link)
|
2021-08-28 10:27:45 -07:00
|
|
|
bool node_entry::should_be_tmpfs(node_entry *child) {
|
2022-12-27 04:41:49 +08:00
|
|
|
struct stat st{};
|
2020-12-30 22:11:24 -08:00
|
|
|
if (lstat(child->node_path().data(), &st) != 0) {
|
2021-08-28 10:27:45 -07:00
|
|
|
return true;
|
2020-12-30 22:11:24 -08:00
|
|
|
} else {
|
|
|
|
child->set_exist(true);
|
|
|
|
if (child->is_lnk() || S_ISLNK(st.st_mode))
|
2021-08-28 10:27:45 -07:00
|
|
|
return true;
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
2021-08-28 10:27:45 -07:00
|
|
|
return false;
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2022-12-27 04:41:49 +08:00
|
|
|
bool dir_node::prepare(bool should_skip_mirror) {
|
|
|
|
if (!skip_mirror() && should_skip_mirror) {
|
|
|
|
set_skip_mirror(true);
|
|
|
|
}
|
2021-08-28 10:27:45 -07:00
|
|
|
bool to_tmpfs = false;
|
2022-12-27 04:41:49 +08:00
|
|
|
if (!exist()) {
|
|
|
|
// If not exist, we need to create it by mounting tmpfs
|
|
|
|
to_tmpfs = true;
|
|
|
|
set_exist(true);
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
for (auto it = children.begin(); it != children.end();) {
|
2021-08-28 10:27:45 -07:00
|
|
|
if (should_be_tmpfs(it->second)) {
|
|
|
|
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;
|
|
|
|
}
|
2021-08-28 10:27:45 -07:00
|
|
|
// Tell parent to upgrade self to tmpfs
|
|
|
|
to_tmpfs = true;
|
2022-03-22 02:43:14 +08:00
|
|
|
// If child is inter_node and it does not (need to) exist, upgrade to module
|
2023-01-20 03:46:35 +08:00
|
|
|
if (auto dn = dyn_cast<inter_node>(it->second)) {
|
2022-03-22 02:43:14 +08:00
|
|
|
if (!dn->exist()) {
|
|
|
|
if (auto nit = upgrade<module_node, inter_node>(it); nit != children.end()) {
|
|
|
|
it = nit;
|
|
|
|
goto next_node;
|
|
|
|
}
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
}
|
2022-12-27 04:41:49 +08:00
|
|
|
if (auto dn = dyn_cast<dir_node>(it->second); dn && dn->prepare(skip_mirror())) {
|
2021-08-28 10:27:45 -07:00
|
|
|
// Upgrade child to tmpfs
|
|
|
|
it = upgrade<tmpfs_node>(it);
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
2020-04-22 05:04:45 -07:00
|
|
|
next_node:
|
2020-12-30 22:11:24 -08:00
|
|
|
++it;
|
|
|
|
}
|
2022-12-27 04:41:49 +08:00
|
|
|
return to_tmpfs || skip_mirror();
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2022-12-27 04:41:49 +08:00
|
|
|
void dir_node::collect_files(const char *module, int dfd) {
|
2020-12-30 22:11:24 -08:00
|
|
|
auto dir = xopen_dir(xopenat(dfd, _name.data(), O_RDONLY | O_CLOEXEC));
|
|
|
|
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()));) {
|
2022-12-27 04:41:49 +08:00
|
|
|
inter_node *dn;
|
2020-12-30 22:11:24 -08:00
|
|
|
if (entry->d_name == ".replace"sv) {
|
2022-12-27 04:41:49 +08:00
|
|
|
set_skip_mirror(true);
|
|
|
|
continue;
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (entry->d_type == DT_DIR) {
|
2022-03-19 12:18:34 +08:00
|
|
|
if (auto it = children.find(entry->d_name); it == children.end()) {
|
|
|
|
dn = emplace<inter_node>(entry->d_name, entry->d_name, module);
|
|
|
|
} else {
|
2022-03-22 02:43:14 +08:00
|
|
|
dn = dyn_cast<inter_node>(it->second);
|
2022-03-19 12:18:34 +08:00
|
|
|
}
|
2022-12-27 04:41:49 +08:00
|
|
|
if (dn) {
|
|
|
|
dn->collect_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-01-20 03:46:35 +08:00
|
|
|
void node_entry::create_and_mount(const char *reason, const string &src) {
|
2020-12-30 22:11:24 -08:00
|
|
|
const string &dest = node_path();
|
|
|
|
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());
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
2020-04-24 02:07:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void module_node::mount() {
|
2020-12-30 22:11:24 -08:00
|
|
|
string src = module_mnt + module + parent()->root()->prefix + node_path();
|
|
|
|
if (exist())
|
|
|
|
clone_attr(mirror_path().data(), src.data());
|
2021-08-28 10:27:45 -07:00
|
|
|
if (isa<tmpfs_node>(parent()))
|
2023-01-20 03:46:35 +08:00
|
|
|
create_and_mount("module", src);
|
2022-12-27 04:41:49 +08:00
|
|
|
else
|
2023-01-20 03:46:35 +08:00
|
|
|
bind_mount("module", src.data(), node_path().data());
|
2020-04-24 02:07:46 -07:00
|
|
|
}
|
|
|
|
|
2021-08-28 10:27:45 -07:00
|
|
|
void tmpfs_node::mount() {
|
2020-12-30 22:11:24 -08:00
|
|
|
string src = mirror_path();
|
|
|
|
const string &dest = node_path();
|
2022-03-19 12:18:34 +08:00
|
|
|
file_attr a{};
|
|
|
|
if (access(src.data(), F_OK) == 0)
|
|
|
|
getattr(src.data(), &a);
|
|
|
|
else
|
|
|
|
getattr(parent()->node_path().data(), &a);
|
2021-08-28 10:27:45 -07:00
|
|
|
if (!isa<tmpfs_node>(parent())) {
|
2020-12-30 22:11:24 -08:00
|
|
|
// We don't need another layer of tmpfs if parent is skel
|
2023-01-20 03:46:35 +08:00
|
|
|
auto worker_dir = MAGISKTMP + "/" WORKERDIR + dest;
|
|
|
|
mkdirs(worker_dir.data(), 0);
|
2022-12-27 04:41:49 +08:00
|
|
|
create_and_mount(skip_mirror() ? "replace" : "tmpfs", worker_dir);
|
2023-01-20 03:46:35 +08:00
|
|
|
} else {
|
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);
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
setattr(dest.data(), &a);
|
|
|
|
dir_node::mount();
|
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) {}
|
|
|
|
|
|
|
|
void mount() override {
|
2022-07-22 16:53:33 +08:00
|
|
|
const string src = MAGISKTMP + "/" + name();
|
|
|
|
if (access(src.data(), F_OK))
|
|
|
|
return;
|
|
|
|
|
2020-12-30 22:11:24 -08:00
|
|
|
const string &dir_name = parent()->node_path();
|
|
|
|
if (name() == "magisk") {
|
|
|
|
for (int i = 0; applet_names[i]; ++i) {
|
|
|
|
string dest = dir_name + "/" + applet_names[i];
|
|
|
|
VLOGD("create", "./magisk", dest.data());
|
|
|
|
xsymlink("./magisk", dest.data());
|
|
|
|
}
|
|
|
|
} else {
|
2022-03-17 03:15:39 -07:00
|
|
|
string dest = dir_name + "/supolicy";
|
|
|
|
VLOGD("create", "./magiskpolicy", dest.data());
|
|
|
|
xsymlink("./magiskpolicy", dest.data());
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
2023-01-20 03:46:35 +08:00
|
|
|
create_and_mount("magisk", src);
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
2020-04-18 05:15:59 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static void inject_magisk_bins(root_node *system) {
|
2020-12-30 22:11:24 -08:00
|
|
|
auto bin = system->child<inter_node>("bin");
|
|
|
|
if (!bin) {
|
|
|
|
bin = new inter_node("bin", "");
|
|
|
|
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
|
|
|
|
|
|
|
// Also delete all applets to make sure no modules can override it
|
|
|
|
for (int i = 0; applet_names[i]; ++i)
|
|
|
|
delete bin->extract(applet_names[i]);
|
2022-03-17 03:15:39 -07:00
|
|
|
delete bin->extract("supolicy");
|
2020-04-18 05:15:59 -07:00
|
|
|
}
|
|
|
|
|
2022-01-14 03:10:02 -08:00
|
|
|
vector<module_info> *module_list;
|
2021-10-27 01:53:16 -07:00
|
|
|
int app_process_32 = -1;
|
|
|
|
int app_process_64 = -1;
|
|
|
|
|
|
|
|
#define mount_zygisk(bit) \
|
|
|
|
if (access("/system/bin/app_process" #bit, F_OK) == 0) { \
|
|
|
|
app_process_##bit = xopen("/system/bin/app_process" #bit, O_RDONLY | O_CLOEXEC); \
|
|
|
|
string zbin = zygisk_bin + "/app_process" #bit; \
|
|
|
|
string mbin = MAGISKTMP + "/magisk" #bit; \
|
|
|
|
int src = xopen(mbin.data(), O_RDONLY | O_CLOEXEC); \
|
|
|
|
int out = xopen(zbin.data(), O_CREAT | O_WRONLY | O_CLOEXEC, 0); \
|
|
|
|
xsendfile(out, src, nullptr, INT_MAX); \
|
|
|
|
close(out); \
|
2022-06-01 01:50:42 -07:00
|
|
|
close(src); \
|
2021-10-27 01:53:16 -07:00
|
|
|
clone_attr("/system/bin/app_process" #bit, zbin.data()); \
|
2023-01-20 03:46:35 +08:00
|
|
|
bind_mount("zygisk", zbin.data(), "/system/bin/app_process" #bit); \
|
2021-09-15 01:59:43 -07:00
|
|
|
}
|
|
|
|
|
2020-05-08 00:45:11 -07:00
|
|
|
void magic_mount() {
|
2020-12-30 22:11:24 -08:00
|
|
|
node_entry::mirror_dir = MAGISKTMP + "/" MIRRDIR;
|
|
|
|
node_entry::module_mnt = MAGISKTMP + "/" MODULEMNT "/";
|
|
|
|
|
|
|
|
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();
|
|
|
|
char *b = buf + sprintf(buf, "%s/" MODULEMNT "/%s/", MAGISKTMP.data(), module);
|
|
|
|
|
|
|
|
// Read props
|
|
|
|
strcpy(b, "system.prop");
|
|
|
|
if (access(buf, F_OK) == 0) {
|
|
|
|
LOGI("%s: loading [system.prop]\n", module);
|
|
|
|
load_prop_file(buf, false);
|
|
|
|
}
|
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);
|
|
|
|
system->collect_files(module, fd);
|
|
|
|
close(fd);
|
2021-10-26 01:50:29 +08:00
|
|
|
}
|
2022-12-14 05:54:55 +08:00
|
|
|
if (MAGISKTMP != "/sbin" || !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);
|
|
|
|
}
|
|
|
|
|
2021-10-14 01:35:29 -07:00
|
|
|
if (!system->is_empty()) {
|
|
|
|
// Handle special read-only partitions
|
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
|
|
|
for (const char *part : { "/vendor", "/vendor_dlkm","/product",
|
|
|
|
"/system_ext", "/system_dlkm",
|
|
|
|
"/odm", "/odm_dlkm" }) {
|
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
|
|
|
|
|
|
|
// Mount on top of modules to enable zygisk
|
2021-09-15 02:49:54 -07:00
|
|
|
if (zygisk_enabled) {
|
|
|
|
string zygisk_bin = MAGISKTMP + "/" ZYGISKBIN;
|
|
|
|
mkdir(zygisk_bin.data(), 0);
|
|
|
|
mount_zygisk(32)
|
|
|
|
mount_zygisk(64)
|
|
|
|
}
|
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);
|
|
|
|
#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) {
|
|
|
|
int off = ssprintf(buf, sz, "%s/%s", MAGISKTMP.data(), RULESDIR);
|
|
|
|
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);
|
|
|
|
}
|