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

View File

@ -24,13 +24,13 @@
#include "flags.h" #include "flags.h"
static char buf[PATH_MAX], buf2[PATH_MAX]; 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 // Precedence: MODULE > SKEL > INTER > DUMMY
#define IS_DUMMY 0x01 /* mount from mirror */ #define IS_DUMMY 0x01 /* mount from mirror */
@ -42,73 +42,236 @@ extern char **environ;
#define IS_LNK(n) (n->type == DT_LNK) #define IS_LNK(n) (n->type == DT_LNK)
#define IS_REG(n) (n->type == DT_REG) #define IS_REG(n) (n->type == DT_REG)
struct node_entry { class node_entry {
public:
const char *module; /* Only used when status & IS_MODULE */ const char *module; /* Only used when status & IS_MODULE */
char *name; char *name;
uint8_t type; uint8_t type;
uint8_t status; uint8_t status;
struct node_entry *parent; node_entry *parent;
struct vector *children; 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) { node_entry::node_entry(const char *module, const char *name, uint8_t type, uint8_t status)
if (node->parent) : node_entry(name, type, status) {
concat_path(node->parent); this->module = module;
size_t len = strlen(buf);
buf[len] = '/';
strcpy(buf + len + 1, node->name);
} }
static char *get_full_path(struct node_entry *node) { node_entry::node_entry(const char *name, uint8_t type, uint8_t status)
buf[0] = '\0'; : type(type), status(status), parent(nullptr) {
concat_path(node); 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); return strdup(buf);
} }
// Free the node int node_entry::get_path(char *path) {
static void destroy_node(struct node_entry *node) { int len = 0;
free(node->name); if (parent)
vec_destroy(node->children); len = parent->get_path(path);
free(node->children); len += sprintf(path + len, "/%s", name);
free(node); return len;
} }
// Free the node and all children recursively node_entry *node_entry::insert(node_entry *node) {
static void destroy_subtree(struct node_entry *node) { node->parent = this;
// Never free parent, since it shall be freed by themselves for (auto &child : children) {
struct node_entry *e; if (strcmp(child->name, node->name) == 0) {
vec_for_each(node->children, e) { if (node->status > child->status) {
destroy_subtree(e); // The new node has higher precedence
} delete child;
destroy_node(node); child = node;
} return 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;
} else { } else {
// Free the new entry, return old delete node;
destroy_node(c); return child;
return e;
} }
} }
} }
// New entry, push back children.push_back(node);
vec_push_back(p->children, c); return node;
return c; }
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) if (access(buf2, X_OK) == -1)
continue; continue;
LOGI("%s.d: exec [%s]\n", stage, entry->d_name); LOGI("%s.d: exec [%s]\n", stage, entry->d_name);
int pid = exec_command(0, NULL, int pid = exec_command(
strcmp(stage, "post-fs-data") ? set_path : set_mirror_path, 0, nullptr,
"sh", buf2, NULL); strcmp(stage, "post-fs-data") ? set_path : set_mirror_path,
"sh", buf2, nullptr);
if (pid != -1) 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) { static void exec_module_script(const char* stage) {
char *module; for (auto &module : module_list) {
vec_for_each(&module_list, module) {
snprintf(buf2, PATH_MAX, "%s/%s/%s.sh", MOUNTPOINT, module, stage); snprintf(buf2, PATH_MAX, "%s/%s/%s.sh", MOUNTPOINT, module, stage);
snprintf(buf, PATH_MAX, "%s/%s/disable", MOUNTPOINT, module); snprintf(buf, PATH_MAX, "%s/%s/disable", MOUNTPOINT, module);
if (access(buf2, F_OK) == -1 || access(buf, F_OK) == 0) if (access(buf2, F_OK) == -1 || access(buf, F_OK) == 0)
continue; continue;
LOGI("%s: exec [%s.sh]\n", module, stage); LOGI("%s: exec [%s.sh]\n", module, stage);
int pid = exec_command(0, NULL, int pid = exec_command(
strcmp(stage, "post-fs-data") ? set_path : set_mirror_path, 0, nullptr,
"sh", buf2, NULL); strcmp(stage, "post-fs-data") ? set_path : set_mirror_path,
"sh", buf2, nullptr);
if (pid != -1) 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 * * Miscellaneous *
*****************/ *****************/
#define alt_img ((char *[]) \ static int bind_mount(const char *from, const char *to) {
{ "/cache/magisk.img", "/data/magisk_merge.img", "/data/adb/magisk_merge.img", NULL }) 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() { static int prepare_img() {
// Merge images // Merge images
@ -419,7 +406,7 @@ static int prepare_img() {
LOGI("* Mounting " MAINIMG "\n"); LOGI("* Mounting " MAINIMG "\n");
// Mounting magisk image // Mounting magisk image
char *magiskloop = mount_image(MAINIMG, MOUNTPOINT); char *magiskloop = mount_image(MAINIMG, MOUNTPOINT);
if (magiskloop == NULL) if (magiskloop == nullptr)
return 1; return 1;
xmkdir(COREDIR, 0755); xmkdir(COREDIR, 0755);
@ -447,7 +434,7 @@ static int prepare_img() {
snprintf(buf, PATH_MAX, "%s/%s/disable", MOUNTPOINT, entry->d_name); snprintf(buf, PATH_MAX, "%s/%s/disable", MOUNTPOINT, entry->d_name);
if (access(buf, F_OK) == 0) if (access(buf, F_OK) == 0)
continue; continue;
vec_push_back(&module_list, strdup(entry->d_name)); module_list.push_back(strdup(entry->d_name));
} }
} }
closedir(dir); closedir(dir);
@ -459,19 +446,19 @@ static int prepare_img() {
} }
static void install_apk(const char *apk) { 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) { while (1) {
sleep(5); sleep(5);
LOGD("apk_install: attempting to install APK"); LOGD("apk_install: attempting to install APK");
int apk_res = -1, pid; 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) { if (pid != -1) {
int err = 0; int err = 0;
while (fdgets(buf, PATH_MAX, apk_res) > 0) { while (fdgets(buf, PATH_MAX, apk_res) > 0) {
LOGD("apk_install: %s", buf); 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); close(apk_res);
// Keep trying until pm is started // Keep trying until pm is started
if (err) if (err)
@ -482,38 +469,35 @@ static void install_apk(const char *apk) {
unlink(apk); unlink(apk);
} }
static int check_data() { static bool check_data() {
struct vector v; bool mnt = false;
vec_init(&v); bool data = false;
file_to_vector("/proc/mounts", &v); Array<char *> mounts;
char *line; file_to_array("/proc/mounts", mounts);
int mnt = 0; for (auto &line : mounts) {
vec_for_each(&v, line) { if (strstr(line, " /data ") && strstr(line, "tmpfs") == nullptr)
if (strstr(line, " /data ") && strstr(line, "tmpfs") == NULL) { mnt = true;
mnt = 1; free(line);
break;
}
} }
vec_deep_destroy(&v); mounts.clear();
int data = 0;
if (mnt) { if (mnt) {
char *crypto = getprop("ro.crypto.state"); char *crypto = getprop("ro.crypto.state");
if (crypto != NULL) { if (crypto != nullptr) {
if (strcmp(crypto, "unencrypted") == 0) { if (strcmp(crypto, "unencrypted") == 0) {
// Unencrypted, we can directly access data // Unencrypted, we can directly access data
data = 1; data = true;
} else { } else {
// Encrypted, check whether vold is started // Encrypted, check whether vold is started
char *vold = getprop("init.svc.vold"); char *vold = getprop("init.svc.vold");
if (vold != NULL) { if (vold != nullptr) {
free(vold); free(vold);
data = 1; data = true;
} }
} }
free(crypto); free(crypto);
} else { } else {
// ro.crypto.state is not set, assume it's unencrypted // ro.crypto.state is not set, assume it's unencrypted
data = 1; data = true;
} }
} }
return data; return data;
@ -521,18 +505,18 @@ static int check_data() {
extern int launch_magiskhide(); extern int launch_magiskhide();
static void *start_magisk_hide(void *args) { static void *start_magisk_hide(void *) {
launch_magiskhide(); launch_magiskhide();
return NULL; return nullptr;
} }
static void auto_start_magiskhide() { static void auto_start_magiskhide() {
if (!start_log_daemon()) if (!start_log_daemon())
return; return;
char *hide_prop = getprop2(MAGISKHIDE_PROP, 1); char *hide_prop = getprop(MAGISKHIDE_PROP, 1);
if (hide_prop == NULL || strcmp(hide_prop, "0") != 0) { if (hide_prop == nullptr || strcmp(hide_prop, "0") != 0) {
pthread_t thread; pthread_t thread;
xpthread_create(&thread, NULL, start_magisk_hide, NULL); xpthread_create(&thread, nullptr, start_magisk_hide, nullptr);
pthread_detach(thread); pthread_detach(thread);
} }
free(hide_prop); free(hide_prop);
@ -565,7 +549,7 @@ void unlock_blocks() {
static void unblock_boot_process() { static void unblock_boot_process() {
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0)); close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0));
pthread_exit(NULL); pthread_exit(nullptr);
} }
static const char wrapper[] = static const char wrapper[] =
@ -621,7 +605,7 @@ void startup() {
void *magisk, *init; void *magisk, *init;
size_t magisk_size, init_size; size_t magisk_size, init_size;
xmount(NULL, "/", NULL, MS_REMOUNT, NULL); xmount(nullptr, "/", nullptr, MS_REMOUNT, nullptr);
// Remove some traits of Magisk // Remove some traits of Magisk
unlink(MAGISKRC); unlink(MAGISKRC);
@ -645,7 +629,7 @@ void startup() {
close(sbin); close(sbin);
// Mount the /sbin tmpfs overlay // Mount the /sbin tmpfs overlay
xmount("tmpfs", "/sbin", "tmpfs", 0, NULL); xmount("tmpfs", "/sbin", "tmpfs", 0, nullptr);
chmod("/sbin", 0755); chmod("/sbin", 0755);
setfilecon("/sbin", "u:object_r:rootfs:s0"); setfilecon("/sbin", "u:object_r:rootfs:s0");
sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC); sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC);
@ -665,15 +649,15 @@ void startup() {
fd = creat("/sbin/magisk", 0755); fd = creat("/sbin/magisk", 0755);
xwrite(fd, wrapper, sizeof(wrapper) - 1); xwrite(fd, wrapper, sizeof(wrapper) - 1);
close(fd); close(fd);
setfilecon("/sbin/magisk.bin", "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"); setfilecon("/sbin/magisk", "u:object_r:" SEPOL_FILE_DOMAIN ":s0");
// Setup magiskinit symlinks // Setup magiskinit symlinks
fd = creat("/sbin/magiskinit", 0755); fd = creat("/sbin/magiskinit", 0755);
xwrite(fd, init, init_size); xwrite(fd, init, init_size);
close(fd); close(fd);
free(init); 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) { for (int i = 0; init_applet[i]; ++i) {
snprintf(buf, PATH_MAX, "/sbin/%s", init_applet[i]); snprintf(buf, PATH_MAX, "/sbin/%s", init_applet[i]);
xsymlink("/sbin/magiskinit", buf); xsymlink("/sbin/magiskinit", buf);
@ -691,10 +675,10 @@ void startup() {
close(root); close(root);
// Alternative binaries paths // 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/data/com.topjohnwu.magisk/install",
"/data/user_de/0/com.topjohnwu.magisk/install", NULL }; "/data/user_de/0/com.topjohnwu.magisk/install", nullptr };
char *bin_path = NULL; const char *bin_path = nullptr;
for (int i = 0; alt_bin[i]; ++i) { for (int i = 0; alt_bin[i]; ++i) {
struct stat st; struct stat st;
if (lstat(alt_bin[i], &st) != -1 && !S_ISLNK(st.st_mode)) { if (lstat(alt_bin[i], &st) != -1 && !S_ISLNK(st.st_mode)) {
@ -723,19 +707,17 @@ void startup() {
xmkdir(BLOCKDIR, 0755); xmkdir(BLOCKDIR, 0755);
LOGI("* Mounting mirrors"); LOGI("* Mounting mirrors");
struct vector mounts; Array<char *> mounts;
vec_init(&mounts); file_to_array("/proc/mounts", mounts);
file_to_vector("/proc/mounts", &mounts);
char *line;
int skip_initramfs = 0; int skip_initramfs = 0;
// Check whether skip_initramfs device // Check whether skip_initramfs device
vec_for_each(&mounts, line) { for (auto &line : mounts) {
if (strstr(line, " /system_root ")) { if (strstr(line, " /system_root ")) {
bind_mount("/system_root/system", MIRRDIR "/system"); bind_mount("/system_root/system", MIRRDIR "/system");
skip_initramfs = 1; skip_initramfs = 1;
} else if (!skip_initramfs && strstr(line, " /system ")) { } else if (!skip_initramfs && strstr(line, " /system ")) {
sscanf(line, "%s %*s %s", buf, buf2); 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 #ifdef MAGISK_DEBUG
LOGI("mount: %s <- %s\n", MIRRDIR "/system", buf); LOGI("mount: %s <- %s\n", MIRRDIR "/system", buf);
#else #else
@ -745,7 +727,7 @@ void startup() {
seperate_vendor = 1; seperate_vendor = 1;
sscanf(line, "%s %*s %s", buf, buf2); sscanf(line, "%s %*s %s", buf, buf2);
xmkdir(MIRRDIR "/vendor", 0755); xmkdir(MIRRDIR "/vendor", 0755);
xmount(buf, MIRRDIR "/vendor", buf2, MS_RDONLY, NULL); xmount(buf, MIRRDIR "/vendor", buf2, MS_RDONLY, nullptr);
#ifdef MAGISK_DEBUG #ifdef MAGISK_DEBUG
LOGI("mount: %s <- %s\n", MIRRDIR "/vendor", buf); LOGI("mount: %s <- %s\n", MIRRDIR "/vendor", buf);
#else #else
@ -754,7 +736,7 @@ void startup() {
} }
free(line); free(line);
} }
vec_destroy(&mounts); mounts.clear();
if (!seperate_vendor) { if (!seperate_vendor) {
xsymlink(MIRRDIR "/system/vendor", MIRRDIR "/vendor"); xsymlink(MIRRDIR "/system/vendor", MIRRDIR "/vendor");
#ifdef MAGISK_DEBUG #ifdef MAGISK_DEBUG
@ -767,12 +749,23 @@ void startup() {
bind_mount(DATABIN, MIRRDIR "/bin"); bind_mount(DATABIN, MIRRDIR "/bin");
if (access(MIRRDIR "/bin/busybox", X_OK) == 0) { if (access(MIRRDIR "/bin/busybox", X_OK) == 0) {
LOGI("* Setting up internal busybox"); 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"); xsymlink(MIRRDIR "/bin/busybox", BBPATH "/busybox");
} }
// Start post-fs-data mode // 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) { 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 // If post-fs-data mode is started, it means startup succeeded
setup_done = 1; 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
start_log_daemon(); start_log_daemon();
LOGI("** post-fs-data mode running\n"); 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 // Merge, trim, mount magisk.img, which will also travel through the modules
// After this, it will create the module list // After this, it will create the module list
if (prepare_img()) if (prepare_img()) {
goto core_only; // Mounting fails, we can only do core only stuffs // Mounting fails, we can only do core only stuffs
core_only();
return;
}
restorecon(); restorecon();
chmod(SECURE_DIR, 0700); chmod(SECURE_DIR, 0700);
@ -806,30 +799,31 @@ void post_fs_data(int client) {
exec_common_script("post-fs-data"); exec_common_script("post-fs-data");
// Core only mode // Core only mode
if (access(DISABLEFILE, F_OK) == 0) if (access(DISABLEFILE, F_OK) == 0) {
goto core_only; core_only();
return;
}
// Execute module scripts // Execute module scripts
LOGI("* Running module post-fs-data scripts\n"); LOGI("* Running module post-fs-data scripts\n");
exec_module_script("post-fs-data"); exec_module_script("post-fs-data");
char *module;
struct node_entry *sys_root, *ven_root = NULL, *child;
// Create the system root entry // Create the system root entry
sys_root = xcalloc(sizeof(*sys_root), 1); node_entry *sys_root = new node_entry("system");
sys_root->name = strdup("system");
sys_root->status = IS_INTER; 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"); LOGI("* Loading modules\n");
vec_for_each(&module_list, module) { for (auto &module : module_list) {
// Read props // Read props
snprintf(buf, PATH_MAX, "%s/%s/system.prop", MOUNTPOINT, module); snprintf(buf, PATH_MAX, "%s/%s/system.prop", MOUNTPOINT, module);
if (access(buf, F_OK) == 0) { if (access(buf, F_OK) == 0) {
LOGI("%s: loading [system.prop]\n", module); LOGI("%s: loading [system.prop]\n", module);
read_prop_file(buf, 0); load_prop_file(buf, 0);
} }
// Check whether enable auto_mount // Check whether enable auto_mount
snprintf(buf, PATH_MAX, "%s/%s/auto_mount", MOUNTPOINT, module); snprintf(buf, PATH_MAX, "%s/%s/auto_mount", MOUNTPOINT, module);
@ -841,7 +835,7 @@ void post_fs_data(int client) {
continue; continue;
// Construct structure // Construct structure
has_modules = 1; has_modules = true;
LOGI("%s: constructing magic mount structure\n", module); LOGI("%s: constructing magic mount structure\n", module);
// If /system/vendor exists in module, create a link outside // If /system/vendor exists in module, create a link outside
snprintf(buf, PATH_MAX, "%s/%s/system/vendor", MOUNTPOINT, module); snprintf(buf, PATH_MAX, "%s/%s/system/vendor", MOUNTPOINT, module);
@ -850,44 +844,31 @@ void post_fs_data(int client) {
unlink(buf2); unlink(buf2);
xsymlink(buf, buf2); xsymlink(buf, buf2);
} }
construct_tree(module, sys_root); sys_root->create_module_tree(module);
} }
if (has_modules) { if (has_modules) {
// Extract the vendor node out of system tree and swap with placeholder // 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) { if (strcmp(child->name, "vendor") == 0) {
ven_root = child; ven_root = child;
child = xcalloc(sizeof(*child), 1); child = new node_entry("vendor", seperate_vendor ? DT_LNK : DT_DIR);
child->type = seperate_vendor ? DT_LNK : DT_DIR;
child->parent = ven_root->parent; child->parent = ven_root->parent;
child->name = strdup("vendor"); ven_root->parent = nullptr;
child->status = 0;
// Swap!
vec_cur(sys_root->children) = child;
ven_root->parent = NULL;
break; break;
} }
} }
// Magic!! // Magic!!
magic_mount(sys_root); sys_root->magic_mount();
if (ven_root) magic_mount(ven_root); if (ven_root) ven_root->magic_mount();
} }
// Cleanup memory // Cleanup memory
destroy_subtree(sys_root); delete sys_root;
if (ven_root) destroy_subtree(ven_root); if (ven_root) delete ven_root;
core_only: 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 late_start(int client) { void late_start(int client) {
@ -903,7 +884,7 @@ void late_start(int client) {
if (!setup_done) { if (!setup_done) {
// The setup failed for some reason, reboot and try again // 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; return;
} }
@ -932,9 +913,9 @@ core_only:
struct db_strings str; struct db_strings str;
memset(&str, 0, sizeof(str)); memset(&str, 0, sizeof(str));
get_db_strings(db, SU_MANAGER, &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 // 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"); install_apk("/data/magisk.apk");
} }
sqlite3_close_v2(db); sqlite3_close_v2(db);
@ -942,7 +923,9 @@ core_only:
} }
// All boot stage done, cleanup // 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) { 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) { static void *request_handler(void *args) {
int client = *((int *) args); int client = *((int *) args);
free(args); delete (int *) args;
int req = read_int(client); int req = read_int(client);
struct ucred credential; struct ucred credential;
@ -88,7 +88,7 @@ static void *request_handler(void *args) {
static void main_daemon() { static void main_daemon() {
android_logging(); android_logging();
setsid(); setsid();
setcon("u:r:"SEPOL_PROC_DOMAIN":s0"); setcon("u:r:" SEPOL_PROC_DOMAIN ":s0");
int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC); int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
xdup2(fd, STDOUT_FILENO); xdup2(fd, STDOUT_FILENO);
xdup2(fd, STDERR_FILENO); xdup2(fd, STDERR_FILENO);
@ -123,7 +123,7 @@ static void main_daemon() {
// Loop forever to listen for requests // Loop forever to listen for requests
while(1) { while(1) {
int *client = xmalloc(sizeof(int)); int *client = new int;
*client = xaccept4(fd, NULL, NULL, SOCK_CLOEXEC); *client = xaccept4(fd, NULL, NULL, SOCK_CLOEXEC);
pthread_t thread; pthread_t thread;
xpthread_create(&thread, NULL, request_handler, client); xpthread_create(&thread, NULL, request_handler, client);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,10 @@
#ifndef IMG_H #ifndef IMG_H
#define IMG_H #define IMG_H
#ifdef __cplusplus
extern "C" {
#endif
int create_img(const char *img, int size); int create_img(const char *img, int size);
int resize_img(const char *img, int size); int resize_img(const char *img, int size);
char *mount_image(const char *img, const char *target); 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 merge_img(const char *source, const char *target);
int trim_img(const char *img, const char *mount, char *loop); int trim_img(const char *img, const char *mount, char *loop);
#ifdef __cplusplus
}
#endif
#endif //IMG_H #endif //IMG_H

View File

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

View File

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

View File

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

View File

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

View File

@ -9,9 +9,7 @@
#define TERM_THREAD SIGUSR1 #define TERM_THREAD SIGUSR1
// Daemon entries // Daemon entries
extern "C" {
int launch_magiskhide(); int launch_magiskhide();
}
int stop_magiskhide(); int stop_magiskhide();
int add_list(int client); int add_list(int client);
int rm_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> #include <unistd.h>

View File

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

View File

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

View File

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

View File

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

View File

@ -17,9 +17,9 @@
#define ATTY_OUT 2 #define ATTY_OUT 2
#define ATTY_ERR 4 #define ATTY_ERR 4
struct su_info { class su_info {
public:
unsigned uid; /* Unique key to find su_info */ unsigned uid; /* Unique key to find su_info */
pthread_mutex_t lock; /* Internal lock */
int count; /* Just a count for debugging purpose */ int count; /* Just a count for debugging purpose */
/* These values should be guarded with internal lock */ /* These values should be guarded with internal lock */
@ -31,19 +31,33 @@ struct su_info {
/* These should be guarded with global cache lock */ /* These should be guarded with global cache lock */
int ref; int ref;
int life; 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_SET(i, e) (i)->dbs.v[e]
#define DB_STR(i, e) (i)->str.s[e] #define DB_STR(i, e) (i)->str.s[e]
struct su_request { struct su_req_base {
unsigned uid; unsigned uid;
unsigned login; bool login;
unsigned keepenv; bool keepenv;
unsigned mount_master; bool mount_master;
char *shell; protected:
char *command; 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_context {
struct su_info *info; 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 <unistd.h>
#include <pthread.h> #include <pthread.h>
#include <stdlib.h> #include <stdlib.h>
@ -25,32 +20,45 @@
#define TIMEOUT 3 #define TIMEOUT 3
#define LOCK_CACHE() pthread_mutex_lock(&cache_lock) #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_CACHE() pthread_mutex_unlock(&cache_lock)
#define UNLOCK_INFO() pthread_mutex_unlock(&info->lock)
static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER; 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) { static void *info_collector(void *node) {
struct su_info *info = node; su_info *info = (su_info *) node;
while (1) { while (1) {
sleep(1); sleep(1);
if (info->life) { if (info->life) {
LOCK_CACHE(); LOCK_CACHE();
if (--info->life == 0 && cache && info->uid == cache->uid) if (--info->life == 0 && cache && info->uid == cache->uid)
cache = NULL; cache = nullptr;
UNLOCK_CACHE(); UNLOCK_CACHE();
} }
if (!info->life && !info->ref) { if (!info->life && !info->ref) {
pthread_mutex_destroy(&info->lock); delete info;
free(info); return nullptr;
return NULL;
} }
} }
} }
static void database_check(struct su_info *info) { static void database_check(su_info *info) {
int uid = info->uid; int uid = info->uid;
sqlite3 *db = get_magiskdb(); sqlite3 *db = get_magiskdb();
if (db) { if (db) {
@ -84,20 +92,16 @@ static void database_check(struct su_info *info) {
} }
static struct su_info *get_su_info(unsigned uid) { static struct su_info *get_su_info(unsigned uid) {
struct su_info *info; su_info *info;
int cache_miss = 0; bool cache_miss = false;
LOCK_CACHE(); LOCK_CACHE();
if (cache && cache->uid == uid) { if (cache && cache->uid == uid) {
info = cache; info = cache;
} else { } else {
cache_miss = 1; cache_miss = true;
info = xcalloc(1, sizeof(*info)); info = new su_info(uid);
info->uid = uid;
info->dbs = DEFAULT_DB_SETTINGS;
info->access = DEFAULT_SU_ACCESS;
pthread_mutex_init(&info->lock, NULL);
cache = info; cache = info;
} }
@ -108,7 +112,7 @@ static struct su_info *get_su_info(unsigned uid) {
// Start a thread to maintain the cache // Start a thread to maintain the cache
if (cache_miss) { if (cache_miss) {
pthread_t thread; pthread_t thread;
xpthread_create(&thread, NULL, info_collector, info); xpthread_create(&thread, nullptr, info_collector, info);
pthread_detach(thread); 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); LOGD("su: request from uid=[%d] (#%d)\n", info->uid, ++info->count);
// Lock before the policy is determined // Lock before the policy is determined
LOCK_INFO(); info->lock();
if (info->access.policy == QUERY) { if (info->access.policy == QUERY) {
// Not cached, get data from database // Not cached, get data from database
@ -173,14 +177,14 @@ static struct su_info *get_su_info(unsigned uid) {
} else { } else {
socket_send_request(fd, info); socket_send_request(fd, info);
int ret = read_int_be(fd); 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(fd);
} }
close(sockfd); close(sockfd);
} }
// Unlock // Unlock
UNLOCK_INFO(); info->unlock();
return info; return info;
} }
@ -224,7 +228,7 @@ static void set_identity(unsigned uid) {
void su_daemon_handler(int client, struct ucred *credential) { void su_daemon_handler(int client, struct ucred *credential) {
LOGD("su: request from client: %d\n", client); 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 // Fail fast
if (info->access.policy == DENY && DB_STR(info, SU_MANAGER)[0] == '\0') { 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 // 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.shell = read_string(client);
ctx.req.command = 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); app_notify(&ctx);
if (info->access.policy == ALLOW) { 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; 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); populate_environment(&ctx.req);
set_identity(ctx.req.uid); 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)); fprintf(stderr, "Cannot execute %s: %s\n", ctx.req.shell, strerror(errno));
PLOGE("exec"); PLOGE("exec");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -391,4 +395,3 @@ void su_daemon_handler(int client, struct ucred *credential) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }

View File

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

View File

@ -66,6 +66,15 @@ public:
T* _node; 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 begin() const { return iterator(_data); }
iterator end() const { return iterator(_data + _size); } iterator end() const { return iterator(_data + _size); }
@ -149,7 +158,8 @@ private:
_capacity *= 2; _capacity *= 2;
T* temp = _data; T* temp = _data;
_data = new T[_capacity]; _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; delete [] temp;
} }
}; };

View File

@ -4,7 +4,6 @@
extern "C" { extern "C" {
#endif #endif
extern void (*freecon)(char * con); extern void (*freecon)(char * con);
extern int (*setcon)(const char * con); extern int (*setcon)(const char * con);
extern int (*getfilecon)(const char *path, 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" { extern "C" {
#endif #endif
#include "vector.h"
#define UID_SHELL (get_shell_uid()) #define UID_SHELL (get_shell_uid())
#define UID_ROOT 0 #define UID_ROOT 0
#define UID_SYSTEM (get_system_uid()) #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_shell_uid();
unsigned get_system_uid(); unsigned get_system_uid();
unsigned get_radio_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); ssize_t fdgets(char *buf, size_t size, int fd);
int is_num(const char *s); int is_num(const char *s);
int exec_array(int err, int *fd, void (*cb)(void), const char *argv[]); 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;
}