Convert indentation to spaces

The tab war is lost
This commit is contained in:
topjohnwu
2020-12-30 22:11:24 -08:00
parent 947a7d6a2f
commit f9bde347bc
78 changed files with 10945 additions and 10945 deletions

View File

@@ -4,7 +4,7 @@
#include <utils.hpp>
int main(int argc, char *argv[]) {
umask(0);
cmdline_logging();
return APPLET_STUB_MAIN(argc, argv);
umask(0);
cmdline_logging();
return APPLET_STUB_MAIN(argc, argv);
}

View File

@@ -15,32 +15,32 @@ using main_fun = int (*)(int, char *[]);
static main_fun applet_main[] = { su_client_main, resetprop_main, magiskhide_main, nullptr };
[[noreturn]] static void call_applet(int argc, char **argv) {
// Applets
for (int i = 0; applet_names[i]; ++i) {
if (strcmp(basename(argv[0]), applet_names[i]) == 0) {
exit((*applet_main[i])(argc, argv));
}
}
fprintf(stderr, "%s: applet not found\n", basename(argv[0]));
exit(1);
// Applets
for (int i = 0; applet_names[i]; ++i) {
if (strcmp(basename(argv[0]), applet_names[i]) == 0) {
exit((*applet_main[i])(argc, argv));
}
}
fprintf(stderr, "%s: applet not found\n", basename(argv[0]));
exit(1);
}
int main(int argc, char *argv[]) {
umask(0);
dload_selinux();
cmdline_logging();
init_argv0(argc, argv);
umask(0);
dload_selinux();
cmdline_logging();
init_argv0(argc, argv);
if (basename(argv[0]) == "magisk"sv) {
if (argc > 1 && argv[1][0] != '-') {
// Calling applet via magisk [applet] args
--argc;
++argv;
} else {
return magisk_main(argc, argv);
}
}
if (basename(argv[0]) == "magisk"sv) {
if (argc > 1 && argv[1][0] != '-') {
// Calling applet via magisk [applet] args
--argc;
++argv;
} else {
return magisk_main(argc, argv);
}
}
call_applet(argc, argv);
call_applet(argc, argv);
}

View File

