Fully migrate Magisk to C++
This commit is contained in:
parent
4351de503f
commit
cda57dd4b4
@ -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)
|
||||||
|
@ -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(
|
||||||
|
0, nullptr,
|
||||||
strcmp(stage, "post-fs-data") ? set_path : set_mirror_path,
|
strcmp(stage, "post-fs-data") ? set_path : set_mirror_path,
|
||||||
"sh", buf2, NULL);
|
"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(
|
||||||
|
0, nullptr,
|
||||||
strcmp(stage, "post-fs-data") ? set_path : set_mirror_path,
|
strcmp(stage, "post-fs-data") ? set_path : set_mirror_path,
|
||||||
"sh", buf2, NULL);
|
"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);
|
||||||
@ -464,14 +451,14 @@ static void install_apk(const char *apk) {
|
|||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
mounts.clear();
|
||||||
vec_deep_destroy(&v);
|
|
||||||
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);
|
||||||
@ -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) {
|
@ -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;
|
||||||
@ -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);
|
@ -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;
|
||||||
}
|
}
|
||||||
@ -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);
|
@ -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;
|
@ -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;
|
|
||||||
}
|
}
|
@ -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;
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 *[]);
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* img.c - All image related functions
|
/* img.cpp - All image related functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
@ -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>
|
@ -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);
|
||||||
|
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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)
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
@ -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[]);
|
||||||
|
@ -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;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user