Fix lowmemorykiller crash hell in Pixel 3

This commit is contained in:
topjohnwu 2018-11-08 13:40:57 -05:00
parent d3947d2cfa
commit 4cdd66ceff

View File

@ -20,7 +20,6 @@
* preserved as it also provides CLI for sepolicy patching (magiskpolicy) * preserved as it also provides CLI for sepolicy patching (magiskpolicy)
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@ -50,6 +49,10 @@
int (*init_applet_main[]) (int, char *[]) = { magiskpolicy_main, magiskpolicy_main, nullptr }; int (*init_applet_main[]) (int, char *[]) = { magiskpolicy_main, magiskpolicy_main, nullptr };
static int root = -1;
static bool mnt_system = false;
static bool mnt_vendor = false;
struct cmdline { struct cmdline {
bool skip_initramfs; bool skip_initramfs;
char slot[3]; char slot[3];
@ -110,13 +113,13 @@ static void parse_device(struct device *dev, const char *uevent) {
LOGD("%s [%s] (%u, %u)\n", dev->devname, dev->partname, (unsigned) dev->major, (unsigned) dev->minor); LOGD("%s [%s] (%u, %u)\n", dev->devname, dev->partname, (unsigned) dev->major, (unsigned) dev->minor);
} }
static int setup_block(struct device *dev, const char *partname) { static bool setup_block(struct device *dev, const char *partname) {
char path[128]; char path[128];
struct dirent *entry; struct dirent *entry;
DIR *dir = opendir("/sys/dev/block"); DIR *dir = opendir("/sys/dev/block");
if (dir == nullptr) if (dir == nullptr)
return 1; return 1;
int found = 0; bool found = false;
while ((entry = readdir(dir))) { while ((entry = readdir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue; continue;
@ -124,29 +127,29 @@ static int setup_block(struct device *dev, const char *partname) {
parse_device(dev, path); parse_device(dev, path);
if (strcasecmp(dev->partname, partname) == 0) { if (strcasecmp(dev->partname, partname) == 0) {
sprintf(dev->path, "/dev/block/%s", dev->devname); sprintf(dev->path, "/dev/block/%s", dev->devname);
found = 1; found = true;
break; break;
} }
} }
closedir(dir); closedir(dir);
if (!found) if (!found)
return 1; return false;
mkdir("/dev", 0755); mkdir("/dev", 0755);
mkdir("/dev/block", 0755); mkdir("/dev/block", 0755);
mknod(dev->path, S_IFBLK | 0600, makedev(dev->major, dev->minor)); mknod(dev->path, S_IFBLK | 0600, makedev(dev->major, dev->minor));
return 0; return true;
} }
static int read_fstab_dt(const struct cmdline *cmd, const char *mnt_point, char *partname) { static bool read_fstab_dt(const struct cmdline *cmd, const char *mnt_point, char *partname) {
char buf[128]; char buf[128];
struct stat st; struct stat st;
sprintf(buf, "/%s", mnt_point); sprintf(buf, "/%s", mnt_point);
lstat(buf, &st); lstat(buf, &st);
// Don't early mount if the mount point is symlink // Don't early mount if the mount point is symlink
if (S_ISLNK(st.st_mode)) if (S_ISLNK(st.st_mode))
return 1; return false;
sprintf(buf, "%s/fstab/%s/dev", cmd->dt_dir, mnt_point); sprintf(buf, "%s/fstab/%s/dev", cmd->dt_dir, mnt_point);
if (access(buf, F_OK) == 0) { if (access(buf, F_OK) == 0) {
int fd = open(buf, O_RDONLY | O_CLOEXEC); int fd = open(buf, O_RDONLY | O_CLOEXEC);
@ -154,12 +157,12 @@ static int read_fstab_dt(const struct cmdline *cmd, const char *mnt_point, char
close(fd); close(fd);
char *name = strrchr(buf, '/') + 1; char *name = strrchr(buf, '/') + 1;
sprintf(partname, "%s%s", name, strend(name, cmd->slot) ? cmd->slot : ""); sprintf(partname, "%s%s", name, strend(name, cmd->slot) ? cmd->slot : "");
return 0; return true;
} }
return 1; return false;
} }
static int verify_precompiled() { static bool verify_precompiled() {
DIR *dir; DIR *dir;
struct dirent *entry; struct dirent *entry;
int fd; int fd;
@ -197,18 +200,18 @@ static int verify_precompiled() {
return memcmp(sys_sha, ven_sha, sizeof(sys_sha)) == 0; return memcmp(sys_sha, ven_sha, sizeof(sys_sha)) == 0;
} }
static int patch_sepolicy() { static bool patch_sepolicy() {
int init_patch = 0; bool init_patch = false;
if (access(SPLIT_PRECOMPILE, R_OK) == 0 && verify_precompiled()) { if (access(SPLIT_PRECOMPILE, R_OK) == 0 && verify_precompiled()) {
init_patch = 1; init_patch = true;
load_policydb(SPLIT_PRECOMPILE); load_policydb(SPLIT_PRECOMPILE);
} else if (access(SPLIT_PLAT_CIL, R_OK) == 0) { } else if (access(SPLIT_PLAT_CIL, R_OK) == 0) {
init_patch = 1; init_patch = true;
compile_split_cil(); compile_split_cil();
} else if (access("/sepolicy", R_OK) == 0) { } else if (access("/sepolicy", R_OK) == 0) {
load_policydb("/sepolicy"); load_policydb("/sepolicy");
} else { } else {
return 1; return false;
} }
sepol_magisk_rules(); sepol_magisk_rules();
@ -235,10 +238,10 @@ static int patch_sepolicy() {
munmap(addr, size); munmap(addr, size);
} }
return 0; return true;
} }
static int unxz(int fd, const uint8_t *buf, size_t size) { static bool unxz(int fd, const uint8_t *buf, size_t size) {
uint8_t out[8192]; uint8_t out[8192];
xz_crc32_init(); xz_crc32_init();
struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 1 << 26); struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 1 << 26);
@ -254,18 +257,18 @@ static int unxz(int fd, const uint8_t *buf, size_t size) {
do { do {
ret = xz_dec_run(dec, &b); ret = xz_dec_run(dec, &b);
if (ret != XZ_OK && ret != XZ_STREAM_END) if (ret != XZ_OK && ret != XZ_STREAM_END)
return 1; return false;
write(fd, out, b.out_pos); write(fd, out, b.out_pos);
b.out_pos = 0; b.out_pos = 0;
} while (b.in_pos != size); } while (b.in_pos != size);
return 0; return true;
} }
static int dump_magisk(const char *path, mode_t mode) { static int dump_magisk(const char *path, mode_t mode) {
int fd = creat(path, mode); int fd = creat(path, mode);
if (fd < 0) if (fd < 0)
return 1; return 1;
if (unxz(fd, magisk_xz, sizeof(magisk_xz))) if (!unxz(fd, magisk_xz, sizeof(magisk_xz)))
return 1; return 1;
close(fd); close(fd);
return 0; return 0;
@ -275,7 +278,7 @@ static int dump_manager(const char *path, mode_t mode) {
int fd = creat(path, mode); int fd = creat(path, mode);
if (fd < 0) if (fd < 0)
return 1; return 1;
if (unxz(fd, manager_xz, sizeof(manager_xz))) if (!unxz(fd, manager_xz, sizeof(manager_xz)))
return 1; return 1;
close(fd); close(fd);
return 0; return 0;
@ -316,6 +319,19 @@ static void patch_socket_name(const char *path) {
munmap(buf, size); munmap(buf, size);
} }
static void exec_init(char *argv[]) {
// Clean up
close(root);
umount("/proc");
umount("/sys");
if (mnt_system)
umount("/system");
if (mnt_vendor)
umount("/vendor");
execv("/init", argv);
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
umask(0); umask(0);
@ -359,9 +375,7 @@ int main(int argc, char *argv[]) {
* Initialize * Initialize
* ***********/ * ***********/
int root = open("/", O_RDONLY | O_CLOEXEC); root = open("/", O_RDONLY | O_CLOEXEC);
bool mnt_system = false;
bool mnt_vendor = false;
if (cmd.skip_initramfs) { if (cmd.skip_initramfs) {
// Clear rootfs // Clear rootfs
@ -378,7 +392,7 @@ int main(int argc, char *argv[]) {
if (!cmd.skip_initramfs && access("/sbin/recovery", F_OK) == 0) { if (!cmd.skip_initramfs && access("/sbin/recovery", F_OK) == 0) {
// Remove Magisk traces // Remove Magisk traces
rm_rf("/.backup"); rm_rf("/.backup");
goto exec_init; exec_init(argv);
} }
/* ************ /* ************
@ -396,21 +410,21 @@ int main(int argc, char *argv[]) {
int system_root = open("/system_root", O_RDONLY | O_CLOEXEC); int system_root = open("/system_root", O_RDONLY | O_CLOEXEC);
// Clone rootfs except /system // Clone rootfs except /system
const char *excl[] = { "overlay", ".backup", "proc", "sys", "init.bak", nullptr }; const char *excl[] = { "system", nullptr };
excl_list = excl; excl_list = excl;
clone_dir(system_root, root); clone_dir(system_root, root);
excl_list = nullptr;
close(system_root); close(system_root);
excl_list = nullptr;
xmkdir("/system", 0755); xmkdir("/system", 0755);
xmount("/system_root/system", "/system", nullptr, MS_BIND, nullptr); xmount("/system_root/system", "/system", nullptr, MS_BIND, nullptr);
} else if (read_fstab_dt(&cmd, "system", partname) == 0) { } else if (read_fstab_dt(&cmd, "system", partname)) {
setup_block(&dev, partname); setup_block(&dev, partname);
xmount(dev.path, "/system", "ext4", MS_RDONLY, nullptr); xmount(dev.path, "/system", "ext4", MS_RDONLY, nullptr);
mnt_system = true; mnt_system = true;
} }
if (read_fstab_dt(&cmd, "vendor", partname) == 0) { if (read_fstab_dt(&cmd, "vendor", partname)) {
setup_block(&dev, partname); setup_block(&dev, partname);
xmount(dev.path, "/vendor", "ext4", MS_RDONLY, nullptr); xmount(dev.path, "/vendor", "ext4", MS_RDONLY, nullptr);
mnt_vendor = true; mnt_vendor = true;
@ -420,13 +434,8 @@ int main(int argc, char *argv[]) {
* Ramdisk Patches * Ramdisk Patches
* ****************/ * ****************/
int fd;
bool injected;
FILE *fp;
char tok[4096];
// Handle ramdisk overlays // Handle ramdisk overlays
fd = open("/overlay", O_RDONLY | O_CLOEXEC); int fd = open("/overlay", O_RDONLY | O_CLOEXEC);
if (fd >= 0) { if (fd >= 0) {
mv_dir(fd, root); mv_dir(fd, root);
close(fd); close(fd);
@ -434,23 +443,23 @@ int main(int argc, char *argv[]) {
} }
// Patch init.rc to load magisk scripts // Patch init.rc to load magisk scripts
bool injected = false;
injected = false; char line[4096];
fp = xfopen("/init.rc", "r"); FILE *fp = xfopen("/init.rc", "r");
fd = creat("/init.rc.new", 0750); fd = creat("/init.rc.new", 0750);
while(fgets(tok, sizeof(tok), fp)) { while(fgets(line, sizeof(line), fp)) {
if (!injected && strncmp(tok, "import", 6) == 0) { if (!injected && strncmp(line, "import", 6) == 0) {
if (strstr(tok, "init.magisk.rc")) { if (strstr(line, "init.magisk.rc")) {
injected = true; injected = true;
} else { } else {
xwrite(fd, "import /init.magisk.rc\n", 23); xwrite(fd, "import /init.magisk.rc\n", 23);
injected = true; injected = true;
} }
} else if (strstr(tok, "selinux.reload_policy")) { } else if (strstr(line, "selinux.reload_policy")) {
// Do not allow sepolicy patch // Do not allow sepolicy patch
continue; continue;
} }
xwrite(fd, tok, strlen(tok)); xwrite(fd, line, strlen(line));
} }
fclose(fp); fclose(fp);
close(fd); close(fd);
@ -465,15 +474,5 @@ int main(int argc, char *argv[]) {
patch_socket_name("/sbin/magisk"); patch_socket_name("/sbin/magisk");
rename("/init.bak", "/sbin/magiskinit"); rename("/init.bak", "/sbin/magiskinit");
exec_init: exec_init(argv);
// Clean up
close(root);
umount("/proc");
umount("/sys");
if (mnt_system)
umount("/system");
if (mnt_vendor)
umount("/vendor");
execv("/init", argv);
} }