@@ -37,64 +37,64 @@ static bool safe_mode = false;
#define mount_mirror(part, flag) \
else if (MNT_DIR_IS("/" #part) && me->mnt_type != "tmpfs"sv && lstat(me->mnt_dir, &st) == 0) \
do_mount_mirror(part, flag)
do_mount_mirror(part, flag)
#define link_mirror(part) \
SETMIR(buf1, part); \
if (access("/system/" #part, F_OK) == 0 && access(buf1, F_OK) != 0) { \
xsymlink("./system/" #part, buf1); \
LOGI("link: %s\n", buf1); \
xsymlink("./system/" #part, buf1); \
LOGI("link: %s\n", buf1); \
}
#define link_orig_dir(dir, part) \
else if (MNT_DIR_IS(dir) && me->mnt_type != "tmpfs"sv) { \
SETMIR(buf1, part); \
rmdir(buf1); \
xsymlink(dir, buf1); \
LOGI("link: %s\n", buf1); \
SETMIR(buf1, part); \
rmdir(buf1); \
xsymlink(dir, buf1); \
LOGI("link: %s\n", buf1); \
}
#define link_orig(part) link_orig_dir("/" #part, part)
static void mount_mirrors() {
char buf1[4096];
char buf2[4096];
char buf1[4096];
char buf2[4096];
LOGI("* Mounting mirrors\n");
LOGI("* Mounting mirrors\n");
parse_mnt("/proc/mounts", [&](mntent *me) {
struct stat st;
if (0) {}
mount_mirror(system, MS_RDONLY)
mount_mirror(vendor, MS_RDONLY)
mount_mirror(product, MS_RDONLY)
mount_mirror(system_ext, MS_RDONLY)
mount_mirror(data, 0)
link_orig(cache)
link_orig(metadata)
link_orig(persist)
link_orig_dir("/mnt/vendor/persist", persist)
else if (SDK_INT >= 24 && MNT_DIR_IS("/proc") && !strstr(me->mnt_opts, "hidepid=2")) {
xmount(nullptr, "/proc", nullptr, MS_REMOUNT, "hidepid=2,gid=3009");
}
return true;
});
SETMIR(buf1, system);
if (access(buf1, F_OK) != 0) {
xsymlink("./system_root/system", buf1);
LOGI("link: %s\n", buf1);
parse_mnt("/proc/mounts", [&](mntent *me) {
struct stat st;
if (MNT_DIR_IS("/") && me->mnt_type != "rootfs"sv && stat("/", &st) == 0) {
do_mount_mirror(system_root, MS_RDONLY)
return false;
}
return true;
});
}
link_mirror(vendor)
link_mirror(product)
link_mirror(system_ext)
parse_mnt("/proc/mounts", [&](mntent *me) {
struct stat st;
if (0) {}
mount_mirror(system, MS_RDONLY)
mount_mirror(vendor, MS_RDONLY)
mount_mirror(product, MS_RDONLY)
mount_mirror(system_ext, MS_RDONLY)
mount_mirror(data, 0)
link_orig(cache)
link_orig(metadata)
link_orig(persist)
link_orig_dir("/mnt/vendor/persist", persist)
else if (SDK_INT >= 24 && MNT_DIR_IS("/proc") && !strstr(me->mnt_opts, "hidepid=2")) {
xmount(nullptr, "/proc", nullptr, MS_REMOUNT, "hidepid=2,gid=3009");
}
return true;
});
SETMIR(buf1, system);
if (access(buf1, F_OK) != 0) {
xsymlink("./system_root/system", buf1);
LOGI("link: %s\n", buf1);
parse_mnt("/proc/mounts", [&](mntent *me) {
struct stat st;
if (MNT_DIR_IS("/") && me->mnt_type != "rootfs"sv && stat("/", &st) == 0) {
do_mount_mirror(system_root, MS_RDONLY)
return false;
}
return true;
});
}
link_mirror(vendor)
link_mirror(product)
link_mirror(system_ext)
}
constexpr char bb_script[] = R"EOF(
@@ -105,167 +105,167 @@ exec /data/adb/magisk/busybox.bin "$@"
)EOF";
static bool magisk_env() {
char buf[4096];
char buf[4096];
LOGI("* Initializing Magisk environment\n");
LOGI("* Initializing Magisk environment\n");
string pkg;
check_manager(&pkg);
string pkg;
check_manager(&pkg);
sprintf(buf, "%s/0/%s/install", APP_DATA_DIR, pkg.data());
sprintf(buf, "%s/0/%s/install", APP_DATA_DIR, pkg.data());
// Alternative binaries paths
const char *alt_bin[] = { "/cache/data_adb/magisk", "/data/magisk", buf };
for (auto alt : alt_bin) {
struct stat st;
if (lstat(alt, &st) == 0) {
if (S_ISLNK(st.st_mode)) {
unlink(alt);
continue;
}
rm_rf(DATABIN);
cp_afc(alt, DATABIN);
rm_rf(alt);
break;
}
}
// Alternative binaries paths
const char *alt_bin[] = { "/cache/data_adb/magisk", "/data/magisk", buf };
for (auto alt : alt_bin) {
struct stat st;
if (lstat(alt, &st) == 0) {
if (S_ISLNK(st.st_mode)) {
unlink(alt);
continue;
}
rm_rf(DATABIN);
cp_afc(alt, DATABIN);
rm_rf(alt);
break;
}
}
// Remove stuffs
rm_rf("/cache/data_adb");
rm_rf("/data/adb/modules/.core");
unlink("/data/adb/magisk.img");
unlink("/data/adb/magisk_merge.img");
unlink("/data/magisk.img");
unlink("/data/magisk_merge.img");
unlink("/data/magisk_debug.log");
// Remove stuffs
rm_rf("/cache/data_adb");
rm_rf("/data/adb/modules/.core");
unlink("/data/adb/magisk.img");
unlink("/data/adb/magisk_merge.img");
unlink("/data/magisk.img");
unlink("/data/magisk_merge.img");
unlink("/data/magisk_debug.log");
// Directories in /data/adb
xmkdir(DATABIN, 0755);
xmkdir(MODULEROOT, 0755);
xmkdir(SECURE_DIR "/post-fs-data.d", 0755);
xmkdir(SECURE_DIR "/service.d", 0755);
// Directories in /data/adb
xmkdir(DATABIN, 0755);
xmkdir(MODULEROOT, 0755);
xmkdir(SECURE_DIR "/post-fs-data.d", 0755);
xmkdir(SECURE_DIR "/service.d", 0755);
// Disable/remove magiskhide, resetprop
if (SDK_INT < 19) {
unlink("/sbin/resetprop");
unlink("/sbin/magiskhide");
}
// Disable/remove magiskhide, resetprop
if (SDK_INT < 19) {
unlink("/sbin/resetprop");
unlink("/sbin/magiskhide");
}
if (access(DATABIN "/busybox.bin", X_OK)) {
if (access(DATABIN "/busybox", X_OK))
return false;
rename(DATABIN "/busybox", DATABIN "/busybox.bin");
}
if (access(DATABIN "/busybox.bin", X_OK)) {
if (access(DATABIN "/busybox", X_OK))
return false;
rename(DATABIN "/busybox", DATABIN "/busybox.bin");
}
sprintf(buf, "%s/" BBPATH "/busybox", MAGISKTMP.data());
{
auto fp = open_file(DATABIN "/busybox", "we");
fprintf(fp.get(), bb_script, buf);
}
chmod(DATABIN "/busybox", 0755);
mkdir(dirname(buf), 0755);
cp_afc(DATABIN "/busybox.bin", buf);
exec_command_async(buf, "--install", "-s", dirname(buf));
sprintf(buf, "%s/" BBPATH "/busybox", MAGISKTMP.data());
{
auto fp = open_file(DATABIN "/busybox", "we");
fprintf(fp.get(), bb_script, buf);
}
chmod(DATABIN "/busybox", 0755);
mkdir(dirname(buf), 0755);
cp_afc(DATABIN "/busybox.bin", buf);
exec_command_async(buf, "--install", "-s", dirname(buf));
return true;
return true;
}
void reboot() {
if (RECOVERY_MODE)
exec_command_sync("/system/bin/reboot", "recovery");
else
exec_command_sync("/system/bin/reboot");
if (RECOVERY_MODE)
exec_command_sync("/system/bin/reboot", "recovery");
else
exec_command_sync("/system/bin/reboot");
}
static bool check_data() {
bool mnt = false;
file_readline("/proc/mounts", [&](string_view s) {
if (str_contains(s, " /data ") && !str_contains(s, "tmpfs")) {
mnt = true;
return false;
}
return true;
});
if (!mnt)
return false;
auto crypto = getprop("ro.crypto.state");
if (!crypto.empty()) {
if (crypto == "unencrypted") {
// Unencrypted, we can directly access data
return true;
} else {
// Encrypted, check whether vold is started
return !getprop("init.svc.vold").empty();
}
}
// ro.crypto.state is not set, assume it's unencrypted
return true;
bool mnt = false;
file_readline("/proc/mounts", [&](string_view s) {
if (str_contains(s, " /data ") && !str_contains(s, "tmpfs")) {
mnt = true;
return false;
}
return true;
});
if (!mnt)
return false;
auto crypto = getprop("ro.crypto.state");
if (!crypto.empty()) {
if (crypto == "unencrypted") {
// Unencrypted, we can directly access data
return true;
} else {
// Encrypted, check whether vold is started
return !getprop("init.svc.vold").empty();
}
}
// ro.crypto.state is not set, assume it's unencrypted
return true;
}
void unlock_blocks() {
int fd, dev, OFF = 0;
int fd, dev, OFF = 0;
auto dir = xopen_dir("/dev/block");
if (!dir)
return;
dev = dirfd(dir.get());
auto dir = xopen_dir("/dev/block");
if (!dir)
return;
dev = dirfd(dir.get());
for (dirent *entry; (entry = readdir(dir.get()));) {
if (entry->d_type == DT_BLK) {
if ((fd = openat(dev, entry->d_name, O_RDONLY | O_CLOEXEC)) < 0)
continue;
if (ioctl(fd, BLKROSET, &OFF) < 0)
PLOGE("unlock %s", entry->d_name);
close(fd);
}
}
for (dirent *entry; (entry = readdir(dir.get()));) {
if (entry->d_type == DT_BLK) {
if ((fd = openat(dev, entry->d_name, O_RDONLY | O_CLOEXEC)) < 0)
continue;
if (ioctl(fd, BLKROSET, &OFF) < 0)
PLOGE("unlock %s", entry->d_name);
close(fd);
}
}
}
#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8)))
static bool check_key_combo() {
uint8_t bitmask[(KEY_MAX + 1) / 8];
vector<int> events;
constexpr char name[] = "/dev/.ev";
uint8_t bitmask[(KEY_MAX + 1) / 8];
vector<int> events;
constexpr char name[] = "/dev/.ev";
// First collect candidate events that accepts volume down
for (int minor = 64; minor < 96; ++minor) {
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
continue;
int fd = open(name, O_RDONLY | O_CLOEXEC);
unlink(name);
if (fd < 0)
continue;
memset(bitmask, 0, sizeof(bitmask));
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
if (test_bit(KEY_VOLUMEDOWN, bitmask))
events.push_back(fd);
else
close(fd);
}
if (events.empty())
return false;
// First collect candidate events that accepts volume down
for (int minor = 64; minor < 96; ++minor) {
if (xmknod(name, S_IFCHR | 0444, makedev(13, minor)))
continue;
int fd = open(name, O_RDONLY | O_CLOEXEC);
unlink(name);
if (fd < 0)
continue;
memset(bitmask, 0, sizeof(bitmask));
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitmask)), bitmask);
if (test_bit(KEY_VOLUMEDOWN, bitmask))
events.push_back(fd);
else
close(fd);
}
if (events.empty())
return false;
run_finally fin([&]{ std::for_each(events.begin(), events.end(), close); });
run_finally fin([&]{ std::for_each(events.begin(), events.end(), close); });
// Check if volume down key is held continuously for more than 3 seconds
for (int i = 0; i < 300; ++i) {
bool pressed = false;
for (const int &fd : events) {
memset(bitmask, 0, sizeof(bitmask));
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
if (test_bit(KEY_VOLUMEDOWN, bitmask)) {
pressed = true;
break;
}
}
if (!pressed)
return false;
// Check every 10ms
usleep(10000);
}
LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n");
return true;
// Check if volume down key is held continuously for more than 3 seconds
for (int i = 0; i < 300; ++i) {
bool pressed = false;
for (const int &fd : events) {
memset(bitmask, 0, sizeof(bitmask));
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
if (test_bit(KEY_VOLUMEDOWN, bitmask)) {
pressed = true;
break;
}
}
if (!pressed)
return false;
// Check every 10ms
usleep(10000);
}
LOGD("KEY_VOLUMEDOWN detected: enter safe mode\n");
return true;
}
/***********************
@@ -275,114 +275,114 @@ static bool check_key_combo() {
static pthread_mutex_t stage_lock = PTHREAD_MUTEX_INITIALIZER;
void post_fs_data(int client) {
// ack
write_int(client, 0);
close(client);
// ack
write_int(client, 0);
close(client);
mutex_guard lock(stage_lock);
mutex_guard lock(stage_lock);
if (getenv("REMOUNT_ROOT"))
xmount(nullptr, "/", nullptr, MS_REMOUNT | MS_RDONLY, nullptr);
if (getenv("REMOUNT_ROOT"))
xmount(nullptr, "/", nullptr, MS_REMOUNT | MS_RDONLY, nullptr);
if (!check_data())
goto unblock_init;
if (!check_data())
goto unblock_init;
DAEMON_STATE = STATE_POST_FS_DATA;
setup_logfile(true);
DAEMON_STATE = STATE_POST_FS_DATA;
setup_logfile(true);
LOGI("** post-fs-data mode running\n");
LOGI("** post-fs-data mode running\n");
unlock_blocks();
mount_mirrors();
unlock_blocks();
mount_mirrors();
if (access(SECURE_DIR, F_OK) != 0) {
if (SDK_INT < 24) {
// There is no FBE pre 7.0, we can directly create the folder without issues
xmkdir(SECURE_DIR, 0700);
} else {
// If the folder is not automatically created by Android,
// do NOT proceed further. Manual creation of the folder
// will cause bootloops on FBE devices.
LOGE(SECURE_DIR " is not present, abort\n");
goto early_abort;
}
}
if (access(SECURE_DIR, F_OK) != 0) {
if (SDK_INT < 24) {
// There is no FBE pre 7.0, we can directly create the folder without issues
xmkdir(SECURE_DIR, 0700);
} else {
// If the folder is not automatically created by Android,
// do NOT proceed further. Manual creation of the folder
// will cause bootloops on FBE devices.
LOGE(SECURE_DIR " is not present, abort\n");
goto early_abort;
}
}
if (!magisk_env()) {
LOGE("* Magisk environment incomplete, abort\n");
goto early_abort;
}
if (!magisk_env()) {
LOGE("* Magisk environment incomplete, abort\n");
goto early_abort;
}
if (getprop("persist.sys.safemode", true) == "1" || check_key_combo()) {
safe_mode = true;
// Disable all modules and magiskhide so next boot will be clean
disable_modules();
stop_magiskhide();
} else {
exec_common_scripts("post-fs-data");
auto_start_magiskhide();
handle_modules();
}
if (getprop("persist.sys.safemode", true) == "1" || check_key_combo()) {
safe_mode = true;
// Disable all modules and magiskhide so next boot will be clean
disable_modules();
stop_magiskhide();
} else {
exec_common_scripts("post-fs-data");
auto_start_magiskhide();
handle_modules();
}
early_abort:
// We still do magic mount because root itself might need it
magic_mount();
DAEMON_STATE = STATE_POST_FS_DATA_DONE;
// We still do magic mount because root itself might need it
magic_mount();
DAEMON_STATE = STATE_POST_FS_DATA_DONE;
unblock_init:
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0));
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0));
}
void late_start(int client) {
// ack
write_int(client, 0);
close(client);
// ack
write_int(client, 0);
close(client);
mutex_guard lock(stage_lock);
run_finally fin([]{ DAEMON_STATE = STATE_LATE_START_DONE; });
setup_logfile(false);
mutex_guard lock(stage_lock);
run_finally fin([]{ DAEMON_STATE = STATE_LATE_START_DONE; });
setup_logfile(false);
LOGI("** late_start service mode running\n");
LOGI("** late_start service mode running\n");
if (DAEMON_STATE < STATE_POST_FS_DATA_DONE || safe_mode)
return;
if (DAEMON_STATE < STATE_POST_FS_DATA_DONE || safe_mode)
return;
exec_common_scripts("service");
exec_module_scripts("service");
exec_common_scripts("service");
exec_module_scripts("service");
}
void boot_complete(int client) {
// ack
write_int(client, 0);
close(client);
// ack
write_int(client, 0);
close(client);
mutex_guard lock(stage_lock);
DAEMON_STATE = STATE_BOOT_COMPLETE;
setup_logfile(false);
mutex_guard lock(stage_lock);
DAEMON_STATE = STATE_BOOT_COMPLETE;
setup_logfile(false);
LOGI("** boot_complete triggered\n");
LOGI("** boot_complete triggered\n");
if (safe_mode)
return;
if (safe_mode)
return;
// At this point it's safe to create the folder
if (access(SECURE_DIR, F_OK) != 0)
xmkdir(SECURE_DIR, 0700);
// At this point it's safe to create the folder
if (access(SECURE_DIR, F_OK) != 0)
xmkdir(SECURE_DIR, 0700);
auto_start_magiskhide();
auto_start_magiskhide();
if (!check_manager()) {
if (access(MANAGERAPK, F_OK) == 0) {
// Only try to install APK when no manager is installed
// Magisk Manager should be upgraded by itself, not through recovery installs
rename(MANAGERAPK, "/data/magisk.apk");
install_apk("/data/magisk.apk");
} else {
// Install stub
auto init = MAGISKTMP + "/magiskinit";
exec_command_sync(init.data(), "-x", "manager", "/data/magisk.apk");
install_apk("/data/magisk.apk");
}
}
unlink(MANAGERAPK);
if (!check_manager()) {
if (access(MANAGERAPK, F_OK) == 0) {
// Only try to install APK when no manager is installed
// Magisk Manager should be upgraded by itself, not through recovery installs
rename(MANAGERAPK, "/data/magisk.apk");
install_apk("/data/magisk.apk");
} else {
// Install stub
auto init = MAGISKTMP + "/magiskinit";
exec_command_sync(init.data(), "-x", "manager", "/data/magisk.apk");
install_apk("/data/magisk.apk");
}
}
unlink(MANAGERAPK);
}

View File

@@ -26,101 +26,101 @@ int DAEMON_STATE = STATE_NONE;
static struct stat self_st;
static bool verify_client(pid_t pid) {
// Verify caller is the same as server
char path[32];
sprintf(path, "/proc/%d/exe", pid);
struct stat st;
return !(stat(path, &st) || st.st_dev != self_st.st_dev || st.st_ino != self_st.st_ino);
// Verify caller is the same as server
char path[32];
sprintf(path, "/proc/%d/exe", pid);
struct stat st;
return !(stat(path, &st) || st.st_dev != self_st.st_dev || st.st_ino != self_st.st_ino);
}
static void request_handler(int client, int req_code, ucred cred) {
switch (req_code) {
case MAGISKHIDE:
magiskhide_handler(client);
break;
case SUPERUSER:
su_daemon_handler(client, &cred);
break;
case POST_FS_DATA:
post_fs_data(client);
break;
case LATE_START:
late_start(client);
break;
case BOOT_COMPLETE:
boot_complete(client);
break;
case SQLITE_CMD:
exec_sql(client);
break;
case REMOVE_MODULES:
remove_modules();
write_int(client, 0);
close(client);
reboot();
break;
default:
close(client);
break;
}
switch (req_code) {
case MAGISKHIDE:
magiskhide_handler(client);
break;
case SUPERUSER:
su_daemon_handler(client, &cred);
break;
case POST_FS_DATA:
post_fs_data(client);
break;
case LATE_START:
late_start(client);
break;
case BOOT_COMPLETE:
boot_complete(client);
break;
case SQLITE_CMD:
exec_sql(client);
break;
case REMOVE_MODULES:
remove_modules();
write_int(client, 0);
close(client);
reboot();
break;
default:
close(client);
break;
}
}
static void handle_request(int client) {
int req_code;
int req_code;
// Verify client credentials
ucred cred;
get_client_cred(client, &cred);
if (cred.uid != 0 && !verify_client(cred.pid))
goto shortcut;
// Verify client credentials
ucred cred;
get_client_cred(client, &cred);
if (cred.uid != 0 && !verify_client(cred.pid))
goto shortcut;
req_code = read_int(client);
if (req_code < 0 || req_code >= DAEMON_CODE_END)
goto shortcut;
req_code = read_int(client);
if (req_code < 0 || req_code >= DAEMON_CODE_END)
goto shortcut;
// Check client permissions
switch (req_code) {
case MAGISKHIDE:
case POST_FS_DATA:
case LATE_START:
case BOOT_COMPLETE:
case SQLITE_CMD:
case GET_PATH:
if (cred.uid != 0) {
write_int(client, ROOT_REQUIRED);
goto shortcut;
}
break;
case REMOVE_MODULES:
if (cred.uid != UID_SHELL && cred.uid != UID_ROOT) {
write_int(client, 1);
goto shortcut;
}
break;
}
// Check client permissions
switch (req_code) {
case MAGISKHIDE:
case POST_FS_DATA:
case LATE_START:
case BOOT_COMPLETE:
case SQLITE_CMD:
case GET_PATH:
if (cred.uid != 0) {
write_int(client, ROOT_REQUIRED);
goto shortcut;
}
break;
case REMOVE_MODULES:
if (cred.uid != UID_SHELL && cred.uid != UID_ROOT) {
write_int(client, 1);
goto shortcut;
}
break;
}
// Simple requests
switch (req_code) {
case CHECK_VERSION:
write_string(client, MAGISK_VERSION ":MAGISK");
goto shortcut;
case CHECK_VERSION_CODE:
write_int(client, MAGISK_VER_CODE);
goto shortcut;
case GET_PATH:
write_string(client, MAGISKTMP.data());
goto shortcut;
case START_DAEMON:
setup_logfile(true);
goto shortcut;
}
// Simple requests
switch (req_code) {
case CHECK_VERSION:
write_string(client, MAGISK_VERSION ":MAGISK");
goto shortcut;
case CHECK_VERSION_CODE:
write_int(client, MAGISK_VER_CODE);
goto shortcut;
case GET_PATH:
write_string(client, MAGISKTMP.data());
goto shortcut;
case START_DAEMON:
setup_logfile(true);
goto shortcut;
}
// Create new thread to handle complex requests
new_daemon_thread([=] { return request_handler(client, req_code, cred); });
return;
// Create new thread to handle complex requests
new_daemon_thread([=] { return request_handler(client, req_code, cred); });
return;
shortcut:
close(client);
close(client);
}
static shared_ptr<FILE> log_file;
@@ -130,185 +130,185 @@ static char *log_buf;
static size_t log_buf_len;
void setup_logfile(bool reset) {
if (file_backed.test_and_set(memory_order_relaxed))
return;
if (reset)
rename(LOGFILE, LOGFILE ".bak");
if (file_backed.test_and_set(memory_order_relaxed))
return;
if (reset)
rename(LOGFILE, LOGFILE ".bak");
int fd = xopen(LOGFILE, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0644);
if (fd < 0) {
log_file.reset();
return;
}
int fd = xopen(LOGFILE, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0644);
if (fd < 0) {
log_file.reset();
return;
}
// Dump all logs in memory (if exists)
if (log_buf)
write(fd, log_buf, log_buf_len);
// Dump all logs in memory (if exists)
if (log_buf)
write(fd, log_buf, log_buf_len);
if (FILE *fp = fdopen(fd, "a")) {
setbuf(fp, nullptr);
log_file.reset(fp, &fclose);
}
if (FILE *fp = fdopen(fd, "a")) {
setbuf(fp, nullptr);
log_file.reset(fp, &fclose);
}
}
static int magisk_log(int prio, const char *fmt, va_list ap) {
va_list args;
va_copy(args, ap);
va_list args;
va_copy(args, ap);
// Log to logcat
__android_log_vprint(prio, "Magisk", fmt, ap);
// Log to logcat
__android_log_vprint(prio, "Magisk", fmt, ap);
auto local_log_file = log_file;
if (!local_log_file)
return 0;
auto local_log_file = log_file;
if (!local_log_file)
return 0;
char buf[4096];
timeval tv;
tm tm;
char type;
switch (prio) {
case ANDROID_LOG_DEBUG:
type = 'D';
break;
case ANDROID_LOG_INFO:
type = 'I';
break;
case ANDROID_LOG_WARN:
type = 'W';
break;
default:
type = 'E';
break;
}
gettimeofday(&tv, nullptr);
localtime_r(&tv.tv_sec, &tm);
size_t len = strftime(buf, sizeof(buf), "%m-%d %T", &tm);
int ms = tv.tv_usec / 1000;
len += sprintf(buf + len, ".%03d %c : ", ms, type);
strcpy(buf + len, fmt);
return vfprintf(local_log_file.get(), buf, args);
char buf[4096];
timeval tv;
tm tm;
char type;
switch (prio) {
case ANDROID_LOG_DEBUG:
type = 'D';
break;
case ANDROID_LOG_INFO:
type = 'I';
break;
case ANDROID_LOG_WARN:
type = 'W';
break;
default:
type = 'E';
break;
}
gettimeofday(&tv, nullptr);
localtime_r(&tv.tv_sec, &tm);
size_t len = strftime(buf, sizeof(buf), "%m-%d %T", &tm);
int ms = tv.tv_usec / 1000;
len += sprintf(buf + len, ".%03d %c : ", ms, type);
strcpy(buf + len, fmt);
return vfprintf(local_log_file.get(), buf, args);
}
static void android_logging() {
auto in_mem_file = make_stream_fp<byte_stream>(log_buf, log_buf_len);
log_file.reset(in_mem_file.release(), [](FILE *) {
free(log_buf);
log_buf = nullptr;
});
log_cb.d = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_DEBUG, fmt, ap); };
log_cb.i = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_INFO, fmt, ap); };
log_cb.w = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_WARN, fmt, ap); };
log_cb.e = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_ERROR, fmt, ap); };
log_cb.ex = nop_ex;
auto in_mem_file = make_stream_fp<byte_stream>(log_buf, log_buf_len);
log_file.reset(in_mem_file.release(), [](FILE *) {
free(log_buf);
log_buf = nullptr;
});
log_cb.d = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_DEBUG, fmt, ap); };
log_cb.i = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_INFO, fmt, ap); };
log_cb.w = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_WARN, fmt, ap); };
log_cb.e = [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_ERROR, fmt, ap); };
log_cb.ex = nop_ex;
}
static void daemon_entry(int ppid) {
android_logging();
android_logging();
int fd = xopen("/dev/null", O_WRONLY);
xdup2(fd, STDOUT_FILENO);
xdup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO)
close(fd);
fd = xopen("/dev/zero", O_RDONLY);
xdup2(fd, STDIN_FILENO);
if (fd > STDERR_FILENO)
close(fd);
int fd = xopen("/dev/null", O_WRONLY);
xdup2(fd, STDOUT_FILENO);
xdup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO)
close(fd);
fd = xopen("/dev/zero", O_RDONLY);
xdup2(fd, STDIN_FILENO);
if (fd > STDERR_FILENO)
close(fd);
setsid();
setcon("u:r:" SEPOL_PROC_DOMAIN ":s0");
setsid();
setcon("u:r:" SEPOL_PROC_DOMAIN ":s0");
LOGI(NAME_WITH_VER(Magisk) " daemon started\n");
LOGI(NAME_WITH_VER(Magisk) " daemon started\n");
// Make sure ppid is not in acct
char src[64], dest[64];
sprintf(src, "/acct/uid_0/pid_%d", ppid);
sprintf(dest, "/acct/uid_0/pid_%d", getpid());
rename(src, dest);
// Make sure ppid is not in acct
char src[64], dest[64];
sprintf(src, "/acct/uid_0/pid_%d", ppid);
sprintf(dest, "/acct/uid_0/pid_%d", getpid());
rename(src, dest);
// Get self stat
xreadlink("/proc/self/exe", src, sizeof(src));
MAGISKTMP = dirname(src);
xstat("/proc/self/exe", &self_st);
// Get self stat
xreadlink("/proc/self/exe", src, sizeof(src));
MAGISKTMP = dirname(src);
xstat("/proc/self/exe", &self_st);
// Get API level
parse_prop_file("/system/build.prop", [](auto key, auto val) -> bool {
if (key == "ro.build.version.sdk") {
SDK_INT = parse_int(val);
return false;
}
return true;
});
if (SDK_INT < 0) {
// In case some devices do not store this info in build.prop, fallback to getprop
auto sdk = getprop("ro.build.version.sdk");
if (!sdk.empty()) {
SDK_INT = parse_int(sdk);
}
}
LOGI("* Device API level: %d\n", SDK_INT);
// Get API level
parse_prop_file("/system/build.prop", [](auto key, auto val) -> bool {
if (key == "ro.build.version.sdk") {
SDK_INT = parse_int(val);
return false;
}
return true;
});
if (SDK_INT < 0) {
// In case some devices do not store this info in build.prop, fallback to getprop
auto sdk = getprop("ro.build.version.sdk");
if (!sdk.empty()) {
SDK_INT = parse_int(sdk);
}
}
LOGI("* Device API level: %d\n", SDK_INT);
restore_tmpcon();
restore_tmpcon();
// SAR cleanups
auto mount_list = MAGISKTMP + "/" ROOTMNT;
if (access(mount_list.data(), F_OK) == 0) {
file_readline(true, mount_list.data(), [](string_view line) -> bool {
umount2(line.data(), MNT_DETACH);
return true;
});
}
unlink("/dev/.se");
// SAR cleanups
auto mount_list = MAGISKTMP + "/" ROOTMNT;
if (access(mount_list.data(), F_OK) == 0) {
file_readline(true, mount_list.data(), [](string_view line) -> bool {
umount2(line.data(), MNT_DETACH);
return true;
});
}
unlink("/dev/.se");
// Load config status
auto config = MAGISKTMP + "/" INTLROOT "/config";
parse_prop_file(config.data(), [](auto key, auto val) -> bool {
if (key == "RECOVERYMODE" && val == "true")
RECOVERY_MODE = true;
return true;
});
// Load config status
auto config = MAGISKTMP + "/" INTLROOT "/config";
parse_prop_file(config.data(), [](auto key, auto val) -> bool {
if (key == "RECOVERYMODE" && val == "true")
RECOVERY_MODE = true;
return true;
});
struct sockaddr_un sun;
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (xbind(fd, (struct sockaddr*) &sun, len))
exit(1);
xlisten(fd, 10);
struct sockaddr_un sun;
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (xbind(fd, (struct sockaddr*) &sun, len))
exit(1);
xlisten(fd, 10);
// Change process name
set_nice_name("magiskd");
// Change process name
set_nice_name("magiskd");
// Block all signals
sigset_t block_set;
sigfillset(&block_set);
pthread_sigmask(SIG_SETMASK, &block_set, nullptr);
// Block all signals
sigset_t block_set;
sigfillset(&block_set);
pthread_sigmask(SIG_SETMASK, &block_set, nullptr);
// Loop forever to listen for requests
for (;;) {
int client = xaccept4(fd, nullptr, nullptr, SOCK_CLOEXEC);
handle_request(client);
}
// Loop forever to listen for requests
for (;;) {
int client = xaccept4(fd, nullptr, nullptr, SOCK_CLOEXEC);
handle_request(client);
}
}
int connect_daemon(bool create) {
struct sockaddr_un sun;
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (connect(fd, (struct sockaddr*) &sun, len)) {
if (!create || getuid() != UID_ROOT || getgid() != UID_ROOT) {
LOGE("No daemon is currently running!\n");
exit(1);
}
struct sockaddr_un sun;
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (connect(fd, (struct sockaddr*) &sun, len)) {
if (!create || getuid() != UID_ROOT || getgid() != UID_ROOT) {
LOGE("No daemon is currently running!\n");
exit(1);
}
int ppid = getpid();
LOGD("client: launching new main daemon process\n");
if (fork_dont_care() == 0) {
close(fd);
daemon_entry(ppid);
}
int ppid = getpid();
LOGD("client: launching new main daemon process\n");
if (fork_dont_care() == 0) {
close(fd);
daemon_entry(ppid);
}
while (connect(fd, (struct sockaddr*) &sun, len))
usleep(10000);
}
return fd;
while (connect(fd, (struct sockaddr*) &sun, len))
usleep(10000);
}
return fd;
}

View File

@@ -26,19 +26,19 @@ static sqlite3 *mDB = nullptr;
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
static int (*sqlite3_open_v2)(
const char *filename,
sqlite3 **ppDb,
int flags,
const char *zVfs);
const char *filename,
sqlite3 **ppDb,
int flags,
const char *zVfs);
static const char *(*sqlite3_errmsg)(sqlite3 *db);
static int (*sqlite3_close)(sqlite3 *db);
static void (*sqlite3_free)(void *v);
static int (*sqlite3_exec)(
sqlite3 *db,
const char *sql,
int (*callback)(void*, int, char**, char**),
void *v,
char **errmsg);
sqlite3 *db,
const char *sql,
int (*callback)(void*, int, char**, char**),
void *v,
char **errmsg);
// Internal Android linker APIs
@@ -46,14 +46,14 @@ static void (*android_get_LD_LIBRARY_PATH)(char *buffer, size_t buffer_size);
static void (*android_update_LD_LIBRARY_PATH)(const char *ld_library_path);
#define DLERR(ptr) if (!(ptr)) { \
LOGE("db: %s\n", dlerror()); \
return false; \
LOGE("db: %s\n", dlerror()); \
return false; \
}
#define DLOAD(handle, arg) {\
auto f = dlsym(handle, #arg); \
DLERR(f) \
*(void **) &(arg) = f; \
auto f = dlsym(handle, #arg); \
DLERR(f) \
*(void **) &(arg) = f; \
}
#ifdef __LP64__
@@ -65,339 +65,339 @@ constexpr char apex_path[] = "/apex/com.android.runtime/lib:/apex/com.android.ar
static int dl_init = 0;
static bool dload_sqlite() {
if (dl_init)
return dl_init > 0;
dl_init = -1;
if (dl_init)
return dl_init > 0;
dl_init = -1;
auto sqlite = dlopen("libsqlite.so", RTLD_LAZY);
if (!sqlite) {
// Should only happen on Android 10+
auto dl = dlopen("libdl_android.so", RTLD_LAZY);
DLERR(dl);
auto sqlite = dlopen("libsqlite.so", RTLD_LAZY);
if (!sqlite) {
// Should only happen on Android 10+
auto dl = dlopen("libdl_android.so", RTLD_LAZY);
DLERR(dl);
DLOAD(dl, android_get_LD_LIBRARY_PATH);
DLOAD(dl, android_update_LD_LIBRARY_PATH);
DLOAD(dl, android_get_LD_LIBRARY_PATH);
DLOAD(dl, android_update_LD_LIBRARY_PATH);
// Inject APEX into LD_LIBRARY_PATH
char ld_path[4096];
memcpy(ld_path, apex_path, sizeof(apex_path));
constexpr int len = sizeof(apex_path) - 1;
android_get_LD_LIBRARY_PATH(ld_path + len, sizeof(ld_path) - len);
android_update_LD_LIBRARY_PATH(ld_path);
sqlite = dlopen("libsqlite.so", RTLD_LAZY);
// Inject APEX into LD_LIBRARY_PATH
char ld_path[4096];
memcpy(ld_path, apex_path, sizeof(apex_path));
constexpr int len = sizeof(apex_path) - 1;
android_get_LD_LIBRARY_PATH(ld_path + len, sizeof(ld_path) - len);
android_update_LD_LIBRARY_PATH(ld_path);
sqlite = dlopen("libsqlite.so", RTLD_LAZY);
// Revert LD_LIBRARY_PATH just in case
android_update_LD_LIBRARY_PATH(ld_path + len);
}
DLERR(sqlite);
// Revert LD_LIBRARY_PATH just in case
android_update_LD_LIBRARY_PATH(ld_path + len);
}
DLERR(sqlite);
DLOAD(sqlite, sqlite3_open_v2);
DLOAD(sqlite, sqlite3_errmsg);
DLOAD(sqlite, sqlite3_close);
DLOAD(sqlite, sqlite3_exec);
DLOAD(sqlite, sqlite3_free);
DLOAD(sqlite, sqlite3_open_v2);
DLOAD(sqlite, sqlite3_errmsg);
DLOAD(sqlite, sqlite3_close);
DLOAD(sqlite, sqlite3_exec);
DLOAD(sqlite, sqlite3_free);
dl_init = 1;
return true;
dl_init = 1;
return true;
}
int db_strings::getKeyIdx(string_view key) const {
int idx = DB_STRING_NUM;
for (int i = 0; i < DB_STRING_NUM; ++i) {
if (key == DB_STRING_KEYS[i])
idx = i;
}
return idx;
int idx = DB_STRING_NUM;
for (int i = 0; i < DB_STRING_NUM; ++i) {
if (key == DB_STRING_KEYS[i])
idx = i;
}
return idx;
}
db_settings::db_settings() {
// Default settings
data[ROOT_ACCESS] = ROOT_ACCESS_APPS_AND_ADB;
data[SU_MULTIUSER_MODE] = MULTIUSER_MODE_OWNER_ONLY;
data[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER;
data[HIDE_CONFIG] = false;
// Default settings
data[ROOT_ACCESS] = ROOT_ACCESS_APPS_AND_ADB;
data[SU_MULTIUSER_MODE] = MULTIUSER_MODE_OWNER_ONLY;
data[SU_MNT_NS] = NAMESPACE_MODE_REQUESTER;
data[HIDE_CONFIG] = false;
}
int db_settings::getKeyIdx(string_view key) const {
int idx = DB_SETTINGS_NUM;
for (int i = 0; i < DB_SETTINGS_NUM; ++i) {
if (key == DB_SETTING_KEYS[i])
idx = i;
}
return idx;
int idx = DB_SETTINGS_NUM;
for (int i = 0; i < DB_SETTINGS_NUM; ++i) {
if (key == DB_SETTING_KEYS[i])
idx = i;
}
return idx;
}
static int ver_cb(void *ver, int, char **data, char **) {
*((int *) ver) = parse_int(data[0]);
return 0;
*((int *) ver) = parse_int(data[0]);
return 0;
}
#define err_ret(e) if (e) return e;
static char *open_and_init_db(sqlite3 *&db) {
if (!dload_sqlite())
return strdup("Cannot load libsqlite.so");
if (!dload_sqlite())
return strdup("Cannot load libsqlite.so");
int ret = sqlite3_open_v2(MAGISKDB, &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr);
if (ret)
return strdup(sqlite3_errmsg(db));
int ver;
bool upgrade = false;
char *err;
sqlite3_exec(db, "PRAGMA user_version", ver_cb, &ver, &err);
err_ret(err);
if (ver > DB_VERSION) {
// Don't support downgrading database
sqlite3_close(db);
return nullptr;
}
if (ver < 3) {
// Policies
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS policies "
"(uid INT, package_name TEXT, policy INT, until INT, "
"logging INT, notification INT, PRIMARY KEY(uid))",
nullptr, nullptr, &err);
err_ret(err);
// Settings
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS settings "
"(key TEXT, value INT, PRIMARY KEY(key))",
nullptr, nullptr, &err);
err_ret(err);
ver = 3;
upgrade = true;
}
if (ver < 4) {
// Strings
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS strings "
"(key TEXT, value TEXT, PRIMARY KEY(key))",
nullptr, nullptr, &err);
err_ret(err);
ver = 4;
upgrade = true;
}
if (ver < 5) {
sqlite3_exec(db, "UPDATE policies SET uid=uid%100000", nullptr, nullptr, &err);
err_ret(err);
/* Directly jump to version 6 */
ver = 6;
upgrade = true;
}
if (ver < 7) {
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS hidelist "
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));",
nullptr, nullptr, &err);
err_ret(err);
/* Directly jump to version 9 */
ver = 9;
upgrade = true;
}
if (ver < 8) {
sqlite3_exec(db,
"BEGIN TRANSACTION;"
"ALTER TABLE hidelist RENAME TO hidelist_tmp;"
"CREATE TABLE IF NOT EXISTS hidelist "
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));"
"INSERT INTO hidelist SELECT process as package_name, process FROM hidelist_tmp;"
"DROP TABLE hidelist_tmp;"
"COMMIT;",
nullptr, nullptr, &err);
err_ret(err);
/* Directly jump to version 9 */
ver = 9;
upgrade = true;
}
if (ver < 9) {
sqlite3_exec(db,
"BEGIN TRANSACTION;"
"ALTER TABLE hidelist RENAME TO hidelist_tmp;"
"CREATE TABLE IF NOT EXISTS hidelist "
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));"
"INSERT INTO hidelist SELECT * FROM hidelist_tmp;"
"DROP TABLE hidelist_tmp;"
"COMMIT;",
nullptr, nullptr, &err);
err_ret(err);
ver = 9;
upgrade = true;
}
if (ver < 10) {
sqlite3_exec(db, "DROP TABLE IF EXISTS logs", nullptr, nullptr, &err);
err_ret(err);
ver = 10;
upgrade = true;
}
int ret = sqlite3_open_v2(MAGISKDB, &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, nullptr);
if (ret)
return strdup(sqlite3_errmsg(db));
int ver;
bool upgrade = false;
char *err;
sqlite3_exec(db, "PRAGMA user_version", ver_cb, &ver, &err);
err_ret(err);
if (ver > DB_VERSION) {
// Don't support downgrading database
sqlite3_close(db);
return nullptr;
}
if (ver < 3) {
// Policies
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS policies "
"(uid INT, package_name TEXT, policy INT, until INT, "
"logging INT, notification INT, PRIMARY KEY(uid))",
nullptr, nullptr, &err);
err_ret(err);
// Settings
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS settings "
"(key TEXT, value INT, PRIMARY KEY(key))",
nullptr, nullptr, &err);
err_ret(err);
ver = 3;
upgrade = true;
}
if (ver < 4) {
// Strings
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS strings "
"(key TEXT, value TEXT, PRIMARY KEY(key))",
nullptr, nullptr, &err);
err_ret(err);
ver = 4;
upgrade = true;
}
if (ver < 5) {
sqlite3_exec(db, "UPDATE policies SET uid=uid%100000", nullptr, nullptr, &err);
err_ret(err);
/* Directly jump to version 6 */
ver = 6;
upgrade = true;
}
if (ver < 7) {
sqlite3_exec(db,
"CREATE TABLE IF NOT EXISTS hidelist "
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));",
nullptr, nullptr, &err);
err_ret(err);
/* Directly jump to version 9 */
ver = 9;
upgrade = true;
}
if (ver < 8) {
sqlite3_exec(db,
"BEGIN TRANSACTION;"
"ALTER TABLE hidelist RENAME TO hidelist_tmp;"
"CREATE TABLE IF NOT EXISTS hidelist "
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));"
"INSERT INTO hidelist SELECT process as package_name, process FROM hidelist_tmp;"
"DROP TABLE hidelist_tmp;"
"COMMIT;",
nullptr, nullptr, &err);
err_ret(err);
/* Directly jump to version 9 */
ver = 9;
upgrade = true;
}
if (ver < 9) {
sqlite3_exec(db,
"BEGIN TRANSACTION;"
"ALTER TABLE hidelist RENAME TO hidelist_tmp;"
"CREATE TABLE IF NOT EXISTS hidelist "
"(package_name TEXT, process TEXT, PRIMARY KEY(package_name, process));"
"INSERT INTO hidelist SELECT * FROM hidelist_tmp;"
"DROP TABLE hidelist_tmp;"
"COMMIT;",
nullptr, nullptr, &err);
err_ret(err);
ver = 9;
upgrade = true;
}
if (ver < 10) {
sqlite3_exec(db, "DROP TABLE IF EXISTS logs", nullptr, nullptr, &err);
err_ret(err);
ver = 10;
upgrade = true;
}
if (upgrade) {
// Set version
char query[32];
sprintf(query, "PRAGMA user_version=%d", ver);
sqlite3_exec(db, query, nullptr, nullptr, &err);
err_ret(err);
}
return nullptr;
if (upgrade) {
// Set version
char query[32];
sprintf(query, "PRAGMA user_version=%d", ver);
sqlite3_exec(db, query, nullptr, nullptr, &err);
err_ret(err);
}
return nullptr;
}
char *db_exec(const char *sql) {
char *err;
if (mDB == nullptr) {
err = open_and_init_db(mDB);
db_err_cmd(err,
// Open fails, remove and reconstruct
unlink(MAGISKDB);
err = open_and_init_db(mDB);
err_ret(err);
);
}
if (mDB) {
sqlite3_exec(mDB, sql, nullptr, nullptr, &err);
return err;
}
return nullptr;
char *err;
if (mDB == nullptr) {
err = open_and_init_db(mDB);
db_err_cmd(err,
// Open fails, remove and reconstruct
unlink(MAGISKDB);
err = open_and_init_db(mDB);
err_ret(err);
);
}
if (mDB) {
sqlite3_exec(mDB, sql, nullptr, nullptr, &err);
return err;
}
return nullptr;
}
char *db_exec(const char *sql, const db_row_cb &fn) {
char *err;
if (mDB == nullptr) {
err = open_and_init_db(mDB);
db_err_cmd(err,
// Open fails, remove and reconstruct
unlink(MAGISKDB);
err = open_and_init_db(mDB);
err_ret(err);
);
}
if (mDB) {
sqlite3_exec(mDB, sql, [](void *cb, int col_num, char **data, char **col_name) -> int {
auto &func = *reinterpret_cast<const db_row_cb*>(cb);
db_row row;
for (int i = 0; i < col_num; ++i)
row[col_name[i]] = data[i];
return func(row) ? 0 : 1;
}, (void *) &fn, &err);
return err;
}
return nullptr;
char *err;
if (mDB == nullptr) {
err = open_and_init_db(mDB);
db_err_cmd(err,
// Open fails, remove and reconstruct
unlink(MAGISKDB);
err = open_and_init_db(mDB);
err_ret(err);
);
}
if (mDB) {
sqlite3_exec(mDB, sql, [](void *cb, int col_num, char **data, char **col_name) -> int {
auto &func = *reinterpret_cast<const db_row_cb*>(cb);
db_row row;
for (int i = 0; i < col_num; ++i)
row[col_name[i]] = data[i];
return func(row) ? 0 : 1;
}, (void *) &fn, &err);
return err;
}
return nullptr;
}
int get_db_settings(db_settings &cfg, int key) {
char *err;
auto settings_cb = [&](db_row &row) -> bool {
cfg[row["key"]] = parse_int(row["value"]);
LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data());
return true;
};
if (key >= 0) {
char query[128];
sprintf(query, "SELECT key, value FROM settings WHERE key='%s'", DB_SETTING_KEYS[key]);
err = db_exec(query, settings_cb);
} else {
err = db_exec("SELECT key, value FROM settings", settings_cb);
}
db_err_cmd(err, return 1);
return 0;
char *err;
auto settings_cb = [&](db_row &row) -> bool {
cfg[row["key"]] = parse_int(row["value"]);
LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data());
return true;
};
if (key >= 0) {
char query[128];
sprintf(query, "SELECT key, value FROM settings WHERE key='%s'", DB_SETTING_KEYS[key]);
err = db_exec(query, settings_cb);
} else {
err = db_exec("SELECT key, value FROM settings", settings_cb);
}
db_err_cmd(err, return 1);
return 0;
}
int get_db_strings(db_strings &str, int key) {
char *err;
auto string_cb = [&](db_row &row) -> bool {
str[row["key"]] = row["value"];
return true;
};
if (key >= 0) {
char query[128];
sprintf(query, "SELECT key, value FROM strings WHERE key='%s'", DB_STRING_KEYS[key]);
err = db_exec(query, string_cb);
} else {
err = db_exec("SELECT key, value FROM strings", string_cb);
}
db_err_cmd(err, return 1);
return 0;
char *err;
auto string_cb = [&](db_row &row) -> bool {
str[row["key"]] = row["value"];
return true;
};
if (key >= 0) {
char query[128];
sprintf(query, "SELECT key, value FROM strings WHERE key='%s'", DB_STRING_KEYS[key]);
err = db_exec(query, string_cb);
} else {
err = db_exec("SELECT key, value FROM strings", string_cb);
}
db_err_cmd(err, return 1);
return 0;
}
int get_uid_policy(su_access &su, int uid) {
char query[256], *err;
sprintf(query, "SELECT policy, logging, notification FROM policies "
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr));
err = db_exec(query, [&](db_row &row) -> bool {
su.policy = (policy_t) parse_int(row["policy"]);
su.log = parse_int(row["logging"]);
su.notify = parse_int(row["notification"]);
LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", su.policy, su.log, su.notify);
return true;
});
db_err_cmd(err, return 1);
return 0;
char query[256], *err;
sprintf(query, "SELECT policy, logging, notification FROM policies "
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr));
err = db_exec(query, [&](db_row &row) -> bool {
su.policy = (policy_t) parse_int(row["policy"]);
su.log = parse_int(row["logging"]);
su.notify = parse_int(row["notification"]);
LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", su.policy, su.log, su.notify);
return true;
});
db_err_cmd(err, return 1);
return 0;
}
bool check_manager(string *pkg) {
db_strings str;
get_db_strings(str, SU_MANAGER);
bool ret = validate_manager(str[SU_MANAGER], 0, nullptr);
if (pkg) {
if (ret)
pkg->swap(str[SU_MANAGER]);
else
*pkg = "xxx"; /* Make sure the return pkg can never exist */
}
return ret;
db_strings str;
get_db_strings(str, SU_MANAGER);
bool ret = validate_manager(str[SU_MANAGER], 0, nullptr);
if (pkg) {
if (ret)
pkg->swap(str[SU_MANAGER]);
else
*pkg = "xxx"; /* Make sure the return pkg can never exist */
}
return ret;
}
bool validate_manager(string &pkg, int userid, struct stat *st) {
struct stat tmp_st;
if (st == nullptr)
st = &tmp_st;
struct stat tmp_st;
if (st == nullptr)
st = &tmp_st;
// Prefer DE storage
char app_path[128];
sprintf(app_path, "%s/%d/%s", APP_DATA_DIR, userid, pkg.data());
if (pkg.empty() || stat(app_path, st)) {
// Check the official package name
sprintf(app_path, "%s/%d/" JAVA_PACKAGE_NAME, APP_DATA_DIR, userid);
if (stat(app_path, st)) {
LOGE("su: cannot find manager\n");
memset(st, 0, sizeof(*st));
pkg.clear();
return false;
} else {
// Switch to official package if exists
pkg = JAVA_PACKAGE_NAME;
}
}
return true;
// Prefer DE storage
char app_path[128];
sprintf(app_path, "%s/%d/%s", APP_DATA_DIR, userid, pkg.data());
if (pkg.empty() || stat(app_path, st)) {
// Check the official package name
sprintf(app_path, "%s/%d/" JAVA_PACKAGE_NAME, APP_DATA_DIR, userid);
if (stat(app_path, st)) {
LOGE("su: cannot find manager\n");
memset(st, 0, sizeof(*st));
pkg.clear();
return false;
} else {
// Switch to official package if exists
pkg = JAVA_PACKAGE_NAME;
}
}
return true;
}
void exec_sql(int client) {
run_finally f([=]{ close(client); });
char *sql = read_string(client);
char *err = db_exec(sql, [&](db_row &row) -> bool {
string out;
bool first = true;
for (auto it : row) {
if (first) first = false;
else out += '|';
out += it.first;
out += '=';
out += it.second;
}
write_int(client, out.length());
xwrite(client, out.data(), out.length());
return true;
});
free(sql);
write_int(client, 0);
db_err_cmd(err, return; );
run_finally f([=]{ close(client); });
char *sql = read_string(client);
char *err = db_exec(sql, [&](db_row &row) -> bool {
string out;
bool first = true;
for (auto it : row) {
if (first) first = false;
else out += '|';
out += it.first;
out += '=';
out += it.second;
}
write_int(client, out.length());
xwrite(client, out.data(), out.length());
return true;
});
free(sql);
write_int(client, 0);
db_err_cmd(err, return; );
}
bool db_err(char *e) {
if (e) {
LOGE("sqlite3_exec: %s\n", e);
sqlite3_free(e);
return true;
}
return false;
if (e) {
LOGE("sqlite3_exec: %s\n", e);
sqlite3_free(e);
return true;
}
return false;
}

