Commit e7108483 authored by topjohnwu's avatar topjohnwu

Unify Magisk configuration

Introduce monogisk tool
parent 8d6f3c24
out/
obj/
libs/
*.zip
......
This diff is collapsed.
Subproject commit fdd700f3e5c2f9d7688d2434d4dbee8c12524411
Subproject commit 99c74b31be15a239fdffe4a727d2d83feb52b8bb
......@@ -14,17 +14,17 @@ LIBFDT := $(EXT_PATH)/dtc/libfdt
# Binaries
########################
ifdef PRECOMPILE
# magisk main binary
include $(CLEAR_VARS)
LOCAL_MODULE := magisk
LOCAL_STATIC_LIBRARIES := libsepol
LOCAL_SHARED_LIBRARIES := libsqlite libselinux
LOCAL_C_INCLUDES := \
jni/include \
jni/external \
$(LIBSELINUX) \
$(LIBSEPOL)
$(LIBSELINUX)
LOCAL_SRC_FILES := \
daemon/magisk.c \
......@@ -41,10 +41,6 @@ LOCAL_SRC_FILES := \
magiskhide/magiskhide.c \
magiskhide/proc_monitor.c \
magiskhide/hide_utils.c \
magiskpolicy/magiskpolicy.c \
magiskpolicy/rules.c \
magiskpolicy/sepolicy.c \
magiskpolicy/api.c \
resetprop/resetprop.cpp \
resetprop/system_properties.cpp \
su/su.c \
......@@ -59,6 +55,37 @@ LOCAL_CPPFLAGS := -std=c++11
LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)
# magiskinit
include $(CLEAR_VARS)
LOCAL_MODULE := magiskinit
LOCAL_STATIC_LIBRARIES := libsepol
LOCAL_C_INCLUDES := jni/include $(LIBSEPOL)
LOCAL_SRC_FILES := \
init/magiskinit.c \
utils/vector.c \
utils/file.c \
utils/xwrap.c \
magiskpolicy/api.c \
magiskpolicy/magiskpolicy.c \
magiskpolicy/rules.c \
magiskpolicy/sepolicy.c
LOCAL_CFLAGS := -DNO_SELINUX
LOCAL_LDFLAGS := -static
include $(BUILD_EXECUTABLE)
# precompile
else
# monogisk
include $(CLEAR_VARS)
LOCAL_MODULE := monogisk
LOCAL_STATIC_LIBRARIES := liblzma
LOCAL_C_INCLUDES := jni/include out/$(TARGET_ARCH_ABI) $(LIBLZMA)
LOCAL_SRC_FILES := init/monogisk.c
LOCAL_LDFLAGS := -static
include $(BUILD_EXECUTABLE)
# magiskboot
include $(CLEAR_VARS)
LOCAL_MODULE := magiskboot
......@@ -81,28 +108,12 @@ LOCAL_SRC_FILES := \
magiskboot/types.c \
magiskboot/dtb.c \
utils/xwrap.c \
utils/file.c \
utils/vector.c
LOCAL_LDLIBS := -lz
include $(BUILD_EXECUTABLE)
# magiskinit
ifeq ($(TARGET_ARCH_ABI), arm64-v8a)
include $(CLEAR_VARS)
LOCAL_MODULE := magiskinit
LOCAL_STATIC_LIBRARIES := libsepol
LOCAL_C_INCLUDES := jni/include $(LIBSEPOL)
LOCAL_SRC_FILES := \
magiskinit.c \
magiskboot/boot_utils.c \
utils/file.c \
utils/xwrap.c \
magiskpolicy/rules.c \
magiskpolicy/sepolicy.c \
magiskpolicy/api.c
LOCAL_CFLAGS := -DNO_SELINUX
LOCAL_LDFLAGS := -static
LOCAL_LDLIBS := -lz
include $(BUILD_EXECUTABLE)
endif
# 32-bit static binaries
ifneq ($(TARGET_ARCH_ABI), x86_64)
......@@ -120,6 +131,9 @@ include jni/external/busybox/Android.mk
endif
endif
# Precompile
endif
########################
# Externals
########################
......
......@@ -568,7 +568,7 @@ void fix_filecon() {
****************/
static void unblock_boot_process() {
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT));
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0));
pthread_exit(NULL);
}
......@@ -743,7 +743,8 @@ void late_start(int client) {
if (buf2 == NULL) buf2 = xmalloc(PATH_MAX);
// Wait till the full patch is done
pthread_join(sepol_patch, NULL);
while (access(PATCHDONE, F_OK) == -1)
usleep(500); /* Wait 0.5ms */
// Run scripts after full patch, most reliable way to run scripts
LOGI("* Running service.d scripts\n");
......
......@@ -103,16 +103,6 @@ static int setup_socket(struct sockaddr_un *sun) {
return fd;
}
static void *large_sepol_patch(void *args) {
LOGD("sepol: Starting large patch thread\n");
// Patch su to everything
sepol_allow("su", ALL, ALL, ALL);
dump_policydb(SELINUX_LOAD);
LOGD("sepol: Large patch done\n");
destroy_policydb();
return NULL;
}
static void *start_magisk_hide(void *args) {
launch_magiskhide(-1);
return NULL;
......@@ -137,11 +127,6 @@ void start_daemon() {
xdup2(fd, STDERR_FILENO);
close(fd);
// Patch selinux with medium patch before we do anything
load_policydb(SELINUX_POLICY);
sepol_med_rules();
dump_policydb(SELINUX_LOAD);
struct sockaddr_un sun;
fd = setup_socket(&sun);
......@@ -159,9 +144,6 @@ void start_daemon() {
// Start the log monitor
monitor_logs();
// Continue the larger patch in another thread, we will join later
xpthread_create(&sepol_patch, NULL, large_sepol_patch, NULL);
LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") daemon started\n");
// Change process name
......
......@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <libgen.h>
#include "utils.h"
#include "magisk.h"
......@@ -12,10 +13,10 @@
char *argv0;
char *applet[] =
{ "su", "resetprop", "magiskpolicy", "supolicy", "magiskhide", NULL };
{ "su", "resetprop", "magiskhide", NULL };
int (*applet_main[]) (int, char *[]) =
{ su_client_main, resetprop_main, magiskpolicy_main, magiskpolicy_main, magiskhide_main, NULL };
{ su_client_main, resetprop_main, magiskhide_main, NULL };
int create_links(const char *bin, const char *path) {
char self[PATH_MAX], linkpath[PATH_MAX];
......@@ -56,7 +57,7 @@ static void usage() {
" --clone-attr SRC DEST clone permission, owner, and selinux context\n"
"\n"
"Supported init services:\n"
" daemon post-fs, post-fs-data, service\n"
" daemon, post-fs, post-fs-data, service\n"
"\n"
"Supported applets:\n"
, argv0, argv0);
......@@ -69,10 +70,7 @@ static void usage() {
int main(int argc, char *argv[]) {
argv0 = argv[0];
char * arg = strrchr(argv[0], '/');
if (arg) ++arg;
else arg = argv[0];
if (strcmp(arg, "magisk") == 0) {
if (strcmp(basename(argv[0]), "magisk") == 0) {
if (argc < 2) usage();
if (strcmp(argv[1], "-c") == 0) {
printf("%s\n", MAGISK_VER_STR);
......@@ -168,16 +166,15 @@ int main(int argc, char *argv[]) {
// It's calling applets
--argc;
++argv;
arg = argv[0];
}
}
// Applets
for (int i = 0; applet[i]; ++i) {
if (strcmp(arg, applet[i]) == 0)
if (strcmp(basename(argv[0]), applet[i]) == 0)
return (*applet_main[i])(argc, argv);
}
fprintf(stderr, "%s: applet not found\n", arg);
fprintf(stderr, "%s: applet not found\n", basename(argv[0]));
return 1;
}
......@@ -8,6 +8,9 @@
#include <errno.h>
#include <stdlib.h>
#define str(a) #a
#define xstr(a) str(a)
#ifdef IS_DAEMON
#include <pthread.h>
......
......@@ -6,9 +6,6 @@
#include "logging.h"
#define str(a) #a
#define xstr(a) str(a)
#define MAGISK_VER_STR xstr(MAGISK_VERSION) ":MAGISK"
#define REQUESTOR_DAEMON_PATH "\0MAGISK"
......@@ -20,6 +17,7 @@
#define LASTLOG "/cache/last_magisk.log"
#define DEBUG_LOG "/data/magisk_debug.log"
#define UNBLOCKFILE "/dev/.magisk.unblock"
#define PATCHDONE "/dev/.magisk.patch.done"
#define DISABLEFILE "/cache/.disable_magisk"
#define UNINSTALLER "/cache/magisk_uninstaller.sh"
#define CACHEMOUNT "/cache/magisk_mount"
......
const char magiskrc[] =
// Triggers
"on post-fs\n"
" start logd\n"
" start magisk_daemon\n"
" wait /dev/.magisk.unblock 5\n"
" rm /dev/.magisk.unblock\n"
" start magisk_pfs\n"
" wait /dev/.magisk.unblock 10\n"
"\n"
"on post-fs-data\n"
" load_persist_props\n"
" rm /dev/.magisk.unblock\n"
" start magisk_pfsd\n"
" wait /dev/.magisk.unblock 10\n"
"\n"
// Services
"service magisk_daemon /sbin/magisk --daemon\n"
" user root\n"
" seclabel u:r:su:s0\n"
"\n"
"service magisk_pfs /sbin/magisk --post-fs\n"
" user root\n"
" seclabel u:r:su:s0\n"
" oneshot\n"
"\n"
"service magisk_pfsd /sbin/magisk --post-fs-data\n"
" user root\n"
" seclabel u:r:su:s0\n"
" oneshot\n"
"\n"
"service magisk_service /sbin/magisk --service\n"
" class late_start\n"
" user root\n"
" seclabel u:r:su:s0\n"
" oneshot\n"
;
......@@ -116,6 +116,8 @@ int fsetattr(int fd, struct file_attr *a);
void fclone_attr(const int sourcefd, const int targetfd);
void clone_attr(const char *source, const char *target);
void restorecon(int dirfd, int force);
void mmap_ro(const char *filename, void **buf, size_t *size);
void mmap_rw(const char *filename, void **buf, size_t *size);
// img.c
......
/* magiskinit.c - Workaround for skip_initramfs devices
/* magiskinit.c - Pre-init Magisk support
*
* This code has to be compiled statically to work properly.
*
* Magiskinit will mount sysfs, parse through uevent files to make the system block device,
* then it'll mount the system partition and clone rootfs except files under /system.
* Folders placed in "overlay" will then be overlayed to the root.
* Lastly, before giving control back to the real init, it'll patch the root files,
* extract (or compile if needed) sepolicy and patch it to load Magisk.
* This binary will be extracted from monogisk, and dos all pre-init operations to setup
* a Magisk environment. The tool modifies rootfs on the fly, providing fundamental support
* such as init, init.rc, and sepolicy patching. Magiskinit is also responsible to construct
* a proper rootfs on skip_initramfs devices.
* On skip_initramfs devices, it will parse kernel cmdline, mount sysfs, parse through
* uevent files to make the system (or vendor if available) block device node, then copy
* rootfs files from system. The "overlay" folder is constructed by monogisk,
* which contains additional files extracted from the tool. These files will be moved to /.
* This tool will be replaced with the real init to continue the boot process, but hardlinks are
* preserved as it also provides CLI for sepolicy patching (magiskpolicy)
*/
......@@ -16,6 +21,7 @@
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <libgen.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
......@@ -25,6 +31,7 @@
#include <cil/cil.h>
#include "magisk.h"
#include "utils.h"
#include "magiskpolicy.h"
......@@ -43,10 +50,6 @@ struct device {
extern policydb_t *policydb;
extern void mmap_ro(const char *filename, void **buf, size_t *size);
extern void mmap_rw(const char *filename, void **buf, size_t *size);
extern void *patch_init_rc(char *data, uint32_t *size);
static void parse_cmdline(struct cmdline *cmd) {
char *tok;
char buffer[4096];
......@@ -120,6 +123,34 @@ static int setup_block(struct device *dev, const char *partname) {
return 0;
}
static void *patch_init_rc(char *data, uint32_t *size) {
int injected = 0;
char *new_data = malloc(*size + 23);
char *old_data = data;
uint32_t pos = 0;
for (char *tok = strsep(&old_data, "\n"); tok; tok = strsep(&old_data, "\n")) {
if (!injected && strncmp(tok, "import", 6) == 0) {
if (strstr(tok, "init.magisk.rc")) {
injected = 1;
} else {
strcpy(new_data + pos, "import /init.magisk.rc\n");
pos += 23;
injected = 1;
}
} else if (strstr(tok, "selinux.reload_policy")) {
continue;
}
// Copy the line
strcpy(new_data + pos, tok);
pos += strlen(tok);
new_data[pos++] = '\n';
}
*size = pos;
return new_data;
}
static void patch_ramdisk() {
void *addr;
size_t size;
......@@ -131,10 +162,12 @@ static void patch_ramdisk() {
}
}
munmap(addr, size);
mmap_rw("/init.rc", &addr, &size);
uint32_t new_size = size;
void *init_rc = patch_init_rc(addr, &new_size);
munmap(addr, size);
int fd = open("/init.rc", O_WRONLY | O_TRUNC | O_CLOEXEC);
write(fd, init_rc, new_size);
close(fd);
......@@ -147,51 +180,11 @@ static int strend(const char *s1, const char *s2) {
return strcmp(s1 + l1 - l2, s2);
}
static void patch_sepolicy() {
static int compile_cil() {
DIR *dir;
struct dirent *entry;
char *sepolicy = NULL, path[128];
if (access("/system_root/sepolicy", R_OK) == 0)
sepolicy = "/system_root/sepolicy";
if (sepolicy == NULL && access("/vendor/etc/selinux/precompiled_sepolicy", R_OK) == 0) {
void *sys_sha = NULL, *ven_sha = NULL;
size_t sys_size = 0, ven_size = 0;
if ((dir = opendir("/vendor/etc/selinux")) == NULL)
goto check_done;
while ((entry = readdir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if (strend(entry->d_name, ".sha256") == 0) {
snprintf(path, sizeof(path), "/vendor/etc/selinux/%s", entry->d_name);
mmap_ro(path, &ven_sha, &ven_size);
break;
}
}
closedir(dir);
if ((dir = opendir("/system/etc/selinux")) == NULL)
goto check_done;
while ((entry = readdir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if (strend(entry->d_name, ".sha256") == 0) {
snprintf(path, sizeof(path), "/system/etc/selinux/%s", entry->d_name);
mmap_ro(path, &sys_sha, &sys_size);
break;
}
}
closedir(dir);
if (sys_size == ven_size && memcmp(sys_sha, ven_sha, sys_size) == 0)
sepolicy = "/vendor/etc/selinux/precompiled_sepolicy";
munmap(sys_sha, sys_size);
munmap(ven_sha, ven_size);
}
check_done:
char path[128];
if (sepolicy) {
load_policydb(sepolicy);
} else {
// Compile cil
struct cil_db *db = NULL;
sepol_policydb_t *pdb = NULL;
void *addr;
......@@ -203,22 +196,22 @@ check_done:
cil_set_policy_version(db, POLICYDB_VERSION_XPERMS_IOCTL);
cil_set_attrs_expand_generated(db, 0);
// plat
mmap_ro("/system/etc/selinux/plat_sepolicy.cil", &addr, &size);
cil_add_file(db, "/system/etc/selinux/plat_sepolicy.cil", addr, size);
munmap(addr, size);
dir = opendir("/system/etc/selinux/mapping");
while ((entry = readdir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if (strend(entry->d_name, ".cil") == 0) {
snprintf(path, sizeof(path), "/system/etc/selinux/mapping/%s", entry->d_name);
// mapping
char plat[10];
int fd = open("/vendor/etc/selinux/plat_sepolicy_vers.txt", O_RDONLY | O_CLOEXEC);
if (fd > 0) {
plat[read(fd, plat, sizeof(plat)) - 1] = '\0';
snprintf(path, sizeof(path), "/system/etc/selinux/mapping/%s.cil", plat);
mmap_ro(path, &addr, &size);
cil_add_file(db, path, addr, size);
munmap(addr, size);
close(fd);
}
}
closedir(dir);
dir = opendir("/vendor/etc/selinux");
while ((entry = readdir(dir))) {
......@@ -238,27 +231,74 @@ check_done:
cil_db_destroy(&db);
policydb = &pdb->p;
return 0;
}
static int verify_precompiled() {
DIR *dir;
struct dirent *entry;
int fd;
char sys_sha[70], ven_sha[70];
dir = opendir("/vendor/etc/selinux");
while ((entry = readdir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if (strend(entry->d_name, ".sha256") == 0) {
fd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_CLOEXEC);
ven_sha[read(fd, ven_sha, sizeof(ven_sha))] = '\0';
close(fd);
break;
}
}
closedir(dir);
dir = opendir("/system/etc/selinux");
while ((entry = readdir(dir))) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
if (strend(entry->d_name, ".sha256") == 0) {
fd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_CLOEXEC);
sys_sha[read(fd, sys_sha, sizeof(sys_sha))] = '\0';
close(fd);
break;
}
}
closedir(dir);
return strcmp(sys_sha, ven_sha);
}
static void patch_sepolicy() {
if (access("/sepolicy", R_OK) == 0) {
load_policydb("/sepolicy");
} else if (access("/vendor/etc/selinux/precompiled_sepolicy", R_OK) == 0
&& verify_precompiled() == 0) {
load_policydb("/vendor/etc/selinux/precompiled_sepolicy");
} else if (access("/system/etc/selinux/plat_sepolicy.cil", R_OK) == 0) {
compile_cil();
}
// Magisk patches
sepol_min_rules();
sepol_med_rules();
dump_policydb("/sepolicy");
destroy_policydb();
}
int main(int argc, char *argv[]) {
if (strcmp(basename(argv[0]), "magiskpolicy") == 0 || strcmp(basename(argv[0]), "supolicy") == 0)
return magiskpolicy_main(argc, argv);
if (argc > 1 && (strcmp(argv[1], "magiskpolicy") == 0 || strcmp(argv[1], "supolicy") == 0))
return magiskpolicy_main(argc - 1, argv + 1);
umask(0);
struct cmdline cmd;
parse_cmdline(&cmd);
if (cmd.skip_initramfs) {
// Normal boot mode
// Clear rootfs
int root = open("/", O_RDONLY | O_CLOEXEC);
if (cmd.skip_initramfs) {
// Exclude overlay folder
excl_list = (char *[]) { "overlay", NULL };
excl_list = (char *[]) { "overlay", ".backup", NULL };
// Clear rootfs
frm_rf(root);
mkdir("/sys", 0755);
......@@ -280,32 +320,45 @@ int main(int argc, char *argv[]) {
mkdir("/system", 0755);
mount("/system_root/system", "/system", NULL, MS_BIND, NULL);
int overlay = open("/overlay", O_RDONLY | O_CLOEXEC);
if (overlay > 0)
mv_dir(overlay, root);
snprintf(partname, sizeof(partname), "vendor%s", cmd.slot);
// We need to mount independent vendor partition
if (setup_block(&dev, partname) == 0)
mount(dev.path, "/vendor", "ext4", MS_RDONLY, NULL);
patch_ramdisk();
patch_sepolicy();
close(root);
close(system_root);
close(overlay);
rmdir("/overlay");
umount("/vendor");
} else {
// Recovery mode
// Revert original init binary
unlink("/init");
rename("/.backup/init", "/init");
link("/.backup/init", "/init");
}
int overlay = open("/overlay", O_RDONLY | O_CLOEXEC);
mv_dir(overlay, root);
patch_ramdisk();
patch_sepolicy();
// Clean up
rmdir("/overlay");
umount("/vendor");
close(overlay);
close(root);
if (fork() == 0) {
// Fork a new process for full patch
setsid();
sepol_allow("su", ALL, ALL, ALL);
while (access(SELINUX_LOAD, W_OK) == -1) {
usleep(500); /* Wait 0.5ms */
}
dump_policydb(SELINUX_LOAD);
close(open(PATCHDONE, O_RDONLY | O_CREAT, 0));
destroy_policydb();
} else {
// Finally, give control back!
execv("/init", argv);
}
return 0;
}
/* monogisk.c - Monolithic binary hosting Magisk binaries
*
* This code has to be compiled statically to work properly.
*
* To unify Magisk support for both legacy "normal" devices and new skip_initramfs devices,
* this tool is born. Magisk binary compilation is split into two parts - first part contains
* "magisk" and "magiskinit". The python build script will load these 2 binaries and compress
* them with lzma2, dumping the results into "dump.h". Monogisk is simply just a static lzma
* extractor embedded with binary blobs, with a few additional operations to construct an
* environment for "magiskinit" to handle the rest of the work.
*/
#include <fcntl.h>
#include <unistd.h>
#include <lzma.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "dump.h"
#include "magiskrc.h"
#define str(a) #a
#define xstr(a) str(a)
#define BUFSIZE 0x100000
lzma_stream strm = LZMA_STREAM_INIT;
static void usage() {
const char usage[] =
"Monogisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu)\n"
"A monolithic binary used as /init to add Magisk support\n"
"\n"
"Usage:\n"
" monogisk -x <binary> <out>\n"
" extract \"magisk\", \"magiskinit\", or \"magiskrc\"\n"
" /init\n"
" Startup the system with Magisk support\n"
"\n";
write(STDERR_FILENO, usage, sizeof(usage));
exit(1);
}
static int unxz(lzma_stream *strm, const void *buf, size_t size, int fd) {
lzma_ret ret = 0;
uint8_t out[BUFSIZE];
strm->next_in = buf;
strm->avail_in = size;
do {
strm->next_out = out;
strm->avail_out = sizeof(out);
ret = lzma_code(strm, LZMA_RUN);
write(fd, out, sizeof(out) - strm->avail_out);
} while (strm->avail_out == 0 && ret == LZMA_OK);
if (ret != LZMA_OK && ret != LZMA_STREAM_END)
write(STDERR_FILENO, "LZMA error!\n", 13);
return ret;
}
static int dump_magisk(const char *path, mode_t mode) {
if (lzma_auto_decoder(&strm, UINT64_MAX, 0) != LZMA_OK)
return 1;
unlink(path);
int fd = creat(path, mode);
int ret = unxz(&strm, magisk_dump, sizeof(magisk_dump), fd);
close(fd);
return ret;
}
static int dump_magiskinit(const char *path, mode_t mode) {
if (lzma_auto_decoder(&strm, UINT64_MAX, 0) != LZMA_OK)
return 1;
unlink(path);
int fd = creat(path, mode);
int ret = unxz(&strm, magiskinit_dump, sizeof(magiskinit_dump), fd);
close(fd);
return ret;
}
static int dump_magiskrc(const char *path, mode_t mode) {
unlink(path);
int fd = creat(path, mode);
write(fd, magiskrc, sizeof(magiskrc));
close(fd);
return 0;
}
static int init_main(int argc, char *argv[]) {
dump_magiskinit("/init", 0750);
mkdir("/overlay", 0);
dump_magiskrc("/overlay/init.magisk.rc", 0750);
mkdir("/overlay/sbin", 0755);
dump_magisk("/overlay/sbin/magisk", 0755);
mkdir("/overlay/root", 0755);
link("/init", "/overlay/root/magiskpolicy");
link("/init", "/overlay/root/supolicy");
execv("/init", argv);
return 1; /* Should not happen */
}
int main(int argc, char *argv[]) {
umask(0);
if (argc == 1)
return init_main(argc, argv);
if (argc < 4)
usage();
if (strcmp(argv[2], "magisk") == 0)
dump_magisk(argv[3], 0755);
else if (strcmp(argv[2], "magiskinit") == 0)
dump_magiskinit(argv[3], 0755);
else
usage();
lzma_end(&strm);
return 0;
}
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include "utils.h"
void mmap_ro(const char *filename, void **buf, size_t *size) {
int fd = xopen(filename, O_RDONLY);
*size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
*buf = *size > 0 ? xmmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0) : NULL;
close(fd);
}
void mmap_rw(const char *filename, void **buf, size_t *size) {
int fd = xopen(filename, O_RDWR);
*size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
*buf = *size > 0 ? xmmap(NULL, *size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0) : NULL;
close(fd);
}
void write_zero(int fd, size_t size) {
size_t pos = lseek(fd, 0, SEEK_CUR);
ftruncate(fd, pos + size);
......@@ -51,35 +34,6 @@ int open_new(const char *filename) {
return xopen(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
}
void *patch_init_rc(char *data, uint32_t *size) {
int injected = 0;
char *new_data = xmalloc(*size + 23);
char *old_data = data;
uint32_t pos = 0;
for (char *tok = strsep(&old_data, "\n"); tok; tok = strsep(&old_data, "\n")) {
if (!injected && strncmp(tok, "import", 6) == 0) {
if (strstr(tok, "init.magisk.rc")) {
injected = 1;
} else {
fprintf(stderr, "Inject [import /init.magisk.rc] to [init.rc]\n");
strcpy(new_data + pos, "import /init.magisk.rc\n");
pos += 23;
injected = 1;
}
} else if (strstr(tok, "selinux.reload_policy")) {
continue;
}
// Copy the line
strcpy(new_data + pos, tok);
pos += strlen(tok);
new_data[pos++] = '\n';
}
*size = pos;
return new_data;
}
int check_verity_pattern(const char *s) {
int pos = 0;
if (s[0] == ',') ++pos;
......
......@@ -186,7 +186,7 @@ static void cpio_test(struct vector *v) {
int ret = STOCK_BOOT;
cpio_entry *f;
const char *OTHER_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", "boot/sbin/launch_daemonsu.sh", NULL };
const char *MAGISK_LIST[] = { "init.magisk.rc", "overlay/init.magisk.rc", NULL };
const char *MAGISK_LIST[] = { ".backup/.magisk", "init.magisk.rc", "overlay/init.magisk.rc", NULL };
vec_for_each(v, f) {
for (int i = 0; OTHER_LIST[i]; ++i) {
if (strcmp(f->filename, OTHER_LIST[i]) == 0) {
......@@ -208,11 +208,6 @@ static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) {
cpio_entry *f;
int skip, write;
vec_for_each(v, f) {
if (strcmp(f->filename, "init.rc") == 0) {
void *new_data = patch_init_rc(f->data, &f->filesize);
free(f->data);
f->data = new_data;
} else {
if (!keepverity) {
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
write = 0;
......@@ -246,7 +241,6 @@ static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) {
}
}
}
}
}
static void cpio_extract(const char *entry, const char *filename, struct vector *v) {
......@@ -265,19 +259,35 @@ static void cpio_extract(const char *entry, const char *filename, struct vector
LOGE("Cannot find the file entry [%s]\n", entry);
}
static void cpio_backup(const char *orig, struct vector *v) {
static void cpio_backup(const char *orig, const char *sha1, struct vector *v) {
struct vector o_body, *o = &o_body, bak;
cpio_entry *m, *n, *dir, *rem;
cpio_entry *m, *n, *rem, *cksm;
char buf[PATH_MAX];
int res, doBak;
dir = xcalloc(sizeof(*dir), 1);
rem = xcalloc(sizeof(*rem), 1);
if (sha1) cksm = xcalloc(sizeof(*cksm), 1);
vec_init(o);
vec_init(&bak);
// First push back the directory and the rmlist
vec_push_back(&bak, dir);
m = xcalloc(sizeof(*m), 1);
m->filename = strdup(".backup");
m->namesize = strlen(m->filename) + 1;
m->mode = S_IFDIR;
vec_push_back(&bak, m);
m = xcalloc(sizeof(*m), 1);
m->filename = strdup(".backup/.magisk");
m->namesize = strlen(m->filename) + 1;
m->mode = S_IFREG;
vec_push_back(&bak, m);
rem = xcalloc(sizeof(*rem), 1);
rem->filename = strdup(".backup/.rmlist");
rem->namesize = strlen(rem->filename) + 1;
rem->mode = S_IFREG;
vec_push_back(&bak, rem);
if (sha1) vec_push_back(&bak, cksm);
parse_cpio(orig, o);
// Remove possible backups in original ramdisk
cpio_rm(1, ".backup", o);
......@@ -287,13 +297,14 @@ static void cpio_backup(const char *orig, struct vector *v) {
vec_sort(v, cpio_cmp);
vec_sort(o, cpio_cmp);
// Init the directory and rmlist
dir->filename = strdup(".backup");
dir->namesize = strlen(dir->filename) + 1;
dir->mode = S_IFDIR;
rem->filename = strdup(".backup/.rmlist");
rem->namesize = strlen(rem->filename) + 1;
rem->mode = S_IFREG;
if (sha1) {
fprintf(stderr, "Save SHA1: [%s] -> [.backup/.sha1]\n", sha1);
cksm->filename = strdup(".backup/.sha1");
cksm->namesize = strlen(cksm->filename) + 1;
cksm->mode = S_IFREG;
cksm->data = strdup(sha1);
cksm->filesize = strlen(sha1) + 1;
}
// Start comparing
size_t i = 0, j = 0;
......@@ -349,12 +360,8 @@ static void cpio_backup(const char *orig, struct vector *v) {
vec_push_back(v, m);
}
// Don't include if empty
if (rem->filesize == 0) {
if (rem->filesize == 0)
rem->remove = 1;
if (bak.size == 2)
dir->remove = 1;
}
// Cleanup
cpio_vec_destroy(o);
......@@ -367,12 +374,14 @@ static int cpio_restore(struct vector *v) {
if (strstr(f->filename, ".backup") != NULL) {
ret = 0;
f->remove = 1;
if (strcmp(f->filename, ".backup") == 0) continue;
if (f->filename[7] == '\0') continue;
if (f->filename[8] == '.') {
if (strcmp(f->filename, ".backup/.rmlist") == 0) {
for (int pos = 0; pos < f->filesize; pos += strlen(f->data + pos) + 1)
cpio_rm(0, f->data + pos, v);
continue;
}
continue;
} else {
n = xcalloc(sizeof(*n), 1);
memcpy(n, f, sizeof(*f));
n->namesize -= 8;
......@@ -380,10 +389,11 @@ static int cpio_restore(struct vector *v) {
n->data = f->data;
f->data = NULL;
n->remove = 0;
fprintf(stderr, "Restoring [%s] -> [%s]\n", f->filename, n->filename);
fprintf(stderr, "Restore [%s] -> [%s]\n", f->filename, n->filename);
cpio_vec_insert(v, n);
}
}
}
// Some known stuff we can remove
cpio_rm(0, "sbin/magic_mask.sh", v);
cpio_rm(0, "init.magisk.rc", v);
......@@ -406,6 +416,8 @@ static void cpio_stocksha1(struct vector *v) {
return;
}
}
} else if (strcmp(f->filename, ".backup/.sha1") == 0) {
printf("%s\n", f->data);
}
}
}
......@@ -443,7 +455,7 @@ int cpio_commands(const char *command, int argc, char *argv[]) {
cmd = RESTORE;
} else if (strcmp(command, "stocksha1") == 0) {
cmd = STOCKSHA1;
} else if (argc == 1 && strcmp(command, "backup") == 0) {
} else if (argc >= 1 && strcmp(command, "backup") == 0) {
cmd = BACKUP;
} else if (argc > 0 && strcmp(command, "rm") == 0) {
cmd = RM;
......@@ -479,7 +491,7 @@ int cpio_commands(const char *command, int argc, char *argv[]) {
cpio_stocksha1(&v);
return 0;
case BACKUP:
cpio_backup(argv[0], &v);
cpio_backup(argv[0], argc > 1 ? argv[1] : NULL, &v);
case RM:
cpio_rm(recursive, argv[0], &v);
break;
......
......@@ -3,6 +3,7 @@
#include <sys/types.h>
#include "logging.h"
#include "bootimg.h"
#define KERNEL_FILE "kernel"
......@@ -12,9 +13,6 @@
#define DTB_FILE "dtb"
#define NEW_BOOT "new-boot.img"
#define str(a) #a
#define xstr(a) str(a)
// Main entries
void unpack(const char *image);
void repack(const char* orig_image, const char* out_image);
......@@ -36,13 +34,10 @@ long long comp(file_t type, int to, const void *from, size_t size);
long long decomp(file_t type, int to, const void *from, size_t size);
// Utils
extern void mmap_ro(const char *filename, void **buf, size_t *size);
extern void mmap_rw(const char *filename, void **buf, size_t *size);
extern void write_zero(int fd, size_t size);
extern void mem_align(size_t *pos, size_t align);
extern void file_align(int fd, size_t align, int out);
extern int open_new(const char *filename);
extern void *patch_init_rc(char *data, uint32_t *size);
extern int check_verity_pattern(const char *s);
extern int check_encryption_pattern(const char *s);
......
......@@ -5,6 +5,7 @@
#include <sys/mman.h>
#include "magiskboot.h"
#include "utils.h"
#include "sha1.h"
/********************
......@@ -47,8 +48,9 @@ static void usage(char *arg0) {
" Return value: 0/stock 1/Magisk 2/other (e.g. phh, SuperSU)\n"
" -patch <KEEPVERITY> <KEEPFORCEENCRYPT>\n"
" Patch cpio for Magisk. KEEP**** are true/false values\n"
" -backup <origcpio>\n"
" -backup <origcpio> [SHA1]\n"
" Create ramdisk backups into <incpio> from <origcpio>\n"
" SHA1 of stock boot image is optional\n"
" -restore\n"
" Restore ramdisk from ramdisk backup within <incpio>\n"
" -stocksha1\n"
......
Subproject commit 3c6a170138cacb1f817c65181bd6e3ef15cfca9e
Subproject commit 9e96824161ddf1d6af516f44cad4d0e904a7abed
......@@ -5,6 +5,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/sendfile.h>
#include <sys/mman.h>
#ifndef NO_SELINUX
#include <selinux/selinux.h>
......@@ -52,6 +53,8 @@ int mkdir_p(const char *pathname, mode_t mode) {
void rm_rf(const char *path) {
int fd = xopen(path, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return;
frm_rf(fd);
close(fd);
rmdir(path);
......@@ -294,6 +297,22 @@ void fclone_attr(const int sourcefd, const int targetfd) {
fsetattr(targetfd, &a);
}
void mmap_ro(const char *filename, void **buf, size_t *size) {
int fd = xopen(filename, O_RDONLY);
*size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
*buf = *size > 0 ? xmmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0) : NULL;
close(fd);
}
void mmap_rw(const char *filename, void **buf, size_t *size) {
int fd = xopen(filename, O_RDWR);
*size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
*buf = *size > 0 ? xmmap(NULL, *size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0) : NULL;
close(fd);
}
#ifndef NO_SELINUX
#define UNLABEL_CON "u:object_r:unlabeled:s0"
......
......@@ -11,18 +11,15 @@
# boot_patch.sh script A script to patch boot. Expect path to boot image as parameter.
# (this file) The script will use binaries and files in its same directory
# to complete the patching process
# magisk binary The main binary for all Magisk operations.
# It is also used to patch the sepolicy in the ramdisk.
# monogisk binary The monolithic binary to replace /init
# magiskboot binary A tool to unpack boot image, decompress ramdisk, extract ramdisk
# , and patch the ramdisk for Magisk support
# init.magisk.rc script A new line will be added to init.rc to import this script.
# All magisk entrypoints are defined here
# chromeos folder This folder should store all the utilities and keys to sign
# (optional) a chromeos device, used in the tablet Pixel C
#
# If the script is not running as root, then the input boot image should be a stock image
# or have a backup included in ramdisk internally, since we cannot access the stock boot
# image placed under /data we've created when previously installing
# image placed under /data we've created when previously installed
#
##########################################################################################
##########################################################################################
......@@ -47,21 +44,6 @@ basename_wrap() {
echo ${1##*/}
}
# --cpio-add <incpio> <mode> <entry> <infile>
cpio_add() {
./magiskboot --cpio-add ramdisk.cpio $1 $2 $3
}
# --cpio-extract <incpio> <entry> <outfile>
cpio_extract() {
./magiskboot --cpio-extract ramdisk.cpio $1 $2
}
# --cpio-mkdir <incpio> <mode> <entry>
cpio_mkdir() {
./magiskboot --cpio-mkdir ramdisk.cpio $1 $2
}
##########################################################################################
# Initialization
##########################################################################################
......@@ -85,6 +67,9 @@ BOOTIMAGE="$1"
chmod -R 755 .
# Extract magisk if doesn't exist
[ -e magisk ] || ./monogisk -x magisk magisk
##########################################################################################
# Unpack
##########################################################################################
......@@ -172,33 +157,11 @@ esac
ui_print "- Patching ramdisk"
if [ ! -z $SHA1 ]; then
cp init.magisk.rc init.magisk.rc.bak
echo "# STOCKSHA1=$SHA1" >> init.magisk.rc
fi
if $SKIP_INITRAMFS; then
cpio_add 750 init magiskinit
cpio_mkdir 000 overlay
cpio_add 750 overlay/init.magisk.rc init.magisk.rc
cpio_mkdir 750 overlay/sbin
cpio_add 755 overlay/sbin/magisk magisk
else
./magiskboot --cpio-patch ramdisk.cpio $KEEPVERITY $KEEPFORCEENCRYPT
cpio_extract sepolicy sepolicy
./magisk magiskpolicy --load sepolicy --save sepolicy --minimal
cpio_add 644 sepolicy sepolicy
rm -f sepolicy
cpio_add 750 init.magisk.rc init.magisk.rc
cpio_add 755 sbin/magisk magisk
fi
mv init.magisk.rc.bak init.magisk.rc 2>/dev/null
./magiskboot --cpio-add ramdisk.cpio 750 init monogisk
./magiskboot --cpio-patch ramdisk.cpio $KEEPVERITY $KEEPFORCEENCRYPT
# Create ramdisk backups
./magiskboot --cpio-backup ramdisk.cpio ramdisk.cpio.orig
./magiskboot --cpio-backup ramdisk.cpio ramdisk.cpio.orig $SHA1
if ! $KEEPVERITY && [ -f dtb ]; then
./magiskboot --dtb-patch dtb && ui_print "- Patching fstab in dtb to remove dm-verity"
......@@ -218,7 +181,7 @@ rm -f ramdisk.cpio.orig
A1020054011440B93FA00F7140020054010840B93FA00F71E0010054001840B91FA00F7181010054
# skip_initramfs -> want_initramfs
$SKIP_INITRAMFS && ./magiskboot --hexpatch kernel \
./magiskboot --hexpatch kernel \
736B69705F696E697472616D6673 \
77616E745F696E697472616D6673
......
......@@ -79,18 +79,12 @@ ui_print "- Constructing environment"
is_mounted /data && MAGISKBIN=/data/magisk || MAGISKBIN=/cache/data_bin
if $BOOTMODE; then
# Cleanup binary mirrors
umount -l /dev/magisk/mirror/bin 2>/dev/null
rm -rf /dev/magisk/mirror/bin 2>/dev/null
fi
# Save our stock boot image dump before removing it
mv /data/magisk/stock_boot* /data 2>/dev/null
# Copy required files
rm -rf $MAGISKBIN 2>/dev/null
mkdir -p $MAGISKBIN
rm -rf $MAGISKBIN/* 2>/dev/null
mkdir -p $MAGISKBIN 2>/dev/null
cp -af $BINDIR/. $COMMONDIR/. $CHROMEDIR $TMPDIR/bin/busybox $MAGISKBIN
chmod -R 755 $MAGISKBIN
......
# Triggers
on post-fs
start logd
start magisk_daemon
wait /dev/.magisk.unblock 5
rm /dev/.magisk.unblock
start magisk_pfs
wait /dev/.magisk.unblock 10
on post-fs-data
load_persist_props
rm /dev/.magisk.unblock
start magisk_pfsd
wait /dev/.magisk.unblock 10
# Services
# Self recoverable service
service magisk_daemon /sbin/magisk --daemon
user root
seclabel u:r:su:s0
# launch post-fs script
service magisk_pfs /sbin/magisk --post-fs
user root
seclabel u:r:su:s0
oneshot
# launch post-fs-data script
service magisk_pfsd /sbin/magisk --post-fs-data
user root
seclabel u:r:su:s0
oneshot
# launch late_start script
service magisk_service /sbin/magisk --service
class late_start
user root
seclabel u:r:su:s0
oneshot
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment