Fully migrate Magisk to C++

This commit is contained in:
topjohnwu 2018-11-04 03:38:06 -05:00
parent 4351de503f
commit cda57dd4b4
27 changed files with 548 additions and 607 deletions

View File

@ -32,14 +32,14 @@ LOCAL_C_INCLUDES := \
$(LIBUTILS)
LOCAL_SRC_FILES := \
misc/applets.c \
misc/img.c \
daemon/magisk.c \
daemon/daemon.c \
daemon/log_daemon.c \
daemon/bootstages.c \
daemon/socket.c \
daemon/db.c \
misc/applets.cpp \
misc/img.cpp \
daemon/magisk.cpp \
daemon/daemon.cpp \
daemon/log_daemon.cpp \
daemon/bootstages.cpp \
daemon/socket.cpp \
daemon/db.cpp \
magiskhide/magiskhide.cpp \
magiskhide/proc_monitor.cpp \
magiskhide/hide_utils.cpp \
@ -47,10 +47,10 @@ LOCAL_SRC_FILES := \
resetprop/resetprop.cpp \
resetprop/system_property_api.cpp \
resetprop/system_property_set.cpp \
su/su.c \
su/connect.c \
su/pts.c \
su/su_daemon.c
su/su.cpp \
su/connect.cpp \
su/pts.cpp \
su/su_daemon.cpp
LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)

View File

@ -24,13 +24,13 @@
#include "flags.h"
static char buf[PATH_MAX], buf2[PATH_MAX];
static struct vector module_list;
static Array<char *> module_list;
extern char **environ;
static int bind_mount(const char *from, const char *to);
/******************
* Node structure *
******************/
/***************
* Magic Mount *
***************/
// Precedence: MODULE > SKEL > INTER > DUMMY
#define IS_DUMMY 0x01 /* mount from mirror */
@ -42,73 +42,236 @@ extern char **environ;
#define IS_LNK(n) (n->type == DT_LNK)
#define IS_REG(n) (n->type == DT_REG)
struct node_entry {
class node_entry {
public:
const char *module; /* Only used when status & IS_MODULE */
char *name;
uint8_t type;
uint8_t status;
struct node_entry *parent;
struct vector *children;
node_entry *parent;
Array<node_entry *> children;
node_entry() = default;
node_entry(const char *, const char *, uint8_t type = 0, uint8_t status = 0);
node_entry(const char *, uint8_t type = 0, uint8_t status = 0);
~node_entry();
void create_module_tree(const char *module);
void magic_mount();
private:
char *get_path();
node_entry *insert(node_entry *);
void clone_skeleton();
int get_path(char *path);
};
static void concat_path(struct node_entry *node) {
if (node->parent)
concat_path(node->parent);
size_t len = strlen(buf);
buf[len] = '/';
strcpy(buf + len + 1, node->name);
node_entry::node_entry(const char *module, const char *name, uint8_t type, uint8_t status)
: node_entry(name, type, status) {
this->module = module;
}
static char *get_full_path(struct node_entry *node) {
buf[0] = '\0';
concat_path(node);
node_entry::node_entry(const char *name, uint8_t type, uint8_t status)
: type(type), status(status), parent(nullptr) {
this->name = strdup(name);
}
node_entry::~node_entry() {
free(name);
for (auto &node : children)
delete node;
}
char *node_entry::get_path() {
get_path(buf);
return strdup(buf);
}
// Free the node
static void destroy_node(struct node_entry *node) {
free(node->name);
vec_destroy(node->children);
free(node->children);
free(node);
int node_entry::get_path(char *path) {
int len = 0;
if (parent)
len = parent->get_path(path);
len += sprintf(path + len, "/%s", name);
return len;
}
// Free the node and all children recursively
static void destroy_subtree(struct node_entry *node) {
// Never free parent, since it shall be freed by themselves
struct node_entry *e;
vec_for_each(node->children, e) {
destroy_subtree(e);
}
destroy_node(node);
}
// Return the child
static struct node_entry *insert_child(struct node_entry *p, struct node_entry *c) {
c->parent = p;
if (p->children == NULL) {
p->children = xmalloc(sizeof(struct vector));
vec_init(p->children);
}
struct node_entry *e;
vec_for_each(p->children, e) {
if (strcmp(e->name, c->name) == 0) {
// Exist duplicate
if (c->status > e->status) {
// Precedence is higher, replace with new node
destroy_subtree(e);
vec_cur(p->children) = c;
return c;
node_entry *node_entry::insert(node_entry *node) {
node->parent = this;
for (auto &child : children) {
if (strcmp(child->name, node->name) == 0) {
if (node->status > child->status) {
// The new node has higher precedence
delete child;
child = node;
return node;
} else {
// Free the new entry, return old
destroy_node(c);
return e;
delete node;
return child;
}
}
}
// New entry, push back
vec_push_back(p->children, c);
return c;
children.push_back(node);
return node;
}
void node_entry::create_module_tree(const char *module) {
DIR *dir;
struct dirent *entry;
char *full_path = get_path();
snprintf(buf, PATH_MAX, "%s/%s%s", MOUNTPOINT, module, full_path);
if (!(dir = xopendir(buf)))
goto cleanup;
while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// Create new node
node_entry *node = new node_entry(module, entry->d_name, entry->d_type);
snprintf(buf, PATH_MAX, "%s/%s", full_path, node->name);
/*
* Clone the parent in the following condition:
* 1. File in module is a symlink
* 2. Target file do not exist
* 3. Target file is a symlink (exclude /system/vendor)
*/
bool clone = false;
if (IS_LNK(node) || access(buf, F_OK) == -1) {
clone = true;
} else if (parent != nullptr || strcmp(node->name, "vendor") != 0) {
struct stat s;
xstat(buf, &s);
if (S_ISLNK(s.st_mode))
clone = true;
}
if (clone) {
// Mark self as a skeleton
status |= IS_SKEL; /* This will not overwrite if parent is module */
node->status = IS_MODULE;
} else if (IS_DIR(node)) {
// Check if marked as replace
snprintf(buf2, PATH_MAX, "%s/%s%s/.replace", MOUNTPOINT, module, buf);
if (access(buf2, F_OK) == 0) {
// Replace everything, mark as leaf
node->status = IS_MODULE;
} else {
// This will be an intermediate node
node->status = IS_INTER;
}
} else if (IS_REG(node)) {
// This is a file, mark as leaf
node->status = IS_MODULE;
}
node = insert(node);
if (node->status & (IS_SKEL | IS_INTER)) {
// Intermediate folder, travel deeper
node->create_module_tree(module);
}
}
closedir(dir);
cleanup:
free(full_path);
}
void node_entry::clone_skeleton() {
DIR *dir;
struct dirent *entry;
struct node_entry *dummy;
// Clone the structure
char *full_path = get_path();
snprintf(buf, PATH_MAX, "%s%s", MIRRDIR, full_path);
if (!(dir = xopendir(buf)))
goto cleanup;
while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// Create dummy node
dummy = new node_entry(entry->d_name, entry->d_type, IS_DUMMY);
insert(dummy);
}
closedir(dir);
if (status & IS_SKEL) {
struct stat s;
char *con;
xstat(full_path, &s);
getfilecon(full_path, &con);
LOGI("mnt_tmpfs : %s\n", full_path);
xmount("tmpfs", full_path, "tmpfs", 0, nullptr);
chmod(full_path, s.st_mode & 0777);
chown(full_path, s.st_uid, s.st_gid);
setfilecon(full_path, con);
free(con);
}
for (auto &child : children) {
snprintf(buf, PATH_MAX, "%s/%s", full_path, child->name);
// Create the dummy file/directory
if (IS_DIR(child))
xmkdir(buf, 0755);
else if (IS_REG(child))
close(creat(buf, 0644));
// Links will be handled later
if (child->parent->parent == nullptr && strcmp(child->name, "vendor") == 0) {
if (IS_LNK(child)) {
cp_afc(MIRRDIR "/system/vendor", "/system/vendor");
LOGI("creat_link: %s <- %s\n", "/system/vendor", MIRRDIR "/system/vendor");
}
// Skip
continue;
} else if (child->status & IS_MODULE) {
// Mount from module file to dummy file
snprintf(buf2, PATH_MAX, "%s/%s%s/%s", MOUNTPOINT, child->module, full_path, child->name);
} else if (child->status & (IS_SKEL | IS_INTER)) {
// It's an intermediate folder, recursive clone
child->clone_skeleton();
continue;
} else if (child->status & IS_DUMMY) {
// Mount from mirror to dummy file
snprintf(buf2, PATH_MAX, "%s%s/%s", MIRRDIR, full_path, child->name);
}
if (IS_LNK(child)) {
// Copy symlinks directly
cp_afc(buf2, buf);
#ifdef MAGISK_DEBUG
LOGI("creat_link: %s <- %s\n",buf, buf2);
#else
LOGI("creat_link: %s\n", buf);
#endif
} else {
snprintf(buf, PATH_MAX, "%s/%s", full_path, child->name);
bind_mount(buf2, buf);
}
}
cleanup:
free(full_path);
}
void node_entry::magic_mount() {
if (status & IS_MODULE) {
// Mount module item
char *real_path = get_path();
snprintf(buf, PATH_MAX, "%s/%s%s", MOUNTPOINT, module, real_path);
bind_mount(buf, real_path);
free(real_path);
} else if (status & IS_SKEL) {
// The node is labeled to be cloned with skeleton, lets do it
clone_skeleton();
} else if (status & IS_INTER) {
// It's an intermediate node, travel deeper
for (auto &child : children)
child->magic_mount();
}
// The only thing goes here should be vendor placeholder
// There should be no dummies, so don't need to handle it here
}
/***********
@ -144,11 +307,12 @@ static void exec_common_script(const char* stage) {
if (access(buf2, X_OK) == -1)
continue;
LOGI("%s.d: exec [%s]\n", stage, entry->d_name);
int pid = exec_command(0, NULL,
strcmp(stage, "post-fs-data") ? set_path : set_mirror_path,
"sh", buf2, NULL);
int pid = exec_command(
0, nullptr,
strcmp(stage, "post-fs-data") ? set_path : set_mirror_path,
"sh", buf2, nullptr);
if (pid != -1)
waitpid(pid, NULL, 0);
waitpid(pid, nullptr, 0);
}
}
@ -156,206 +320,19 @@ static void exec_common_script(const char* stage) {
}
static void exec_module_script(const char* stage) {
char *module;
vec_for_each(&module_list, module) {
for (auto &module : module_list) {
snprintf(buf2, PATH_MAX, "%s/%s/%s.sh", MOUNTPOINT, module, stage);
snprintf(buf, PATH_MAX, "%s/%s/disable", MOUNTPOINT, module);
if (access(buf2, F_OK) == -1 || access(buf, F_OK) == 0)
continue;
LOGI("%s: exec [%s.sh]\n", module, stage);
int pid = exec_command(0, NULL,
strcmp(stage, "post-fs-data") ? set_path : set_mirror_path,
"sh", buf2, NULL);
int pid = exec_command(
0, nullptr,
strcmp(stage, "post-fs-data") ? set_path : set_mirror_path,
"sh", buf2, nullptr);
if (pid != -1)
waitpid(pid, NULL, 0);
waitpid(pid, nullptr, 0);
}
}
/***************
* Magic Mount *
***************/
static int bind_mount(const char *from, const char *to) {
int ret = xmount(from, to, NULL, MS_BIND, NULL);
#ifdef MAGISK_DEBUG
LOGI("bind_mount: %s <- %s\n", to, from);
#else
LOGI("bind_mount: %s\n", to);
#endif
return ret;
}
static void construct_tree(const char *module, struct node_entry *parent) {
DIR *dir;
struct dirent *entry;
struct node_entry *node;
char *parent_path = get_full_path(parent);
snprintf(buf, PATH_MAX, "%s/%s%s", MOUNTPOINT, module, parent_path);
if (!(dir = xopendir(buf)))
goto cleanup;
while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// Create new node
node = xcalloc(sizeof(*node), 1);
node->module = module;
node->name = strdup(entry->d_name);
node->type = entry->d_type;
snprintf(buf, PATH_MAX, "%s/%s", parent_path, node->name);
/*
* Clone the parent in the following condition:
* 1. File in module is a symlink
* 2. Target file do not exist
* 3. Target file is a symlink, but not /system/vendor
*/
int clone = 0;
if (IS_LNK(node) || access(buf, F_OK) == -1) {
clone = 1;
} else if (parent->parent != NULL || strcmp(node->name, "vendor") != 0) {
struct stat s;
xstat(buf, &s);
if (S_ISLNK(s.st_mode))
clone = 1;
}
if (clone) {
// Mark the parent folder as a skeleton
parent->status |= IS_SKEL; /* This will not overwrite if parent is module */
node->status = IS_MODULE;
} else if (IS_DIR(node)) {
// Check if marked as replace
snprintf(buf2, PATH_MAX, "%s/%s%s/.replace", MOUNTPOINT, module, buf);
if (access(buf2, F_OK) == 0) {
// Replace everything, mark as leaf
node->status = IS_MODULE;
} else {
// This will be an intermediate node
node->status = IS_INTER;
}
} else if (IS_REG(node)) {
// This is a leaf, mark as target
node->status = IS_MODULE;
}
node = insert_child(parent, node);
if (node->status & (IS_SKEL | IS_INTER)) {
// Intermediate folder, travel deeper
construct_tree(module, node);
}
}
closedir(dir);
cleanup:
free(parent_path);
}
static void clone_skeleton(struct node_entry *node) {
DIR *dir;
struct dirent *entry;
struct node_entry *dummy, *child;
// Clone the structure
char *full_path = get_full_path(node);
snprintf(buf, PATH_MAX, "%s%s", MIRRDIR, full_path);
if (!(dir = xopendir(buf)))
goto cleanup;
while ((entry = xreaddir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// Create dummy node
dummy = xcalloc(sizeof(*dummy), 1);
dummy->name = strdup(entry->d_name);
dummy->type = entry->d_type;
dummy->status = IS_DUMMY;
insert_child(node, dummy);
}
closedir(dir);
if (node->status & IS_SKEL) {
struct stat s;
char *con;
xstat(full_path, &s);
getfilecon(full_path, &con);
LOGI("mnt_tmpfs : %s\n", full_path);
xmount("tmpfs", full_path, "tmpfs", 0, NULL);
chmod(full_path, s.st_mode & 0777);
chown(full_path, s.st_uid, s.st_gid);
setfilecon(full_path, con);
free(con);
}
vec_for_each(node->children, child) {
snprintf(buf, PATH_MAX, "%s/%s", full_path, child->name);
// Create the dummy file/directory
if (IS_DIR(child))
xmkdir(buf, 0755);
else if (IS_REG(child))
close(creat(buf, 0644));
// Links will be handled later
if (child->parent->parent == NULL && strcmp(child->name, "vendor") == 0) {
if (IS_LNK(child)) {
cp_afc(MIRRDIR "/system/vendor", "/system/vendor");
LOGI("creat_link: %s <- %s\n", "/system/vendor", MIRRDIR "/system/vendor");
}
// Skip
continue;
} else if (child->status & IS_MODULE) {
// Mount from module file to dummy file
snprintf(buf2, PATH_MAX, "%s/%s%s/%s", MOUNTPOINT, child->module, full_path, child->name);
} else if (child->status & (IS_SKEL | IS_INTER)) {
// It's an intermediate folder, recursive clone
clone_skeleton(child);
continue;
} else if (child->status & IS_DUMMY) {
// Mount from mirror to dummy file
snprintf(buf2, PATH_MAX, "%s%s/%s", MIRRDIR, full_path, child->name);
}
if (IS_LNK(child)) {
// Copy symlinks directly
cp_afc(buf2, buf);
#ifdef MAGISK_DEBUG
LOGI("creat_link: %s <- %s\n",buf, buf2);
#else
LOGI("creat_link: %s\n", buf);
#endif
} else {
snprintf(buf, PATH_MAX, "%s/%s", full_path, child->name);
bind_mount(buf2, buf);
}
}
cleanup:
free(full_path);
}
static void magic_mount(struct node_entry *node) {
char *real_path;
struct node_entry *child;
if (node->status & IS_MODULE) {
// The real deal, mount module item
real_path = get_full_path(node);
snprintf(buf, PATH_MAX, "%s/%s%s", MOUNTPOINT, node->module, real_path);
bind_mount(buf, real_path);
free(real_path);
} else if (node->status & IS_SKEL) {
// The node is labeled to be cloned with skeleton, lets do it
clone_skeleton(node);
} else if (node->status & IS_INTER) {
// It's an intermediate node, travel deeper
vec_for_each(node->children, child)
magic_mount(child);
}
// The only thing goes here should be vendor placeholder
// There should be no dummies, so don't need to handle it here
}
/****************
@ -399,8 +376,18 @@ static void simple_mount(const char *path) {
* Miscellaneous *
*****************/
#define alt_img ((char *[]) \
{ "/cache/magisk.img", "/data/magisk_merge.img", "/data/adb/magisk_merge.img", NULL })
static int bind_mount(const char *from, const char *to) {
int ret = xmount(from, to, nullptr, MS_BIND, nullptr);
#ifdef MAGISK_DEBUG
LOGI("bind_mount: %s <- %s\n", to, from);
#else
LOGI("bind_mount: %s\n", to);
#endif
return ret;
}
#define alt_img ((const char *[]) \
{ "/cache/magisk.img", "/data/magisk_merge.img", "/data/adb/magisk_merge.img", nullptr })
static int prepare_img() {
// Merge images
@ -419,7 +406,7 @@ static int prepare_img() {
LOGI("* Mounting " MAINIMG "\n");
// Mounting magisk image
char *magiskloop = mount_image(MAINIMG, MOUNTPOINT);
if (magiskloop == NULL)
if (magiskloop == nullptr)
return 1;
xmkdir(COREDIR, 0755);
@ -447,7 +434,7 @@ static int prepare_img() {
snprintf(buf, PATH_MAX, "%s/%s/disable", MOUNTPOINT, entry->d_name);
if (access(buf, F_OK) == 0)
continue;
vec_push_back(&module_list, strdup(entry->d_name));
module_list.push_back(strdup(entry->d_name));
}
}
closedir(dir);
@ -459,19 +446,19 @@ static int prepare_img() {
}
static void install_apk(const char *apk) {
setfilecon(apk, "u:object_r:"SEPOL_FILE_DOMAIN":s0");
setfilecon(apk, "u:object_r:" SEPOL_FILE_DOMAIN ":s0");
while (1) {
sleep(5);
LOGD("apk_install: attempting to install APK");
int apk_res = -1, pid;
pid = exec_command(1, &apk_res, NULL, "/system/bin/pm", "install", "-r", apk, NULL);
pid = exec_command(1, &apk_res, nullptr, "/system/bin/pm", "install", "-r", apk, nullptr);
if (pid != -1) {
int err = 0;
while (fdgets(buf, PATH_MAX, apk_res) > 0) {
LOGD("apk_install: %s", buf);
err |= strstr(buf, "Error:") != NULL;
err |= strstr(buf, "Error:") != nullptr;
}
waitpid(pid, NULL, 0);
waitpid(pid, nullptr, 0);
close(apk_res);
// Keep trying until pm is started
if (err)
@ -482,38 +469,35 @@ static void install_apk(const char *apk) {
unlink(apk);
}
static int check_data() {
struct vector v;
vec_init(&v);
file_to_vector("/proc/mounts", &v);
char *line;
int mnt = 0;
vec_for_each(&v, line) {
if (strstr(line, " /data ") && strstr(line, "tmpfs") == NULL) {
mnt = 1;
break;
}
static bool check_data() {
bool mnt = false;
bool data = false;
Array<char *> mounts;
file_to_array("/proc/mounts", mounts);
for (auto &line : mounts) {
if (strstr(line, " /data ") && strstr(line, "tmpfs") == nullptr)
mnt = true;
free(line);
}
vec_deep_destroy(&v);
int data = 0;
mounts.clear();
if (mnt) {
char *crypto = getprop("ro.crypto.state");
if (crypto != NULL) {
if (crypto != nullptr) {
if (strcmp(crypto, "unencrypted") == 0) {
// Unencrypted, we can directly access data
data = 1;
data = true;
} else {
// Encrypted, check whether vold is started
char *vold = getprop("init.svc.vold");
if (vold != NULL) {
if (vold != nullptr) {
free(vold);
data = 1;
data = true;
}
}
free(crypto);
} else {
// ro.crypto.state is not set, assume it's unencrypted
data = 1;
data = true;
}
}
return data;
@ -521,18 +505,18 @@ static int check_data() {
extern int launch_magiskhide();
static void *start_magisk_hide(void *args) {
static void *start_magisk_hide(void *) {
launch_magiskhide();
return NULL;
return nullptr;
}
static void auto_start_magiskhide() {
if (!start_log_daemon())
return;
char *hide_prop = getprop2(MAGISKHIDE_PROP, 1);
if (hide_prop == NULL || strcmp(hide_prop, "0") != 0) {
char *hide_prop = getprop(MAGISKHIDE_PROP, 1);
if (hide_prop == nullptr || strcmp(hide_prop, "0") != 0) {
pthread_t thread;
xpthread_create(&thread, NULL, start_magisk_hide, NULL);
xpthread_create(&thread, nullptr, start_magisk_hide, nullptr);
pthread_detach(thread);
}
free(hide_prop);
@ -565,7 +549,7 @@ void unlock_blocks() {
static void unblock_boot_process() {
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0));
pthread_exit(NULL);
pthread_exit(nullptr);
}
static const char wrapper[] =
@ -621,7 +605,7 @@ void startup() {
void *magisk, *init;
size_t magisk_size, init_size;
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
xmount(nullptr, "/", nullptr, MS_REMOUNT, nullptr);
// Remove some traits of Magisk
unlink(MAGISKRC);
@ -645,7 +629,7 @@ void startup() {
close(sbin);
// Mount the /sbin tmpfs overlay
xmount("tmpfs", "/sbin", "tmpfs", 0, NULL);
xmount("tmpfs", "/sbin", "tmpfs", 0, nullptr);
chmod("/sbin", 0755);
setfilecon("/sbin", "u:object_r:rootfs:s0");
sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC);
@ -665,15 +649,15 @@ void startup() {
fd = creat("/sbin/magisk", 0755);
xwrite(fd, wrapper, sizeof(wrapper) - 1);
close(fd);
setfilecon("/sbin/magisk.bin", "u:object_r:"SEPOL_FILE_DOMAIN":s0");
setfilecon("/sbin/magisk", "u:object_r:"SEPOL_FILE_DOMAIN":s0");
setfilecon("/sbin/magisk.bin", "u:object_r:" SEPOL_FILE_DOMAIN ":s0");
setfilecon("/sbin/magisk", "u:object_r:" SEPOL_FILE_DOMAIN ":s0");
// Setup magiskinit symlinks
fd = creat("/sbin/magiskinit", 0755);
xwrite(fd, init, init_size);
close(fd);
free(init);
setfilecon("/sbin/magiskinit", "u:object_r:"SEPOL_FILE_DOMAIN":s0");
setfilecon("/sbin/magiskinit", "u:object_r:" SEPOL_FILE_DOMAIN ":s0");
for (int i = 0; init_applet[i]; ++i) {
snprintf(buf, PATH_MAX, "/sbin/%s", init_applet[i]);
xsymlink("/sbin/magiskinit", buf);
@ -691,10 +675,10 @@ void startup() {
close(root);
// Alternative binaries paths
char *alt_bin[] = { "/cache/data_bin", "/data/magisk",
const char *alt_bin[] = { "/cache/data_bin", "/data/magisk",
"/data/data/com.topjohnwu.magisk/install",
"/data/user_de/0/com.topjohnwu.magisk/install", NULL };
char *bin_path = NULL;
"/data/user_de/0/com.topjohnwu.magisk/install", nullptr };
const char *bin_path = nullptr;
for (int i = 0; alt_bin[i]; ++i) {
struct stat st;
if (lstat(alt_bin[i], &st) != -1 && !S_ISLNK(st.st_mode)) {
@ -723,19 +707,17 @@ void startup() {
xmkdir(BLOCKDIR, 0755);
LOGI("* Mounting mirrors");
struct vector mounts;
vec_init(&mounts);
file_to_vector("/proc/mounts", &mounts);
char *line;
Array<char *> mounts;
file_to_array("/proc/mounts", mounts);
int skip_initramfs = 0;
// Check whether skip_initramfs device
vec_for_each(&mounts, line) {
for (auto &line : mounts) {
if (strstr(line, " /system_root ")) {
bind_mount("/system_root/system", MIRRDIR "/system");
skip_initramfs = 1;
} else if (!skip_initramfs && strstr(line, " /system ")) {
sscanf(line, "%s %*s %s", buf, buf2);
xmount(buf, MIRRDIR "/system", buf2, MS_RDONLY, NULL);
xmount(buf, MIRRDIR "/system", buf2, MS_RDONLY, nullptr);
#ifdef MAGISK_DEBUG
LOGI("mount: %s <- %s\n", MIRRDIR "/system", buf);
#else
@ -745,7 +727,7 @@ void startup() {
seperate_vendor = 1;
sscanf(line, "%s %*s %s", buf, buf2);
xmkdir(MIRRDIR "/vendor", 0755);
xmount(buf, MIRRDIR "/vendor", buf2, MS_RDONLY, NULL);
xmount(buf, MIRRDIR "/vendor", buf2, MS_RDONLY, nullptr);
#ifdef MAGISK_DEBUG
LOGI("mount: %s <- %s\n", MIRRDIR "/vendor", buf);
#else
@ -754,7 +736,7 @@ void startup() {
}
free(line);
}
vec_destroy(&mounts);
mounts.clear();
if (!seperate_vendor) {
xsymlink(MIRRDIR "/system/vendor", MIRRDIR "/vendor");
#ifdef MAGISK_DEBUG
@ -767,12 +749,23 @@ void startup() {
bind_mount(DATABIN, MIRRDIR "/bin");
if (access(MIRRDIR "/bin/busybox", X_OK) == 0) {
LOGI("* Setting up internal busybox");
exec_command_sync(MIRRDIR "/bin/busybox", "--install", "-s", BBPATH, NULL);
exec_command_sync(MIRRDIR "/bin/busybox", "--install", "-s", BBPATH, nullptr);
xsymlink(MIRRDIR "/bin/busybox", BBPATH "/busybox");
}
// Start post-fs-data mode
execl("/sbin/magisk.bin", "magisk", "--post-fs-data", NULL);
execl("/sbin/magisk.bin", "magisk", "--post-fs-data", nullptr);
}
static void core_only() {
// Systemless hosts
if (access(HOSTSFILE, F_OK) == 0) {
LOGI("* Enabling systemless hosts file support");
bind_mount(HOSTSFILE, "/system/etc/hosts");
}
auto_start_magiskhide();
unblock_boot_process();
}
void post_fs_data(int client) {
@ -783,20 +776,20 @@ void post_fs_data(int client) {
// If post-fs-data mode is started, it means startup succeeded
setup_done = 1;
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
xmount(nullptr, "/", nullptr, MS_REMOUNT | MS_RDONLY, nullptr);
// Start log_daemon
start_log_daemon();
LOGI("** post-fs-data mode running\n");
// Allocate buffer
vec_init(&module_list);
// Merge, trim, mount magisk.img, which will also travel through the modules
// After this, it will create the module list
if (prepare_img())
goto core_only; // Mounting fails, we can only do core only stuffs
if (prepare_img()) {
// Mounting fails, we can only do core only stuffs
core_only();
return;
}
restorecon();
chmod(SECURE_DIR, 0700);
@ -806,30 +799,31 @@ void post_fs_data(int client) {
exec_common_script("post-fs-data");
// Core only mode
if (access(DISABLEFILE, F_OK) == 0)
goto core_only;
if (access(DISABLEFILE, F_OK) == 0) {
core_only();
return;
}
// Execute module scripts
LOGI("* Running module post-fs-data scripts\n");
exec_module_script("post-fs-data");
char *module;
struct node_entry *sys_root, *ven_root = NULL, *child;
// Create the system root entry
sys_root = xcalloc(sizeof(*sys_root), 1);
sys_root->name = strdup("system");
node_entry *sys_root = new node_entry("system");
sys_root->status = IS_INTER;
int has_modules = 0;
// Vendor root entry
node_entry *ven_root = nullptr;
bool has_modules = false;
LOGI("* Loading modules\n");
vec_for_each(&module_list, module) {
for (auto &module : module_list) {
// Read props
snprintf(buf, PATH_MAX, "%s/%s/system.prop", MOUNTPOINT, module);
if (access(buf, F_OK) == 0) {
LOGI("%s: loading [system.prop]\n", module);
read_prop_file(buf, 0);
load_prop_file(buf, 0);
}
// Check whether enable auto_mount
snprintf(buf, PATH_MAX, "%s/%s/auto_mount", MOUNTPOINT, module);
@ -841,7 +835,7 @@ void post_fs_data(int client) {
continue;
// Construct structure
has_modules = 1;
has_modules = true;
LOGI("%s: constructing magic mount structure\n", module);
// If /system/vendor exists in module, create a link outside
snprintf(buf, PATH_MAX, "%s/%s/system/vendor", MOUNTPOINT, module);
@ -850,44 +844,31 @@ void post_fs_data(int client) {
unlink(buf2);
xsymlink(buf, buf2);
}
construct_tree(module, sys_root);
sys_root->create_module_tree(module);
}
if (has_modules) {
// Extract the vendor node out of system tree and swap with placeholder
vec_for_each(sys_root->children, child) {
for (auto &child : sys_root->children) {
if (strcmp(child->name, "vendor") == 0) {
ven_root = child;
child = xcalloc(sizeof(*child), 1);
child->type = seperate_vendor ? DT_LNK : DT_DIR;
child = new node_entry("vendor", seperate_vendor ? DT_LNK : DT_DIR);
child->parent = ven_root->parent;
child->name = strdup("vendor");
child->status = 0;
// Swap!
vec_cur(sys_root->children) = child;
ven_root->parent = NULL;
ven_root->parent = nullptr;
break;
}
}
// Magic!!
magic_mount(sys_root);
if (ven_root) magic_mount(ven_root);
sys_root->magic_mount();
if (ven_root) ven_root->magic_mount();
}
// Cleanup memory
destroy_subtree(sys_root);
if (ven_root) destroy_subtree(ven_root);
delete sys_root;
if (ven_root) delete ven_root;
core_only:
// Systemless hosts
if (access(HOSTSFILE, F_OK) == 0) {
LOGI("* Enabling systemless hosts file support");
bind_mount(HOSTSFILE, "/system/etc/hosts");
}
auto_start_magiskhide();
unblock_boot_process();
core_only();
}
void late_start(int client) {
@ -903,7 +884,7 @@ void late_start(int client) {
if (!setup_done) {
// The setup failed for some reason, reboot and try again
exec_command_sync("/system/bin/reboot", NULL);
exec_command_sync("/system/bin/reboot", nullptr);
return;
}
@ -932,9 +913,9 @@ core_only:
struct db_strings str;
memset(&str, 0, sizeof(str));
get_db_strings(db, SU_MANAGER, &str);
if (validate_manager(str.s[SU_MANAGER], 0, NULL)) {
if (validate_manager(str.s[SU_MANAGER], 0, nullptr)) {
// There is no manager installed, install the stub
exec_command_sync("/sbin/magiskinit", "-x", "manager", "/data/magisk.apk", NULL);
exec_command_sync("/sbin/magiskinit", "-x", "manager", "/data/magisk.apk", nullptr);
install_apk("/data/magisk.apk");
}
sqlite3_close_v2(db);
@ -942,7 +923,9 @@ core_only:
}
// All boot stage done, cleanup
vec_deep_destroy(&module_list);
for (auto &module : module_list)
free(module);
module_list.clear();
}
void boot_complete(int client) {

View File

@ -31,7 +31,7 @@ static void get_client_cred(int fd, struct ucred *cred) {
static void *request_handler(void *args) {
int client = *((int *) args);
free(args);
delete (int *) args;
int req = read_int(client);
struct ucred credential;
@ -88,7 +88,7 @@ static void *request_handler(void *args) {
static void main_daemon() {
android_logging();
setsid();
setcon("u:r:"SEPOL_PROC_DOMAIN":s0");
setcon("u:r:" SEPOL_PROC_DOMAIN ":s0");
int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
xdup2(fd, STDOUT_FILENO);
xdup2(fd, STDERR_FILENO);
@ -123,7 +123,7 @@ static void main_daemon() {
// Loop forever to listen for requests
while(1) {
int *client = xmalloc(sizeof(int));
int *client = new int;
*client = xaccept4(fd, NULL, NULL, SOCK_CLOEXEC);
pthread_t thread;
xpthread_create(&thread, NULL, request_handler, client);

View File

@ -10,8 +10,8 @@
#define DB_VERSION 7
static int ver_cb(void *v, int col_num, char **data, char **col_name) {
*((int *) v) = atoi(data[0]);
static int ver_cb(void *ver, int, char **data, char **) {
*((int *) ver) = atoi(data[0]);
return 0;
}
@ -19,7 +19,7 @@ static int ver_cb(void *v, int col_num, char **data, char **col_name) {
if (err) { \
LOGE("sqlite3_exec: %s\n", err); \
sqlite3_free(err); \
return NULL; \
return nullptr; \
}
static sqlite3 *open_and_init_db() {
@ -27,7 +27,7 @@ static sqlite3 *open_and_init_db() {
int ret = sqlite3_open(MAGISKDB, &db);
if (ret) {
LOGE("sqlite3 open failure: %s\n", sqlite3_errstr(ret));
return NULL;
return nullptr;
}
int ver, upgrade = 0;
char *err;
@ -36,7 +36,7 @@ static sqlite3 *open_and_init_db() {
if (ver > DB_VERSION) {
// Don't support downgrading database
sqlite3_close_v2(db);
return NULL;
return nullptr;
}
if (ver < 3) {
// Policies
@ -44,20 +44,20 @@ static sqlite3 *open_and_init_db() {
"CREATE TABLE IF NOT EXISTS policies "
"(uid INT, package_name TEXT, policy INT, until INT, "
"logging INT, notification INT, PRIMARY KEY(uid))",
NULL, NULL, &err);
nullptr, nullptr, &err);
err_abort(err);
// Logs
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS logs "
"(from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, "
"to_uid INT, action INT, time INT, command TEXT)",
NULL, NULL, &err);
nullptr, nullptr, &err);
err_abort(err);
// Settings
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS settings "
"(key TEXT, value INT, PRIMARY KEY(key))",
NULL, NULL, &err);
nullptr, nullptr, &err);
err_abort(err);
ver = 3;
upgrade = 1;
@ -67,13 +67,13 @@ static sqlite3 *open_and_init_db() {
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS strings "
"(key TEXT, value TEXT, PRIMARY KEY(key))",
NULL, NULL, &err);
nullptr, nullptr, &err);
err_abort(err);
ver = 4;
upgrade = 1;
}
if (ver == 4) {
sqlite3_exec(db, "UPDATE policies SET uid=uid%100000", NULL, NULL, &err);
sqlite3_exec(db, "UPDATE policies SET uid=uid%100000", nullptr, nullptr, &err);
err_abort(err);
/* Skip version 5 */
ver = 6;
@ -84,7 +84,7 @@ static sqlite3 *open_and_init_db() {
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS hidelist "
"(process TEXT, PRIMARY KEY(process))",
NULL, NULL, &err);
nullptr, nullptr, &err);
err_abort(err);
ver = 7;
upgrade =1 ;
@ -94,7 +94,7 @@ static sqlite3 *open_and_init_db() {
// Set version
char query[32];
sprintf(query, "PRAGMA user_version=%d", ver);
sqlite3_exec(db, query, NULL, NULL, &err);
sqlite3_exec(db, query, nullptr, nullptr, &err);
err_abort(err);
}
return db;
@ -102,7 +102,7 @@ static sqlite3 *open_and_init_db() {
sqlite3 *get_magiskdb() {
sqlite3 *db = open_and_init_db();
if (db == NULL) {
if (db == nullptr) {
// Open fails, remove and reconstruct
unlink(MAGISKDB);
db = open_and_init_db();
@ -111,7 +111,7 @@ sqlite3 *get_magiskdb() {
}
static int settings_cb(void *v, int col_num, char **data, char **col_name) {
struct db_settings *dbs = v;
auto dbs = (db_settings *) v;
int key = -1, value;
for (int i = 0; i < col_num; ++i) {
if (strcmp(col_name[i], "key") == 0) {
@ -131,7 +131,7 @@ static int settings_cb(void *v, int col_num, char **data, char **col_name) {
}
int get_db_settings(sqlite3 *db, int key, struct db_settings *dbs) {
if (db == NULL)
if (db == nullptr)
return 1;
char *err;
if (key > 0) {
@ -150,7 +150,7 @@ int get_db_settings(sqlite3 *db, int key, struct db_settings *dbs) {
}
static int strings_cb(void *v, int col_num, char **data, char **col_name) {
struct db_strings *dbs = v;
auto dbs = (db_strings *) v;
int key = -1;
char *value;
for (int i = 0; i < col_num; ++i) {
@ -171,7 +171,7 @@ static int strings_cb(void *v, int col_num, char **data, char **col_name) {
}
int get_db_strings(sqlite3 *db, int key, struct db_strings *str) {
if (db == NULL)
if (db == nullptr)
return 1;
char *err;
if (key > 0) {
@ -190,7 +190,7 @@ int get_db_strings(sqlite3 *db, int key, struct db_strings *str) {
}
static int policy_cb(void *v, int col_num, char **data, char **col_name) {
struct su_access *su = v;
auto su = (su_access *) v;
for (int i = 0; i < col_num; i++) {
if (strcmp(col_name[i], "policy") == 0)
su->policy = (policy_t) atoi(data[i]);
@ -204,11 +204,11 @@ static int policy_cb(void *v, int col_num, char **data, char **col_name) {
}
int get_uid_policy(sqlite3 *db, int uid, struct su_access *su) {
if (db == NULL)
if (db == nullptr)
return 1;
char query[256], *err;
sprintf(query, "SELECT policy, logging, notification FROM policies "
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(NULL));
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr));
sqlite3_exec(db, query, policy_cb, su, &err);
if (err) {
LOGE("sqlite3_exec: %s\n", err);
@ -219,7 +219,7 @@ int get_uid_policy(sqlite3 *db, int uid, struct su_access *su) {
}
int validate_manager(char *alt_pkg, int userid, struct stat *st) {
if (st == NULL) {
if (st == nullptr) {
struct stat stat;
st = &stat;
}
@ -229,7 +229,7 @@ int validate_manager(char *alt_pkg, int userid, struct stat *st) {
sprintf(app_path, "%s/%d/%s", base, userid, alt_pkg[0] ? alt_pkg : "xxx");
if (stat(app_path, st)) {
// Check the official package name
sprintf(app_path, "%s/%d/"JAVA_PACKAGE_NAME, base, userid);
sprintf(app_path, "%s/%d/" JAVA_PACKAGE_NAME, base, userid);
if (stat(app_path, st)) {
LOGE("su: cannot find manager");
memset(st, 0, sizeof(*st));
@ -256,7 +256,7 @@ int exec_sql(const char *sql) {
sqlite3 *db = get_magiskdb();
if (db) {
char *err;
sqlite3_exec(db, sql, print_cb, NULL, &err);
sqlite3_exec(db, sql, print_cb, nullptr, &err);
sqlite3_close_v2(db);
if (err) {
fprintf(stderr, "sql_err: %s\n", err);

View File

@ -19,7 +19,7 @@
#include "flags.h"
int log_daemon_started = 0;
static struct vector log_cmd, clear_cmd;
static Array<const char *> log_cmd, clear_cmd;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
enum {
@ -33,7 +33,7 @@ struct log_listener {
};
static int am_proc_start_filter(const char *log) {
return strstr(log, "am_proc_start") != NULL;
return strstr(log, "am_proc_start") != nullptr;
}
static int magisk_log_filter(const char *log) {
@ -52,17 +52,17 @@ static struct log_listener events[] = {
};
#define EVENT_NUM (sizeof(events) / sizeof(struct log_listener))
static void sigpipe_handler(int sig) {
static void sigpipe_handler(int) {
close(events[HIDE_EVENT].fd);
events[HIDE_EVENT].fd = -1;
}
static void *monitor_thread(void *args) {
static void *monitor_thread(void *) {
// Block SIGPIPE to prevent interruption
sigset_t block_set;
sigemptyset(&block_set);
sigaddset(&block_set, SIGPIPE);
pthread_sigmask(SIG_SETMASK, &block_set, NULL);
pthread_sigmask(SIG_SETMASK, &block_set, nullptr);
// Give the main daemon some time before we monitor it
sleep(5);
int fd;
@ -77,12 +77,12 @@ static void *monitor_thread(void *args) {
}
}
static void *logcat_thread(void *args) {
static void *logcat_thread(void *) {
int log_fd = -1, log_pid;
char line[4096];
while (1) {
// Start logcat
log_pid = exec_array(0, &log_fd, NULL, (const char **) vec_entry(&log_cmd));
log_pid = exec_array(0, &log_fd, nullptr, log_cmd.data());
FILE *logs = fdopen(log_fd, "r");
while (fgets(line, sizeof(line), logs)) {
if (line[0] == '-')
@ -99,12 +99,12 @@ static void *logcat_thread(void *args) {
fclose(logs);
log_fd = -1;
kill(log_pid, SIGTERM);
waitpid(log_pid, NULL, 0);
waitpid(log_pid, nullptr, 0);
LOGI("magisklogd: logcat output EOF");
// Clear buffer
log_pid = exec_array(0, NULL, NULL, (const char **) vec_entry(&clear_cmd));
waitpid(log_pid, NULL, 0);
log_pid = exec_array(0, nullptr, nullptr, clear_cmd.data());
waitpid(log_pid, nullptr, 0);
}
}
@ -117,36 +117,42 @@ static void log_daemon() {
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = sigpipe_handler;
sigaction(SIGPIPE, &act, NULL);
sigaction(SIGPIPE, &act, nullptr);
// Setup log dumps
rename(LOGFILE, LOGFILE ".bak");
events[LOG_EVENT].fd = xopen(LOGFILE, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC | O_APPEND, 0644);
// Construct cmdline
vec_init(&log_cmd);
vec_push_back(&log_cmd, MIRRDIR "/system/bin/logcat");
log_cmd.push_back(MIRRDIR "/system/bin/logcat");
// Test whether these buffers actually works
const char* b[] = { "main", "events", "crash" };
for (int i = 0; i < 3; ++i) {
if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-b", b[i], "-d", "-f", "/dev/null", NULL) == 0)
vec_push_back_all(&log_cmd, "-b", b[i], NULL);
if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-b", b[i], "-d", "-f", "/dev/null", nullptr) == 0) {
log_cmd.push_back("-b");
log_cmd.push_back(b[i]);
}
}
chmod("/dev/null", 0666);
vec_dup(&log_cmd, &clear_cmd);
vec_push_back_all(&log_cmd, "-v", "threadtime", "-s", "am_proc_start", "Magisk", NULL);
clear_cmd = log_cmd;
log_cmd.push_back("-v");
log_cmd.push_back("threadtime");
log_cmd.push_back("-s");
log_cmd.push_back("am_proc_start");
log_cmd.push_back("Magisk");
#ifdef MAGISK_DEBUG
vec_push_back(&log_cmd, "*:F");
log_cmd.push_back("*:F");
#endif
vec_push_back(&log_cmd, NULL);
vec_push_back(&clear_cmd, "-c");
vec_push_back(&clear_cmd, NULL);
log_cmd.push_back(nullptr);
clear_cmd.push_back("-c");
clear_cmd.push_back(nullptr);
// Start worker threads
pthread_t thread;
pthread_create(&thread, NULL, monitor_thread, NULL);
pthread_create(&thread, nullptr, monitor_thread, nullptr);
pthread_detach(thread);
xpthread_create(&thread, NULL, logcat_thread, NULL);
xpthread_create(&thread, nullptr, logcat_thread, nullptr);
pthread_detach(thread);
// Handle socket requests
@ -157,7 +163,7 @@ static void log_daemon() {
exit(1);
xlisten(sockfd, 10);
while(1) {
int fd = xaccept4(sockfd, NULL, NULL, SOCK_CLOEXEC);
int fd = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
switch(read_int(fd)) {
case HIDE_CONNECT:
pthread_mutex_lock(&lock);
@ -175,7 +181,7 @@ static void log_daemon() {
int start_log_daemon() {
if (!log_daemon_started) {
if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-d", "-f", "/dev/null", NULL) == 0) {
if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-d", "-f", "/dev/null", nullptr) == 0) {
if (fork_dont_care() == 0)
log_daemon();
log_daemon_started = 1;

View File

@ -26,7 +26,7 @@ static int create_links(const char *bin, const char *path) {
return ret;
}
static void usage() {
[[noreturn]] static void usage() {
fprintf(stderr,
"Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) multi-call binary\n"
"\n"
@ -117,5 +117,4 @@ int magisk_main(int argc, char *argv[]) {
}
usage();
return 1;
}

View File

@ -50,6 +50,7 @@ int socket_accept(int sockfd, int timeout) {
int recv_fd(int sockfd) {
// Need to receive data from the message, otherwise don't care about it.
char iovbuf;
struct cmsghdr *cmsg;
struct iovec iov = {
.iov_base = &iovbuf,
@ -79,7 +80,7 @@ int recv_fd(int sockfd) {
goto error;
}
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg == NULL ||
cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
@ -104,8 +105,9 @@ error:
*/
void send_fd(int sockfd, int fd) {
// Need to send some data in the message, this will do.
char junk[] = { '\0' };
struct iovec iov = {
.iov_base = "",
.iov_base = junk,
.iov_len = 1,
};
@ -166,7 +168,7 @@ void write_int_be(int fd, int val) {
}
static char *rd_str(int fd, int len) {
char* val = xmalloc(sizeof(char) * (len + 1));
char *val = (char *) xmalloc(sizeof(char) * (len + 1));
xxread(fd, val, len);
val[len] = '\0';
return val;

View File

@ -4,10 +4,6 @@
#include <sqlite3.h>
#include <sys/stat.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************
* DB Settings *
***************/
@ -19,7 +15,7 @@ extern "C" {
"mnt_ns" \
})
#define DB_SETTINGS_NUM (sizeof(DB_SETTING_KEYS) / sizeof(char*))
#define DB_SETTINGS_NUM 3
// Settings indices
enum {
@ -52,15 +48,14 @@ enum {
struct db_settings {
int v[DB_SETTINGS_NUM];
db_settings()
: v {
ROOT_ACCESS_APPS_AND_ADB,
MULTIUSER_MODE_OWNER_ONLY,
NAMESPACE_MODE_REQUESTER
} {}
};
#define DEFAULT_DB_SETTINGS \
(struct db_settings) { .v = { \
ROOT_ACCESS_APPS_AND_ADB, \
MULTIUSER_MODE_OWNER_ONLY, \
NAMESPACE_MODE_REQUESTER, \
}}
/**************
* DB Strings *
**************/
@ -70,7 +65,7 @@ NAMESPACE_MODE_REQUESTER, \
"requester", \
})
#define DB_STRING_NUM (sizeof(DB_STRING_KEYS) / sizeof(char*))
#define DB_STRING_NUM 1
// Strings indices
enum {
@ -79,6 +74,10 @@ enum {
struct db_strings {
char s[DB_STRING_NUM][128];
db_strings() {
for (int i = 0; i < DB_STRING_NUM; ++i)
s[i][0] = '\0';
}
};
/*************
@ -97,19 +96,19 @@ struct su_access {
int notify;
};
#define DEFAULT_SU_ACCESS (struct su_access) { \
#define DEFAULT_SU_ACCESS (su_access) { \
.policy = QUERY, \
.log = 1, \
.notify = 1 \
}
#define SILENT_SU_ACCESS (struct su_access) { \
#define SILENT_SU_ACCESS (su_access) { \
.policy = ALLOW, \
.log = 0, \
.notify = 0 \
}
#define NO_SU_ACCESS (struct su_access) { \
#define NO_SU_ACCESS (su_access) { \
.policy = DENY, \
.log = 0, \
.notify = 0 \
@ -126,8 +125,4 @@ int get_uid_policy(sqlite3 *db, int uid, struct su_access *su);
int validate_manager(char *alt_pkg, int userid, struct stat *st);
int exec_sql(const char *sql);
#ifdef __cplusplus
}
#endif
#endif //DB_H

View File

@ -1,6 +1,10 @@
#ifndef IMG_H
#define IMG_H
#ifdef __cplusplus
extern "C" {
#endif
int create_img(const char *img, int size);
int resize_img(const char *img, int size);
char *mount_image(const char *img, const char *target);
@ -8,4 +12,8 @@ int umount_image(const char *target, const char *device);
int merge_img(const char *source, const char *target);
int trim_img(const char *img, const char *mount, char *loop);
#ifdef __cplusplus
}
#endif
#endif //IMG_H

View File

@ -45,8 +45,8 @@ extern "C" {
extern char *argv0; /* For changing process name */
#define applet_names ((char *[]) { "magisk", "su", "resetprop", "magiskhide", "imgtool", NULL })
#define init_applet ((char *[]) { "magiskpolicy", "supolicy", NULL })
#define applet_names ((const char *[]) { "magisk", "su", "resetprop", "magiskhide", "imgtool", NULL })
#define init_applet ((const char *[]) { "magiskpolicy", "supolicy", NULL })
extern int (*applet_main[]) (int, char *[]), (*init_applet_main[]) (int, char *[]);

View File

@ -1,25 +1,12 @@
/* resetprop.h - API for resetprop
*/
#ifndef _RESETPROP_H_
#define _RESETPROP_H_
#ifdef __cplusplus
extern "C" {
#endif
#pragma once
int prop_exist(const char *name);
int setprop(const char *name, const char *value);
int setprop2(const char *name, const char *value, const int trigger);
char *getprop(const char *name);
char *getprop2(const char *name, int persist);
int deleteprop(const char *name);
int deleteprop2(const char *name, const int persist);
int read_prop_file(const char* filename, const int trigger);
void getprop_all(void (*callback)(const char *, const char *, void *), void *cookie, int persist);
int setprop(const char *name, const char *value, const bool trigger = true);
char *getprop(const char *name, bool persist = false);
void getprop(void (*callback)(const char *, const char *, void *), void *cookie, bool persist = false);
int deleteprop(const char *name, bool persist = false);
int load_prop_file(const char *filename, const bool trigger = true);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -51,7 +51,7 @@ void hide_sensitive_props() {
value = getprop(prop_key[i]);
if (value) {
if (strcmp(value, prop_value[i]) != 0)
setprop2(prop_key[i], prop_value[i], 0);
setprop(prop_key[i], prop_value[i], false);
free(value);
}
}
@ -133,10 +133,10 @@ static void kill_process(const char *name) {
void clean_magisk_props() {
LOGD("hide_utils: Cleaning magisk props\n");
getprop_all([](const char *name, auto, auto) -> void {
getprop([](const char *name, auto, auto) -> void {
if (strstr(name, "magisk"))
deleteprop2(name, 0);
}, nullptr, 0);
deleteprop(name);
}, nullptr, false);
}
static int add_list(sqlite3 *db, char *proc) {

View File

@ -39,14 +39,14 @@ int launch_magiskhide() {
if (!log_daemon_started) {
setprop(MAGISKHIDE_PROP, "0");
// Remove without actually removing persist props
deleteprop2(MAGISKHIDE_PROP, 0);
deleteprop(MAGISKHIDE_PROP);
return LOGCAT_DISABLED;
}
hide_enabled = 1;
LOGI("* Starting MagiskHide\n");
deleteprop2(MAGISKHIDE_PROP, 1);
deleteprop(MAGISKHIDE_PROP, true);
hide_sensitive_props();
@ -77,7 +77,7 @@ int stop_magiskhide() {
hide_enabled = 0;
setprop(MAGISKHIDE_PROP, "0");
// Remove without actually removing persist props
deleteprop2(MAGISKHIDE_PROP, 0);
deleteprop(MAGISKHIDE_PROP);
pthread_kill(proc_monitor_thread, TERM_THREAD);
return DAEMON_SUCCESS;

View File

@ -9,9 +9,7 @@
#define TERM_THREAD SIGUSR1
// Daemon entries
extern "C" {
int launch_magiskhide();
}
int stop_magiskhide();
int add_list(int client);
int rm_list(int client);

View File

@ -1,4 +1,4 @@
/* img.c - All image related functions
/* img.cpp - All image related functions
*/
#include <unistd.h>

View File

@ -112,9 +112,9 @@ static int init_resetprop() {
return 0;
}
static void print_props(int persist) {
static void print_props(bool persist) {
auto prop_list = Array<prop_t>();
getprop_all(collect_props, &prop_list, persist);
getprop(collect_props, &prop_list, persist);
prop_list.sort();
for (auto &prop : prop_list)
printf("[%s]: [%s]\n", prop.name, prop.value);
@ -129,12 +129,8 @@ int prop_exist(const char *name) {
return __system_property_find(name) != nullptr;
}
char *getprop(const char *name) {
return getprop2(name, 0);
}
// Get prop by name, return string (should free manually!)
char *getprop2(const char *name, int persist) {
char *getprop(const char *name, bool persist) {
if (!check_legal_property_name(name) || init_resetprop())
return nullptr;
const prop_info *pi = __system_property_find(name);
@ -157,7 +153,7 @@ char *getprop2(const char *name, int persist) {
}
}
void getprop_all(void (*callback)(const char *, const char *, void *), void *cookie, int persist) {
void getprop(void (*callback)(const char *, const char *, void *), void *cookie, bool persist) {
if (init_resetprop()) return;
read_cb_t read_cb(callback, cookie);
__system_property_foreach(read_props, &read_cb);
@ -167,11 +163,7 @@ void getprop_all(void (*callback)(const char *, const char *, void *), void *coo
}
}
int setprop(const char *name, const char *value) {
return setprop2(name, value, 1);
}
int setprop2(const char *name, const char *value, const int trigger) {
int setprop(const char *name, const char *value, const bool trigger) {
if (!check_legal_property_name(name))
return 1;
if (init_resetprop())
@ -205,11 +197,7 @@ int setprop2(const char *name, const char *value, const int trigger) {
return ret;
}
int deleteprop(const char *name) {
return deleteprop2(name, 1);
}
int deleteprop2(const char *name, int persist) {
int deleteprop(const char *name, bool persist) {
if (!check_legal_property_name(name))
return 1;
if (init_resetprop()) return -1;
@ -221,7 +209,7 @@ int deleteprop2(const char *name, int persist) {
return __system_property_del(name) && !(persist && strncmp(name, "persist.", 8) == 0);
}
int read_prop_file(const char* filename, const int trigger) {
int load_prop_file(const char *filename, const bool trigger) {
if (init_resetprop()) return -1;
LOGD("resetprop: Load prop file [%s]\n", filename);
FILE *fp = fopen(filename, "r");
@ -255,7 +243,7 @@ int read_prop_file(const char* filename, const int trigger) {
if ( ((pch == nullptr) || (i >= (pch - line))) || (pch >= line + read - 1) ) continue;
// Separate the string
*pch = '\0';
setprop2(line + i, pch + 1, trigger);
setprop(line + i, pch + 1, trigger);
}
free(line);
fclose(fp);
@ -264,8 +252,8 @@ int read_prop_file(const char* filename, const int trigger) {
int resetprop_main(int argc, char *argv[]) {
log_cb.d = [](auto fmt, auto ap) -> int { return verbose ? vfprintf(stderr, fmt, ap) : 0; };
int trigger = 1, persist = 0;
bool trigger = true, persist = false;
char *argv0 = argv[0], *prop;
--argc;
@ -277,9 +265,9 @@ int resetprop_main(int argc, char *argv[]) {
switch (argv[0][idx]) {
case '-':
if (strcmp(argv[0], "--file") == 0 && argc == 2) {
return read_prop_file(argv[1], trigger);
return load_prop_file(argv[1], trigger);
} else if (strcmp(argv[0], "--delete") == 0 && argc == 2) {
return deleteprop2(argv[1], persist);
return deleteprop(argv[1], persist);
} else if (strcmp(argv[0], "--help") == 0) {
usage(argv0);
}
@ -309,13 +297,13 @@ int resetprop_main(int argc, char *argv[]) {
print_props(persist);
return 0;
case 1:
prop = getprop2(argv[0], persist);
prop = getprop(argv[0], persist);
if (prop == nullptr) return 1;
printf("%s\n", prop);
free(prop);
return 0;
case 2:
return setprop2(argv[0], argv[1], trigger);
return setprop(argv[0], argv[1], trigger);
default:
usage(argv0);
}

View File

@ -19,7 +19,7 @@
#define AM_PATH "/system/bin/app_process", "/system/bin", "com.android.commands.am.Am"
static char *get_command(const struct su_request *to) {
static const char *get_command(const struct su_request *to) {
if (to->command[0])
return to->command;
if (to->shell[0])
@ -27,7 +27,7 @@ static char *get_command(const struct su_request *to) {
return DEFAULT_SHELL;
}
static void silent_run(char * const args[]) {
static void silent_run(const char *args[]) {
if (fork_dont_care())
return;
int zero = open("/dev/zero", O_RDONLY | O_CLOEXEC);
@ -36,7 +36,7 @@ static void silent_run(char * const args[]) {
xdup2(null, 1);
xdup2(null, 2);
setenv("CLASSPATH", "/system/framework/am.jar", 1);
execv(args[0], args);
execv(args[0], (char **) args);
PLOGE("exec am");
_exit(EXIT_FAILURE);
}
@ -71,7 +71,7 @@ void app_log(struct su_context *ctx) {
char policy[2];
sprintf(policy, "%d", ctx->info->access.policy);
char *cmd[] = {
const char *cmd[] = {
AM_PATH, "broadcast",
"-a", "android.intent.action.BOOT_COMPLETED",
"-p", DB_STR(ctx->info, SU_MANAGER),
@ -84,7 +84,7 @@ void app_log(struct su_context *ctx) {
"--ei", "policy", policy,
"--es", "command", get_command(&ctx->req),
"--ez", "notify", ctx->info->access.notify ? "true" : "false",
NULL
nullptr
};
silent_run(cmd);
}
@ -101,7 +101,7 @@ void app_notify(struct su_context *ctx) {
char policy[2];
sprintf(policy, "%d", ctx->info->access.policy);
char *cmd[] = {
const char *cmd[] = {
AM_PATH, "broadcast",
"-a", "android.intent.action.BOOT_COMPLETED",
"-p", DB_STR(ctx->info, SU_MANAGER),
@ -110,7 +110,7 @@ void app_notify(struct su_context *ctx) {
"--es", "action", "notify",
"--ei", "from.uid", fromUid,
"--ei", "policy", policy,
NULL
nullptr
};
silent_run(cmd);
}
@ -118,15 +118,15 @@ void app_notify(struct su_context *ctx) {
void app_connect(const char *socket, struct su_info *info) {
char user[8];
setup_user(user, info);
char *cmd[] = {
const char *cmd[] = {
AM_PATH, "broadcast",
"-a", "android.intent.action.BOOT_COMPLETED",
"-p", DB_STR(info, SU_MANAGER),
"-f", "0x00000020",
"--user", user,
"--es", "action", "request",
"--es", "socket", (char *) socket,
NULL
"--es", "socket", socket,
nullptr
};
silent_run(cmd);
}
@ -135,4 +135,3 @@ void socket_send_request(int fd, struct su_info *info) {
write_key_token(fd, "uid", info->uid);
write_string_be(fd, "eof");
}

View File

@ -9,7 +9,6 @@
* helper functions to handle raw input mode and terminal window resizing
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

View File

@ -8,7 +8,6 @@
/* su.c - The main function running in the daemon
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -95,6 +94,12 @@ static void setup_sighandlers(void (*handler)(int)) {
}
}
// Default values
su_req_base::su_req_base()
: uid(UID_ROOT), login(false), keepenv(false), mount_master(false) {}
su_request::su_request()
: shell(DEFAULT_SHELL), command("") {}
/*
* Connect daemon, send argc, argv, cwd, pts slave
*/
@ -112,15 +117,7 @@ int su_client_main(int argc, char *argv[]) {
{ NULL, 0, NULL, 0 },
};
struct su_request su_req = {
.uid = UID_ROOT,
.login = 0,
.keepenv = 0,
.mount_master = 0,
.shell = DEFAULT_SHELL,
.command = "",
};
su_request su_req;
for (int i = 0; i < argc; i++) {
// Replace -cn with -z, -mm with -M for supporting getopt_long
@ -140,11 +137,11 @@ int su_client_main(int argc, char *argv[]) {
usage(EXIT_SUCCESS);
break;
case 'l':
su_req.login = 1;
su_req.login = true;
break;
case 'm':
case 'p':
su_req.keepenv = 1;
su_req.keepenv = true;
break;
case 's':
su_req.shell = optarg;
@ -159,7 +156,7 @@ int su_client_main(int argc, char *argv[]) {
// Do nothing, placed here for legacy support :)
break;
case 'M':
su_req.mount_master = 1;
su_req.mount_master = true;
break;
default:
/* Bionic getopt_long doesn't terminate its error output by newline */
@ -169,7 +166,7 @@ int su_client_main(int argc, char *argv[]) {
}
if (optind < argc && strcmp(argv[optind], "-") == 0) {
su_req.login = 1;
su_req.login = true;
optind++;
}
/* username or uid */
@ -200,7 +197,7 @@ int su_client_main(int argc, char *argv[]) {
}
// Send su_request
xwrite(fd, &su_req, 4 * sizeof(unsigned));
xwrite(fd, &su_req, sizeof(su_req_base));
write_string(fd, su_req.shell);
write_string(fd, su_req.command);
@ -242,4 +239,4 @@ int su_client_main(int argc, char *argv[]) {
close(fd);
return code;
}
}

View File

@ -17,9 +17,9 @@
#define ATTY_OUT 2
#define ATTY_ERR 4
struct su_info {
class su_info {
public:
unsigned uid; /* Unique key to find su_info */
pthread_mutex_t lock; /* Internal lock */
int count; /* Just a count for debugging purpose */
/* These values should be guarded with internal lock */
@ -31,19 +31,33 @@ struct su_info {
/* These should be guarded with global cache lock */
int ref;
int life;
su_info(unsigned uid);
~su_info();
void lock();
void unlock();
private:
pthread_mutex_t _lock; /* Internal lock */
};
#define DB_SET(i, e) (i)->dbs.v[e]
#define DB_STR(i, e) (i)->str.s[e]
struct su_request {
struct su_req_base {
unsigned uid;
unsigned login;
unsigned keepenv;
unsigned mount_master;
char *shell;
char *command;
};
bool login;
bool keepenv;
bool mount_master;
protected:
su_req_base();
} __attribute__((packed));
struct su_request : public su_req_base {
const char *shell;
const char *command;
su_request();
} __attribute__((packed));
struct su_context {
struct su_info *info;

View File

@ -1,8 +1,3 @@
/* su_daemon.c - The entrypoint for su, connect to daemon and send correct info
*/
#define _GNU_SOURCE
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
@ -25,32 +20,45 @@
#define TIMEOUT 3
#define LOCK_CACHE() pthread_mutex_lock(&cache_lock)
#define LOCK_INFO() pthread_mutex_lock(&info->lock)
#define UNLOCK_CACHE() pthread_mutex_unlock(&cache_lock)
#define UNLOCK_INFO() pthread_mutex_unlock(&info->lock)
static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
static struct su_info *cache;
static su_info *cache;
su_info::su_info(unsigned uid) :
uid(uid), access(DEFAULT_SU_ACCESS), _lock(PTHREAD_MUTEX_INITIALIZER),
count(0), ref(0), life(0), mgr_st({}) {}
su_info::~su_info() {
pthread_mutex_destroy(&_lock);
}
void su_info::lock() {
pthread_mutex_lock(&_lock);
}
void su_info::unlock() {
pthread_mutex_unlock(&_lock);
}
static void *info_collector(void *node) {
struct su_info *info = node;
su_info *info = (su_info *) node;
while (1) {
sleep(1);
if (info->life) {
LOCK_CACHE();
if (--info->life == 0 && cache && info->uid == cache->uid)
cache = NULL;
cache = nullptr;
UNLOCK_CACHE();
}
if (!info->life && !info->ref) {
pthread_mutex_destroy(&info->lock);
free(info);
return NULL;
delete info;
return nullptr;
}
}
}
static void database_check(struct su_info *info) {
static void database_check(su_info *info) {
int uid = info->uid;
sqlite3 *db = get_magiskdb();
if (db) {
@ -84,20 +92,16 @@ static void database_check(struct su_info *info) {
}
static struct su_info *get_su_info(unsigned uid) {
struct su_info *info;
int cache_miss = 0;
su_info *info;
bool cache_miss = false;
LOCK_CACHE();
if (cache && cache->uid == uid) {
info = cache;
} else {
cache_miss = 1;
info = xcalloc(1, sizeof(*info));
info->uid = uid;
info->dbs = DEFAULT_DB_SETTINGS;
info->access = DEFAULT_SU_ACCESS;
pthread_mutex_init(&info->lock, NULL);
cache_miss = true;
info = new su_info(uid);
cache = info;
}
@ -108,7 +112,7 @@ static struct su_info *get_su_info(unsigned uid) {
// Start a thread to maintain the cache
if (cache_miss) {
pthread_t thread;
xpthread_create(&thread, NULL, info_collector, info);
xpthread_create(&thread, nullptr, info_collector, info);
pthread_detach(thread);
}
@ -117,7 +121,7 @@ static struct su_info *get_su_info(unsigned uid) {
LOGD("su: request from uid=[%d] (#%d)\n", info->uid, ++info->count);
// Lock before the policy is determined
LOCK_INFO();
info->lock();
if (info->access.policy == QUERY) {
// Not cached, get data from database
@ -173,14 +177,14 @@ static struct su_info *get_su_info(unsigned uid) {
} else {
socket_send_request(fd, info);
int ret = read_int_be(fd);
info->access.policy = ret < 0 ? DENY : ret;
info->access.policy = ret < 0 ? DENY : static_cast<policy_t>(ret);
close(fd);
}
close(sockfd);
}
// Unlock
UNLOCK_INFO();
info->unlock();
return info;
}
@ -224,7 +228,7 @@ static void set_identity(unsigned uid) {
void su_daemon_handler(int client, struct ucred *credential) {
LOGD("su: request from client: %d\n", client);
struct su_info *info = get_su_info(credential->uid);
su_info *info = get_su_info(credential->uid);
// Fail fast
if (info->access.policy == DENY && DB_STR(info, SU_MANAGER)[0] == '\0') {
@ -289,7 +293,7 @@ void su_daemon_handler(int client, struct ucred *credential) {
}
// Read su_request
xxread(client, &ctx.req, 4 * sizeof(unsigned));
xxread(client, &ctx.req, sizeof(su_req_base));
ctx.req.shell = read_string(client);
ctx.req.command = read_string(client);
@ -367,7 +371,7 @@ void su_daemon_handler(int client, struct ucred *credential) {
app_notify(&ctx);
if (info->access.policy == ALLOW) {
char* argv[] = { NULL, NULL, NULL, NULL };
const char *argv[] = { nullptr, nullptr, nullptr, nullptr };
argv[0] = ctx.req.login ? "-" : ctx.req.shell;
@ -381,7 +385,7 @@ void su_daemon_handler(int client, struct ucred *credential) {
populate_environment(&ctx.req);
set_identity(ctx.req.uid);
execvp(ctx.req.shell, argv);
execvp(ctx.req.shell, (char **) argv);
fprintf(stderr, "Cannot execute %s: %s\n", ctx.req.shell, strerror(errno));
PLOGE("exec");
exit(EXIT_FAILURE);
@ -391,4 +395,3 @@ void su_daemon_handler(int client, struct ucred *credential) {
exit(EXIT_FAILURE);
}
}

View File

@ -9,7 +9,6 @@ LOCAL_SRC_FILES := \
selinux.cpp \
logging.cpp \
xwrap.cpp \
vector.c \
legacy.c
vector.c
include $(BUILD_STATIC_LIBRARY)

View File

@ -66,6 +66,15 @@ public:
T* _node;
};
T& operator = (const T& a) {
_size = a._size;
_capacity = a._capacity;
_data = new T[_capacity];
for(int i = 0; i < _size; ++i)
_data[i] = (T&&) a[i];
return *this;
}
iterator begin() const { return iterator(_data); }
iterator end() const { return iterator(_data + _size); }
@ -149,7 +158,8 @@ private:
_capacity *= 2;
T* temp = _data;
_data = new T[_capacity];
for(int i = 0; i < _size; ++i) _data[i] = (T&&) temp[i];
for(int i = 0; i < _size; ++i)
_data[i] = (T&&) temp[i];
delete [] temp;
}
};

View File

@ -4,7 +4,6 @@
extern "C" {
#endif
extern void (*freecon)(char * con);
extern int (*setcon)(const char * con);
extern int (*getfilecon)(const char *path, char ** con);

View File

@ -18,8 +18,6 @@ int file_to_array(const char* filename, Array<char *> &arr);
extern "C" {
#endif
#include "vector.h"
#define UID_SHELL (get_shell_uid())
#define UID_ROOT 0
#define UID_SYSTEM (get_system_uid())
@ -86,8 +84,6 @@ int xpoll(struct pollfd *fds, nfds_t nfds, int timeout);
unsigned get_shell_uid();
unsigned get_system_uid();
unsigned get_radio_uid();
int file_to_vector(const char* filename, struct vector *v);
int vector_to_file(const char* filename, struct vector *v);
ssize_t fdgets(char *buf, size_t size, int fd);
int is_num(const char *s);
int exec_array(int err, int *fd, void (*cb)(void), const char *argv[]);

View File

@ -1,41 +0,0 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "utils.h"
#include "logging.h"
/* All the string should be freed manually!! */
int file_to_vector(const char* filename, struct vector *v) {
if (access(filename, R_OK) != 0)
return 1;
char *line = NULL;
size_t len = 0;
ssize_t read;
FILE *fp = xfopen(filename, "r");
if (fp == NULL)
return 1;
while ((read = getline(&line, &len, fp)) != -1) {
// Remove end newline
if (line[read - 1] == '\n')
line[read - 1] = '\0';
vec_push_back(v, line);
line = NULL;
}
fclose(fp);
return 0;
}
int vector_to_file(const char *filename, struct vector *v) {
FILE *fp = xfopen(filename, "w");
if (fp == NULL)
return 1;
char *line;
vec_for_each(v, line) {
fprintf(fp, "%s\n", line);
}
fclose(fp);
return 0;
}