View File

@@ -10,7 +10,7 @@
using namespace std;
[[noreturn]] static void usage() {
fprintf(stderr,
fprintf(stderr,
R"EOF(Magisk - Multi-purpose Utility
Usage: magisk [applet [arguments]...]
@@ -39,92 +39,92 @@ Advanced Options (Internal APIs):
Available applets:
)EOF");
for (int i = 0; applet_names[i]; ++i)
fprintf(stderr, i ? ", %s" : " %s", applet_names[i]);
fprintf(stderr, "\n\n");
exit(1);
for (int i = 0; applet_names[i]; ++i)
fprintf(stderr, i ? ", %s" : " %s", applet_names[i]);
fprintf(stderr, "\n\n");
exit(1);
}
int magisk_main(int argc, char *argv[]) {
if (argc < 2)
usage();
if (argv[1] == "-c"sv) {
printf(MAGISK_VERSION ":MAGISK (" str(MAGISK_VER_CODE) ")\n");
return 0;
} else if (argv[1] == "-v"sv) {
int fd = connect_daemon();
write_int(fd, CHECK_VERSION);
char *v = read_string(fd);
printf("%s\n", v);
free(v);
return 0;
} else if (argv[1] == "-V"sv) {
int fd = connect_daemon();
write_int(fd, CHECK_VERSION_CODE);
printf("%d\n", read_int(fd));
return 0;
} else if (argv[1] == "--list"sv) {
for (int i = 0; applet_names[i]; ++i)
printf("%s\n", applet_names[i]);
return 0;
} else if (argv[1] == "--unlock-blocks"sv) {
unlock_blocks();
return 0;
} else if (argv[1] == "--restorecon"sv) {
restorecon();
return 0;
} else if (argc >= 4 && argv[1] == "--clone-attr"sv) {;
clone_attr(argv[2], argv[3]);
return 0;
} else if (argc >= 4 && argv[1] == "--clone"sv) {
cp_afc(argv[2], argv[3]);
return 0;
} else if (argv[1] == "--daemon"sv) {
int fd = connect_daemon(true);
write_int(fd, START_DAEMON);
return 0;
} else if (argv[1] == "--post-fs-data"sv) {
int fd = connect_daemon(true);
write_int(fd, POST_FS_DATA);
return read_int(fd);
} else if (argv[1] == "--service"sv) {
int fd = connect_daemon(true);
write_int(fd, LATE_START);
return read_int(fd);
} else if (argv[1] == "--boot-complete"sv) {
int fd = connect_daemon(true);
write_int(fd, BOOT_COMPLETE);
return read_int(fd);
} else if (argc >= 3 && argv[1] == "--sqlite"sv) {
int fd = connect_daemon();
write_int(fd, SQLITE_CMD);
write_string(fd, argv[2]);
for (;;) {
char *res = read_string(fd);
if (res[0] == '\0') {
return 0;
}
printf("%s\n", res);
free(res);
}
} else if (argv[1] == "--remove-modules"sv) {
int fd = connect_daemon();
write_int(fd, REMOVE_MODULES);
return read_int(fd);
} else if (argv[1] == "--path"sv) {
int fd = connect_daemon();
write_int(fd, GET_PATH);
char *path = read_string(fd);
printf("%s\n", path);
return 0;
} else if (argc >= 3 && argv[1] == "--install-module"sv) {
install_module(argv[2]);
}
if (argc < 2)
usage();
if (argv[1] == "-c"sv) {
printf(MAGISK_VERSION ":MAGISK (" str(MAGISK_VER_CODE) ")\n");
return 0;
} else if (argv[1] == "-v"sv) {
int fd = connect_daemon();
write_int(fd, CHECK_VERSION);
char *v = read_string(fd);
printf("%s\n", v);
free(v);
return 0;
} else if (argv[1] == "-V"sv) {
int fd = connect_daemon();
write_int(fd, CHECK_VERSION_CODE);
printf("%d\n", read_int(fd));
return 0;
} else if (argv[1] == "--list"sv) {
for (int i = 0; applet_names[i]; ++i)
printf("%s\n", applet_names[i]);
return 0;
} else if (argv[1] == "--unlock-blocks"sv) {
unlock_blocks();
return 0;
} else if (argv[1] == "--restorecon"sv) {
restorecon();
return 0;
} else if (argc >= 4 && argv[1] == "--clone-attr"sv) {;
clone_attr(argv[2], argv[3]);
return 0;
} else if (argc >= 4 && argv[1] == "--clone"sv) {
cp_afc(argv[2], argv[3]);
return 0;
} else if (argv[1] == "--daemon"sv) {
int fd = connect_daemon(true);
write_int(fd, START_DAEMON);
return 0;
} else if (argv[1] == "--post-fs-data"sv) {
int fd = connect_daemon(true);
write_int(fd, POST_FS_DATA);
return read_int(fd);
} else if (argv[1] == "--service"sv) {
int fd = connect_daemon(true);
write_int(fd, LATE_START);
return read_int(fd);
} else if (argv[1] == "--boot-complete"sv) {
int fd = connect_daemon(true);
write_int(fd, BOOT_COMPLETE);
return read_int(fd);
} else if (argc >= 3 && argv[1] == "--sqlite"sv) {
int fd = connect_daemon();
write_int(fd, SQLITE_CMD);
write_string(fd, argv[2]);
for (;;) {
char *res = read_string(fd);
if (res[0] == '\0') {
return 0;
}
printf("%s\n", res);
free(res);
}
} else if (argv[1] == "--remove-modules"sv) {
int fd = connect_daemon();
write_int(fd, REMOVE_MODULES);
return read_int(fd);
} else if (argv[1] == "--path"sv) {
int fd = connect_daemon();
write_int(fd, GET_PATH);
char *path = read_string(fd);
printf("%s\n", path);
return 0;
} else if (argc >= 3 && argv[1] == "--install-module"sv) {
install_module(argv[2]);
}
#if 0
/* Entry point for testing stuffs */
else if (argv[1] == "--test"sv) {
return 0;
}
/* Entry point for testing stuffs */
else if (argv[1] == "--test"sv) {
return 0;
}
#endif
usage();
usage();
}

File diff suppressed because it is too large Load Diff

View File

@@ -15,89 +15,89 @@ using namespace std;
#define EXEC_CON "u:object_r:" SEPOL_EXEC_TYPE ":s0"
static void restore_syscon(int dirfd) {
struct dirent *entry;
DIR *dir;
char *con;
struct dirent *entry;
DIR *dir;
char *con;
fgetfilecon(dirfd, &con);
if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0)
fsetfilecon(dirfd, SYSTEM_CON);
freecon(con);
fgetfilecon(dirfd, &con);
if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0)
fsetfilecon(dirfd, SYSTEM_CON);
freecon(con);
dir = xfdopendir(dirfd);
while ((entry = xreaddir(dir))) {
int fd = openat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
if (entry->d_type == DT_DIR) {
restore_syscon(fd);
} else if (entry->d_type == DT_REG) {
fgetfilecon(fd, &con);
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
fsetfilecon(fd, SYSTEM_CON);
freecon(con);
} else if (entry->d_type == DT_LNK) {
getfilecon_at(dirfd, entry->d_name, &con);
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
setfilecon_at(dirfd, entry->d_name, con);
freecon(con);
}
close(fd);
}
dir = xfdopendir(dirfd);
while ((entry = xreaddir(dir))) {
int fd = openat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
if (entry->d_type == DT_DIR) {
restore_syscon(fd);
} else if (entry->d_type == DT_REG) {
fgetfilecon(fd, &con);
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
fsetfilecon(fd, SYSTEM_CON);
freecon(con);
} else if (entry->d_type == DT_LNK) {
getfilecon_at(dirfd, entry->d_name, &con);
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
setfilecon_at(dirfd, entry->d_name, con);
freecon(con);
}
close(fd);
}
}
static void restore_magiskcon(int dirfd) {
struct dirent *entry;
DIR *dir;
struct dirent *entry;
DIR *dir;
fsetfilecon(dirfd, MAGISK_CON);
fchown(dirfd, 0, 0);
fsetfilecon(dirfd, MAGISK_CON);
fchown(dirfd, 0, 0);
dir = xfdopendir(dirfd);
while ((entry = xreaddir(dir))) {
int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
if (entry->d_type == DT_DIR) {
restore_magiskcon(fd);
} else if (entry->d_type) {
fsetfilecon(fd, MAGISK_CON);
fchown(fd, 0, 0);
}
close(fd);
}
dir = xfdopendir(dirfd);
while ((entry = xreaddir(dir))) {
int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
if (entry->d_type == DT_DIR) {
restore_magiskcon(fd);
} else if (entry->d_type) {
fsetfilecon(fd, MAGISK_CON);
fchown(fd, 0, 0);
}
close(fd);
}
}
void restorecon() {
int fd = xopen(SELINUX_CONTEXT, O_WRONLY | O_CLOEXEC);
if (write(fd, ADB_CON, sizeof(ADB_CON)) >= 0)
lsetfilecon(SECURE_DIR, ADB_CON);
close(fd);
lsetfilecon(MODULEROOT, SYSTEM_CON);
fd = xopen(MODULEROOT, O_RDONLY | O_CLOEXEC);
restore_syscon(fd);
close(fd);
fd = xopen(DATABIN, O_RDONLY | O_CLOEXEC);
restore_magiskcon(fd);
close(fd);
int fd = xopen(SELINUX_CONTEXT, O_WRONLY | O_CLOEXEC);
if (write(fd, ADB_CON, sizeof(ADB_CON)) >= 0)
lsetfilecon(SECURE_DIR, ADB_CON);
close(fd);
lsetfilecon(MODULEROOT, SYSTEM_CON);
fd = xopen(MODULEROOT, O_RDONLY | O_CLOEXEC);
restore_syscon(fd);
close(fd);
fd = xopen(DATABIN, O_RDONLY | O_CLOEXEC);
restore_magiskcon(fd);
close(fd);
}
void restore_tmpcon() {
if (MAGISKTMP == "/system/bin") {
// Running with emulator.sh
if (SDK_INT >= 26)
lsetfilecon("/system/bin/magisk", EXEC_CON);
return;
}
if (MAGISKTMP == "/system/bin") {
// Running with emulator.sh
if (SDK_INT >= 26)
lsetfilecon("/system/bin/magisk", EXEC_CON);
return;
}
if (MAGISKTMP == "/sbin")
setfilecon(MAGISKTMP.data(), ROOT_CON);
else
chmod(MAGISKTMP.data(), 0700);
if (MAGISKTMP == "/sbin")
setfilecon(MAGISKTMP.data(), ROOT_CON);
else
chmod(MAGISKTMP.data(), 0700);
auto dir = xopen_dir(MAGISKTMP.data());
int dfd = dirfd(dir.get());
auto dir = xopen_dir(MAGISKTMP.data());
int dfd = dirfd(dir.get());
for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (SDK_INT >= 26 && entry->d_name == "magisk"sv)
setfilecon_at(dfd, entry->d_name, EXEC_CON);
else
setfilecon_at(dfd, entry->d_name, SYSTEM_CON);
}
for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (SDK_INT >= 26 && entry->d_name == "magisk"sv)
setfilecon_at(dfd, entry->d_name, EXEC_CON);
else
setfilecon_at(dfd, entry->d_name, SYSTEM_CON);
}
}

