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

@@ -13,121 +13,121 @@ using namespace std;
template<typename Func>
static void parse_cmdline(const Func &fn) {
char cmdline[4096];
int fd = xopen("/proc/cmdline", O_RDONLY | O_CLOEXEC);
cmdline[read(fd, cmdline, sizeof(cmdline))] = '\0';
close(fd);
char cmdline[4096];
int fd = xopen("/proc/cmdline", O_RDONLY | O_CLOEXEC);
cmdline[read(fd, cmdline, sizeof(cmdline))] = '\0';
close(fd);
char *tok, *eql, *tmp, *saveptr;
saveptr = cmdline;
while ((tok = strtok_r(nullptr, " \n", &saveptr)) != nullptr) {
eql = strchr(tok, '=');
if (eql) {
*eql = '\0';
if (eql[1] == '"') {
tmp = strchr(saveptr, '"');
if (tmp != nullptr) {
*tmp = '\0';
saveptr[-1] = ' ';
saveptr = tmp + 1;
eql++;
}
}
fn(tok, eql + 1);
} else {
fn(tok, "");
}
}
char *tok, *eql, *tmp, *saveptr;
saveptr = cmdline;
while ((tok = strtok_r(nullptr, " \n", &saveptr)) != nullptr) {
eql = strchr(tok, '=');
if (eql) {
*eql = '\0';
if (eql[1] == '"') {
tmp = strchr(saveptr, '"');
if (tmp != nullptr) {
*tmp = '\0';
saveptr[-1] = ' ';
saveptr = tmp + 1;
eql++;
}
}
fn(tok, eql + 1);
} else {
fn(tok, "");
}
}
}
#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 const char *name = "/event";
uint8_t bitmask[(KEY_MAX + 1) / 8];
vector<int> events;
constexpr const char *name = "/event";
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_VOLUMEUP, bitmask))
events.push_back(fd);
else
close(fd);
}
if (events.empty())
return false;
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_VOLUMEUP, 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); });
// Return true if volume up key is held for more than 3 seconds
int count = 0;
for (int i = 0; i < 500; ++i) {
for (const int &fd : events) {
memset(bitmask, 0, sizeof(bitmask));
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
if (test_bit(KEY_VOLUMEUP, bitmask)) {
count++;
break;
}
}
if (count >= 300) {
LOGD("KEY_VOLUMEUP detected: disable system-as-root\n");
return true;
}
// Check every 10ms
usleep(10000);
}
return false;
// Return true if volume up key is held for more than 3 seconds
int count = 0;
for (int i = 0; i < 500; ++i) {
for (const int &fd : events) {
memset(bitmask, 0, sizeof(bitmask));
ioctl(fd, EVIOCGKEY(sizeof(bitmask)), bitmask);
if (test_bit(KEY_VOLUMEUP, bitmask)) {
count++;
break;
}
}
if (count >= 300) {
LOGD("KEY_VOLUMEUP detected: disable system-as-root\n");
return true;
}
// Check every 10ms
usleep(10000);
}
return false;
}
static FILE *kmsg;
static char kmsg_buf[4096];
static int vprintk(const char *fmt, va_list ap) {
vsnprintf(kmsg_buf + 12, sizeof(kmsg_buf) - 12, fmt, ap);
return fprintf(kmsg, "%s", kmsg_buf);
vsnprintf(kmsg_buf + 12, sizeof(kmsg_buf) - 12, fmt, ap);
return fprintf(kmsg, "%s", kmsg_buf);
}
void setup_klog() {
// Shut down first 3 fds
int fd;
if (access("/dev/null", W_OK) == 0) {
fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
} else {
mknod("/null", S_IFCHR | 0666, makedev(1, 3));
fd = xopen("/null", O_RDWR | O_CLOEXEC);
unlink("/null");
}
xdup3(fd, STDIN_FILENO, O_CLOEXEC);
xdup3(fd, STDOUT_FILENO, O_CLOEXEC);
xdup3(fd, STDERR_FILENO, O_CLOEXEC);
if (fd > STDERR_FILENO)
close(fd);
// Shut down first 3 fds
int fd;
if (access("/dev/null", W_OK) == 0) {
fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
} else {
mknod("/null", S_IFCHR | 0666, makedev(1, 3));
fd = xopen("/null", O_RDWR | O_CLOEXEC);
unlink("/null");
}
xdup3(fd, STDIN_FILENO, O_CLOEXEC);
xdup3(fd, STDOUT_FILENO, O_CLOEXEC);
xdup3(fd, STDERR_FILENO, O_CLOEXEC);
if (fd > STDERR_FILENO)
close(fd);
if (access("/dev/kmsg", W_OK) == 0) {
fd = xopen("/dev/kmsg", O_WRONLY | O_CLOEXEC);
} else {
mknod("/kmsg", S_IFCHR | 0666, makedev(1, 11));
fd = xopen("/kmsg", O_WRONLY | O_CLOEXEC);
unlink("/kmsg");
}
if (access("/dev/kmsg", W_OK) == 0) {
fd = xopen("/dev/kmsg", O_WRONLY | O_CLOEXEC);
} else {
mknod("/kmsg", S_IFCHR | 0666, makedev(1, 11));
fd = xopen("/kmsg", O_WRONLY | O_CLOEXEC);
unlink("/kmsg");
}
kmsg = fdopen(fd, "w");
setbuf(kmsg, nullptr);
log_cb.d = log_cb.i = log_cb.w = log_cb.e = vprintk;
log_cb.ex = nop_ex;
strcpy(kmsg_buf, "magiskinit: ");
kmsg = fdopen(fd, "w");
setbuf(kmsg, nullptr);
log_cb.d = log_cb.i = log_cb.w = log_cb.e = vprintk;
log_cb.ex = nop_ex;
strcpy(kmsg_buf, "magiskinit: ");
// Disable kmsg rate limiting
if (FILE *rate = fopen("/proc/sys/kernel/printk_devkmsg", "w")) {
fprintf(rate, "on\n");
fclose(rate);
}
// Disable kmsg rate limiting
if (FILE *rate = fopen("/proc/sys/kernel/printk_devkmsg", "w")) {
fprintf(rate, "on\n");
fclose(rate);
}
}
#define read_dt(name, key) \
@@ -141,78 +141,78 @@ if (access(file_name, R_OK) == 0){ \
}
void load_kernel_info(cmdline *cmd) {
// Get kernel data using procfs and sysfs
xmkdir("/proc", 0755);
xmount("proc", "/proc", "proc", 0, nullptr);
xmkdir("/sys", 0755);
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
// Get kernel data using procfs and sysfs
xmkdir("/proc", 0755);
xmount("proc", "/proc", "proc", 0, nullptr);
xmkdir("/sys", 0755);
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
// Log to kernel
setup_klog();
// Log to kernel
setup_klog();
parse_cmdline([=](string_view key, const char *value) -> void {
if (key == "androidboot.slot_suffix") {
strcpy(cmd->slot, value);
} else if (key == "androidboot.slot") {
cmd->slot[0] = '_';
strcpy(cmd->slot + 1, value);
} else if (key == "skip_initramfs") {
cmd->skip_initramfs = true;
} else if (key == "androidboot.force_normal_boot") {
cmd->force_normal_boot = value[0] == '1';
} else if (key == "rootwait") {
cmd->rootwait = true;
} else if (key == "androidboot.android_dt_dir") {
strcpy(cmd->dt_dir, value);
} else if (key == "androidboot.hardware") {
strcpy(cmd->hardware, value);
} else if (key == "androidboot.hardware.platform") {
strcpy(cmd->hardware_plat, value);
} else if (key == "androidboot.fstab_suffix") {
strcpy(cmd->fstab_suffix, value);
}
});
parse_cmdline([=](string_view key, const char *value) -> void {
if (key == "androidboot.slot_suffix") {
strcpy(cmd->slot, value);
} else if (key == "androidboot.slot") {
cmd->slot[0] = '_';
strcpy(cmd->slot + 1, value);
} else if (key == "skip_initramfs") {
cmd->skip_initramfs = true;
} else if (key == "androidboot.force_normal_boot") {
cmd->force_normal_boot = value[0] == '1';
} else if (key == "rootwait") {
cmd->rootwait = true;
} else if (key == "androidboot.android_dt_dir") {
strcpy(cmd->dt_dir, value);
} else if (key == "androidboot.hardware") {
strcpy(cmd->hardware, value);
} else if (key == "androidboot.hardware.platform") {
strcpy(cmd->hardware_plat, value);
} else if (key == "androidboot.fstab_suffix") {
strcpy(cmd->fstab_suffix, value);
}
});
LOGD("Kernel cmdline info:\n");
LOGD("skip_initramfs=[%d]\n", cmd->skip_initramfs);
LOGD("force_normal_boot=[%d]\n", cmd->force_normal_boot);
LOGD("rootwait=[%d]\n", cmd->rootwait);
LOGD("slot=[%s]\n", cmd->slot);
LOGD("dt_dir=[%s]\n", cmd->dt_dir);
LOGD("fstab_suffix=[%s]\n", cmd->fstab_suffix);
LOGD("hardware=[%s]\n", cmd->hardware);
LOGD("hardware.platform=[%s]\n", cmd->hardware_plat);
LOGD("Kernel cmdline info:\n");
LOGD("skip_initramfs=[%d]\n", cmd->skip_initramfs);
LOGD("force_normal_boot=[%d]\n", cmd->force_normal_boot);
LOGD("rootwait=[%d]\n", cmd->rootwait);
LOGD("slot=[%s]\n", cmd->slot);
LOGD("dt_dir=[%s]\n", cmd->dt_dir);
LOGD("fstab_suffix=[%s]\n", cmd->fstab_suffix);
LOGD("hardware=[%s]\n", cmd->hardware);
LOGD("hardware.platform=[%s]\n", cmd->hardware_plat);
parse_prop_file("/.backup/.magisk", [=](auto key, auto value) -> bool {
if (key == "RECOVERYMODE" && value == "true") {
LOGD("Running in recovery mode, waiting for key...\n");
cmd->skip_initramfs = !check_key_combo();
return false;
}
return true;
});
parse_prop_file("/.backup/.magisk", [=](auto key, auto value) -> bool {
if (key == "RECOVERYMODE" && value == "true") {
LOGD("Running in recovery mode, waiting for key...\n");
cmd->skip_initramfs = !check_key_combo();
return false;
}
return true;
});
if (cmd->dt_dir[0] == '\0')
strcpy(cmd->dt_dir, DEFAULT_DT_DIR);
if (cmd->dt_dir[0] == '\0')
strcpy(cmd->dt_dir, DEFAULT_DT_DIR);
char file_name[128];
read_dt("fstab_suffix", fstab_suffix)
read_dt("hardware", hardware)
read_dt("hardware.platform", hardware_plat)
char file_name[128];
read_dt("fstab_suffix", fstab_suffix)
read_dt("hardware", hardware)
read_dt("hardware.platform", hardware_plat)
LOGD("Device tree info:\n");
LOGD("dt_dir=[%s]\n", cmd->dt_dir);
LOGD("fstab_suffix=[%s]\n", cmd->fstab_suffix);
LOGD("hardware=[%s]\n", cmd->hardware);
LOGD("hardware.platform=[%s]\n", cmd->hardware_plat);
LOGD("Device tree info:\n");
LOGD("dt_dir=[%s]\n", cmd->dt_dir);
LOGD("fstab_suffix=[%s]\n", cmd->fstab_suffix);
LOGD("hardware=[%s]\n", cmd->hardware);
LOGD("hardware.platform=[%s]\n", cmd->hardware_plat);
}
bool check_two_stage() {
if (access("/apex", F_OK) == 0)
return true;
if (access("/system/bin/init", F_OK) == 0)
return true;
// If we still have no indication, parse the original init and see what's up
auto init = raw_data::mmap_ro("/.backup/init");
return init.contains("selinux_setup");
if (access("/apex", F_OK) == 0)
return true;
if (access("/system/bin/init", F_OK) == 0)
return true;
// If we still have no indication, parse the original init and see what's up
auto init = raw_data::mmap_ro("/.backup/init");
return init.contains("selinux_setup");
}

