mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-10-16 09:52:31 +00:00
Convert indentation to spaces
The tab war is lost
This commit is contained in:
@@ -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");
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
};
|
||||
|
@@ -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("/");
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user