View File

@@ -11,139 +11,139 @@ using namespace std;
#define BBEXEC_CMD bbpath(), "sh"
static const char *bbpath() {
static string path;
if (path.empty())
path = MAGISKTMP + "/" BBPATH "/busybox";
return path.data();
static string path;
if (path.empty())
path = MAGISKTMP + "/" BBPATH "/busybox";
return path.data();
}
static void set_script_env() {
setenv("ASH_STANDALONE", "1", 1);
char new_path[4096];
sprintf(new_path, "%s:%s", getenv("PATH"), MAGISKTMP.data());
setenv("PATH", new_path, 1);
setenv("ASH_STANDALONE", "1", 1);
char new_path[4096];
sprintf(new_path, "%s:%s", getenv("PATH"), MAGISKTMP.data());
setenv("PATH", new_path, 1);
};
void exec_script(const char *script) {
exec_t exec {
.pre_exec = set_script_env,
.fork = fork_no_orphan
};
exec_command_sync(exec, BBEXEC_CMD, script);
exec_t exec {
.pre_exec = set_script_env,
.fork = fork_no_orphan
};
exec_command_sync(exec, BBEXEC_CMD, script);
}
static timespec pfs_timeout;
#define PFS_SETUP() \
if (pfs) { \
if (int pid = xfork()) { \
if (pid < 0) \
return; \
/* In parent process, simply wait for child to finish */ \
waitpid(pid, nullptr, 0); \
return; \
} \
timer_pid = xfork(); \
if (timer_pid == 0) { \
/* In timer process, count down */ \
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &pfs_timeout, nullptr); \
exit(0); \
} \
if (int pid = xfork()) { \
if (pid < 0) \
return; \
/* In parent process, simply wait for child to finish */ \
waitpid(pid, nullptr, 0); \
return; \
} \
timer_pid = xfork(); \
if (timer_pid == 0) { \
/* In timer process, count down */ \
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &pfs_timeout, nullptr); \
exit(0); \
} \
}
#define PFS_WAIT() \
if (pfs) { \
/* If we ran out of time, don't block */ \
if (timer_pid < 0) \
continue; \
if (int pid = waitpid(-1, nullptr, 0); pid == timer_pid) { \
LOGW("* post-fs-data scripts blocking phase timeout\n"); \
timer_pid = -1; \
} \
/* If we ran out of time, don't block */ \
if (timer_pid < 0) \
continue; \
if (int pid = waitpid(-1, nullptr, 0); pid == timer_pid) { \
LOGW("* post-fs-data scripts blocking phase timeout\n"); \
timer_pid = -1; \
} \
}
#define PFS_DONE() \
if (pfs) { \
if (timer_pid > 0) \
kill(timer_pid, SIGKILL); \
exit(0); \
if (timer_pid > 0) \
kill(timer_pid, SIGKILL); \
exit(0); \
}
void exec_common_scripts(const char *stage) {
LOGI("* Running %s.d scripts\n", stage);
char path[4096];
char *name = path + sprintf(path, SECURE_DIR "/%s.d", stage);
auto dir = xopen_dir(path);
if (!dir) return;
LOGI("* Running %s.d scripts\n", stage);
char path[4096];
char *name = path + sprintf(path, SECURE_DIR "/%s.d", stage);
auto dir = xopen_dir(path);
if (!dir) return;
bool pfs = stage == "post-fs-data"sv;
int timer_pid = -1;
if (pfs) {
// Setup timer
clock_gettime(CLOCK_MONOTONIC, &pfs_timeout);
pfs_timeout.tv_sec += POST_FS_DATA_SCRIPT_MAX_TIME;
}
PFS_SETUP()
bool pfs = stage == "post-fs-data"sv;
int timer_pid = -1;
if (pfs) {
// Setup timer
clock_gettime(CLOCK_MONOTONIC, &pfs_timeout);
pfs_timeout.tv_sec += POST_FS_DATA_SCRIPT_MAX_TIME;
}
PFS_SETUP()
*(name++) = '/';
int dfd = dirfd(dir.get());
for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (entry->d_type == DT_REG) {
if (faccessat(dfd, entry->d_name, X_OK, 0) != 0)
continue;
LOGI("%s.d: exec [%s]\n", stage, entry->d_name);
strcpy(name, entry->d_name);
exec_t exec {
.pre_exec = set_script_env,
.fork = pfs ? xfork : fork_dont_care
};
exec_command(exec, BBEXEC_CMD, path);
PFS_WAIT()
}
}
*(name++) = '/';
int dfd = dirfd(dir.get());
for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (entry->d_type == DT_REG) {
if (faccessat(dfd, entry->d_name, X_OK, 0) != 0)
continue;
LOGI("%s.d: exec [%s]\n", stage, entry->d_name);
strcpy(name, entry->d_name);
exec_t exec {
.pre_exec = set_script_env,
.fork = pfs ? xfork : fork_dont_care
};
exec_command(exec, BBEXEC_CMD, path);
PFS_WAIT()
}
}
PFS_DONE()
PFS_DONE()
}
// Return if a > b
static bool timespec_larger(timespec *a, timespec *b) {
if (a->tv_sec != b->tv_sec)
return a->tv_sec > b->tv_sec;
return a->tv_nsec > b->tv_nsec;
if (a->tv_sec != b->tv_sec)
return a->tv_sec > b->tv_sec;
return a->tv_nsec > b->tv_nsec;
}
void exec_module_scripts(const char *stage, const vector<string> &module_list) {
LOGI("* Running module %s scripts\n", stage);
if (module_list.empty())
return;
LOGI("* Running module %s scripts\n", stage);
if (module_list.empty())
return;
bool pfs = stage == "post-fs-data"sv;
if (pfs) {
timespec now{};
clock_gettime(CLOCK_MONOTONIC, &now);
// If we had already timed out, treat it as service mode
if (timespec_larger(&now, &pfs_timeout))
pfs = false;
}
int timer_pid = -1;
PFS_SETUP()
bool pfs = stage == "post-fs-data"sv;
if (pfs) {
timespec now{};
clock_gettime(CLOCK_MONOTONIC, &now);
// If we had already timed out, treat it as service mode
if (timespec_larger(&now, &pfs_timeout))
pfs = false;
}
int timer_pid = -1;
PFS_SETUP()
char path[4096];
for (auto &m : module_list) {
const char* module = m.data();
sprintf(path, MODULEROOT "/%s/%s.sh", module, stage);
if (access(path, F_OK) == -1)
continue;
LOGI("%s: exec [%s.sh]\n", module, stage);
exec_t exec {
.pre_exec = set_script_env,
.fork = pfs ? xfork : fork_dont_care
};
exec_command(exec, BBEXEC_CMD, path);
PFS_WAIT()
}
char path[4096];
for (auto &m : module_list) {
const char* module = m.data();
sprintf(path, MODULEROOT "/%s/%s.sh", module, stage);
if (access(path, F_OK) == -1)
continue;
LOGI("%s: exec [%s.sh]\n", module, stage);
exec_t exec {
.pre_exec = set_script_env,
.fork = pfs ? xfork : fork_dont_care
};
exec_command(exec, BBEXEC_CMD, path);
PFS_WAIT()
}
PFS_DONE()
PFS_DONE()
}
constexpr char install_script[] = R"EOF(
@@ -154,23 +154,23 @@ rm -f $APK
)EOF";
void install_apk(const char *apk) {
setfilecon(apk, "u:object_r:" SEPOL_FILE_TYPE ":s0");
exec_t exec {
.fork = fork_no_orphan
};
char cmds[sizeof(install_script) + 4096];
sprintf(cmds, install_script, apk);
exec_command_sync(exec, "/system/bin/sh", "-c", cmds);
setfilecon(apk, "u:object_r:" SEPOL_FILE_TYPE ":s0");
exec_t exec {
.fork = fork_no_orphan
};
char cmds[sizeof(install_script) + 4096];
sprintf(cmds, install_script, apk);
exec_command_sync(exec, "/system/bin/sh", "-c", cmds);
}
[[noreturn]] __printflike(2, 3)
static void abort(FILE *fp, const char *fmt, ...) {
va_list valist;
va_start(valist, fmt);
vfprintf(fp, fmt, valist);
fprintf(fp, "\n\n");
va_end(valist);
exit(1);
va_list valist;
va_start(valist, fmt);
vfprintf(fp, fmt, valist);
fprintf(fp, "\n\n");
va_end(valist);
exit(1);
}
constexpr char install_module_script[] = R"EOF(
@@ -181,24 +181,24 @@ exit 0'
)EOF";
void install_module(const char *file) {
if (getuid() != 0)
abort(stderr, "Run this command with root");
if (access(DATABIN, F_OK) ||
access(DATABIN "/busybox", X_OK) ||
access(DATABIN "/util_functions.sh", F_OK))
abort(stderr, "Incomplete Magisk install");
if (access(file, F_OK))
abort(stderr, "'%s' does not exist", file);
if (getuid() != 0)
abort(stderr, "Run this command with root");
if (access(DATABIN, F_OK) ||
access(DATABIN "/busybox", X_OK) ||
access(DATABIN "/util_functions.sh", F_OK))
abort(stderr, "Incomplete Magisk install");
if (access(file, F_OK))
abort(stderr, "'%s' does not exist", file);
setenv("OUTFD", "1", 1);
setenv("ZIPFILE", file, 1);
setenv("ASH_STANDALONE", "1", 1);
setenv("OUTFD", "1", 1);
setenv("ZIPFILE", file, 1);
setenv("ASH_STANDALONE", "1", 1);
int fd = xopen("/dev/null", O_RDONLY);
xdup2(fd, STDERR_FILENO);
close(fd);
int fd = xopen("/dev/null", O_RDONLY);
xdup2(fd, STDERR_FILENO);
close(fd);
const char *argv[] = { "/system/bin/sh", "-c", install_module_script, nullptr };
execve(argv[0], (char **) argv, environ);
abort(stdout, "Failed to execute BusyBox shell");
const char *argv[] = { "/system/bin/sh", "-c", install_module_script, nullptr };
execve(argv[0], (char **) argv, environ);
abort(stdout, "Failed to execute BusyBox shell");
}