View File

@@ -24,163 +24,163 @@ using namespace std;
#define ENABLE_TEST 0
constexpr int (*init_applet_main[])(int, char *[]) =
{ magiskpolicy_main, magiskpolicy_main, nullptr };
{ magiskpolicy_main, magiskpolicy_main, nullptr };
static bool unxz(int fd, const uint8_t *buf, size_t size) {
uint8_t out[8192];
xz_crc32_init();
struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 1 << 26);
struct xz_buf b = {
.in = buf,
.in_pos = 0,
.in_size = size,
.out = out,
.out_pos = 0,
.out_size = sizeof(out)
};
enum xz_ret ret;
do {
ret = xz_dec_run(dec, &b);
if (ret != XZ_OK && ret != XZ_STREAM_END)
return false;
write(fd, out, b.out_pos);
b.out_pos = 0;
} while (b.in_pos != size);
return true;
uint8_t out[8192];
xz_crc32_init();
struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 1 << 26);
struct xz_buf b = {
.in = buf,
.in_pos = 0,
.in_size = size,
.out = out,
.out_pos = 0,
.out_size = sizeof(out)
};
enum xz_ret ret;
do {
ret = xz_dec_run(dec, &b);
if (ret != XZ_OK && ret != XZ_STREAM_END)
return false;
write(fd, out, b.out_pos);
b.out_pos = 0;
} while (b.in_pos != size);
return true;
}
int dump_magisk(const char *path, mode_t mode) {
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
if (fd < 0)
return 1;
if (!unxz(fd, magisk_xz, sizeof(magisk_xz)))
return 1;
close(fd);
return 0;
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
if (fd < 0)
return 1;
if (!unxz(fd, magisk_xz, sizeof(magisk_xz)))
return 1;
close(fd);
return 0;
}
static int dump_manager(const char *path, mode_t mode) {
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
if (fd < 0)
return 1;
if (!unxz(fd, manager_xz, sizeof(manager_xz)))
return 1;
close(fd);
return 0;
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
if (fd < 0)
return 1;
if (!unxz(fd, manager_xz, sizeof(manager_xz)))
return 1;
close(fd);
return 0;
}
class RecoveryInit : public BaseInit {
public:
RecoveryInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}
void start() override {
LOGD("Ramdisk is recovery, abort\n");
rename("/.backup/init", "/init");
rm_rf("/.backup");
exec_init();
}
RecoveryInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}
void start() override {
LOGD("Ramdisk is recovery, abort\n");
rename("/.backup/init", "/init");
rm_rf("/.backup");
exec_init();
}
};
#if ENABLE_TEST
class TestInit : public BaseInit {
public:
TestInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
void start() override {
// Place init tests here
}
TestInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {};
void start() override {
// Place init tests here
}
};
static int test_main(int argc, char *argv[]) {
// Log to console
cmdline_logging();
log_cb.ex = nop_ex;
// Log to console
cmdline_logging();
log_cb.ex = nop_ex;
// Switch to isolate namespace
xunshare(CLONE_NEWNS);
xmount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr);
// Switch to isolate namespace
xunshare(CLONE_NEWNS);
xmount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr);
// Unmount everything in reverse
vector<string> mounts;
parse_mnt("/proc/mounts", [&](mntent *me) {
if (me->mnt_dir != "/"sv)
mounts.emplace_back(me->mnt_dir);
return true;
});
for (auto &m : reversed(mounts))
xumount(m.data());
// Unmount everything in reverse
vector<string> mounts;
parse_mnt("/proc/mounts", [&](mntent *me) {
if (me->mnt_dir != "/"sv)
mounts.emplace_back(me->mnt_dir);
return true;
});
for (auto &m : reversed(mounts))
xumount(m.data());
// chroot jail
chdir(dirname(argv[0]));
chroot(".");
chdir("/");
// chroot jail
chdir(dirname(argv[0]));
chroot(".");
chdir("/");
cmdline cmd{};
load_kernel_info(&cmd);
cmdline cmd{};
load_kernel_info(&cmd);
auto init = make_unique<TestInit>(argv, &cmd);
init->start();
auto init = make_unique<TestInit>(argv, &cmd);
init->start();
return 1;
return 1;
}
#endif // ENABLE_TEST
static int magisk_proxy_main(int argc, char *argv[]) {
setup_klog();
auto init = make_unique<MagiskProxy>(argv);
init->start();
return 1;
setup_klog();
auto init = make_unique<MagiskProxy>(argv);
init->start();
return 1;
}
int main(int argc, char *argv[]) {
umask(0);
umask(0);
auto name = basename(argv[0]);
if (name == "magisk"sv)
return magisk_proxy_main(argc, argv);
for (int i = 0; init_applet[i]; ++i) {
if (strcmp(name, init_applet[i]) == 0)
return (*init_applet_main[i])(argc, argv);
}
auto name = basename(argv[0]);
if (name == "magisk"sv)
return magisk_proxy_main(argc, argv);
for (int i = 0; init_applet[i]; ++i) {
if (strcmp(name, init_applet[i]) == 0)
return (*init_applet_main[i])(argc, argv);
}
#if ENABLE_TEST
if (getenv("INIT_TEST") != nullptr)
return test_main(argc, argv);
if (getenv("INIT_TEST") != nullptr)
return test_main(argc, argv);
#endif
if (argc > 1 && argv[1] == "-x"sv) {
if (argv[2] == "magisk"sv)
return dump_magisk(argv[3], 0755);
else if (argv[2] == "manager"sv)
return dump_manager(argv[3], 0644);
}
if (argc > 1 && argv[1] == "-x"sv) {
if (argv[2] == "magisk"sv)
return dump_magisk(argv[3], 0755);
else if (argv[2] == "manager"sv)
return dump_manager(argv[3], 0644);
}
if (getpid() != 1)
return 1;
if (getpid() != 1)
return 1;
BaseInit *init;
cmdline cmd{};
BaseInit *init;
cmdline cmd{};
if (argc > 1 && argv[1] == "selinux_setup"sv) {
setup_klog();
init = new SecondStageInit(argv);
} else {
// This will also mount /sys and /proc
load_kernel_info(&cmd);
if (argc > 1 && argv[1] == "selinux_setup"sv) {
setup_klog();
init = new SecondStageInit(argv);
} else {
// This will also mount /sys and /proc
load_kernel_info(&cmd);
if (cmd.skip_initramfs) {
init = new SARInit(argv, &cmd);
} else {
if (cmd.force_normal_boot)
init = new FirstStageInit(argv, &cmd);
else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
init = new RecoveryInit(argv, &cmd);
else if (check_two_stage())
init = new FirstStageInit(argv, &cmd);
else
init = new RootFSInit(argv, &cmd);
}
}
if (cmd.skip_initramfs) {
init = new SARInit(argv, &cmd);
} else {
if (cmd.force_normal_boot)
init = new FirstStageInit(argv, &cmd);
else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
init = new RecoveryInit(argv, &cmd);
else if (check_two_stage())
init = new FirstStageInit(argv, &cmd);
else
init = new RootFSInit(argv, &cmd);
}
}
// Run the main routine
init->start();
exit(1);
// Run the main routine
init->start();
exit(1);
}

View File

