mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-25 02:27:51 +00:00
Use /data as tmpfs mount point in 2SI setup
Design credit to @yujincheng08 Close #5146. Fix #5491, fix #3752 Previously, Magisk changes the mount point from /system to /system_root by patching fstab to prevent the original init from changing root. The reason why we want to prevent the original init from switching the root directory is because it will then be read-only, making patching and injecting magiskinit into the boot chain difficult. This commit (ab)uses the fact that the /data folder will never be part of early mount (because it is handled very late in the boot by vold), so that we can use it as the mount point of tmpfs to store files. Some advantages of this method: - No need to switch root manually - No need to modify fstab, which significantly improves compatibility e.g. avoid hacks for weird devices like those using oplus.fstab, and avoid hacking init to bypass fstab in device trees - Supports skip_mount.cfg - Support DSU
This commit is contained in:
parent
9b60c005c7
commit
810d27a618
@ -63,13 +63,11 @@ LOCAL_SRC_FILES := \
|
|||||||
init/rootdir.cpp \
|
init/rootdir.cpp \
|
||||||
init/getinfo.cpp \
|
init/getinfo.cpp \
|
||||||
init/twostage.cpp \
|
init/twostage.cpp \
|
||||||
core/socket.cpp \
|
|
||||||
magiskpolicy/sepolicy.cpp \
|
magiskpolicy/sepolicy.cpp \
|
||||||
magiskpolicy/magiskpolicy.cpp \
|
magiskpolicy/magiskpolicy.cpp \
|
||||||
magiskpolicy/rules.cpp \
|
magiskpolicy/rules.cpp \
|
||||||
magiskpolicy/policydb.cpp \
|
magiskpolicy/policydb.cpp \
|
||||||
magiskpolicy/statement.cpp \
|
magiskpolicy/statement.cpp
|
||||||
magiskboot/pattern.cpp
|
|
||||||
|
|
||||||
LOCAL_LDFLAGS := -static
|
LOCAL_LDFLAGS := -static
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
@ -34,7 +34,6 @@ struct fstab_entry {
|
|||||||
fstab_entry(fstab_entry &&) = default;
|
fstab_entry(fstab_entry &&) = default;
|
||||||
fstab_entry &operator=(const fstab_entry&) = delete;
|
fstab_entry &operator=(const fstab_entry&) = delete;
|
||||||
fstab_entry &operator=(fstab_entry&&) = default;
|
fstab_entry &operator=(fstab_entry&&) = default;
|
||||||
void to_file(FILE *fp);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define INIT_SOCKET "MAGISKINIT"
|
#define INIT_SOCKET "MAGISKINIT"
|
||||||
@ -44,7 +43,6 @@ extern std::vector<std::string> mount_list;
|
|||||||
|
|
||||||
bool unxz(int fd, const uint8_t *buf, size_t size);
|
bool unxz(int fd, const uint8_t *buf, size_t size);
|
||||||
void load_kernel_info(BootConfig *config);
|
void load_kernel_info(BootConfig *config);
|
||||||
bool is_dsu();
|
|
||||||
bool check_two_stage();
|
bool check_two_stage();
|
||||||
void setup_klog();
|
void setup_klog();
|
||||||
const char *backup_init();
|
const char *backup_init();
|
||||||
@ -107,7 +105,6 @@ public:
|
|||||||
class FirstStageInit : public BaseInit {
|
class FirstStageInit : public BaseInit {
|
||||||
private:
|
private:
|
||||||
void prepare();
|
void prepare();
|
||||||
void get_default_fstab(char *buf, size_t len);
|
|
||||||
public:
|
public:
|
||||||
FirstStageInit(char *argv[], BootConfig *cmd) : BaseInit(argv, cmd) {
|
FirstStageInit(char *argv[], BootConfig *cmd) : BaseInit(argv, cmd) {
|
||||||
LOGD("%s\n", __FUNCTION__);
|
LOGD("%s\n", __FUNCTION__);
|
||||||
@ -124,17 +121,14 @@ public:
|
|||||||
|
|
||||||
class SARInit : public SARBase {
|
class SARInit : public SARBase {
|
||||||
private:
|
private:
|
||||||
bool is_two_stage;
|
bool early_mount();
|
||||||
|
|
||||||
void early_mount();
|
|
||||||
void first_stage_prep();
|
void first_stage_prep();
|
||||||
public:
|
public:
|
||||||
SARInit(char *argv[], BootConfig *cmd) : MagiskInit(argv, cmd), is_two_stage(false) {
|
SARInit(char *argv[], BootConfig *cmd) : MagiskInit(argv, cmd) {
|
||||||
LOGD("%s\n", __FUNCTION__);
|
LOGD("%s\n", __FUNCTION__);
|
||||||
};
|
};
|
||||||
void start() override {
|
void start() override {
|
||||||
early_mount();
|
if (early_mount())
|
||||||
if (is_two_stage)
|
|
||||||
first_stage_prep();
|
first_stage_prep();
|
||||||
else
|
else
|
||||||
patch_rootdir();
|
patch_rootdir();
|
||||||
@ -178,8 +172,10 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void start() override {
|
void start() override {
|
||||||
if (prepare()) patch_rootfs();
|
if (prepare())
|
||||||
else patch_rootdir();
|
patch_rootfs();
|
||||||
|
else
|
||||||
|
patch_rootdir();
|
||||||
exec_init();
|
exec_init();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -205,27 +205,6 @@ static void switch_root(const string &path) {
|
|||||||
frm_rf(root);
|
frm_rf(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_dsu() {
|
|
||||||
strcpy(blk_info.partname, "metadata");
|
|
||||||
xmkdir("/metadata", 0755);
|
|
||||||
if (setup_block(true) < 0 ||
|
|
||||||
xmount(blk_info.block_dev, "/metadata", "ext4", MS_RDONLY, nullptr)) {
|
|
||||||
PLOGE("Failed to mount /metadata");
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
run_finally f([]{ xumount2("/metadata", MNT_DETACH); });
|
|
||||||
constexpr auto dsu_status = "/metadata/gsi/dsu/install_status";
|
|
||||||
if (xaccess(dsu_status, F_OK) == 0) {
|
|
||||||
char status[PATH_MAX] = {0};
|
|
||||||
auto fp = xopen_file(dsu_status, "r");
|
|
||||||
fgets(status, sizeof(status), fp.get());
|
|
||||||
if (status == "ok"sv || status == "0"sv)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MagiskInit::mount_rules_dir(const char *dev_base, const char *mnt_base) {
|
void MagiskInit::mount_rules_dir(const char *dev_base, const char *mnt_base) {
|
||||||
char path[128];
|
char path[128];
|
||||||
xrealpath(dev_base, blk_info.block_dev);
|
xrealpath(dev_base, blk_info.block_dev);
|
||||||
@ -327,10 +306,14 @@ void RootFSInit::early_mount() {
|
|||||||
void SARBase::backup_files() {
|
void SARBase::backup_files() {
|
||||||
if (access("/overlay.d", F_OK) == 0)
|
if (access("/overlay.d", F_OK) == 0)
|
||||||
backup_folder("/overlay.d", overlays);
|
backup_folder("/overlay.d", overlays);
|
||||||
|
else if (access("/data/overlay.d", F_OK) == 0)
|
||||||
|
backup_folder("/data/overlay.d", overlays);
|
||||||
|
|
||||||
self = mmap_data("/proc/self/exe");
|
self = mmap_data("/proc/self/exe");
|
||||||
if (access("/.backup/.magisk", R_OK) == 0)
|
if (access("/.backup/.magisk", R_OK) == 0)
|
||||||
magisk_config = mmap_data("/.backup/.magisk");
|
magisk_config = mmap_data("/.backup/.magisk");
|
||||||
|
else if (access("/data/.backup/.magisk", R_OK) == 0)
|
||||||
|
magisk_config = mmap_data("/data/.backup/.magisk");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SARBase::mount_system_root() {
|
void SARBase::mount_system_root() {
|
||||||
@ -367,13 +350,13 @@ mount_root:
|
|||||||
xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr);
|
xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SARInit::early_mount() {
|
bool SARInit::early_mount() {
|
||||||
backup_files();
|
backup_files();
|
||||||
mount_system_root();
|
mount_system_root();
|
||||||
switch_root("/system_root");
|
switch_root("/system_root");
|
||||||
|
|
||||||
// Use the apex folder to determine whether 2SI (Android 10+)
|
// Use the apex folder to determine whether 2SI (Android 10+)
|
||||||
is_two_stage = access("/apex", F_OK) == 0;
|
bool is_two_stage = access("/apex", F_OK) == 0;
|
||||||
LOGD("is_two_stage: [%d]\n", is_two_stage);
|
LOGD("is_two_stage: [%d]\n", is_two_stage);
|
||||||
|
|
||||||
if (!is_two_stage) {
|
if (!is_two_stage) {
|
||||||
@ -386,26 +369,8 @@ void SARInit::early_mount() {
|
|||||||
#endif
|
#endif
|
||||||
mount_with_dt();
|
mount_with_dt();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool SecondStageInit::prepare() {
|
return is_two_stage;
|
||||||
backup_files();
|
|
||||||
|
|
||||||
umount2("/init", MNT_DETACH);
|
|
||||||
umount2("/proc/self/exe", MNT_DETACH);
|
|
||||||
|
|
||||||
// some weird devices, like meizu, embrace two stage init but still have legacy rootfs behaviour
|
|
||||||
bool legacy = false;
|
|
||||||
if (access("/system_root", F_OK) == 0) {
|
|
||||||
if (access("/system_root/proc", F_OK) == 0) {
|
|
||||||
switch_root("/system_root");
|
|
||||||
} else {
|
|
||||||
xmount("/system_root", "/system", nullptr, MS_MOVE, nullptr);
|
|
||||||
rmdir("/system_root");
|
|
||||||
legacy = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return legacy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseInit::exec_init() {
|
void BaseInit::exec_init() {
|
||||||
|
@ -240,7 +240,7 @@ void SARBase::patch_rootdir() {
|
|||||||
make_pair(SPLIT_PLAT_CIL, "xxx"), /* Force loading monolithic sepolicy */
|
make_pair(SPLIT_PLAT_CIL, "xxx"), /* Force loading monolithic sepolicy */
|
||||||
make_pair(MONOPOLICY, sepol) /* Redirect /sepolicy to custom path */
|
make_pair(MONOPOLICY, sepol) /* Redirect /sepolicy to custom path */
|
||||||
});
|
});
|
||||||
if constexpr (avd_hack) {
|
if (avd_hack) {
|
||||||
// Force disable early mount on original init
|
// Force disable early mount on original init
|
||||||
init.patch({ make_pair("android,fstab", "xxx") });
|
init.patch({ make_pair("android,fstab", "xxx") });
|
||||||
}
|
}
|
||||||
@ -276,23 +276,9 @@ void SARBase::patch_rootdir() {
|
|||||||
// sepolicy
|
// sepolicy
|
||||||
patch_sepolicy(sepol);
|
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);
|
|
||||||
// Wait for daemon to finish restoring files
|
|
||||||
read_int(sockfd);
|
|
||||||
} else {
|
|
||||||
LOGD("Restore backup files locally\n");
|
|
||||||
restore_folder(ROOTOVL, overlays);
|
|
||||||
overlays.clear();
|
|
||||||
}
|
|
||||||
close(sockfd);
|
|
||||||
|
|
||||||
// Handle overlay.d
|
// Handle overlay.d
|
||||||
|
restore_folder(ROOTOVL, overlays);
|
||||||
|
overlays.clear();
|
||||||
load_overlay_rc(ROOTOVL);
|
load_overlay_rc(ROOTOVL);
|
||||||
if (access(ROOTOVL "/sbin", F_OK) == 0) {
|
if (access(ROOTOVL "/sbin", F_OK) == 0) {
|
||||||
// Move files in overlay.d/sbin into tmp_dir
|
// Move files in overlay.d/sbin into tmp_dir
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include <magisk.hpp>
|
#include <magisk.hpp>
|
||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
@ -10,228 +8,34 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
void fstab_entry::to_file(FILE *fp) {
|
#define INIT_PATH "/system/bin/init"
|
||||||
fprintf(fp, "%s %s %s %s %s\n", dev.data(), mnt_point.data(),
|
#define REDIR_PATH "/data/magiskinit"
|
||||||
type.data(), mnt_flags.data(), fsmgr_flags.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
#define set_info(val) \
|
|
||||||
line[val##1] = '\0'; \
|
|
||||||
entry.val = &line[val##0];
|
|
||||||
|
|
||||||
static void read_fstab_file(const char *fstab_file, vector<fstab_entry> &fstab) {
|
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FSR "/first_stage_ramdisk"
|
|
||||||
|
|
||||||
extern uint32_t patch_verity(void *buf, uint32_t size);
|
|
||||||
|
|
||||||
static void append_oplus(vector<fstab_entry> &fstab) {
|
|
||||||
LOGD("Found fstab file: oplus.fstab\n");
|
|
||||||
map<string, string> bind_map;
|
|
||||||
vector<fstab_entry> entry_list;
|
|
||||||
|
|
||||||
{
|
|
||||||
// Make sure no duplicate mnt_point exists
|
|
||||||
set<string_view> mount_points;
|
|
||||||
|
|
||||||
// Add main fstab entry mnt_points
|
|
||||||
for (auto &entry: fstab) {
|
|
||||||
mount_points.emplace(entry.mnt_point);
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<fstab_entry> oplus_fstab;
|
|
||||||
read_fstab_file("oplus.fstab", oplus_fstab);
|
|
||||||
|
|
||||||
for (auto &entry : oplus_fstab) {
|
|
||||||
if (mount_points.count(entry.mnt_point))
|
|
||||||
continue;
|
|
||||||
if (str_contains(entry.mnt_flags, "bind")) {
|
|
||||||
bind_map.emplace(std::move(entry.dev), std::move(entry.mnt_point));
|
|
||||||
} else {
|
|
||||||
mount_points.emplace(entry.mnt_point);
|
|
||||||
entry_list.emplace_back(std::move(entry));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &entry : entry_list) {
|
|
||||||
// Mount before switch root, fix img path
|
|
||||||
if (str_starts(entry.dev, "loop@/system/"))
|
|
||||||
entry.dev.insert(5, "/system_root");
|
|
||||||
|
|
||||||
// change bind mount entries to dev mount since some users reported bind is not working
|
|
||||||
// in this case, we drop the original mount point and leave only the one from bind entry
|
|
||||||
// because some users reported keeping the original mount point causes bootloop
|
|
||||||
if (auto it = bind_map.find(entry.mnt_point); it != bind_map.end()) {
|
|
||||||
entry.mnt_point = it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
fstab.push_back(std::move(entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
unlink("oplus.fstab");
|
|
||||||
}
|
|
||||||
|
|
||||||
void FirstStageInit::get_default_fstab(char *buf, size_t len) {
|
|
||||||
buf[0] = '\0';
|
|
||||||
|
|
||||||
// Find existing fstab file
|
|
||||||
for (const char *suffix : { config->fstab_suffix, config->hardware, config->hardware_plat }) {
|
|
||||||
if (suffix[0] == '\0')
|
|
||||||
continue;
|
|
||||||
for (const char *prefix: { "odm/etc/fstab", "vendor/etc/fstab", "system/etc/fstab", "fstab" }) {
|
|
||||||
snprintf(buf, len, "%s.%s", prefix, suffix);
|
|
||||||
if (access(buf, F_OK) == 0) {
|
|
||||||
LOGD("Found fstab file: %s\n", buf);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[0] = '\0';
|
|
||||||
|
|
||||||
// No existing fstab file is found, create a valid path
|
|
||||||
const char *suffix = [&]() -> const char * {
|
|
||||||
if (config->fstab_suffix[0])
|
|
||||||
return config->fstab_suffix;
|
|
||||||
if (config->hardware[0])
|
|
||||||
return config->hardware;
|
|
||||||
if (config->hardware_plat[0])
|
|
||||||
return config->hardware_plat;
|
|
||||||
return nullptr;
|
|
||||||
}();
|
|
||||||
if (suffix == nullptr) {
|
|
||||||
LOGE("Cannot determine fstab suffix!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
snprintf(buf, len, "fstab.%s", suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FirstStageInit::prepare() {
|
void FirstStageInit::prepare() {
|
||||||
if (is_dsu()) {
|
xmkdirs("/data", 0755);
|
||||||
rename(backup_init(), "/init");
|
xmount("tmpfs", "/data", "tmpfs", 0, "mode=755");
|
||||||
LOGI("Skip loading Magisk because of DSU\n");
|
cp_afc("/init" /* magiskinit */, REDIR_PATH);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
run_finally finally([]{ chdir("/"); });
|
unlink("/init");
|
||||||
if (config->force_normal_boot) {
|
xrename(backup_init(), "/init");
|
||||||
xmkdirs(FSR "/system/bin", 0755);
|
|
||||||
rename("/init" /* magiskinit */, FSR "/system/bin/init");
|
|
||||||
symlink("/system/bin/init", FSR "/init");
|
|
||||||
rename(backup_init(), "/init");
|
|
||||||
|
|
||||||
rename("/.backup", FSR "/.backup");
|
|
||||||
rename("/overlay.d", FSR "/overlay.d");
|
|
||||||
|
|
||||||
chdir(FSR);
|
|
||||||
} else {
|
|
||||||
xmkdir("/system", 0755);
|
|
||||||
xmkdir("/system/bin", 0755);
|
|
||||||
rename("/init" /* magiskinit */ , "/system/bin/init");
|
|
||||||
rename(backup_init(), "/init");
|
|
||||||
}
|
|
||||||
|
|
||||||
char fstab_file[128];
|
|
||||||
get_default_fstab(fstab_file, sizeof(fstab_file));
|
|
||||||
|
|
||||||
// Empty fstab file path is an error
|
|
||||||
if (fstab_file[0] == '\0')
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Try to load dt fstab
|
|
||||||
vector<fstab_entry> fstab;
|
|
||||||
read_dt_fstab(fstab);
|
|
||||||
|
|
||||||
if (!fstab.empty()) {
|
|
||||||
// Dump dt fstab to fstab file in rootfs and force init to use it instead
|
|
||||||
|
|
||||||
// If there's any error in dt fstab, skip loading it
|
|
||||||
bool skip = false;
|
|
||||||
|
|
||||||
// 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";
|
|
||||||
}
|
|
||||||
// If the entry contains slotselect but the current slot is empty, error occurs
|
|
||||||
if (config->slot[0] == '\0' && str_contains(entry.fsmgr_flags, "slotselect")) {
|
|
||||||
skip = true;
|
|
||||||
break;
|
|
||||||
} // TODO: else if expected_field checks and fs_mgr_flags checks
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skip) {
|
|
||||||
// When dt fstab fails, fall back to default fstab
|
|
||||||
LOGI("dt fstab contains error, fall back to default fstab\n");
|
|
||||||
fstab.clear();
|
|
||||||
read_fstab_file(fstab_file, fstab);
|
|
||||||
} else {
|
|
||||||
// Patch init to force IsDtFstabCompatible() return false
|
|
||||||
auto init = mmap_data("/init", true);
|
|
||||||
init.patch({make_pair("android,fstab", "xxx")});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
read_fstab_file(fstab_file, fstab);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append oppo's custom fstab
|
|
||||||
if (access("oplus.fstab", F_OK) == 0)
|
|
||||||
append_oplus(fstab);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
LOGD("Write fstab file: %s\n", fstab_file);
|
auto init = mmap_data("/init", true);
|
||||||
auto fp = xopen_file(fstab_file, "we");
|
// Redirect original init to magiskinit
|
||||||
for (auto &entry : fstab) {
|
init.patch({ make_pair(INIT_PATH, REDIR_PATH) });
|
||||||
// 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);
|
|
||||||
|
|
||||||
entry.to_file(fp.get());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
chmod(fstab_file, 0644);
|
|
||||||
|
// Copy files to tmpfs
|
||||||
|
cp_afc(".backup", "/data/.backup");
|
||||||
|
cp_afc("overlay.d", "/data/overlay.d");
|
||||||
}
|
}
|
||||||
|
|
||||||
#define INIT_PATH "/system/bin/init"
|
|
||||||
#define REDIR_PATH "/system/bin/am"
|
|
||||||
|
|
||||||
void SARInit::first_stage_prep() {
|
void SARInit::first_stage_prep() {
|
||||||
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
|
xmount("tmpfs", "/data", "tmpfs", 0, "mode=755");
|
||||||
|
|
||||||
// Patch init binary
|
// Patch init binary
|
||||||
int src = xopen("/init", O_RDONLY);
|
int src = xopen("/init", O_RDONLY);
|
||||||
int dest = xopen("/dev/init", O_CREAT | O_WRONLY, 0);
|
int dest = xopen("/data/init", O_CREAT | O_WRONLY, 0);
|
||||||
{
|
{
|
||||||
auto init = mmap_data("/init");
|
auto init = mmap_data("/init");
|
||||||
init.patch({ make_pair(INIT_PATH, REDIR_PATH) });
|
init.patch({ make_pair(INIT_PATH, REDIR_PATH) });
|
||||||
@ -239,58 +43,35 @@ void SARInit::first_stage_prep() {
|
|||||||
fclone_attr(src, dest);
|
fclone_attr(src, dest);
|
||||||
close(dest);
|
close(dest);
|
||||||
}
|
}
|
||||||
|
xmount("/data/init", "/init", nullptr, MS_BIND, nullptr);
|
||||||
|
|
||||||
// Replace redirect init with magiskinit
|
// Replace redirect init with magiskinit
|
||||||
dest = xopen("/dev/magiskinit", O_CREAT | O_WRONLY, 0);
|
dest = xopen(REDIR_PATH, O_CREAT | O_WRONLY, 0);
|
||||||
write(dest, self.buf, self.sz);
|
write(dest, self.buf, self.sz);
|
||||||
fclone_attr(src, dest);
|
fclone_attr(src, dest);
|
||||||
close(src);
|
close(src);
|
||||||
close(dest);
|
close(dest);
|
||||||
|
|
||||||
xmount("/dev/init", "/init", nullptr, MS_BIND, nullptr);
|
// Copy files to tmpfs
|
||||||
xmount("/dev/magiskinit", REDIR_PATH, nullptr, MS_BIND, nullptr);
|
xmkdir("/data/.backup", 0);
|
||||||
xumount2("/dev", MNT_DETACH);
|
xmkdir("/data/overlay.d", 0);
|
||||||
|
restore_folder("/data/overlay.d", overlays);
|
||||||
// Block SIGUSR1
|
int cfg = xopen("/data/.backup/config", O_WRONLY | O_CREAT, 0);
|
||||||
sigset_t block, old;
|
xwrite(cfg, magisk_config.buf, magisk_config.sz);
|
||||||
sigemptyset(&block);
|
close(cfg);
|
||||||
sigaddset(&block, SIGUSR1);
|
}
|
||||||
sigprocmask(SIG_BLOCK, &block, &old);
|
|
||||||
|
bool SecondStageInit::prepare() {
|
||||||
if (int child = xfork()) {
|
backup_files();
|
||||||
LOGD("init daemon [%d]\n", child);
|
|
||||||
// Wait for children signal
|
umount2("/init", MNT_DETACH);
|
||||||
int sig;
|
umount2("/proc/self/exe", MNT_DETACH);
|
||||||
sigwait(&block, &sig);
|
umount2("/data", MNT_DETACH);
|
||||||
|
|
||||||
// Restore sigmask
|
// Some weird devices like meizu, uses 2SI but still have legacy rootfs
|
||||||
sigprocmask(SIG_SETMASK, &old, nullptr);
|
// Check if root and system are on the same filesystem
|
||||||
} else {
|
struct stat root{}, system{};
|
||||||
// Establish socket for 2nd stage ack
|
xstat("/", &root);
|
||||||
struct sockaddr_un sun{};
|
xstat("/system", &system);
|
||||||
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
return root.st_dev != system.st_dev;
|
||||||
xbind(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET));
|
|
||||||
xlisten(sockfd, 1);
|
|
||||||
|
|
||||||
// Resume parent
|
|
||||||
kill(getppid(), SIGUSR1);
|
|
||||||
|
|
||||||
// Wait for second stage ack
|
|
||||||
int client = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);
|
|
||||||
|
|
||||||
// Write backup files
|
|
||||||
string tmp_dir = read_string(client);
|
|
||||||
chdir(tmp_dir.data());
|
|
||||||
int cfg = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0);
|
|
||||||
xwrite(cfg, magisk_config.buf, magisk_config.sz);
|
|
||||||
close(cfg);
|
|
||||||
restore_folder(ROOTOVL, overlays);
|
|
||||||
|
|
||||||
// Ack and bail out!
|
|
||||||
write_int(client, 0);
|
|
||||||
close(client);
|
|
||||||
close(sockfd);
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user