View File

@@ -7,30 +7,30 @@
#include <utils.hpp>
static size_t socket_len(sockaddr_un *sun) {
if (sun->sun_path[0])
return sizeof(sa_family_t) + strlen(sun->sun_path) + 1;
else
return sizeof(sa_family_t) + strlen(sun->sun_path + 1) + 1;
if (sun->sun_path[0])
return sizeof(sa_family_t) + strlen(sun->sun_path) + 1;
else
return sizeof(sa_family_t) + strlen(sun->sun_path + 1) + 1;
}
socklen_t setup_sockaddr(sockaddr_un *sun, const char *name) {
memset(sun, 0, sizeof(*sun));
sun->sun_family = AF_UNIX;
strcpy(sun->sun_path + 1, name);
return socket_len(sun);
memset(sun, 0, sizeof(*sun));
sun->sun_family = AF_UNIX;
strcpy(sun->sun_path + 1, name);
return socket_len(sun);
}
int socket_accept(int sockfd, int timeout) {
struct pollfd pfd = {
.fd = sockfd,
.events = POLL_IN
};
return xpoll(&pfd, 1, timeout * 1000) <= 0 ? -1 : xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
struct pollfd pfd = {
.fd = sockfd,
.events = POLL_IN
};
return xpoll(&pfd, 1, timeout * 1000) <= 0 ? -1 : xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
}
void get_client_cred(int fd, struct ucred *cred) {
socklen_t ucred_length = sizeof(*cred);
getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &ucred_length);
socklen_t ucred_length = sizeof(*cred);
getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &ucred_length);
}
/*
@@ -43,50 +43,50 @@ void get_client_cred(int fd, struct ucred *cred) {
* On error the function terminates by calling exit(-1)
*/
int recv_fd(int sockfd) {
// Need to receive data from the message, otherwise don't care about it.
char iovbuf;
struct cmsghdr *cmsg;
// Need to receive data from the message, otherwise don't care about it.
char iovbuf;
struct cmsghdr *cmsg;
struct iovec iov = {
.iov_base = &iovbuf,
.iov_len = 1,
};
struct iovec iov = {
.iov_base = &iovbuf,
.iov_len = 1,
};
char cmsgbuf[CMSG_SPACE(sizeof(int))];
char cmsgbuf[CMSG_SPACE(sizeof(int))];
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = cmsgbuf,
.msg_controllen = sizeof(cmsgbuf),
};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = cmsgbuf,
.msg_controllen = sizeof(cmsgbuf),
};
xrecvmsg(sockfd, &msg, MSG_WAITALL);
xrecvmsg(sockfd, &msg, MSG_WAITALL);
// Was a control message actually sent?
switch (msg.msg_controllen) {
case 0:
// No, so the file descriptor was closed and won't be used.
return -1;
case sizeof(cmsgbuf):
// Yes, grab the file descriptor from it.
break;
default:
goto error;
}
// Was a control message actually sent?
switch (msg.msg_controllen) {
case 0:
// No, so the file descriptor was closed and won't be used.
return -1;
case sizeof(cmsgbuf):
// Yes, grab the file descriptor from it.
break;
default:
goto error;
}
cmsg = CMSG_FIRSTHDR(&msg);
cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg == nullptr ||
cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
cmsg->cmsg_level != SOL_SOCKET ||
cmsg->cmsg_type != SCM_RIGHTS) {
if (cmsg == nullptr ||
cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
cmsg->cmsg_level != SOL_SOCKET ||
cmsg->cmsg_type != SCM_RIGHTS) {
error:
LOGE("unable to read fd\n");
exit(-1);
}
LOGE("unable to read fd\n");
exit(-1);
}
return *(int *)CMSG_DATA(cmsg);
return *(int *)CMSG_DATA(cmsg);
}
/*
@@ -99,106 +99,106 @@ error:
* but no control message with the FD is sent.
*/
void send_fd(int sockfd, int fd) {
// Need to send some data in the message, this will do.
char junk[] = { '\0' };
struct iovec iov = {
.iov_base = junk,
.iov_len = 1,
};
// Need to send some data in the message, this will do.
char junk[] = { '\0' };
struct iovec iov = {
.iov_base = junk,
.iov_len = 1,
};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
};
char cmsgbuf[CMSG_SPACE(sizeof(int))];
char cmsgbuf[CMSG_SPACE(sizeof(int))];
if (fd != -1) {
// Is the file descriptor actually open?
if (fcntl(fd, F_GETFD) == -1) {
if (errno != EBADF) {
PLOGE("unable to send fd");
}
// It's closed, don't send a control message or sendmsg will EBADF.
} else {
// It's open, send the file descriptor in a control message.
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
if (fd != -1) {
// Is the file descriptor actually open?
if (fcntl(fd, F_GETFD) == -1) {
if (errno != EBADF) {
PLOGE("unable to send fd");
}
// It's closed, don't send a control message or sendmsg will EBADF.
} else {
// It's open, send the file descriptor in a control message.
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*(int *)CMSG_DATA(cmsg) = fd;
}
}
*(int *)CMSG_DATA(cmsg) = fd;
}
}
xsendmsg(sockfd, &msg, 0);
xsendmsg(sockfd, &msg, 0);
}
int read_int(int fd) {
int val;
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
return -1;
return val;
int val;
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
return -1;
return val;
}
int read_int_be(int fd) {
uint32_t val;
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
return -1;
return ntohl(val);
uint32_t val;
if (xxread(fd, &val, sizeof(val)) != sizeof(val))
return -1;
return ntohl(val);
}
void write_int(int fd, int val) {
if (fd < 0) return;
xwrite(fd, &val, sizeof(val));
if (fd < 0) return;
xwrite(fd, &val, sizeof(val));
}
void write_int_be(int fd, int val) {
uint32_t nl = htonl(val);
xwrite(fd, &nl, sizeof(nl));
uint32_t nl = htonl(val);
xwrite(fd, &nl, sizeof(nl));
}
static char *rd_str(int fd, int len) {
char *val = (char *) xmalloc(sizeof(char) * (len + 1));
xxread(fd, val, len);
val[len] = '\0';
return val;
char *val = (char *) xmalloc(sizeof(char) * (len + 1));
xxread(fd, val, len);
val[len] = '\0';
return val;
}
char* read_string(int fd) {
int len = read_int(fd);
return rd_str(fd, len);
int len = read_int(fd);
return rd_str(fd, len);
}
char* read_string_be(int fd) {
int len = read_int_be(fd);
return rd_str(fd, len);
int len = read_int_be(fd);
return rd_str(fd, len);
}
void write_string(int fd, const char *val) {
if (fd < 0) return;
int len = strlen(val);
write_int(fd, len);
xwrite(fd, val, len);
if (fd < 0) return;
int len = strlen(val);
write_int(fd, len);
xwrite(fd, val, len);
}
void write_string_be(int fd, const char *val) {
int len = strlen(val);
write_int_be(fd, len);
xwrite(fd, val, len);
int len = strlen(val);
write_int_be(fd, len);
xwrite(fd, val, len);
}
void write_key_value(int fd, const char *key, const char *val) {
write_string_be(fd, key);
write_string_be(fd, val);
write_string_be(fd, key);
write_string_be(fd, val);
}
void write_key_token(int fd, const char *key, int tok) {
char val[16];
sprintf(val, "%d", tok);
write_key_value(fd, key, val);
char val[16];
sprintf(val, "%d", tok);
write_key_value(fd, key, val);
}