@@ -3,27 +3,27 @@
#include "raw_data.hpp"
struct cmdline {
bool skip_initramfs;
bool force_normal_boot;
bool rootwait;
char slot[3];
char dt_dir[64];
char fstab_suffix[32];
char hardware[32];
char hardware_plat[32];
bool skip_initramfs;
bool force_normal_boot;
bool rootwait;
char slot[3];
char dt_dir[64];
char fstab_suffix[32];
char hardware[32];
char hardware_plat[32];
};
struct fstab_entry {
std::string dev;
std::string mnt_point;
std::string type;
std::string mnt_flags;
std::string fsmgr_flags;
std::string dev;
std::string mnt_point;
std::string type;
std::string mnt_flags;
std::string fsmgr_flags;
fstab_entry() = default;
fstab_entry(const fstab_entry &) = delete;
fstab_entry(fstab_entry &&) = default;
void to_file(FILE *fp);
fstab_entry() = default;
fstab_entry(const fstab_entry &) = delete;
fstab_entry(fstab_entry &&) = default;
void to_file(FILE *fp);
};
#define INIT_SOCKET "MAGISKINIT"
@@ -40,41 +40,41 @@ void setup_klog();
class BaseInit {
protected:
cmdline *cmd;
char **argv;
std::vector<std::string> mount_list;
cmdline *cmd;
char **argv;
std::vector<std::string> mount_list;
[[noreturn]] void exec_init();
void read_dt_fstab(std::vector<fstab_entry> &fstab);
[[noreturn]] void exec_init();
void read_dt_fstab(std::vector<fstab_entry> &fstab);
public:
BaseInit(char *argv[], cmdline *cmd) : cmd(cmd), argv(argv), mount_list{"/sys", "/proc"} {}
virtual ~BaseInit() = default;
virtual void start() = 0;
BaseInit(char *argv[], cmdline *cmd) : cmd(cmd), argv(argv), mount_list{"/sys", "/proc"} {}
virtual ~BaseInit() = default;
virtual void start() = 0;
};
class MagiskInit : public BaseInit {
protected:
auto_data<HEAP> self;
auto_data<HEAP> config;
std::string custom_rules_dir;
auto_data<HEAP> self;
auto_data<HEAP> config;
std::string custom_rules_dir;
void mount_with_dt();
bool patch_sepolicy(const char *file);
void setup_tmp(const char *path);
void mount_rules_dir(const char *dev_base, const char *mnt_base);
void mount_with_dt();
bool patch_sepolicy(const char *file);
void setup_tmp(const char *path);
void mount_rules_dir(const char *dev_base, const char *mnt_base);
public:
MagiskInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}
MagiskInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}
};
class SARBase : public MagiskInit {
protected:
std::vector<raw_file> overlays;
std::vector<raw_file> overlays;
void backup_files();
void patch_rootdir();
void mount_system_root();
void backup_files();
void patch_rootdir();
void mount_system_root();
public:
SARBase(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {}
SARBase(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {}
};
/***************
@@ -83,31 +83,31 @@ public:
class FirstStageInit : public BaseInit {
private:
void prepare();
void prepare();
public:
FirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {
LOGD("%s\n", __FUNCTION__);
};
void start() override {
prepare();
exec_init();
}
FirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {
LOGD("%s\n", __FUNCTION__);
};
void start() override {
prepare();
exec_init();
}
};
class SecondStageInit : public SARBase {
private:
void prepare();
void prepare();
public:
SecondStageInit(char *argv[]) : SARBase(argv, nullptr) {
LOGD("%s\n", __FUNCTION__);
// Do not unmount /sys and /proc
mount_list.clear();
};
void start() override {
prepare();
patch_rootdir();
exec_init();
}
SecondStageInit(char *argv[]) : SARBase(argv, nullptr) {
LOGD("%s\n", __FUNCTION__);
// Do not unmount /sys and /proc
mount_list.clear();
};
void start() override {
prepare();
patch_rootdir();
exec_init();
}
};
/*************
@@ -116,22 +116,22 @@ public:
class SARInit : public SARBase {
private:
bool is_two_stage;
bool is_two_stage;
void early_mount();
void first_stage_prep();
void early_mount();
void first_stage_prep();
public:
SARInit(char *argv[], cmdline *cmd) : SARBase(argv, cmd), is_two_stage(false) {
LOGD("%s\n", __FUNCTION__);
};
void start() override {
early_mount();
if (is_two_stage)
first_stage_prep();
else
patch_rootdir();
exec_init();
}
SARInit(char *argv[], cmdline *cmd) : SARBase(argv, cmd), is_two_stage(false) {
LOGD("%s\n", __FUNCTION__);
};
void start() override {
early_mount();
if (is_two_stage)
first_stage_prep();
else
patch_rootdir();
exec_init();
}
};
/************
@@ -140,23 +140,23 @@ public:
class RootFSInit : public MagiskInit {
private:
void early_mount();
void patch_rootfs();
void early_mount();
void patch_rootfs();
public:
RootFSInit(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {
LOGD("%s\n", __FUNCTION__);
}
void start() override {
early_mount();
patch_rootfs();
exec_init();
}
RootFSInit(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {
LOGD("%s\n", __FUNCTION__);
}
void start() override {
early_mount();
patch_rootfs();
exec_init();
}
};
class MagiskProxy : public MagiskInit {
public:
explicit MagiskProxy(char *argv[]) : MagiskInit(argv, nullptr) {
LOGD("%s\n", __FUNCTION__);
}
void start() override;
explicit MagiskProxy(char *argv[]) : MagiskInit(argv, nullptr) {
LOGD("%s\n", __FUNCTION__);
}
void start() override;
};

View File

@@ -11,406 +11,406 @@
using namespace std;
static string rtrim(string &&str) {
// Trim space, newline, and null byte from end of string
while (memchr(" \n\r", str[str.length() - 1], 4))
str.pop_back();
return std::move(str);
// Trim space, newline, and null byte from end of string
while (memchr(" \n\r", str[str.length() - 1], 4))
str.pop_back();
return std::move(str);
}
struct devinfo {
int major;
int minor;
char devname[32];
char partname[32];
char dmname[32];
int major;
int minor;
char devname[32];
char partname[32];
char dmname[32];
};
static vector<devinfo> dev_list;
static void parse_device(devinfo *dev, const char *uevent) {
dev->partname[0] = '\0';
parse_prop_file(uevent, [=](string_view key, string_view value) -> bool {
if (key == "MAJOR")
dev->major = parse_int(value.data());
else if (key == "MINOR")
dev->minor = parse_int(value.data());
else if (key == "DEVNAME")
strcpy(dev->devname, value.data());
else if (key == "PARTNAME")
strcpy(dev->partname, value.data());
dev->partname[0] = '\0';
parse_prop_file(uevent, [=](string_view key, string_view value) -> bool {
if (key == "MAJOR")
dev->major = parse_int(value.data());
else if (key == "MINOR")
dev->minor = parse_int(value.data());
else if (key == "DEVNAME")
strcpy(dev->devname, value.data());
else if (key == "PARTNAME")
strcpy(dev->partname, value.data());
return true;
});
return true;
});
}
static void collect_devices() {
char path[128];
devinfo dev{};
if (auto dir = xopen_dir("/sys/dev/block"); dir) {
for (dirent *entry; (entry = readdir(dir.get()));) {
if (entry->d_name == "."sv || entry->d_name == ".."sv)
continue;
sprintf(path, "/sys/dev/block/%s/uevent", entry->d_name);
parse_device(&dev, path);
sprintf(path, "/sys/dev/block/%s/dm/name", entry->d_name);
if (access(path, F_OK) == 0) {
auto name = rtrim(full_read(path));
strcpy(dev.dmname, name.data());
}
dev_list.push_back(dev);
}
}
char path[128];
devinfo dev{};
if (auto dir = xopen_dir("/sys/dev/block"); dir) {
for (dirent *entry; (entry = readdir(dir.get()));) {
if (entry->d_name == "."sv || entry->d_name == ".."sv)
continue;
sprintf(path, "/sys/dev/block/%s/uevent", entry->d_name);
parse_device(&dev, path);
sprintf(path, "/sys/dev/block/%s/dm/name", entry->d_name);
if (access(path, F_OK) == 0) {
auto name = rtrim(full_read(path));
strcpy(dev.dmname, name.data());
}
dev_list.push_back(dev);
}
}
}
static struct {
char partname[32];
char block_dev[64];
char partname[32];
char block_dev[64];
} blk_info;
static int64_t setup_block(bool write_block) {
if (dev_list.empty())
collect_devices();
xmkdir("/dev", 0755);
xmkdir("/dev/block", 0755);
if (dev_list.empty())
collect_devices();
xmkdir("/dev", 0755);
xmkdir("/dev/block", 0755);
for (int tries = 0; tries < 3; ++tries) {
for (auto &dev : dev_list) {
if (strcasecmp(dev.partname, blk_info.partname) == 0)
LOGD("Setup %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor);
else if (strcasecmp(dev.dmname, blk_info.partname) == 0)
LOGD("Setup %s: [%s] (%d, %d)\n", dev.dmname, dev.devname, dev.major, dev.minor);
else
continue;
for (int tries = 0; tries < 3; ++tries) {
for (auto &dev : dev_list) {
if (strcasecmp(dev.partname, blk_info.partname) == 0)
LOGD("Setup %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor);
else if (strcasecmp(dev.dmname, blk_info.partname) == 0)
LOGD("Setup %s: [%s] (%d, %d)\n", dev.dmname, dev.devname, dev.major, dev.minor);
else
continue;
if (write_block) {
sprintf(blk_info.block_dev, "/dev/block/%s", dev.devname);
}
dev_t rdev = makedev(dev.major, dev.minor);
mknod(blk_info.block_dev, S_IFBLK | 0600, rdev);
return rdev;
}
// Wait 10ms and try again
usleep(10000);
dev_list.clear();
collect_devices();
}
if (write_block) {
sprintf(blk_info.block_dev, "/dev/block/%s", dev.devname);
}
dev_t rdev = makedev(dev.major, dev.minor);
mknod(blk_info.block_dev, S_IFBLK | 0600, rdev);
return rdev;
}
// Wait 10ms and try again
usleep(10000);
dev_list.clear();
collect_devices();
}
// The requested partname does not exist
return -1;
// The requested partname does not exist
return -1;
}
static bool is_lnk(const char *name) {
struct stat st;
if (lstat(name, &st))
return false;
return S_ISLNK(st.st_mode);
struct stat st;
if (lstat(name, &st))
return false;
return S_ISLNK(st.st_mode);
}
#define read_info(val) \
if (access(#val, F_OK) == 0) {\
entry.val = rtrim(full_read(#val)); \
entry.val = rtrim(full_read(#val)); \
}
void BaseInit::read_dt_fstab(vector<fstab_entry> &fstab) {
if (access(cmd->dt_dir, F_OK) != 0)
return;
if (access(cmd->dt_dir, F_OK) != 0)
return;
char cwd[128];
getcwd(cwd, sizeof(cwd));
chdir(cmd->dt_dir);
run_finally cd([&]{ chdir(cwd); });
char cwd[128];
getcwd(cwd, sizeof(cwd));
chdir(cmd->dt_dir);
run_finally cd([&]{ chdir(cwd); });
if (access("fstab", F_OK) != 0)
return;
chdir("fstab");
if (access("fstab", F_OK) != 0)
return;
chdir("fstab");
// Make sure dt fstab is enabled
if (access("status", F_OK) == 0) {
auto status = rtrim(full_read("status"));
if (status != "okay" && status != "ok")
return;
}
// Make sure dt fstab is enabled
if (access("status", F_OK) == 0) {
auto status = rtrim(full_read("status"));
if (status != "okay" && status != "ok")
return;
}
auto dir = xopen_dir(".");
for (dirent *dp; (dp = xreaddir(dir.get()));) {
if (dp->d_type != DT_DIR)
continue;
chdir(dp->d_name);
run_finally f([]{ chdir(".."); });
auto dir = xopen_dir(".");
for (dirent *dp; (dp = xreaddir(dir.get()));) {
if (dp->d_type != DT_DIR)
continue;
chdir(dp->d_name);
run_finally f([]{ chdir(".."); });
if (access("status", F_OK) == 0) {
auto status = rtrim(full_read("status"));
if (status != "okay" && status != "ok")
continue;
}
if (access("status", F_OK) == 0) {
auto status = rtrim(full_read("status"));
if (status != "okay" && status != "ok")
continue;
}
fstab_entry entry;
fstab_entry entry;
read_info(dev);
read_info(mnt_point) else {
entry.mnt_point = "/";
entry.mnt_point += dp->d_name;
}
read_info(type);
read_info(mnt_flags);
read_info(fsmgr_flags);
read_info(dev);
read_info(mnt_point) else {
entry.mnt_point = "/";
entry.mnt_point += dp->d_name;
}
read_info(type);
read_info(mnt_flags);
read_info(fsmgr_flags);
fstab.emplace_back(std::move(entry));
}
fstab.emplace_back(std::move(entry));
}
}
void MagiskInit::mount_with_dt() {
vector<fstab_entry> fstab;
read_dt_fstab(fstab);
for (const auto &entry : fstab) {
if (is_lnk(entry.mnt_point.data()))
continue;
// Derive partname from dev
sprintf(blk_info.partname, "%s%s", basename(entry.dev.data()), cmd->slot);
setup_block(true);
xmkdir(entry.mnt_point.data(), 0755);
xmount(blk_info.block_dev, entry.mnt_point.data(), entry.type.data(), MS_RDONLY, nullptr);
mount_list.push_back(entry.mnt_point);
}
vector<fstab_entry> fstab;
read_dt_fstab(fstab);
for (const auto &entry : fstab) {
if (is_lnk(entry.mnt_point.data()))
continue;
// Derive partname from dev
sprintf(blk_info.partname, "%s%s", basename(entry.dev.data()), cmd->slot);
setup_block(true);
xmkdir(entry.mnt_point.data(), 0755);
xmount(blk_info.block_dev, entry.mnt_point.data(), entry.type.data(), MS_RDONLY, nullptr);
mount_list.push_back(entry.mnt_point);
}
}
static void switch_root(const string &path) {
LOGD("Switch root to %s\n", path.data());
int root = xopen("/", O_RDONLY);
vector<string> mounts;
parse_mnt("/proc/mounts", [&](mntent *me) {
// Skip root and self
if (me->mnt_dir == "/"sv || me->mnt_dir == path)
return true;
// Do not include subtrees
for (const auto &m : mounts) {
if (strncmp(me->mnt_dir, m.data(), m.length()) == 0 && me->mnt_dir[m.length()] == '/')
return true;
}
mounts.emplace_back(me->mnt_dir);
return true;
});
for (auto &dir : mounts) {
auto new_path = path + dir;
mkdir(new_path.data(), 0755);
xmount(dir.data(), new_path.data(), nullptr, MS_MOVE, nullptr);
}
chdir(path.data());
xmount(path.data(), "/", nullptr, MS_MOVE, nullptr);
chroot(".");
LOGD("Switch root to %s\n", path.data());
int root = xopen("/", O_RDONLY);
vector<string> mounts;
parse_mnt("/proc/mounts", [&](mntent *me) {
// Skip root and self
if (me->mnt_dir == "/"sv || me->mnt_dir == path)
return true;
// Do not include subtrees
for (const auto &m : mounts) {
if (strncmp(me->mnt_dir, m.data(), m.length()) == 0 && me->mnt_dir[m.length()] == '/')
return true;
}
mounts.emplace_back(me->mnt_dir);
return true;
});
for (auto &dir : mounts) {
auto new_path = path + dir;
mkdir(new_path.data(), 0755);
xmount(dir.data(), new_path.data(), nullptr, MS_MOVE, nullptr);
}
chdir(path.data());
xmount(path.data(), "/", nullptr, MS_MOVE, nullptr);
chroot(".");
LOGD("Cleaning rootfs\n");
frm_rf(root);
LOGD("Cleaning rootfs\n");
frm_rf(root);
}
void MagiskInit::mount_rules_dir(const char *dev_base, const char *mnt_base) {
char path[128];
xrealpath(dev_base, blk_info.block_dev);
xrealpath(mnt_base, path);
char *b = blk_info.block_dev + strlen(blk_info.block_dev);
char *p = path + strlen(path);
char path[128];
xrealpath(dev_base, blk_info.block_dev);
xrealpath(mnt_base, path);
char *b = blk_info.block_dev + strlen(blk_info.block_dev);
char *p = path + strlen(path);
auto do_mount = [&](const char *type) -> bool {
xmkdir(path, 0755);
bool success = xmount(blk_info.block_dev, path, type, 0, nullptr) == 0;
if (success)
mount_list.emplace_back(path);
return success;
};
auto do_mount = [&](const char *type) -> bool {
xmkdir(path, 0755);
bool success = xmount(blk_info.block_dev, path, type, 0, nullptr) == 0;
if (success)
mount_list.emplace_back(path);
return success;
};
// First try userdata
strcpy(blk_info.partname, "userdata");
strcpy(b, "/data");
strcpy(p, "/data");
if (setup_block(false) < 0) {
// Try NVIDIA naming scheme
strcpy(blk_info.partname, "UDA");
if (setup_block(false) < 0)
goto cache;
}
// Try to mount with either ext4 or f2fs
// Failure means either FDE or metadata encryption
if (!do_mount("ext4") && !do_mount("f2fs"))
goto cache;
// First try userdata
strcpy(blk_info.partname, "userdata");
strcpy(b, "/data");
strcpy(p, "/data");
if (setup_block(false) < 0) {
// Try NVIDIA naming scheme
strcpy(blk_info.partname, "UDA");
if (setup_block(false) < 0)
goto cache;
}
// Try to mount with either ext4 or f2fs
// Failure means either FDE or metadata encryption
if (!do_mount("ext4") && !do_mount("f2fs"))
goto cache;
strcpy(p, "/data/unencrypted");
if (access(path, F_OK) == 0) {
// FBE, need to use an unencrypted path
custom_rules_dir = path + "/magisk"s;
} else {
// Skip if /data/adb does not exist
strcpy(p, "/data/adb");
if (access(path, F_OK) != 0)
return;
// Unencrypted, directly use module paths
custom_rules_dir = string(mnt_base) + MODULEROOT;
}
goto success;
strcpy(p, "/data/unencrypted");
if (access(path, F_OK) == 0) {
// FBE, need to use an unencrypted path
custom_rules_dir = path + "/magisk"s;
} else {
// Skip if /data/adb does not exist
strcpy(p, "/data/adb");
if (access(path, F_OK) != 0)
return;
// Unencrypted, directly use module paths
custom_rules_dir = string(mnt_base) + MODULEROOT;
}
goto success;
cache:
// Fallback to cache
strcpy(blk_info.partname, "cache");
strcpy(b, "/cache");
strcpy(p, "/cache");
if (setup_block(false) < 0) {
// Try NVIDIA naming scheme
strcpy(blk_info.partname, "CAC");
if (setup_block(false) < 0)
goto metadata;
}
if (!do_mount("ext4"))
goto metadata;
custom_rules_dir = path + "/magisk"s;
goto success;
// Fallback to cache
strcpy(blk_info.partname, "cache");
strcpy(b, "/cache");
strcpy(p, "/cache");
if (setup_block(false) < 0) {
// Try NVIDIA naming scheme
strcpy(blk_info.partname, "CAC");
if (setup_block(false) < 0)
goto metadata;
}
if (!do_mount("ext4"))
goto metadata;
custom_rules_dir = path + "/magisk"s;
goto success;
metadata:
// Fallback to metadata
strcpy(blk_info.partname, "metadata");
strcpy(b, "/metadata");
strcpy(p, "/metadata");
if (setup_block(false) < 0 || !do_mount("ext4"))
goto persist;
custom_rules_dir = path + "/magisk"s;
goto success;
// Fallback to metadata
strcpy(blk_info.partname, "metadata");
strcpy(b, "/metadata");
strcpy(p, "/metadata");
if (setup_block(false) < 0 || !do_mount("ext4"))
goto persist;
custom_rules_dir = path + "/magisk"s;
goto success;
persist:
// Fallback to persist
strcpy(blk_info.partname, "persist");
strcpy(b, "/persist");
strcpy(p, "/persist");
if (setup_block(false) < 0 || !do_mount("ext4"))
return;
custom_rules_dir = path + "/magisk"s;
// Fallback to persist
strcpy(blk_info.partname, "persist");
strcpy(b, "/persist");
strcpy(p, "/persist");
if (setup_block(false) < 0 || !do_mount("ext4"))
return;
custom_rules_dir = path + "/magisk"s;
success:
// Create symlinks so we don't need to go through this logic again
strcpy(p, "/sepolicy.rules");
xsymlink(custom_rules_dir.data(), path);
// Create symlinks so we don't need to go through this logic again
strcpy(p, "/sepolicy.rules");
xsymlink(custom_rules_dir.data(), path);
}
void RootFSInit::early_mount() {
self = raw_data::read("/init");
self = raw_data::read("/init");
LOGD("Restoring /init\n");
rename("/.backup/init", "/init");
LOGD("Restoring /init\n");
rename("/.backup/init", "/init");
mount_with_dt();
mount_with_dt();
}
void SARBase::backup_files() {
if (access("/overlay.d", F_OK) == 0)
backup_folder("/overlay.d", overlays);
if (access("/overlay.d", F_OK) == 0)
backup_folder("/overlay.d", overlays);
self = raw_data::read("/proc/self/exe");
if (access("/.backup/.magisk", R_OK) == 0)
config = raw_data::read("/.backup/.magisk");
self = raw_data::read("/proc/self/exe");
if (access("/.backup/.magisk", R_OK) == 0)
config = raw_data::read("/.backup/.magisk");
}
void SARBase::mount_system_root() {
LOGD("Early mount system_root\n");
strcpy(blk_info.block_dev, "/dev/root");
LOGD("Early mount system_root\n");
strcpy(blk_info.block_dev, "/dev/root");
do {
// Try legacy SAR dm-verity
strcpy(blk_info.partname, "vroot");
auto dev = setup_block(false);
if (dev >= 0)
goto mount_root;
do {
// Try legacy SAR dm-verity
strcpy(blk_info.partname, "vroot");
auto dev = setup_block(false);
if (dev >= 0)
goto mount_root;
// Try NVIDIA naming scheme
strcpy(blk_info.partname, "APP");
dev = setup_block(false);
if (dev >= 0)
goto mount_root;
// Try NVIDIA naming scheme
strcpy(blk_info.partname, "APP");
dev = setup_block(false);
if (dev >= 0)
goto mount_root;
sprintf(blk_info.partname, "system%s", cmd->slot);
dev = setup_block(false);
if (dev >= 0)
goto mount_root;
sprintf(blk_info.partname, "system%s", cmd->slot);
dev = setup_block(false);
if (dev >= 0)
goto mount_root;
// Poll forever if rootwait was given in cmdline
} while (cmd->rootwait);
// Poll forever if rootwait was given in cmdline
} while (cmd->rootwait);
// We don't really know what to do at this point...
LOGE("Cannot find root partition, abort\n");
exit(1);
// We don't really know what to do at this point...
LOGE("Cannot find root partition, abort\n");
exit(1);
mount_root:
xmkdir("/system_root", 0755);
if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr))
xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr);
xmkdir("/system_root", 0755);
if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr))
xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr);
}
void SARInit::early_mount() {
backup_files();
mount_system_root();
switch_root("/system_root");
backup_files();
mount_system_root();
switch_root("/system_root");
{
auto init = raw_data::mmap_ro("/init");
is_two_stage = init.contains("selinux_setup");
}
LOGD("is_two_stage: [%d]\n", is_two_stage);
{
auto init = raw_data::mmap_ro("/init");
is_two_stage = init.contains("selinux_setup");
}
LOGD("is_two_stage: [%d]\n", is_two_stage);
if (!is_two_stage) {
// Make dev writable
xmkdir("/dev", 0755);
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
mount_list.emplace_back("/dev");
mount_with_dt();
}
if (!is_two_stage) {
// Make dev writable
xmkdir("/dev", 0755);
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
mount_list.emplace_back("/dev");
mount_with_dt();
}
}
void SecondStageInit::prepare() {
backup_files();
backup_files();
umount2("/init", MNT_DETACH);
umount2("/proc/self/exe", MNT_DETACH);
umount2("/init", MNT_DETACH);
umount2("/proc/self/exe", MNT_DETACH);
if (access("/system_root", F_OK) == 0)
switch_root("/system_root");
if (access("/system_root", F_OK) == 0)
switch_root("/system_root");
}
void BaseInit::exec_init() {
// Unmount in reverse order
for (auto &p : reversed(mount_list)) {
if (xumount(p.data()) == 0)
LOGD("Unmount [%s]\n", p.data());
}
execv("/init", argv);
exit(1);
// Unmount in reverse order
for (auto &p : reversed(mount_list)) {
if (xumount(p.data()) == 0)
LOGD("Unmount [%s]\n", p.data());
}
execv("/init", argv);
exit(1);
}
static void patch_socket_name(const char *path) {
char rstr[16];
gen_rand_str(rstr, sizeof(rstr));
auto bin = raw_data::mmap_rw(path);
bin.patch({ make_pair(MAIN_SOCKET, rstr) });
char rstr[16];
gen_rand_str(rstr, sizeof(rstr));
auto bin = raw_data::mmap_rw(path);
bin.patch({ make_pair(MAIN_SOCKET, rstr) });
}
void MagiskInit::setup_tmp(const char *path) {
LOGD("Setup Magisk tmp at %s\n", path);
xmount("tmpfs", path, "tmpfs", 0, "mode=755");
LOGD("Setup Magisk tmp at %s\n", path);
xmount("tmpfs", path, "tmpfs", 0, "mode=755");
chdir(path);
chdir(path);
xmkdir(INTLROOT, 0755);
xmkdir(MIRRDIR, 0);
xmkdir(BLOCKDIR, 0);
xmkdir(INTLROOT, 0755);
xmkdir(MIRRDIR, 0);
xmkdir(BLOCKDIR, 0);
int fd = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0);
xwrite(fd, config.buf, config.sz);
close(fd);
fd = xopen("magiskinit", O_WRONLY | O_CREAT, 0755);
xwrite(fd, self.buf, self.sz);
close(fd);
dump_magisk("magisk", 0755);
patch_socket_name("magisk");
int fd = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0);
xwrite(fd, config.buf, config.sz);
close(fd);
fd = xopen("magiskinit", O_WRONLY | O_CREAT, 0755);
xwrite(fd, self.buf, self.sz);
close(fd);
dump_magisk("magisk", 0755);
patch_socket_name("magisk");
// Create applet symlinks
for (int i = 0; applet_names[i]; ++i)
xsymlink("./magisk", applet_names[i]);
xsymlink("./magiskinit", "magiskpolicy");
xsymlink("./magiskinit", "supolicy");
// Create applet symlinks
for (int i = 0; applet_names[i]; ++i)
xsymlink("./magisk", applet_names[i]);
xsymlink("./magiskinit", "magiskpolicy");
xsymlink("./magiskinit", "supolicy");
chdir("/");
chdir("/");
}

View File

@@ -3,62 +3,62 @@
using namespace std;
int data_holder::patch(str_pairs list) {
if (buf == nullptr)
return 0;
int count = 0;
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
for (auto [from, to] : list) {
if (memcmp(p, from.data(), from.length() + 1) == 0) {
LOGD("Replace [%s] -> [%s]\n", from.data(), to.data());
memset(p, 0, from.length());
memcpy(p, to.data(), to.length());
++count;
p += from.length();
}
}
}
return count;
if (buf == nullptr)
return 0;
int count = 0;
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
for (auto [from, to] : list) {
if (memcmp(p, from.data(), from.length() + 1) == 0) {
LOGD("Replace [%s] -> [%s]\n", from.data(), to.data());
memset(p, 0, from.length());
memcpy(p, to.data(), to.length());
++count;
p += from.length();
}
}
}
return count;
}
bool data_holder::contains(string_view pattern) {
if (buf == nullptr)
return false;
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
if (memcmp(p, pattern.data(), pattern.length() + 1) == 0) {
LOGD("Found pattern [%s]\n", pattern.data());
return true;
}
}
return false;
if (buf == nullptr)
return false;
for (uint8_t *p = buf, *eof = buf + sz; p < eof; ++p) {
if (memcmp(p, pattern.data(), pattern.length() + 1) == 0) {
LOGD("Found pattern [%s]\n", pattern.data());
return true;
}
}
return false;
}
void data_holder::consume(data_holder &other) {
buf = other.buf;
sz = other.sz;
other.buf = nullptr;
other.sz = 0;
buf = other.buf;
sz = other.sz;
other.buf = nullptr;
other.sz = 0;
}
auto_data<HEAP> raw_data::read(int fd) {
auto_data<HEAP> data;
fd_full_read(fd, data.buf, data.sz);
return data;
auto_data<HEAP> data;
fd_full_read(fd, data.buf, data.sz);
return data;
}
auto_data<HEAP> raw_data::read(const char *name) {
auto_data<HEAP> data;
full_read(name, data.buf, data.sz);
return data;
auto_data<HEAP> data;
full_read(name, data.buf, data.sz);
return data;
}
auto_data<MMAP> raw_data::mmap_rw(const char *name) {
auto_data<MMAP> data;
::mmap_rw(name, data.buf, data.sz);
return data;
auto_data<MMAP> data;
::mmap_rw(name, data.buf, data.sz);
return data;
}
auto_data<MMAP> raw_data::mmap_ro(const char *name) {
auto_data<MMAP> data;
::mmap_ro(name, data.buf, data.sz);
return data;
auto_data<MMAP> data;
::mmap_ro(name, data.buf, data.sz);
return data;
}

View File

@@ -3,30 +3,30 @@
#include <utils.hpp>
struct data_holder {
uint8_t *buf = nullptr;
size_t sz = 0;
using str_pairs = std::initializer_list<std::pair<std::string_view, std::string_view>>;
int patch(str_pairs list);
bool contains(std::string_view pattern);
uint8_t *buf = nullptr;
size_t sz = 0;
using str_pairs = std::initializer_list<std::pair<std::string_view, std::string_view>>;
int patch(str_pairs list);
bool contains(std::string_view pattern);
protected:
void consume(data_holder &other);
void consume(data_holder &other);
};
enum data_type { HEAP, MMAP };
template <data_type T>
struct auto_data : public data_holder {
auto_data<T>() = default;
auto_data<T>(const auto_data&) = delete;
auto_data<T>(auto_data<T> &&other) { consume(other); }
~auto_data<T>() {}
auto_data<T>& operator=(auto_data<T> &&other) { consume(other); return *this; }
auto_data<T>() = default;
auto_data<T>(const auto_data&) = delete;
auto_data<T>(auto_data<T> &&other) { consume(other); }
~auto_data<T>() {}
auto_data<T>& operator=(auto_data<T> &&other) { consume(other); return *this; }
};
template <> inline auto_data<MMAP>::~auto_data<MMAP>() { if (buf) munmap(buf, sz); }
template <> inline auto_data<HEAP>::~auto_data<HEAP>() { free(buf); }
namespace raw_data {
auto_data<HEAP> read(const char *name);
auto_data<HEAP> read(int fd);
auto_data<MMAP> mmap_rw(const char *name);
auto_data<MMAP> mmap_ro(const char *name);
auto_data<HEAP> read(const char *name);
auto_data<HEAP> read(int fd);
auto_data<MMAP> mmap_rw(const char *name);
auto_data<MMAP> mmap_ro(const char *name);
}

View File

@@ -20,164 +20,164 @@ using namespace std;
static vector<string> rc_list;
static void patch_init_rc(const char *src, const char *dest, const char *tmp_dir) {
FILE *rc = xfopen(dest, "we");
file_readline(src, [=](string_view line) -> bool {
// Do not start vaultkeeper
if (str_contains(line, "start vaultkeeper")) {
LOGD("Remove vaultkeeper\n");
return true;
}
// Do not run flash_recovery
if (str_starts(line, "service flash_recovery")) {
LOGD("Remove flash_recovery\n");
fprintf(rc, "service flash_recovery /system/bin/xxxxx\n");
return true;
}
// Else just write the line
fprintf(rc, "%s", line.data());
return true;
});
FILE *rc = xfopen(dest, "we");
file_readline(src, [=](string_view line) -> bool {
// Do not start vaultkeeper
if (str_contains(line, "start vaultkeeper")) {
LOGD("Remove vaultkeeper\n");
return true;
}
// Do not run flash_recovery
if (str_starts(line, "service flash_recovery")) {
LOGD("Remove flash_recovery\n");
fprintf(rc, "service flash_recovery /system/bin/xxxxx\n");
return true;
}
// Else just write the line
fprintf(rc, "%s", line.data());
return true;
});
fprintf(rc, "\n");
fprintf(rc, "\n");
// Inject custom rc scripts
for (auto &script : rc_list) {
// Replace template arguments of rc scripts with dynamic paths
replace_all(script, "${MAGISKTMP}", tmp_dir);
fprintf(rc, "\n%s\n", script.data());
}
rc_list.clear();
// Inject custom rc scripts
for (auto &script : rc_list) {
// Replace template arguments of rc scripts with dynamic paths
replace_all(script, "${MAGISKTMP}", tmp_dir);
fprintf(rc, "\n%s\n", script.data());
}
rc_list.clear();
// Inject Magisk rc scripts
char pfd_svc[16], ls_svc[16], bc_svc[16];
gen_rand_str(pfd_svc, sizeof(pfd_svc));
gen_rand_str(ls_svc, sizeof(ls_svc));
gen_rand_str(bc_svc, sizeof(bc_svc));
LOGD("Inject magisk services: [%s] [%s] [%s]\n", pfd_svc, ls_svc, bc_svc);
fprintf(rc, MAGISK_RC, tmp_dir, pfd_svc, ls_svc, bc_svc);
// Inject Magisk rc scripts
char pfd_svc[16], ls_svc[16], bc_svc[16];
gen_rand_str(pfd_svc, sizeof(pfd_svc));
gen_rand_str(ls_svc, sizeof(ls_svc));
gen_rand_str(bc_svc, sizeof(bc_svc));
LOGD("Inject magisk services: [%s] [%s] [%s]\n", pfd_svc, ls_svc, bc_svc);
fprintf(rc, MAGISK_RC, tmp_dir, pfd_svc, ls_svc, bc_svc);
fclose(rc);
clone_attr(src, dest);
fclose(rc);
clone_attr(src, dest);
}
static void load_overlay_rc(const char *overlay) {
auto dir = open_dir(overlay);
if (!dir) return;
auto dir = open_dir(overlay);
if (!dir) return;
int dfd = dirfd(dir.get());
// Do not allow overwrite init.rc
unlinkat(dfd, "init.rc", 0);
for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (str_ends(entry->d_name, ".rc")) {
LOGD("Found rc script [%s]\n", entry->d_name);
int rc = xopenat(dfd, entry->d_name, O_RDONLY | O_CLOEXEC);
rc_list.push_back(fd_full_read(rc));
close(rc);
unlinkat(dfd, entry->d_name, 0);
}
}
int dfd = dirfd(dir.get());
// Do not allow overwrite init.rc
unlinkat(dfd, "init.rc", 0);
for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (str_ends(entry->d_name, ".rc")) {
LOGD("Found rc script [%s]\n", entry->d_name);
int rc = xopenat(dfd, entry->d_name, O_RDONLY | O_CLOEXEC);
rc_list.push_back(fd_full_read(rc));
close(rc);
unlinkat(dfd, entry->d_name, 0);
}
}
}
bool MagiskInit::patch_sepolicy(const char *file) {
bool patch_init = false;
sepolicy *sepol = nullptr;
bool patch_init = false;
sepolicy *sepol = nullptr;
if (access(SPLIT_PLAT_CIL, R_OK) == 0) {
LOGD("sepol: split policy\n");
patch_init = true;
} else if (access("/sepolicy", R_OK) == 0) {
LOGD("sepol: monolithic policy\n");
sepol = sepolicy::from_file("/sepolicy");
} else {
LOGD("sepol: no selinux\n");
return false;
}
if (access(SPLIT_PLAT_CIL, R_OK) == 0) {
LOGD("sepol: split policy\n");
patch_init = true;
} else if (access("/sepolicy", R_OK) == 0) {
LOGD("sepol: monolithic policy\n");
sepol = sepolicy::from_file("/sepolicy");
} else {
LOGD("sepol: no selinux\n");
return false;
}
if (access(SELINUX_VERSION, F_OK) != 0) {
// Mount selinuxfs to communicate with kernel
xmount("selinuxfs", SELINUX_MNT, "selinuxfs", 0, nullptr);
mount_list.emplace_back(SELINUX_MNT);
}
if (access(SELINUX_VERSION, F_OK) != 0) {
// Mount selinuxfs to communicate with kernel
xmount("selinuxfs", SELINUX_MNT, "selinuxfs", 0, nullptr);
mount_list.emplace_back(SELINUX_MNT);
}
if (patch_init)
sepol = sepolicy::from_split();
if (patch_init)
sepol = sepolicy::from_split();
sepol->magisk_rules();
sepol->magisk_rules();
// Custom rules
if (!custom_rules_dir.empty()) {
if (auto dir = open_dir(custom_rules_dir.data())) {
for (dirent *entry; (entry = xreaddir(dir.get()));) {
auto rule = custom_rules_dir + "/" + entry->d_name + "/sepolicy.rule";
if (access(rule.data(), R_OK) == 0) {
LOGD("Loading custom sepolicy patch: [%s]\n", rule.data());
sepol->load_rule_file(rule.data());
}
}
}
}
// Custom rules
if (!custom_rules_dir.empty()) {
if (auto dir = open_dir(custom_rules_dir.data())) {
for (dirent *entry; (entry = xreaddir(dir.get()));) {
auto rule = custom_rules_dir + "/" + entry->d_name + "/sepolicy.rule";
if (access(rule.data(), R_OK) == 0) {
LOGD("Loading custom sepolicy patch: [%s]\n", rule.data());
sepol->load_rule_file(rule.data());
}
}
}
}
LOGD("Dumping sepolicy to: [%s]\n", file);
sepol->to_file(file);
delete sepol;
LOGD("Dumping sepolicy to: [%s]\n", file);
sepol->to_file(file);
delete sepol;
// Remove OnePlus stupid debug sepolicy and use our own
if (access("/sepolicy_debug", F_OK) == 0) {
unlink("/sepolicy_debug");
link("/sepolicy", "/sepolicy_debug");
}
// Remove OnePlus stupid debug sepolicy and use our own
if (access("/sepolicy_debug", F_OK) == 0) {
unlink("/sepolicy_debug");
link("/sepolicy", "/sepolicy_debug");
}
return patch_init;
return patch_init;
}
static void recreate_sbin(const char *mirror, bool use_bind_mount) {
auto dp = xopen_dir(mirror);
int src = dirfd(dp.get());
char buf[4096];
for (dirent *entry; (entry = xreaddir(dp.get()));) {
string sbin_path = "/sbin/"s + entry->d_name;
struct stat st;
fstatat(src, entry->d_name, &st, AT_SYMLINK_NOFOLLOW);
if (S_ISLNK(st.st_mode)) {
xreadlinkat(src, entry->d_name, buf, sizeof(buf));
xsymlink(buf, sbin_path.data());
} else {
sprintf(buf, "%s/%s", mirror, entry->d_name);
if (use_bind_mount) {
auto mode = st.st_mode & 0777;
// Create dummy
if (S_ISDIR(st.st_mode))
xmkdir(sbin_path.data(), mode);
else
close(xopen(sbin_path.data(), O_CREAT | O_WRONLY | O_CLOEXEC, mode));
auto dp = xopen_dir(mirror);
int src = dirfd(dp.get());
char buf[4096];
for (dirent *entry; (entry = xreaddir(dp.get()));) {
string sbin_path = "/sbin/"s + entry->d_name;
struct stat st;
fstatat(src, entry->d_name, &st, AT_SYMLINK_NOFOLLOW);
if (S_ISLNK(st.st_mode)) {
xreadlinkat(src, entry->d_name, buf, sizeof(buf));
xsymlink(buf, sbin_path.data());
} else {
sprintf(buf, "%s/%s", mirror, entry->d_name);
if (use_bind_mount) {
auto mode = st.st_mode & 0777;
// Create dummy
if (S_ISDIR(st.st_mode))
xmkdir(sbin_path.data(), mode);
else
close(xopen(sbin_path.data(), O_CREAT | O_WRONLY | O_CLOEXEC, mode));
xmount(buf, sbin_path.data(), nullptr, MS_BIND, nullptr);
} else {
xsymlink(buf, sbin_path.data());
}
}
}
xmount(buf, sbin_path.data(), nullptr, MS_BIND, nullptr);
} else {
xsymlink(buf, sbin_path.data());
}
}
}
}
static string magic_mount_list;
static void magic_mount(const string &sdir, const string &ddir = "") {
auto dir = xopen_dir(sdir.data());
for (dirent *entry; (entry = xreaddir(dir.get()));) {
string src = sdir + "/" + entry->d_name;
string dest = ddir + "/" + entry->d_name;
if (access(dest.data(), F_OK) == 0) {
if (entry->d_type == DT_DIR) {
// Recursive
magic_mount(src, dest);
} else {
LOGD("Mount [%s] -> [%s]\n", src.data(), dest.data());
xmount(src.data(), dest.data(), nullptr, MS_BIND, nullptr);
magic_mount_list += dest;
magic_mount_list += '\n';
}
}
}
auto dir = xopen_dir(sdir.data());
for (dirent *entry; (entry = xreaddir(dir.get()));) {
string src = sdir + "/" + entry->d_name;
string dest = ddir + "/" + entry->d_name;
if (access(dest.data(), F_OK) == 0) {
if (entry->d_type == DT_DIR) {
// Recursive
magic_mount(src, dest);
} else {
LOGD("Mount [%s] -> [%s]\n", src.data(), dest.data());
xmount(src.data(), dest.data(), nullptr, MS_BIND, nullptr);
magic_mount_list += dest;
magic_mount_list += '\n';
}
}
}
}
#define ROOTMIR MIRRDIR "/system_root"
@@ -186,169 +186,169 @@ static void magic_mount(const string &sdir, const string &ddir = "") {
#define NEW_INITRC "/system/etc/init/hw/init.rc"
void SARBase::patch_rootdir() {
string tmp_dir;
const char *sepol;
string tmp_dir;
const char *sepol;
if (access("/sbin", F_OK) == 0) {
tmp_dir = "/sbin";
sepol = "/sbin/.se";
} else {
char buf[8];
gen_rand_str(buf, sizeof(buf));
tmp_dir = "/dev/"s + buf;
xmkdir(tmp_dir.data(), 0);
sepol = "/dev/.se";
}
if (access("/sbin", F_OK) == 0) {
tmp_dir = "/sbin";
sepol = "/sbin/.se";
} else {
char buf[8];
gen_rand_str(buf, sizeof(buf));
tmp_dir = "/dev/"s + buf;
xmkdir(tmp_dir.data(), 0);
sepol = "/dev/.se";
}
setup_tmp(tmp_dir.data());
chdir(tmp_dir.data());
setup_tmp(tmp_dir.data());
chdir(tmp_dir.data());
mount_rules_dir(BLOCKDIR, MIRRDIR);
mount_rules_dir(BLOCKDIR, MIRRDIR);
// Mount system_root mirror
xmkdir(ROOTMIR, 0755);
xmount("/", ROOTMIR, nullptr, MS_BIND, nullptr);
mount_list.emplace_back(tmp_dir + "/" ROOTMIR);
// Mount system_root mirror
xmkdir(ROOTMIR, 0755);
xmount("/", ROOTMIR, nullptr, MS_BIND, nullptr);
mount_list.emplace_back(tmp_dir + "/" ROOTMIR);
// Recreate original sbin structure if necessary
if (tmp_dir == "/sbin")
recreate_sbin(ROOTMIR "/sbin", true);
// Recreate original sbin structure if necessary
if (tmp_dir == "/sbin")
recreate_sbin(ROOTMIR "/sbin", true);
// Patch init
int patch_count;
{
int src = xopen("/init", O_RDONLY | O_CLOEXEC);
auto init = raw_data::read(src);
patch_count = init.patch({
make_pair(SPLIT_PLAT_CIL, "xxx"), /* Force loading monolithic sepolicy */
make_pair(MONOPOLICY, sepol) /* Redirect /sepolicy to custom path */
});
xmkdir(ROOTOVL, 0);
int dest = xopen(ROOTOVL "/init", O_CREAT | O_WRONLY | O_CLOEXEC, 0);
xwrite(dest, init.buf, init.sz);
fclone_attr(src, dest);
close(src);
close(dest);
}
// Patch init
int patch_count;
{
int src = xopen("/init", O_RDONLY | O_CLOEXEC);
auto init = raw_data::read(src);
patch_count = init.patch({
make_pair(SPLIT_PLAT_CIL, "xxx"), /* Force loading monolithic sepolicy */
make_pair(MONOPOLICY, sepol) /* Redirect /sepolicy to custom path */
});
xmkdir(ROOTOVL, 0);
int dest = xopen(ROOTOVL "/init", O_CREAT | O_WRONLY | O_CLOEXEC, 0);
xwrite(dest, init.buf, init.sz);
fclone_attr(src, dest);
close(src);
close(dest);
}
if (patch_count != 2 && access(LIBSELINUX, F_OK) == 0) {
// init is dynamically linked, need to patch libselinux
auto lib = raw_data::read(LIBSELINUX);
lib.patch({make_pair(MONOPOLICY, sepol)});
xmkdirs(dirname(ROOTOVL LIBSELINUX), 0755);
int dest = xopen(ROOTOVL LIBSELINUX, O_CREAT | O_WRONLY | O_CLOEXEC, 0);
xwrite(dest, lib.buf, lib.sz);
close(dest);
clone_attr(LIBSELINUX, ROOTOVL LIBSELINUX);
}
if (patch_count != 2 && access(LIBSELINUX, F_OK) == 0) {
// init is dynamically linked, need to patch libselinux
auto lib = raw_data::read(LIBSELINUX);
lib.patch({make_pair(MONOPOLICY, sepol)});
xmkdirs(dirname(ROOTOVL LIBSELINUX), 0755);
int dest = xopen(ROOTOVL LIBSELINUX, O_CREAT | O_WRONLY | O_CLOEXEC, 0);
xwrite(dest, lib.buf, lib.sz);
close(dest);
clone_attr(LIBSELINUX, ROOTOVL LIBSELINUX);
}
// sepolicy
patch_sepolicy(sepol);
// sepolicy
patch_sepolicy(sepol);
// Restore backup files
struct sockaddr_un sun;
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (connect(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET)) == 0) {
LOGD("ACK init daemon to write backup files\n");
// Let daemon know where tmp_dir is
write_string(sockfd, tmp_dir.data());
// Wait for daemon to finish restoring files
int ack;
read(sockfd, &ack, sizeof(ack));
} else {
LOGD("Restore backup files locally\n");
restore_folder(ROOTOVL, overlays);
overlays.clear();
}
close(sockfd);
// Restore backup files
struct sockaddr_un sun;
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (connect(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET)) == 0) {
LOGD("ACK init daemon to write backup files\n");
// Let daemon know where tmp_dir is
write_string(sockfd, tmp_dir.data());
// Wait for daemon to finish restoring files
int ack;
read(sockfd, &ack, sizeof(ack));
} else {
LOGD("Restore backup files locally\n");
restore_folder(ROOTOVL, overlays);
overlays.clear();
}
close(sockfd);
// Handle overlay.d
load_overlay_rc(ROOTOVL);
if (access(ROOTOVL "/sbin", F_OK) == 0) {
// Move files in overlay.d/sbin into tmp_dir
mv_path(ROOTOVL "/sbin", ".");
}
// Handle overlay.d
load_overlay_rc(ROOTOVL);
if (access(ROOTOVL "/sbin", F_OK) == 0) {
// Move files in overlay.d/sbin into tmp_dir
mv_path(ROOTOVL "/sbin", ".");
}
// Patch init.rc
if (access("/init.rc", F_OK) == 0) {
patch_init_rc("/init.rc", ROOTOVL "/init.rc", tmp_dir.data());
} else {
// Android 11's new init.rc
xmkdirs(dirname(ROOTOVL NEW_INITRC), 0755);
patch_init_rc(NEW_INITRC, ROOTOVL NEW_INITRC, tmp_dir.data());
}
// Patch init.rc
if (access("/init.rc", F_OK) == 0) {
patch_init_rc("/init.rc", ROOTOVL "/init.rc", tmp_dir.data());
} else {
// Android 11's new init.rc
xmkdirs(dirname(ROOTOVL NEW_INITRC), 0755);
patch_init_rc(NEW_INITRC, ROOTOVL NEW_INITRC, tmp_dir.data());
}
// Mount rootdir
magic_mount(ROOTOVL);
int dest = xopen(ROOTMNT, O_WRONLY | O_CREAT | O_CLOEXEC, 0);
write(dest, magic_mount_list.data(), magic_mount_list.length());
close(dest);
// Mount rootdir
magic_mount(ROOTOVL);
int dest = xopen(ROOTMNT, O_WRONLY | O_CREAT | O_CLOEXEC, 0);
write(dest, magic_mount_list.data(), magic_mount_list.length());
close(dest);
chdir("/");
chdir("/");
}
#define TMP_MNTDIR "/dev/mnt"
#define TMP_RULESDIR "/.backup/.sepolicy.rules"
void RootFSInit::patch_rootfs() {
// Handle custom sepolicy rules
xmkdir(TMP_MNTDIR, 0755);
mount_rules_dir("/dev/block", TMP_MNTDIR);
// Preserve custom rule path
if (!custom_rules_dir.empty()) {
string rules_dir = "./" + custom_rules_dir.substr(sizeof(TMP_MNTDIR));
xsymlink(rules_dir.data(), TMP_RULESDIR);
}
// Handle custom sepolicy rules
xmkdir(TMP_MNTDIR, 0755);
mount_rules_dir("/dev/block", TMP_MNTDIR);
// Preserve custom rule path
if (!custom_rules_dir.empty()) {
string rules_dir = "./" + custom_rules_dir.substr(sizeof(TMP_MNTDIR));
xsymlink(rules_dir.data(), TMP_RULESDIR);
}
if (patch_sepolicy("/sepolicy")) {
auto init = raw_data::mmap_rw("/init");
init.patch({ make_pair(SPLIT_PLAT_CIL, "xxx") });
}
if (patch_sepolicy("/sepolicy")) {
auto init = raw_data::mmap_rw("/init");
init.patch({ make_pair(SPLIT_PLAT_CIL, "xxx") });
}
// Handle overlays
if (access("/overlay.d", F_OK) == 0) {
LOGD("Merge overlay.d\n");
load_overlay_rc("/overlay.d");
mv_path("/overlay.d", "/");
}
// Handle overlays
if (access("/overlay.d", F_OK) == 0) {
LOGD("Merge overlay.d\n");
load_overlay_rc("/overlay.d");
mv_path("/overlay.d", "/");
}
patch_init_rc("/init.rc", "/init.p.rc", "/sbin");
rename("/init.p.rc", "/init.rc");
patch_init_rc("/init.rc", "/init.p.rc", "/sbin");
rename("/init.p.rc", "/init.rc");
// Create hardlink mirror of /sbin to /root
mkdir("/root", 0750);
clone_attr("/sbin", "/root");
link_path("/sbin", "/root");
// Create hardlink mirror of /sbin to /root
mkdir("/root", 0750);
clone_attr("/sbin", "/root");
link_path("/sbin", "/root");
// Dump magiskinit as magisk
int fd = xopen("/sbin/magisk", O_WRONLY | O_CREAT, 0755);
write(fd, self.buf, self.sz);
close(fd);
// Dump magiskinit as magisk
int fd = xopen("/sbin/magisk", O_WRONLY | O_CREAT, 0755);
write(fd, self.buf, self.sz);
close(fd);
}
void MagiskProxy::start() {
// Mount rootfs as rw to do post-init rootfs patches
xmount(nullptr, "/", nullptr, MS_REMOUNT, nullptr);
// Mount rootfs as rw to do post-init rootfs patches
xmount(nullptr, "/", nullptr, MS_REMOUNT, nullptr);
// Backup stuffs before removing them
self = raw_data::read("/sbin/magisk");
config = raw_data::read("/.backup/.magisk");
char custom_rules_dir[64];
custom_rules_dir[0] = '\0';
xreadlink(TMP_RULESDIR, custom_rules_dir, sizeof(custom_rules_dir));
// Backup stuffs before removing them
self = raw_data::read("/sbin/magisk");
config = raw_data::read("/.backup/.magisk");
char custom_rules_dir[64];
custom_rules_dir[0] = '\0';
xreadlink(TMP_RULESDIR, custom_rules_dir, sizeof(custom_rules_dir));
unlink("/sbin/magisk");
rm_rf("/.backup");
unlink("/sbin/magisk");
rm_rf("/.backup");
setup_tmp("/sbin");
setup_tmp("/sbin");
// Create symlinks pointing back to /root
recreate_sbin("/root", false);
// Create symlinks pointing back to /root
recreate_sbin("/root", false);
if (custom_rules_dir[0])
xsymlink(custom_rules_dir, "/sbin/" RULESDIR);
if (custom_rules_dir[0])
xsymlink(custom_rules_dir, "/sbin/" RULESDIR);
// Tell magiskd to remount rootfs
setenv("REMOUNT_ROOT", "1", 1);
execv("/sbin/magisk", argv);
// Tell magiskd to remount rootfs
setenv("REMOUNT_ROOT", "1", 1);
execv("/sbin/magisk", argv);
}

View File

@@ -9,8 +9,8 @@
using namespace std;
void fstab_entry::to_file(FILE *fp) {
fprintf(fp, "%s %s %s %s %s\n", dev.data(), mnt_point.data(),
type.data(), mnt_flags.data(), fsmgr_flags.data());
fprintf(fp, "%s %s %s %s %s\n", dev.data(), mnt_point.data(),
type.data(), mnt_flags.data(), fsmgr_flags.data());
}
#define set_info(val) \
@@ -22,193 +22,193 @@ entry.val = &line[val##0];
extern uint32_t patch_verity(void *buf, uint32_t size);
void FirstStageInit::prepare() {
if (cmd->force_normal_boot) {
xmkdirs(FSR "/system/bin", 0755);
rename("/init" /* magiskinit */, FSR "/system/bin/init");
symlink("/system/bin/init", FSR "/init");
rename("/.backup", FSR "/.backup");
rename("/overlay.d", FSR "/overlay.d");
xsymlink("/system/bin/init", "/init");
if (cmd->force_normal_boot) {
xmkdirs(FSR "/system/bin", 0755);
rename("/init" /* magiskinit */, FSR "/system/bin/init");
symlink("/system/bin/init", FSR "/init");
rename("/.backup", FSR "/.backup");
rename("/overlay.d", FSR "/overlay.d");
xsymlink("/system/bin/init", "/init");
chdir(FSR);
} else {
xmkdir("/system", 0755);
xmkdir("/system/bin", 0755);
rename("/init" /* magiskinit */ , "/system/bin/init");
rename("/.backup/init", "/init");
}
chdir(FSR);
} else {
xmkdir("/system", 0755);
xmkdir("/system/bin", 0755);
rename("/init" /* magiskinit */ , "/system/bin/init");
rename("/.backup/init", "/init");
}
// Try to load fstab from dt
vector<fstab_entry> fstab;
read_dt_fstab(fstab);
// Try to load fstab from dt
vector<fstab_entry> fstab;
read_dt_fstab(fstab);
char fstab_file[128];
fstab_file[0] = '\0';
char fstab_file[128];
fstab_file[0] = '\0';
// Find existing fstab file
for (const char *hw : { cmd->fstab_suffix, cmd->hardware, cmd->hardware_plat }) {
if (hw[0] == '\0')
continue;
sprintf(fstab_file, "fstab.%s", hw);
if (access(fstab_file, F_OK) != 0) {
fstab_file[0] = '\0';
continue;
} else {
LOGD("Found fstab file: %s\n", fstab_file);
break;
}
}
// Find existing fstab file
for (const char *hw : { cmd->fstab_suffix, cmd->hardware, cmd->hardware_plat }) {
if (hw[0] == '\0')
continue;
sprintf(fstab_file, "fstab.%s", hw);
if (access(fstab_file, F_OK) != 0) {
fstab_file[0] = '\0';
continue;
} else {
LOGD("Found fstab file: %s\n", fstab_file);
break;
}
}
if (fstab.empty()) {
// fstab has to be somewhere in ramdisk
if (fstab_file[0] == '\0') {
LOGE("Cannot find fstab file in ramdisk!\n");
return;
}
if (fstab.empty()) {
// fstab has to be somewhere in ramdisk
if (fstab_file[0] == '\0') {
LOGE("Cannot find fstab file in ramdisk!\n");
return;
}
// Parse and load fstab file
file_readline(fstab_file, [&](string_view l) -> bool {
if (l[0] == '#' || l.length() == 1)
return true;
char *line = (char *) l.data();
// Parse and load fstab file
file_readline(fstab_file, [&](string_view l) -> bool {
if (l[0] == '#' || l.length() == 1)
return true;
char *line = (char *) l.data();
int dev0, dev1, mnt_point0, mnt_point1, type0, type1,
mnt_flags0, mnt_flags1, fsmgr_flags0, fsmgr_flags1;
int dev0, dev1, mnt_point0, mnt_point1, type0, type1,
mnt_flags0, mnt_flags1, fsmgr_flags0, fsmgr_flags1;
sscanf(line, "%n%*s%n %n%*s%n %n%*s%n %n%*s%n %n%*s%n",
&dev0, &dev1, &mnt_point0, &mnt_point1, &type0, &type1,
&mnt_flags0, &mnt_flags1, &fsmgr_flags0, &fsmgr_flags1);
sscanf(line, "%n%*s%n %n%*s%n %n%*s%n %n%*s%n %n%*s%n",
&dev0, &dev1, &mnt_point0, &mnt_point1, &type0, &type1,
&mnt_flags0, &mnt_flags1, &fsmgr_flags0, &fsmgr_flags1);
fstab_entry entry;
fstab_entry entry;
set_info(dev);
set_info(mnt_point);
set_info(type);
set_info(mnt_flags);
set_info(fsmgr_flags);
set_info(dev);
set_info(mnt_point);
set_info(type);
set_info(mnt_flags);
set_info(fsmgr_flags);
fstab.emplace_back(std::move(entry));
return true;
});
} else {
// All dt fstab entries should be first_stage_mount
for (auto &entry : fstab) {
if (!str_contains(entry.fsmgr_flags, "first_stage_mount")) {
if (!entry.fsmgr_flags.empty())
entry.fsmgr_flags += ',';
entry.fsmgr_flags += "first_stage_mount";
}
}
fstab.emplace_back(std::move(entry));
return true;
});
} else {
// All dt fstab entries should be first_stage_mount
for (auto &entry : fstab) {
if (!str_contains(entry.fsmgr_flags, "first_stage_mount")) {
if (!entry.fsmgr_flags.empty())
entry.fsmgr_flags += ',';
entry.fsmgr_flags += "first_stage_mount";
}
}
// Dump dt fstab to fstab file in rootfs
if (fstab_file[0] == '\0') {
const char *suffix =
cmd->fstab_suffix[0] ? cmd->fstab_suffix :
(cmd->hardware[0] ? cmd->hardware :
(cmd->hardware_plat[0] ? cmd->hardware_plat : nullptr));
if (suffix == nullptr) {
LOGE("Cannot determine fstab suffix!\n");
return;
}
sprintf(fstab_file, "fstab.%s", suffix);
}
// Dump dt fstab to fstab file in rootfs
if (fstab_file[0] == '\0') {
const char *suffix =
cmd->fstab_suffix[0] ? cmd->fstab_suffix :
(cmd->hardware[0] ? cmd->hardware :
(cmd->hardware_plat[0] ? cmd->hardware_plat : nullptr));
if (suffix == nullptr) {
LOGE("Cannot determine fstab suffix!\n");
return;
}
sprintf(fstab_file, "fstab.%s", suffix);
}
// Patch init to force IsDtFstabCompatible() return false
auto init = raw_data::mmap_rw("/init");
init.patch({ make_pair("android,fstab", "xxx") });
}
// Patch init to force IsDtFstabCompatible() return false
auto init = raw_data::mmap_rw("/init");
init.patch({ make_pair("android,fstab", "xxx") });
}
{
LOGD("Write fstab file: %s\n", fstab_file);
auto fp = xopen_file(fstab_file, "we");
for (auto &entry : fstab) {
// Redirect system mnt_point so init won't switch root in first stage init
if (entry.mnt_point == "/system")
entry.mnt_point = "/system_root";
{
LOGD("Write fstab file: %s\n", fstab_file);
auto fp = xopen_file(fstab_file, "we");
for (auto &entry : fstab) {
// Redirect system mnt_point so init won't switch root in first stage init
if (entry.mnt_point == "/system")
entry.mnt_point = "/system_root";
// Force remove AVB for 2SI since it may bootloop some devices
auto len = patch_verity(entry.fsmgr_flags.data(), entry.fsmgr_flags.length());
entry.fsmgr_flags.resize(len);
// Force remove AVB for 2SI since it may bootloop some devices
auto len = patch_verity(entry.fsmgr_flags.data(), entry.fsmgr_flags.length());
entry.fsmgr_flags.resize(len);
entry.to_file(fp.get());
}
}
chmod(fstab_file, 0644);
entry.to_file(fp.get());
}
}
chmod(fstab_file, 0644);
chdir("/");
chdir("/");
}
#define INIT_PATH "/system/bin/init"
#define REDIR_PATH "/system/bin/am"
void SARInit::first_stage_prep() {
int pid = getpid();
int pid = getpid();
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
// Patch init binary
int src = xopen("/init", O_RDONLY);
int dest = xopen("/dev/init", O_CREAT | O_WRONLY, 0);
{
auto init = raw_data::read(src);
init.patch({ make_pair(INIT_PATH, REDIR_PATH) });
write(dest, init.buf, init.sz);
fclone_attr(src, dest);
close(dest);
}
// Patch init binary
int src = xopen("/init", O_RDONLY);
int dest = xopen("/dev/init", O_CREAT | O_WRONLY, 0);
{
auto init = raw_data::read(src);
init.patch({ make_pair(INIT_PATH, REDIR_PATH) });
write(dest, init.buf, init.sz);
fclone_attr(src, dest);
close(dest);
}
// Replace redirect init with magiskinit
dest = xopen("/dev/magiskinit", O_CREAT | O_WRONLY, 0);
write(dest, self.buf, self.sz);
fclone_attr(src, dest);
close(src);
close(dest);
// Replace redirect init with magiskinit
dest = xopen("/dev/magiskinit", O_CREAT | O_WRONLY, 0);
write(dest, self.buf, self.sz);
fclone_attr(src, dest);
close(src);
close(dest);
xmount("/dev/init", "/init", nullptr, MS_BIND, nullptr);
xmount("/dev/magiskinit", REDIR_PATH, nullptr, MS_BIND, nullptr);
xumount2("/dev", MNT_DETACH);
xmount("/dev/init", "/init", nullptr, MS_BIND, nullptr);
xmount("/dev/magiskinit", REDIR_PATH, nullptr, MS_BIND, nullptr);
xumount2("/dev", MNT_DETACH);
// Block SIGUSR1
sigset_t block, old;
sigemptyset(&block);
sigaddset(&block, SIGUSR1);
sigprocmask(SIG_BLOCK, &block, &old);
// Block SIGUSR1
sigset_t block, old;
sigemptyset(&block);
sigaddset(&block, SIGUSR1);
sigprocmask(SIG_BLOCK, &block, &old);
if (int child = xfork(); child) {
LOGD("init daemon [%d]\n", child);
// Wait for children signal
int sig;
sigwait(&block, &sig);
if (int child = xfork(); child) {
LOGD("init daemon [%d]\n", child);
// Wait for children signal
int sig;
sigwait(&block, &sig);
// Restore sigmask
sigprocmask(SIG_SETMASK, &old, nullptr);
} else {
// Establish socket for 2nd stage ack
struct sockaddr_un sun;
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
xbind(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET));
xlisten(sockfd, 1);
// Restore sigmask
sigprocmask(SIG_SETMASK, &old, nullptr);
} else {
// Establish socket for 2nd stage ack
struct sockaddr_un sun;
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
xbind(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET));
xlisten(sockfd, 1);
// Resume parent
kill(pid, SIGUSR1);
// Resume parent
kill(pid, SIGUSR1);
// Wait for second stage ack
int client = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
// Wait for second stage ack
int client = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
// Write backup files
char *tmp_dir = read_string(client);
chdir(tmp_dir);
free(tmp_dir);
int cfg = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0);
xwrite(cfg, config.buf, config.sz);
close(cfg);
restore_folder(ROOTOVL, overlays);
// Write backup files
char *tmp_dir = read_string(client);
chdir(tmp_dir);
free(tmp_dir);
int cfg = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0);
xwrite(cfg, config.buf, config.sz);
close(cfg);
restore_folder(ROOTOVL, overlays);
// Ack and bail out!
write(sockfd, &sockfd, sizeof(sockfd));
close(client);
close(sockfd);
// Ack and bail out!
write(sockfd, &sockfd, sizeof(sockfd));
close(client);
close(sockfd);
exit(0);
}
exit(0);
}
}