mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-25 03:37:30 +00:00
Rename module core to native
This commit is contained in:
3
native/.gitignore
vendored
Normal file
3
native/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/build
|
||||
obj
|
||||
libs
|
20
native/build.gradle
Normal file
20
native/build.gradle
Normal file
@@ -0,0 +1,20 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path 'jni/Android.mk'
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
// Passes an optional argument to ndk-build.
|
||||
arguments "GRADLE=true"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
138
native/jni/Android.mk
Normal file
138
native/jni/Android.mk
Normal file
@@ -0,0 +1,138 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# Some handy paths
|
||||
EXT_PATH := jni/external
|
||||
SE_PATH := $(EXT_PATH)/selinux
|
||||
LIBSELINUX := $(SE_PATH)/libselinux/include
|
||||
LIBSEPOL := $(SE_PATH)/libsepol/include $(SE_PATH)/libsepol/cil/include
|
||||
LIBLZMA := $(EXT_PATH)/xz/src/liblzma/api
|
||||
LIBLZ4 := $(EXT_PATH)/lz4/lib
|
||||
LIBBZ2 := $(EXT_PATH)/bzip2
|
||||
LIBFDT := $(EXT_PATH)/dtc/libfdt
|
||||
UTIL_SRC := utils/cpio.c \
|
||||
utils/file.c \
|
||||
utils/img.c \
|
||||
utils/list.c \
|
||||
utils/misc.c \
|
||||
utils/pattern.c \
|
||||
utils/vector.c \
|
||||
utils/xwrap.c
|
||||
|
||||
########################
|
||||
# Binaries
|
||||
########################
|
||||
|
||||
ifneq "$(or $(PRECOMPILE), $(GRADLE))" ""
|
||||
|
||||
# magisk main binary
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magisk
|
||||
LOCAL_SHARED_LIBRARIES := libsqlite libselinux
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
jni/include \
|
||||
jni/external/include \
|
||||
$(LIBSELINUX)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
core/magisk.c \
|
||||
core/daemon.c \
|
||||
core/log_monitor.c \
|
||||
core/bootstages.c \
|
||||
core/socket.c \
|
||||
magiskhide/magiskhide.c \
|
||||
magiskhide/proc_monitor.c \
|
||||
magiskhide/hide_utils.c \
|
||||
resetprop/resetprop.cpp \
|
||||
resetprop/system_properties.cpp \
|
||||
su/su.c \
|
||||
su/activity.c \
|
||||
su/db.c \
|
||||
su/pts.c \
|
||||
su/su_daemon.c \
|
||||
su/su_socket.c \
|
||||
$(UTIL_SRC)
|
||||
|
||||
LOCAL_CFLAGS := -DIS_DAEMON -DSELINUX
|
||||
LOCAL_LDLIBS := -llog
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
endif
|
||||
|
||||
ifndef PRECOMPILE
|
||||
|
||||
# magiskinit
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magiskinit
|
||||
LOCAL_STATIC_LIBRARIES := libsepol liblzma
|
||||
LOCAL_C_INCLUDES := \
|
||||
jni/include \
|
||||
jni/magiskpolicy \
|
||||
../out/$(TARGET_ARCH_ABI) \
|
||||
$(LIBSEPOL) \
|
||||
$(LIBLZMA)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
core/magiskinit.c \
|
||||
core/socket.c \
|
||||
magiskpolicy/api.c \
|
||||
magiskpolicy/magiskpolicy.c \
|
||||
magiskpolicy/rules.c \
|
||||
magiskpolicy/sepolicy.c \
|
||||
$(UTIL_SRC)
|
||||
|
||||
LOCAL_LDFLAGS := -static
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# magiskboot
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magiskboot
|
||||
LOCAL_STATIC_LIBRARIES := liblzma liblz4 libbz2 libfdt
|
||||
LOCAL_C_INCLUDES := \
|
||||
jni/include \
|
||||
jni/external/include \
|
||||
$(LIBLZMA) \
|
||||
$(LIBLZ4) \
|
||||
$(LIBBZ2) \
|
||||
$(LIBFDT)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
external/sha1/sha1.c \
|
||||
magiskboot/main.c \
|
||||
magiskboot/bootimg.c \
|
||||
magiskboot/hexpatch.c \
|
||||
magiskboot/compress.c \
|
||||
magiskboot/types.c \
|
||||
magiskboot/dtb.c \
|
||||
magiskboot/ramdisk.c \
|
||||
$(UTIL_SRC)
|
||||
|
||||
LOCAL_CFLAGS := -DXWRAP_EXIT
|
||||
LOCAL_LDLIBS := -lz
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# 32-bit static binaries
|
||||
ifndef GRADLE # Do not run gradle sync on these binaries
|
||||
ifneq ($(TARGET_ARCH_ABI), x86_64)
|
||||
ifneq ($(TARGET_ARCH_ABI), arm64-v8a)
|
||||
# b64xz
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := b64xz
|
||||
LOCAL_STATIC_LIBRARIES := liblzma
|
||||
LOCAL_C_INCLUDES := $(LIBLZMA)
|
||||
LOCAL_SRC_FILES := b64xz.c
|
||||
LOCAL_LDFLAGS := -static
|
||||
include $(BUILD_EXECUTABLE)
|
||||
# Busybox
|
||||
include jni/external/busybox/Android.mk
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# Precompile
|
||||
endif
|
||||
|
||||
########################
|
||||
# Externals
|
||||
########################
|
||||
include jni/external/Android.mk
|
4
native/jni/Application.mk
Normal file
4
native/jni/Application.mk
Normal file
@@ -0,0 +1,4 @@
|
||||
APP_ABI := x86 x86_64 armeabi-v7a arm64-v8a
|
||||
APP_PLATFORM := android-21
|
||||
APP_CFLAGS := $(MAGISK_FLAGS) -std=gnu99
|
||||
APP_CPPFLAGS := -std=c++11
|
83
native/jni/b64xz.c
Normal file
83
native/jni/b64xz.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/* b64xz.c - Base64-XZ Extractor
|
||||
*
|
||||
* This program expects data from stdin. The data should be compressed with xz and
|
||||
* then encoded into base64 format. What b64xz does is basically the reverse of the
|
||||
* mentioned process: decode base64 to uint8_ts, decompress xz, then dump to stdout
|
||||
*
|
||||
* The compiled binary will be hex-dumped into update-binary
|
||||
* Busybox will be xz-compressed, base64 encoded and dumped into update-binary
|
||||
* This program is to recover busybox for Magisk installation environment
|
||||
*
|
||||
* I intentionally removed stdio. This will result in a smaller binary size because
|
||||
* all I/O are handled by system calls (read/write) instead of libc wrappers
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <lzma.h>
|
||||
|
||||
#define BUFSIZE 8192
|
||||
|
||||
static const char trans_tbl[] =
|
||||
"|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
|
||||
|
||||
static void decodeblock(uint8_t* in, uint8_t* out) {
|
||||
out[0] = (uint8_t)(in[0] << 2 | in[1] >> 4);
|
||||
out[1] = (uint8_t)(in[1] << 4 | in[2] >> 2);
|
||||
out[2] = (uint8_t)(((in[2] << 6) & 0xc0) | in[3]);
|
||||
}
|
||||
|
||||
static int unxz(lzma_stream *strm, void *buf, size_t size) {
|
||||
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(STDOUT_FILENO, 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;
|
||||
}
|
||||
|
||||
int main(int argc, char const* argv[]) {
|
||||
if (argc > 1)
|
||||
return 0;
|
||||
|
||||
uint8_t in[4], buf[BUFSIZE];
|
||||
int len = 0, pos = 0;
|
||||
char c;
|
||||
|
||||
// Setup lzma stream
|
||||
lzma_stream strm = LZMA_STREAM_INIT;
|
||||
if (lzma_auto_decoder(&strm, UINT64_MAX, 0) != LZMA_OK) {
|
||||
write(STDERR_FILENO, "Unable to init lzma stream\n", 28);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (read(STDIN_FILENO, &c, sizeof(c)) == 1) {
|
||||
c = ((c < 43 || c > 122) ? -1 : (trans_tbl[c - 43] == '$' ? -1 : trans_tbl[c - 43] - 62));
|
||||
if (c >= 0)
|
||||
in[len++] = c;
|
||||
if (len < 4)
|
||||
continue;
|
||||
len = 0;
|
||||
decodeblock(in, buf + pos);
|
||||
pos += 3;
|
||||
if (pos > sizeof(buf) - 3) {
|
||||
// Buffer is full, unxz
|
||||
if (unxz(&strm, buf, pos))
|
||||
return 1;
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
if (pos) {
|
||||
if (unxz(&strm, buf, pos))
|
||||
return 1;
|
||||
}
|
||||
lzma_end(&strm);
|
||||
return 0;
|
||||
}
|
683
native/jni/core/bootstages.c
Normal file
683
native/jni/core/bootstages.c
Normal file
@@ -0,0 +1,683 @@
|
||||
/* bootstages.c - Core bootstage operations
|
||||
*
|
||||
* All bootstage operations, including simple mount in post-fs,
|
||||
* magisk mount in post-fs-data, various image handling, script
|
||||
* execution, load modules, install Magisk Manager etc.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/wait.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
#include "daemon.h"
|
||||
#include "resetprop.h"
|
||||
|
||||
static char *buf, *buf2;
|
||||
static struct vector module_list;
|
||||
|
||||
extern char **environ;
|
||||
|
||||
/******************
|
||||
* Node structure *
|
||||
******************/
|
||||
|
||||
// Precedence: MODULE > SKEL > INTER > DUMMY
|
||||
#define IS_DUMMY 0x01 /* mount from mirror */
|
||||
#define IS_INTER 0x02 /* intermediate node */
|
||||
#define IS_SKEL 0x04 /* mount from skeleton */
|
||||
#define IS_MODULE 0x08 /* mount from module */
|
||||
|
||||
#define IS_DIR(n) (n->type == DT_DIR)
|
||||
#define IS_LNK(n) (n->type == DT_LNK)
|
||||
#define IS_REG(n) (n->type == DT_REG)
|
||||
|
||||
struct node_entry {
|
||||
const char *module; /* Only used when status & IS_MODULE */
|
||||
char *name;
|
||||
uint8_t type;
|
||||
uint8_t status;
|
||||
struct node_entry *parent;
|
||||
struct vector *children;
|
||||
};
|
||||
|
||||
static void concat_path(struct node_entry *node) {
|
||||
if (node->parent)
|
||||
concat_path(node->parent);
|
||||
int len = strlen(buf);
|
||||
buf[len] = '/';
|
||||
strcpy(buf + len + 1, node->name);
|
||||
}
|
||||
|
||||
static char *get_full_path(struct node_entry *node) {
|
||||
buf[0] = '\0';
|
||||
concat_path(node);
|
||||
return strdup(buf);
|
||||
}
|
||||
|
||||
// Free the node
|
||||
static void destroy_node(struct node_entry *node) {
|
||||
free(node->name);
|
||||
vec_destroy(node->children);
|
||||
free(node->children);
|
||||
free(node);
|
||||
}
|
||||
|
||||
// Free the node and all children recursively
|
||||
static void destroy_subtree(struct node_entry *node) {
|
||||
// Never free parent, since it shall be freed by themselves
|
||||
struct node_entry *e;
|
||||
vec_for_each(node->children, e) {
|
||||
destroy_subtree(e);
|
||||
}
|
||||
destroy_node(node);
|
||||
}
|
||||
|
||||
// Return the child
|
||||
static struct node_entry *insert_child(struct node_entry *p, struct node_entry *c) {
|
||||
c->parent = p;
|
||||
if (p->children == NULL) {
|
||||
p->children = xmalloc(sizeof(struct vector));
|
||||
vec_init(p->children);
|
||||
}
|
||||
struct node_entry *e;
|
||||
vec_for_each(p->children, e) {
|
||||
if (strcmp(e->name, c->name) == 0) {
|
||||
// Exist duplicate
|
||||
if (c->status > e->status) {
|
||||
// Precedence is higher, replace with new node
|
||||
destroy_subtree(e);
|
||||
vec_cur(p->children) = c;
|
||||
return c;
|
||||
} else {
|
||||
// Free the new entry, return old
|
||||
destroy_node(c);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
// New entry, push back
|
||||
vec_push_back(p->children, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
/***********
|
||||
* setenvs *
|
||||
***********/
|
||||
|
||||
static void bb_setenv(struct vector *v) {
|
||||
for (int i = 0; environ[i]; ++i) {
|
||||
if (strncmp(environ[i], "PATH=", 5) == 0) {
|
||||
snprintf(buf, PATH_MAX, "PATH=%s:%s", BBPATH, strchr(environ[i], '=') + 1);
|
||||
vec_push_back(v, strdup(buf));
|
||||
} else {
|
||||
vec_push_back(v, strdup(environ[i]));
|
||||
}
|
||||
}
|
||||
vec_push_back(v, NULL);
|
||||
}
|
||||
|
||||
static void pm_setenv(struct vector *v) {
|
||||
for (int i = 0; environ[i]; ++i) {
|
||||
if (strncmp(environ[i], "CLASSPATH=", 10) != 0)
|
||||
vec_push_back(v, strdup(environ[i]));
|
||||
}
|
||||
vec_push_back(v, strdup("CLASSPATH=/system/framework/pm.jar"));
|
||||
vec_push_back(v, NULL);
|
||||
}
|
||||
|
||||
/***********
|
||||
* Scripts *
|
||||
***********/
|
||||
|
||||
static void exec_common_script(const char* stage) {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
snprintf(buf2, PATH_MAX, "%s/%s.d", COREDIR, stage);
|
||||
|
||||
if (!(dir = xopendir(buf2)))
|
||||
return;
|
||||
|
||||
while ((entry = xreaddir(dir))) {
|
||||
if (entry->d_type == DT_REG) {
|
||||
snprintf(buf2, PATH_MAX, "%s/%s.d/%s", COREDIR, stage, entry->d_name);
|
||||
if (access(buf2, X_OK) == -1)
|
||||
continue;
|
||||
LOGI("%s.d: exec [%s]\n", stage, entry->d_name);
|
||||
int pid = exec_command(0, NULL, bb_setenv, "sh", buf2, NULL);
|
||||
if (pid != -1)
|
||||
waitpid(pid, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static void exec_module_script(const char* stage) {
|
||||
char *module;
|
||||
vec_for_each(&module_list, module) {
|
||||
snprintf(buf2, PATH_MAX, "%s/%s/%s.sh", MOUNTPOINT, module, stage);
|
||||
snprintf(buf, PATH_MAX, "%s/%s/disable", MOUNTPOINT, module);
|
||||
if (access(buf2, F_OK) == -1 || access(buf, F_OK) == 0)
|
||||
continue;
|
||||
LOGI("%s: exec [%s.sh]\n", module, stage);
|
||||
int pid = exec_command(0, NULL, bb_setenv, "sh", buf2, NULL);
|
||||
if (pid != -1)
|
||||
waitpid(pid, NULL, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/***************
|
||||
* Magic Mount *
|
||||
***************/
|
||||
|
||||
static void construct_tree(const char *module, struct node_entry *parent) {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
struct node_entry *node;
|
||||
|
||||
char *parent_path = get_full_path(parent);
|
||||
snprintf(buf, PATH_MAX, "%s/%s%s", MOUNTPOINT, module, parent_path);
|
||||
|
||||
if (!(dir = xopendir(buf)))
|
||||
goto cleanup;
|
||||
|
||||
while ((entry = xreaddir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
// Create new node
|
||||
node = xcalloc(sizeof(*node), 1);
|
||||
node->module = module;
|
||||
node->name = strdup(entry->d_name);
|
||||
node->type = entry->d_type;
|
||||
snprintf(buf, PATH_MAX, "%s/%s", parent_path, node->name);
|
||||
|
||||
/*
|
||||
* Clone the parent in the following condition:
|
||||
* 1. File in module is a symlink
|
||||
* 2. Target file do not exist
|
||||
* 3. Target file is a symlink, but not /system/vendor
|
||||
*/
|
||||
int clone = 0;
|
||||
if (IS_LNK(node) || access(buf, F_OK) == -1) {
|
||||
clone = 1;
|
||||
} else if (parent->parent != NULL || strcmp(node->name, "vendor") != 0) {
|
||||
struct stat s;
|
||||
xstat(buf, &s);
|
||||
if (S_ISLNK(s.st_mode))
|
||||
clone = 1;
|
||||
}
|
||||
|
||||
if (clone) {
|
||||
// Mark the parent folder as a skeleton
|
||||
parent->status |= IS_SKEL; /* This will not overwrite if parent is module */
|
||||
node->status = IS_MODULE;
|
||||
} else if (IS_DIR(node)) {
|
||||
// Check if marked as replace
|
||||
snprintf(buf2, PATH_MAX, "%s/%s%s/.replace", MOUNTPOINT, module, buf);
|
||||
if (access(buf2, F_OK) == 0) {
|
||||
// Replace everything, mark as leaf
|
||||
node->status = IS_MODULE;
|
||||
} else {
|
||||
// This will be an intermediate node
|
||||
node->status = IS_INTER;
|
||||
}
|
||||
} else if (IS_REG(node)) {
|
||||
// This is a leaf, mark as target
|
||||
node->status = IS_MODULE;
|
||||
}
|
||||
node = insert_child(parent, node);
|
||||
if (node->status & (IS_SKEL | IS_INTER)) {
|
||||
// Intermediate folder, travel deeper
|
||||
construct_tree(module, node);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
cleanup:
|
||||
free(parent_path);
|
||||
}
|
||||
|
||||
static void clone_skeleton(struct node_entry *node) {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
struct node_entry *dummy, *child;
|
||||
|
||||
// Clone the structure
|
||||
char *full_path = get_full_path(node);
|
||||
snprintf(buf, PATH_MAX, "%s%s", MIRRDIR, full_path);
|
||||
if (!(dir = xopendir(buf)))
|
||||
goto cleanup;
|
||||
while ((entry = xreaddir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
// Create dummy node
|
||||
dummy = xcalloc(sizeof(*dummy), 1);
|
||||
dummy->name = strdup(entry->d_name);
|
||||
dummy->type = entry->d_type;
|
||||
dummy->status = IS_DUMMY;
|
||||
insert_child(node, dummy);
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
if (node->status & IS_SKEL) {
|
||||
struct stat s;
|
||||
char *con;
|
||||
xstat(full_path, &s);
|
||||
getfilecon(full_path, &con);
|
||||
LOGI("mnt_tmpfs : %s\n", full_path);
|
||||
xmount("tmpfs", full_path, "tmpfs", 0, NULL);
|
||||
chmod(full_path, s.st_mode & 0777);
|
||||
chown(full_path, s.st_uid, s.st_gid);
|
||||
setfilecon(full_path, con);
|
||||
free(con);
|
||||
}
|
||||
|
||||
vec_for_each(node->children, child) {
|
||||
snprintf(buf, PATH_MAX, "%s/%s", full_path, child->name);
|
||||
|
||||
// Create the dummy file/directory
|
||||
if (IS_DIR(child))
|
||||
xmkdir(buf, 0755);
|
||||
else if (IS_REG(child))
|
||||
close(creat(buf, 0644));
|
||||
// Links will be handled later
|
||||
|
||||
if (child->parent->parent == NULL && strcmp(child->name, "vendor") == 0) {
|
||||
if (IS_LNK(child)) {
|
||||
cp_afc(MIRRDIR "/system/vendor", "/system/vendor");
|
||||
LOGI("creat_link: %s <- %s\n", "/system/vendor", MIRRDIR "/system/vendor");
|
||||
}
|
||||
// Skip
|
||||
continue;
|
||||
} else if (child->status & IS_MODULE) {
|
||||
// Mount from module file to dummy file
|
||||
snprintf(buf2, PATH_MAX, "%s/%s%s/%s", MOUNTPOINT, child->module, full_path, child->name);
|
||||
} else if (child->status & (IS_SKEL | IS_INTER)) {
|
||||
// It's an intermediate folder, recursive clone
|
||||
clone_skeleton(child);
|
||||
continue;
|
||||
} else if (child->status & IS_DUMMY) {
|
||||
// Mount from mirror to dummy file
|
||||
snprintf(buf2, PATH_MAX, "%s%s/%s", MIRRDIR, full_path, child->name);
|
||||
}
|
||||
|
||||
if (IS_LNK(child)) {
|
||||
// Copy symlinks directly
|
||||
cp_afc(buf2, buf);
|
||||
#ifdef MAGISK_DEBUG
|
||||
LOGI("creat_link: %s <- %s\n",buf, buf2);
|
||||
#else
|
||||
LOGI("creat_link: %s\n", buf);
|
||||
#endif
|
||||
} else {
|
||||
snprintf(buf, PATH_MAX, "%s/%s", full_path, child->name);
|
||||
bind_mount(buf2, buf);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(full_path);
|
||||
}
|
||||
|
||||
static void magic_mount(struct node_entry *node) {
|
||||
char *real_path;
|
||||
struct node_entry *child;
|
||||
|
||||
if (node->status & IS_MODULE) {
|
||||
// The real deal, mount module item
|
||||
real_path = get_full_path(node);
|
||||
snprintf(buf, PATH_MAX, "%s/%s%s", MOUNTPOINT, node->module, real_path);
|
||||
bind_mount(buf, real_path);
|
||||
free(real_path);
|
||||
} else if (node->status & IS_SKEL) {
|
||||
// The node is labeled to be cloned with skeleton, lets do it
|
||||
clone_skeleton(node);
|
||||
} else if (node->status & IS_INTER) {
|
||||
// It's an intermediate node, travel deeper
|
||||
vec_for_each(node->children, child)
|
||||
magic_mount(child);
|
||||
}
|
||||
// The only thing goes here should be vendor placeholder
|
||||
// There should be no dummies, so don't need to handle it here
|
||||
}
|
||||
|
||||
/****************
|
||||
* Simple Mount *
|
||||
****************/
|
||||
|
||||
static void simple_mount(const char *path) {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
snprintf(buf, PATH_MAX, "%s%s", CACHEMOUNT, path);
|
||||
if (!(dir = opendir(buf)))
|
||||
return;
|
||||
|
||||
while ((entry = xreaddir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
// Target file path
|
||||
snprintf(buf2, PATH_MAX, "%s/%s", path, entry->d_name);
|
||||
// Only mount existing file
|
||||
if (access(buf2, F_OK) == -1)
|
||||
continue;
|
||||
if (entry->d_type == DT_DIR) {
|
||||
char *new_path = strdup(buf2);
|
||||
simple_mount(new_path);
|
||||
free(new_path);
|
||||
} else if (entry->d_type == DT_REG) {
|
||||
// Actual file path
|
||||
snprintf(buf, PATH_MAX, "%s%s", CACHEMOUNT, buf2);
|
||||
// Clone all attributes
|
||||
clone_attr(buf2, buf);
|
||||
// Finally, mount the file
|
||||
bind_mount(buf, buf2);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
/*****************
|
||||
* Miscellaneous *
|
||||
*****************/
|
||||
|
||||
#define alt_img ((char *[]) \
|
||||
{ "/cache/magisk.img", "/data/magisk_merge.img", "/data/adb/magisk_merge.img", NULL })
|
||||
|
||||
static int prepare_img() {
|
||||
// Merge images
|
||||
for (int i = 0; alt_img[i]; ++i) {
|
||||
if (merge_img(alt_img[i], MAINIMG)) {
|
||||
LOGE("Image merge %s -> " MAINIMG " failed!\n", alt_img[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (access(MAINIMG, F_OK) == -1) {
|
||||
if (create_img(MAINIMG, 64))
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOGI("* Mounting " MAINIMG "\n");
|
||||
// Mounting magisk image
|
||||
char *magiskloop = mount_image(MAINIMG, MOUNTPOINT);
|
||||
if (magiskloop == NULL)
|
||||
return 1;
|
||||
|
||||
xmkdir(COREDIR, 0755);
|
||||
xmkdir(COREDIR "/post-fs-data.d", 0755);
|
||||
xmkdir(COREDIR "/service.d", 0755);
|
||||
xmkdir(COREDIR "/props", 0755);
|
||||
|
||||
DIR *dir = xopendir(MOUNTPOINT);
|
||||
struct dirent *entry;
|
||||
while ((entry = xreaddir(dir))) {
|
||||
if (entry->d_type == DT_DIR) {
|
||||
if (strcmp(entry->d_name, ".") == 0 ||
|
||||
strcmp(entry->d_name, "..") == 0 ||
|
||||
strcmp(entry->d_name, ".core") == 0 ||
|
||||
strcmp(entry->d_name, "lost+found") == 0)
|
||||
continue;
|
||||
snprintf(buf, PATH_MAX, "%s/%s/remove", MOUNTPOINT, entry->d_name);
|
||||
if (access(buf, F_OK) == 0) {
|
||||
snprintf(buf, PATH_MAX, "%s/%s", MOUNTPOINT, entry->d_name);
|
||||
rm_rf(buf);
|
||||
continue;
|
||||
}
|
||||
snprintf(buf, PATH_MAX, "%s/%s/disable", MOUNTPOINT, entry->d_name);
|
||||
if (access(buf, F_OK) == 0)
|
||||
continue;
|
||||
vec_push_back(&module_list, strdup(entry->d_name));
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
// Trim image
|
||||
umount_image(MOUNTPOINT, magiskloop);
|
||||
free(magiskloop);
|
||||
trim_img(MAINIMG);
|
||||
|
||||
// Remount them back :)
|
||||
magiskloop = mount_image(MAINIMG, MOUNTPOINT);
|
||||
free(magiskloop);
|
||||
|
||||
// Fix file selinux contexts
|
||||
fix_filecon();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fix_filecon() {
|
||||
int dirfd = xopen(MOUNTPOINT, O_RDONLY | O_CLOEXEC);
|
||||
restorecon(dirfd, 0);
|
||||
close(dirfd);
|
||||
}
|
||||
|
||||
/****************
|
||||
* Entry points *
|
||||
****************/
|
||||
|
||||
static void unblock_boot_process() {
|
||||
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
void post_fs(int client) {
|
||||
LOGI("** post-fs mode running\n");
|
||||
// ack
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
|
||||
// Uninstall or core only mode
|
||||
if (access(UNINSTALLER, F_OK) == 0 || access(DISABLEFILE, F_OK) == 0)
|
||||
goto unblock;
|
||||
|
||||
// Allocate buffer
|
||||
buf = xmalloc(PATH_MAX);
|
||||
buf2 = xmalloc(PATH_MAX);
|
||||
|
||||
simple_mount("/system");
|
||||
simple_mount("/vendor");
|
||||
|
||||
unblock:
|
||||
unblock_boot_process();
|
||||
}
|
||||
|
||||
void post_fs_data(int client) {
|
||||
// ack
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
if (!is_daemon_init && !check_data())
|
||||
goto unblock;
|
||||
|
||||
// Start the debug log
|
||||
start_debug_full_log();
|
||||
|
||||
LOGI("** post-fs-data mode running\n");
|
||||
|
||||
// Allocate buffer
|
||||
if (buf == NULL) buf = xmalloc(PATH_MAX);
|
||||
if (buf2 == NULL) buf2 = xmalloc(PATH_MAX);
|
||||
vec_init(&module_list);
|
||||
|
||||
// Initialize
|
||||
if (!is_daemon_init)
|
||||
daemon_init();
|
||||
|
||||
// uninstaller
|
||||
if (access(UNINSTALLER, F_OK) == 0) {
|
||||
close(open(UNBLOCKFILE, O_RDONLY | O_CREAT));
|
||||
setenv("BOOTMODE", "true", 1);
|
||||
exec_command(0, NULL, bb_setenv, "sh", UNINSTALLER, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge, trim, mount magisk.img, which will also travel through the modules
|
||||
// After this, it will create the module list
|
||||
if (prepare_img())
|
||||
goto core_only; // Mounting fails, we can only do core only stuffs
|
||||
|
||||
// Run common scripts
|
||||
LOGI("* Running post-fs-data.d scripts\n");
|
||||
exec_common_script("post-fs-data");
|
||||
|
||||
// Core only mode
|
||||
if (access(DISABLEFILE, F_OK) == 0)
|
||||
goto core_only;
|
||||
|
||||
// Execute module scripts
|
||||
LOGI("* Running module post-fs-data scripts\n");
|
||||
exec_module_script("post-fs-data");
|
||||
|
||||
char *module;
|
||||
struct node_entry *sys_root, *ven_root = NULL, *child;
|
||||
|
||||
// Create the system root entry
|
||||
sys_root = xcalloc(sizeof(*sys_root), 1);
|
||||
sys_root->name = strdup("system");
|
||||
sys_root->status = IS_INTER;
|
||||
|
||||
int has_modules = 0;
|
||||
|
||||
LOGI("* Loading modules\n");
|
||||
vec_for_each(&module_list, module) {
|
||||
// Read props
|
||||
snprintf(buf, PATH_MAX, "%s/%s/system.prop", MOUNTPOINT, module);
|
||||
if (access(buf, F_OK) == 0) {
|
||||
LOGI("%s: loading [system.prop]\n", module);
|
||||
read_prop_file(buf, 0);
|
||||
}
|
||||
// Check whether enable auto_mount
|
||||
snprintf(buf, PATH_MAX, "%s/%s/auto_mount", MOUNTPOINT, module);
|
||||
if (access(buf, F_OK) == -1)
|
||||
continue;
|
||||
// Double check whether the system folder exists
|
||||
snprintf(buf, PATH_MAX, "%s/%s/system", MOUNTPOINT, module);
|
||||
if (access(buf, F_OK) == -1)
|
||||
continue;
|
||||
|
||||
// Construct structure
|
||||
has_modules = 1;
|
||||
LOGI("%s: constructing magic mount structure\n", module);
|
||||
// If /system/vendor exists in module, create a link outside
|
||||
snprintf(buf, PATH_MAX, "%s/%s/system/vendor", MOUNTPOINT, module);
|
||||
if (access(buf, F_OK) == 0) {
|
||||
snprintf(buf2, PATH_MAX, "%s/%s/vendor", MOUNTPOINT, module);
|
||||
unlink(buf2);
|
||||
xsymlink(buf, buf2);
|
||||
}
|
||||
construct_tree(module, sys_root);
|
||||
}
|
||||
|
||||
if (has_modules) {
|
||||
// Extract the vendor node out of system tree and swap with placeholder
|
||||
vec_for_each(sys_root->children, child) {
|
||||
if (strcmp(child->name, "vendor") == 0) {
|
||||
ven_root = child;
|
||||
child = xcalloc(sizeof(*child), 1);
|
||||
child->type = seperate_vendor ? DT_LNK : DT_DIR;
|
||||
child->parent = ven_root->parent;
|
||||
child->name = strdup("vendor");
|
||||
child->status = 0;
|
||||
// Swap!
|
||||
vec_cur(sys_root->children) = child;
|
||||
ven_root->parent = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Magic!!
|
||||
magic_mount(sys_root);
|
||||
if (ven_root) magic_mount(ven_root);
|
||||
}
|
||||
|
||||
// Cleanup memory
|
||||
destroy_subtree(sys_root);
|
||||
if (ven_root) destroy_subtree(ven_root);
|
||||
|
||||
core_only:
|
||||
// Systemless hosts
|
||||
if (access(HOSTSFILE, F_OK) == 0) {
|
||||
LOGI("* Enabling systemless hosts file support");
|
||||
bind_mount(HOSTSFILE, "/system/etc/hosts");
|
||||
}
|
||||
|
||||
auto_start_magiskhide();
|
||||
|
||||
unblock:
|
||||
unblock_boot_process();
|
||||
}
|
||||
|
||||
void late_start(int client) {
|
||||
LOGI("** late_start service mode running\n");
|
||||
// ack
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
|
||||
// Allocate buffer
|
||||
if (buf == NULL) buf = xmalloc(PATH_MAX);
|
||||
if (buf2 == NULL) buf2 = xmalloc(PATH_MAX);
|
||||
|
||||
// Wait till the full patch is done
|
||||
wait_till_exists(PATCHDONE);
|
||||
unlink(PATCHDONE);
|
||||
|
||||
// Run scripts after full patch, most reliable way to run scripts
|
||||
LOGI("* Running service.d scripts\n");
|
||||
exec_common_script("service");
|
||||
|
||||
// Core only mode
|
||||
if (access(DISABLEFILE, F_OK) == 0)
|
||||
goto core_only;
|
||||
|
||||
LOGI("* Running module service scripts\n");
|
||||
exec_module_script("service");
|
||||
|
||||
core_only:
|
||||
// Install Magisk Manager if exists
|
||||
if (access(MANAGERAPK, F_OK) == 0) {
|
||||
rename(MANAGERAPK, "/data/magisk.apk");
|
||||
setfilecon("/data/magisk.apk", "u:object_r:su_file:s0");
|
||||
while (1) {
|
||||
sleep(5);
|
||||
int apk_res = -1, pid;
|
||||
pid = exec_command(1, &apk_res, pm_setenv,
|
||||
"app_process",
|
||||
"/system/bin", "com.android.commands.pm.Pm",
|
||||
"install", "-r", "/data/magisk.apk", NULL);
|
||||
if (pid != -1) {
|
||||
int err = 0;
|
||||
while (fdgets(buf, PATH_MAX, apk_res) > 0) {
|
||||
LOGD("apk_install: %s", buf);
|
||||
err |= strstr(buf, "Error:") != NULL;
|
||||
}
|
||||
waitpid(pid, NULL, 0);
|
||||
close(apk_res);
|
||||
// Keep trying until pm is started
|
||||
if (err)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unlink("/data/magisk.apk");
|
||||
}
|
||||
|
||||
// All boot stage done, cleanup everything
|
||||
free(buf);
|
||||
free(buf2);
|
||||
buf = buf2 = NULL;
|
||||
vec_deep_destroy(&module_list);
|
||||
|
||||
stop_debug_full_log();
|
||||
}
|
313
native/jni/core/daemon.c
Normal file
313
native/jni/core/daemon.c
Normal file
@@ -0,0 +1,313 @@
|
||||
/* daemon.c - Magisk Daemon
|
||||
*
|
||||
* Start the daemon and wait for requests
|
||||
* Connect the daemon and send requests through sockets
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
#include "daemon.h"
|
||||
#include "resetprop.h"
|
||||
|
||||
int is_daemon_init = 0, seperate_vendor = 0;
|
||||
|
||||
static void *request_handler(void *args) {
|
||||
int client = *((int *) args);
|
||||
free(args);
|
||||
client_request req = read_int(client);
|
||||
|
||||
struct ucred credential;
|
||||
get_client_cred(client, &credential);
|
||||
|
||||
switch (req) {
|
||||
case LAUNCH_MAGISKHIDE:
|
||||
case STOP_MAGISKHIDE:
|
||||
case ADD_HIDELIST:
|
||||
case RM_HIDELIST:
|
||||
case LS_HIDELIST:
|
||||
case POST_FS:
|
||||
case POST_FS_DATA:
|
||||
case LATE_START:
|
||||
if (credential.uid != 0) {
|
||||
write_int(client, ROOT_REQUIRED);
|
||||
close(client);
|
||||
return NULL;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (req) {
|
||||
case LAUNCH_MAGISKHIDE:
|
||||
launch_magiskhide(client);
|
||||
break;
|
||||
case STOP_MAGISKHIDE:
|
||||
stop_magiskhide(client);
|
||||
break;
|
||||
case ADD_HIDELIST:
|
||||
add_hide_list(client);
|
||||
break;
|
||||
case RM_HIDELIST:
|
||||
rm_hide_list(client);
|
||||
break;
|
||||
case LS_HIDELIST:
|
||||
ls_hide_list(client);
|
||||
break;
|
||||
case SUPERUSER:
|
||||
su_daemon_receiver(client, &credential);
|
||||
break;
|
||||
case CHECK_VERSION:
|
||||
write_string(client, MAGISK_VER_STR);
|
||||
close(client);
|
||||
break;
|
||||
case CHECK_VERSION_CODE:
|
||||
write_int(client, MAGISK_VER_CODE);
|
||||
close(client);
|
||||
break;
|
||||
case POST_FS:
|
||||
post_fs(client);
|
||||
break;
|
||||
case POST_FS_DATA:
|
||||
post_fs_data(client);
|
||||
break;
|
||||
case LATE_START:
|
||||
late_start(client);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void *start_magisk_hide(void *args) {
|
||||
launch_magiskhide(-1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void auto_start_magiskhide() {
|
||||
char *hide_prop = getprop2(MAGISKHIDE_PROP, 1);
|
||||
if (hide_prop == NULL || strcmp(hide_prop, "0") != 0) {
|
||||
pthread_t thread;
|
||||
xpthread_create(&thread, NULL, start_magisk_hide, NULL);
|
||||
pthread_detach(thread);
|
||||
}
|
||||
free(hide_prop);
|
||||
}
|
||||
|
||||
void daemon_init() {
|
||||
is_daemon_init = 1;
|
||||
|
||||
// Magisk binaries
|
||||
char *bin_path = NULL;
|
||||
if (access("/cache/data_bin", F_OK) == 0)
|
||||
bin_path = "/cache/data_bin";
|
||||
else if (access("/data/data/com.topjohnwu.magisk/install", F_OK) == 0)
|
||||
bin_path = "/data/data/com.topjohnwu.magisk/install";
|
||||
else if (access("/data/user_de/0/com.topjohnwu.magisk/install", F_OK) == 0)
|
||||
bin_path = "/data/user_de/0/com.topjohnwu.magisk/install";
|
||||
if (bin_path) {
|
||||
rm_rf(DATABIN);
|
||||
cp_afc(bin_path, DATABIN);
|
||||
rm_rf(bin_path);
|
||||
}
|
||||
|
||||
// Migration
|
||||
rm_rf("/data/magisk");
|
||||
unlink("/data/magisk.img");
|
||||
unlink("/data/magisk_debug.log");
|
||||
chmod("/data/adb", 0700);
|
||||
|
||||
LOGI("* Creating /sbin overlay");
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
int root, sbin;
|
||||
char buf[PATH_MAX], buf2[PATH_MAX];
|
||||
|
||||
// Setup links under /sbin
|
||||
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
|
||||
xmkdir("/root", 0755);
|
||||
chmod("/root", 0755);
|
||||
root = xopen("/root", O_RDONLY | O_CLOEXEC);
|
||||
sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC);
|
||||
dir = xfdopendir(sbin);
|
||||
while((entry = xreaddir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
|
||||
linkat(sbin, entry->d_name, root, entry->d_name, 0);
|
||||
if (strcmp(entry->d_name, "magisk") == 0)
|
||||
unlinkat(sbin, entry->d_name, 0);
|
||||
}
|
||||
close(sbin);
|
||||
|
||||
xmount("tmpfs", "/sbin", "tmpfs", 0, NULL);
|
||||
chmod("/sbin", 0755);
|
||||
setfilecon("/sbin", "u:object_r:rootfs:s0");
|
||||
dir = xfdopendir(root);
|
||||
while((entry = xreaddir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
|
||||
snprintf(buf, PATH_MAX, "/root/%s", entry->d_name);
|
||||
snprintf(buf2, PATH_MAX, "/sbin/%s", entry->d_name);
|
||||
xsymlink(buf, buf2);
|
||||
}
|
||||
for (int i = 0; applet[i]; ++i) {
|
||||
snprintf(buf2, PATH_MAX, "/sbin/%s", applet[i]);
|
||||
xsymlink("/root/magisk", buf2);
|
||||
}
|
||||
for (int i = 0; init_applet[i]; ++i) {
|
||||
snprintf(buf2, PATH_MAX, "/sbin/%s", init_applet[i]);
|
||||
xsymlink("/root/magiskinit", buf2);
|
||||
}
|
||||
close(root);
|
||||
|
||||
// Backward compatibility
|
||||
xsymlink(DATABIN, "/data/magisk");
|
||||
xsymlink(MAINIMG, "/data/magisk.img");
|
||||
xsymlink(MOUNTPOINT, "/magisk");
|
||||
|
||||
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
|
||||
|
||||
LOGI("* Mounting mirrors");
|
||||
struct vector mounts;
|
||||
vec_init(&mounts);
|
||||
file_to_vector("/proc/mounts", &mounts);
|
||||
char *line;
|
||||
int skip_initramfs = 0;
|
||||
// Check whether skip_initramfs device
|
||||
vec_for_each(&mounts, line) {
|
||||
if (strstr(line, " /system_root ")) {
|
||||
xmkdirs(MIRRDIR "/system", 0755);
|
||||
bind_mount("/system_root/system", MIRRDIR "/system");
|
||||
skip_initramfs = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
vec_for_each(&mounts, line) {
|
||||
if (!skip_initramfs && strstr(line, " /system ")) {
|
||||
sscanf(line, "%s", buf);
|
||||
xmkdirs(MIRRDIR "/system", 0755);
|
||||
xmount(buf, MIRRDIR "/system", "ext4", MS_RDONLY, NULL);
|
||||
#ifdef MAGISK_DEBUG
|
||||
LOGI("mount: %s -> %s\n", buf, MIRRDIR "/system");
|
||||
#else
|
||||
LOGI("mount: %s\n", MIRRDIR "/system");
|
||||
#endif
|
||||
} else if (strstr(line, " /vendor ")) {
|
||||
seperate_vendor = 1;
|
||||
sscanf(line, "%s", buf);
|
||||
xmkdirs(MIRRDIR "/vendor", 0755);
|
||||
xmount(buf, MIRRDIR "/vendor", "ext4", MS_RDONLY, NULL);
|
||||
#ifdef MAGISK_DEBUG
|
||||
LOGI("mount: %s -> %s\n", buf, MIRRDIR "/vendor");
|
||||
#else
|
||||
LOGI("mount: %s\n", MIRRDIR "/vendor");
|
||||
#endif
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
vec_destroy(&mounts);
|
||||
if (!seperate_vendor) {
|
||||
xsymlink(MIRRDIR "/system/vendor", MIRRDIR "/vendor");
|
||||
#ifdef MAGISK_DEBUG
|
||||
LOGI("link: %s -> %s\n", MIRRDIR "/system/vendor", MIRRDIR "/vendor");
|
||||
#else
|
||||
LOGI("link: %s\n", MIRRDIR "/vendor");
|
||||
#endif
|
||||
}
|
||||
xmkdirs(MIRRDIR "/bin", 0755);
|
||||
bind_mount(DATABIN, MIRRDIR "/bin");
|
||||
|
||||
LOGI("* Setting up internal busybox");
|
||||
xmkdirs(BBPATH, 0755);
|
||||
exec_command_sync(MIRRDIR "/bin/busybox", "--install", "-s", BBPATH, NULL);
|
||||
xsymlink(MIRRDIR "/bin/busybox", BBPATH "/busybox");
|
||||
}
|
||||
|
||||
void start_daemon() {
|
||||
setsid();
|
||||
setcon("u:r:su:s0");
|
||||
umask(0);
|
||||
int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
|
||||
xdup2(fd, STDIN_FILENO);
|
||||
xdup2(fd, STDOUT_FILENO);
|
||||
xdup2(fd, STDERR_FILENO);
|
||||
close(fd);
|
||||
|
||||
// Block user signals
|
||||
sigset_t block_set;
|
||||
sigemptyset(&block_set);
|
||||
sigaddset(&block_set, SIGUSR1);
|
||||
sigaddset(&block_set, SIGUSR2);
|
||||
pthread_sigmask(SIG_SETMASK, &block_set, NULL);
|
||||
|
||||
struct sockaddr_un sun;
|
||||
fd = setup_socket(&sun);
|
||||
|
||||
if (xbind(fd, (struct sockaddr*) &sun, sizeof(sun)))
|
||||
exit(1);
|
||||
xlisten(fd, 10);
|
||||
|
||||
if ((is_daemon_init = (access(MAGISKTMP, F_OK) == 0))) {
|
||||
// Restart stuffs if the daemon is restarted
|
||||
exec_command_sync("logcat", "-b", "all", "-c", NULL);
|
||||
auto_start_magiskhide();
|
||||
start_debug_log();
|
||||
} else if (check_data()) {
|
||||
daemon_init();
|
||||
}
|
||||
|
||||
// Start the log monitor
|
||||
monitor_logs();
|
||||
|
||||
LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") daemon started\n");
|
||||
|
||||
// Change process name
|
||||
strcpy(argv0, "magisk_daemon");
|
||||
|
||||
// Unlock all blocks for rw
|
||||
unlock_blocks();
|
||||
|
||||
// Loop forever to listen for requests
|
||||
while(1) {
|
||||
int *client = xmalloc(sizeof(int));
|
||||
*client = xaccept4(fd, NULL, NULL, SOCK_CLOEXEC);
|
||||
pthread_t thread;
|
||||
xpthread_create(&thread, NULL, request_handler, client);
|
||||
// Detach the thread, we will never join it
|
||||
pthread_detach(thread);
|
||||
}
|
||||
}
|
||||
|
||||
/* Connect the daemon, and return a socketfd */
|
||||
int connect_daemon() {
|
||||
struct sockaddr_un sun;
|
||||
int fd = setup_socket(&sun);
|
||||
if (connect(fd, (struct sockaddr*) &sun, sizeof(sun))) {
|
||||
// If we cannot access the daemon, we start a daemon in the child process if possible
|
||||
|
||||
if (getuid() != UID_ROOT || getgid() != UID_ROOT) {
|
||||
fprintf(stderr, "No daemon is currently running!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (xfork() == 0) {
|
||||
LOGD("client: connect fail, try launching new daemon process\n");
|
||||
close(fd);
|
||||
start_daemon();
|
||||
}
|
||||
|
||||
while (connect(fd, (struct sockaddr*) &sun, sizeof(sun)))
|
||||
usleep(10000);
|
||||
}
|
||||
return fd;
|
||||
}
|
178
native/jni/core/log_monitor.c
Normal file
178
native/jni/core/log_monitor.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/* log_monitor.c - New thread to monitor logcat
|
||||
*
|
||||
* A universal logcat monitor for many usages. Add listeners to the list,
|
||||
* and the pointer of the new log line will be sent through pipes to trigger
|
||||
* asynchronous events without polling
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
|
||||
extern int is_daemon_init;
|
||||
|
||||
static int am_proc_start_filter(const char *log) {
|
||||
return strstr(log, "am_proc_start") != NULL;
|
||||
}
|
||||
|
||||
static int magisk_log_filter(const char *log) {
|
||||
char *ss;
|
||||
return (ss = strstr(log, " Magisk")) && (ss[-1] != 'D') && (ss[-1] != 'V');
|
||||
}
|
||||
|
||||
static int magisk_debug_log_filter(const char *log) {
|
||||
return strstr(log, "Magisk") != NULL;
|
||||
}
|
||||
|
||||
struct log_listener log_events[] = {
|
||||
{ /* HIDE_EVENT */
|
||||
.fd = -1,
|
||||
.filter = am_proc_start_filter
|
||||
},
|
||||
{ /* LOG_EVENT */
|
||||
.fd = -1,
|
||||
.filter = magisk_log_filter
|
||||
},
|
||||
{ /* DEBUG_EVENT */
|
||||
.fd = -1,
|
||||
.filter = magisk_debug_log_filter
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef MAGISK_DEBUG
|
||||
static int debug_log_pid, debug_log_fd;
|
||||
#endif
|
||||
|
||||
static void *logger_thread(void *args) {
|
||||
int log_fd = -1, log_pid;
|
||||
char line[4096];
|
||||
|
||||
LOGD("log_monitor: logger start");
|
||||
|
||||
while (1) {
|
||||
// Start logcat
|
||||
log_pid = exec_command(0, &log_fd, NULL, "logcat", "-b", "events", "-b", "main", "-v", "threadtime", "-s", "am_proc_start", "-s", "Magisk", NULL);
|
||||
while (fdgets(line, sizeof(line), log_fd)) {
|
||||
for (int i = 0; i < (sizeof(log_events) / sizeof(struct log_listener)); ++i) {
|
||||
if (log_events[i].fd > 0 && log_events[i].filter(line)) {
|
||||
char *s = strdup(line);
|
||||
xwrite(log_events[i].fd, &s, sizeof(s));
|
||||
}
|
||||
}
|
||||
if (kill(log_pid, 0))
|
||||
break;
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
close(log_fd);
|
||||
log_fd = -1;
|
||||
kill(log_pid, SIGTERM);
|
||||
waitpid(log_pid, NULL, 0);
|
||||
|
||||
// Clear buffer before restart
|
||||
exec_command_sync("logcat", "-b", "events", "-b", "main", "-c", NULL);
|
||||
}
|
||||
|
||||
// Should never be here, but well...
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *magisk_log_thread(void *args) {
|
||||
// Buffer logs before we have data access
|
||||
struct vector logs;
|
||||
vec_init(&logs);
|
||||
|
||||
int pipefd[2];
|
||||
if (xpipe2(pipefd, O_CLOEXEC) == -1)
|
||||
return NULL;
|
||||
|
||||
// Register our listener
|
||||
log_events[LOG_EVENT].fd = pipefd[1];
|
||||
|
||||
LOGD("log_monitor: magisk log dumper start");
|
||||
|
||||
FILE *log = NULL;
|
||||
for (char *line; xxread(pipefd[0], &line, sizeof(line)) > 0; free(line)) {
|
||||
if (!is_daemon_init) {
|
||||
vec_push_back(&logs, strdup(line));
|
||||
} else {
|
||||
if (log == NULL) {
|
||||
// Dump buffered logs to file
|
||||
log = xfopen(LOGFILE, "w");
|
||||
setbuf(log, NULL);
|
||||
char *tmp;
|
||||
vec_for_each(&logs, tmp) {
|
||||
fprintf(log, "%s", tmp);
|
||||
free(tmp);
|
||||
}
|
||||
vec_destroy(&logs);
|
||||
}
|
||||
fprintf(log, "%s", line);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *debug_magisk_log_thread(void *args) {
|
||||
FILE *log = xfopen(DEBUG_LOG, "a");
|
||||
setbuf(log, NULL);
|
||||
int pipefd[2];
|
||||
if (xpipe2(pipefd, O_CLOEXEC) == -1)
|
||||
return NULL;
|
||||
|
||||
LOGD("log_monitor: debug log dumper start");
|
||||
|
||||
// Register our listener
|
||||
log_events[DEBUG_EVENT].fd = pipefd[1];
|
||||
|
||||
for (char *line; xxread(pipefd[0], &line, sizeof(line)) > 0; free(line))
|
||||
fprintf(log, "%s", line);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Start new threads to monitor logcat and dump to logfile */
|
||||
void monitor_logs() {
|
||||
pthread_t thread;
|
||||
|
||||
// Start log file dumper before monitor
|
||||
xpthread_create(&thread, NULL, magisk_log_thread, NULL);
|
||||
pthread_detach(thread);
|
||||
|
||||
// Start logcat monitor
|
||||
xpthread_create(&thread, NULL, logger_thread, NULL);
|
||||
pthread_detach(thread);
|
||||
|
||||
}
|
||||
|
||||
void start_debug_full_log() {
|
||||
#ifdef MAGISK_DEBUG
|
||||
// Log everything initially
|
||||
debug_log_fd = xopen(DEBUG_LOG, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, 0644);
|
||||
debug_log_pid = exec_command(0, &debug_log_fd, NULL, "logcat", "-v", "threadtime", NULL);
|
||||
close(debug_log_fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
void stop_debug_full_log() {
|
||||
#ifdef MAGISK_DEBUG
|
||||
// Stop recording the boot logcat after every boot task is done
|
||||
kill(debug_log_pid, SIGTERM);
|
||||
waitpid(debug_log_pid, NULL, 0);
|
||||
// Start debug thread
|
||||
start_debug_log();
|
||||
#endif
|
||||
}
|
||||
|
||||
void start_debug_log() {
|
||||
#ifdef MAGISK_DEBUG
|
||||
pthread_t thread;
|
||||
// Start debug thread
|
||||
xpthread_create(&thread, NULL, debug_magisk_log_thread, NULL);
|
||||
pthread_detach(thread);
|
||||
#endif
|
||||
}
|
177
native/jni/core/magisk.c
Normal file
177
native/jni/core/magisk.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/* main.c - The multicall entry point
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "magisk.h"
|
||||
#include "daemon.h"
|
||||
|
||||
char *argv0;
|
||||
|
||||
int (*applet_main[]) (int, char *[]) = { su_client_main, resetprop_main, magiskhide_main, NULL };
|
||||
|
||||
int create_links(const char *bin, const char *path) {
|
||||
char self[PATH_MAX], linkpath[PATH_MAX];
|
||||
if (bin == NULL) {
|
||||
xreadlink("/proc/self/exe", self, sizeof(self));
|
||||
bin = self;
|
||||
}
|
||||
int ret = 0;
|
||||
for (int i = 0; applet[i]; ++i) {
|
||||
snprintf(linkpath, sizeof(linkpath), "%s/%s", path, applet[i]);
|
||||
unlink(linkpath);
|
||||
ret |= symlink(bin, linkpath);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usage() {
|
||||
fprintf(stderr,
|
||||
"Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) multi-call binary\n"
|
||||
"\n"
|
||||
"Usage: %s [applet [arguments]...]\n"
|
||||
" or: %s [options]...\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -c print current binary version\n"
|
||||
" -v print running daemon version\n"
|
||||
" -V print running daemon version code\n"
|
||||
" --list list all available applets\n"
|
||||
" --install [SOURCE] DIR symlink all applets to DIR. SOURCE is optional\n"
|
||||
" --createimg IMG SIZE create ext4 image. SIZE is interpreted in MB\n"
|
||||
" --imgsize IMG report ext4 image used/total size\n"
|
||||
" --resizeimg IMG SIZE resize ext4 image. SIZE is interpreted in MB\n"
|
||||
" --mountimg IMG PATH mount IMG to PATH and prints the loop device\n"
|
||||
" --umountimg PATH LOOP unmount PATH and delete LOOP device\n"
|
||||
" --[init service] start init service\n"
|
||||
" --unlock-blocks set BLKROSET flag to OFF for all block devices\n"
|
||||
" --restorecon fix selinux context on Magisk files and folders\n"
|
||||
" --clone-attr SRC DEST clone permission, owner, and selinux context\n"
|
||||
"\n"
|
||||
"Supported init services:\n"
|
||||
" daemon, post-fs, post-fs-data, service\n"
|
||||
"\n"
|
||||
"Supported applets:\n"
|
||||
, argv0, argv0);
|
||||
|
||||
for (int i = 0; applet[i]; ++i)
|
||||
fprintf(stderr, i ? ", %s" : " %s", applet[i]);
|
||||
fprintf(stderr, "\n\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
argv0 = argv[0];
|
||||
if (strcmp(basename(argv[0]), "magisk") == 0) {
|
||||
if (argc < 2) usage();
|
||||
if (strcmp(argv[1], "-c") == 0) {
|
||||
printf("%s (%d)\n", MAGISK_VER_STR, MAGISK_VER_CODE);
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "-v") == 0) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, CHECK_VERSION);
|
||||
char *v = read_string(fd);
|
||||
printf("%s\n", v);
|
||||
free(v);
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "-V") == 0) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, CHECK_VERSION_CODE);
|
||||
printf("%d\n", read_int(fd));
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--install") == 0) {
|
||||
if (argc < 3) usage();
|
||||
if (argc == 3) return create_links(NULL, argv[2]);
|
||||
else return create_links(argv[2], argv[3]);
|
||||
} else if (strcmp(argv[1], "--list") == 0) {
|
||||
for (int i = 0; applet[i]; ++i)
|
||||
printf("%s\n", applet[i]);
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--createimg") == 0) {
|
||||
if (argc < 4) usage();
|
||||
int size;
|
||||
sscanf(argv[3], "%d", &size);
|
||||
return create_img(argv[2], size);
|
||||
} else if (strcmp(argv[1], "--imgsize") == 0) {
|
||||
if (argc < 3) usage();
|
||||
int used, total;
|
||||
if (get_img_size(argv[2], &used, &total)) {
|
||||
fprintf(stderr, "Cannot check %s size\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
printf("%d %d\n", used, total);
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--resizeimg") == 0) {
|
||||
if (argc < 4) usage();
|
||||
int used, total, size;
|
||||
sscanf(argv[3], "%d", &size);
|
||||
if (get_img_size(argv[2], &used, &total)) {
|
||||
fprintf(stderr, "Cannot check %s size\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
if (size <= used) {
|
||||
fprintf(stderr, "Cannot resize smaller than %dM\n", used);
|
||||
return 1;
|
||||
}
|
||||
return resize_img(argv[2], size);
|
||||
} else if (strcmp(argv[1], "--mountimg") == 0) {
|
||||
if (argc < 4) usage();
|
||||
char *loop = mount_image(argv[2], argv[3]);
|
||||
if (loop == NULL) {
|
||||
fprintf(stderr, "Cannot mount image!\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("%s\n", loop);
|
||||
free(loop);
|
||||
return 0;
|
||||
}
|
||||
} else if (strcmp(argv[1], "--umountimg") == 0) {
|
||||
if (argc < 4) usage();
|
||||
umount_image(argv[2], argv[3]);
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--unlock-blocks") == 0) {
|
||||
unlock_blocks();
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--restorecon") == 0) {
|
||||
fix_filecon();
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--clone-attr") == 0) {
|
||||
if (argc < 4) usage();
|
||||
clone_attr(argv[2], argv[3]);
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--daemon") == 0) {
|
||||
if (xfork() == 0)
|
||||
start_daemon();
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--post-fs") == 0) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, POST_FS);
|
||||
return read_int(fd);
|
||||
} else if (strcmp(argv[1], "--post-fs-data") == 0) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, POST_FS_DATA);
|
||||
return read_int(fd);
|
||||
} else if (strcmp(argv[1], "--service") == 0) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, LATE_START);
|
||||
return read_int(fd);
|
||||
} else {
|
||||
// It's calling applets
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
}
|
||||
|
||||
// Applets
|
||||
for (int i = 0; applet[i]; ++i) {
|
||||
if (strcmp(basename(argv[0]), applet[i]) == 0)
|
||||
return (*applet_main[i])(argc, argv);
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: applet not found\n", basename(argv[0]));
|
||||
return 1;
|
||||
}
|
547
native/jni/core/magiskinit.c
Normal file
547
native/jni/core/magiskinit.c
Normal file
@@ -0,0 +1,547 @@
|
||||
/* magiskinit.c - Pre-init Magisk support
|
||||
*
|
||||
* This code has to be compiled statically to work properly.
|
||||
*
|
||||
* To unify Magisk support for both legacy "normal" devices and new skip_initramfs devices,
|
||||
* magisk binary compilation is split into two parts - first part only compiles "magisk".
|
||||
* The python build script will load the magisk main binary and compress with lzma2, dumping
|
||||
* the results into "dump.h". The "magisk" binary is embedded into this binary, and will
|
||||
* get extracted to the overlay folder along with init.magisk.rc.
|
||||
*
|
||||
* This tool does all pre-init operations to setup a Magisk environment, which pathces rootfs
|
||||
* on the fly, providing fundamental support such as init, init.rc, and sepolicy patching.
|
||||
*
|
||||
* Magiskinit is also responsible for constructing 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.
|
||||
*
|
||||
* 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)
|
||||
*/
|
||||
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#include <lzma.h>
|
||||
#include <cil/cil.h>
|
||||
|
||||
#include "dump.h"
|
||||
#include "magiskrc.h"
|
||||
#include "utils.h"
|
||||
#include "magiskpolicy.h"
|
||||
#include "daemon.h"
|
||||
#include "cpio.h"
|
||||
#include "magisk.h"
|
||||
|
||||
#ifdef MAGISK_DEBUG
|
||||
#define VLOG(fmt, ...) printf(fmt, __VA_ARGS__)
|
||||
#else
|
||||
#define VLOG(fmt, ...)
|
||||
#endif
|
||||
|
||||
extern policydb_t *policydb;
|
||||
int (*init_applet_main[]) (int, char *[]) = { magiskpolicy_main, magiskpolicy_main, NULL };
|
||||
static int keepverity = 0, keepencrypt = 0;
|
||||
|
||||
struct cmdline {
|
||||
int skip_initramfs;
|
||||
char slot[3];
|
||||
};
|
||||
|
||||
struct device {
|
||||
dev_t major;
|
||||
dev_t minor;
|
||||
char devname[32];
|
||||
char partname[32];
|
||||
char path[64];
|
||||
};
|
||||
|
||||
static void parse_cmdline(struct cmdline *cmd) {
|
||||
// cleanup
|
||||
cmd->skip_initramfs = 0;
|
||||
cmd->slot[0] = '\0';
|
||||
|
||||
char cmdline[4096];
|
||||
mkdir("/proc", 0555);
|
||||
xmount("proc", "/proc", "proc", 0, NULL);
|
||||
int fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC);
|
||||
cmdline[read(fd, cmdline, sizeof(cmdline))] = '\0';
|
||||
close(fd);
|
||||
umount("/proc");
|
||||
for (char *tok = strtok(cmdline, " "); tok; tok = strtok(NULL, " ")) {
|
||||
if (strncmp(tok, "androidboot.slot_suffix", 23) == 0) {
|
||||
sscanf(tok, "androidboot.slot_suffix=%s", cmd->slot);
|
||||
} else if (strncmp(tok, "androidboot.slot", 16) == 0) {
|
||||
cmd->slot[0] = '_';
|
||||
sscanf(tok, "androidboot.slot=%s", cmd->slot + 1);
|
||||
} else if (strcmp(tok, "skip_initramfs") == 0) {
|
||||
cmd->skip_initramfs = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_device(struct device *dev, char *uevent) {
|
||||
dev->partname[0] = '\0';
|
||||
char *tok;
|
||||
tok = strtok(uevent, "\n");
|
||||
while (tok != NULL) {
|
||||
if (strncmp(tok, "MAJOR", 5) == 0) {
|
||||
sscanf(tok, "MAJOR=%ld", (long*) &dev->major);
|
||||
} else if (strncmp(tok, "MINOR", 5) == 0) {
|
||||
sscanf(tok, "MINOR=%ld", (long*) &dev->minor);
|
||||
} else if (strncmp(tok, "DEVNAME", 7) == 0) {
|
||||
sscanf(tok, "DEVNAME=%s", dev->devname);
|
||||
} else if (strncmp(tok, "PARTNAME", 8) == 0) {
|
||||
sscanf(tok, "PARTNAME=%s", dev->partname);
|
||||
}
|
||||
tok = strtok(NULL, "\n");
|
||||
}
|
||||
VLOG("%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) {
|
||||
char buffer[1024], path[128];
|
||||
struct dirent *entry;
|
||||
DIR *dir = opendir("/sys/dev/block");
|
||||
if (dir == NULL)
|
||||
return 1;
|
||||
int found = 0;
|
||||
while ((entry = readdir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
snprintf(path, sizeof(path), "/sys/dev/block/%s/uevent", entry->d_name);
|
||||
int fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
ssize_t size = read(fd, buffer, sizeof(buffer));
|
||||
buffer[size] = '\0';
|
||||
close(fd);
|
||||
parse_device(dev, buffer);
|
||||
if (strcmp(dev->partname, partname) == 0) {
|
||||
snprintf(dev->path, sizeof(dev->path), "/dev/block/%s", dev->devname);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
if (!found)
|
||||
return 1;
|
||||
|
||||
mkdir("/dev", 0755);
|
||||
mkdir("/dev/block", 0755);
|
||||
mknod(dev->path, S_IFBLK | 0600, makedev(dev->major, dev->minor));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fstab_patch_cb(int dirfd, struct dirent *entry) {
|
||||
if (entry->d_type == DT_REG && strstr(entry->d_name, "fstab")) {
|
||||
void *buf;
|
||||
size_t _size;
|
||||
uint32_t size;
|
||||
full_read_at(dirfd, entry->d_name, &buf, &_size);
|
||||
size = _size; /* Type conversion */
|
||||
if (!keepverity)
|
||||
patch_verity(&buf, &size, 1);
|
||||
if (!keepencrypt)
|
||||
patch_encryption(&buf, &size);
|
||||
int fstab = xopenat(dirfd, entry->d_name, O_WRONLY | O_CLOEXEC);
|
||||
write(fstab, buf, size);
|
||||
close(fstab);
|
||||
}
|
||||
}
|
||||
|
||||
static void patch_ramdisk(int root) {
|
||||
void *addr;
|
||||
size_t size;
|
||||
mmap_rw("/init", &addr, &size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (memcmp(addr + i, SPLIT_PLAT_CIL, sizeof(SPLIT_PLAT_CIL) - 1) == 0) {
|
||||
memcpy(addr + i + sizeof(SPLIT_PLAT_CIL) - 4, "xxx", 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
munmap(addr, size);
|
||||
|
||||
full_read("/init.rc", &addr, &size);
|
||||
patch_init_rc(&addr, &size);
|
||||
int fd = creat("/init.rc", 0750);
|
||||
write(fd, addr, size);
|
||||
close(fd);
|
||||
free(addr);
|
||||
|
||||
/* Disabled for now */
|
||||
|
||||
// char *key, *value;
|
||||
// full_read("/.backup/.magisk", &addr, &size);
|
||||
// for (char *tok = strtok(addr, "\n"); tok; tok = strtok(NULL, "\n")) {
|
||||
// key = tok;
|
||||
// value = strchr(tok, '=') + 1;
|
||||
// value[-1] = '\0';
|
||||
// if (strcmp(key, "KEEPVERITY") == 0)
|
||||
// keepverity = strcmp(value, "true") == 0;
|
||||
// else if (strcmp(key, "KEEPFORCEENCRYPT") == 0)
|
||||
// keepencrypt = strcmp(value, "true") == 0;
|
||||
// }
|
||||
|
||||
// excl_list = (char *[]) { "system_root", "system", "vendor", NULL };
|
||||
// in_order_walk(root, fstab_patch_cb);
|
||||
// if (!keepverity)
|
||||
// unlink("/verity_key");
|
||||
}
|
||||
|
||||
static int strend(const char *s1, const char *s2) {
|
||||
int l1 = strlen(s1);
|
||||
int l2 = strlen(s2);
|
||||
return strcmp(s1 + l1 - l2, s2);
|
||||
}
|
||||
|
||||
static int compile_cil() {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
char path[128];
|
||||
|
||||
struct cil_db *db = NULL;
|
||||
sepol_policydb_t *pdb = NULL;
|
||||
void *addr;
|
||||
size_t size;
|
||||
|
||||
cil_db_init(&db);
|
||||
cil_set_mls(db, 1);
|
||||
cil_set_multiple_decls(db, 1);
|
||||
cil_set_disable_neverallow(db, 1);
|
||||
cil_set_target_platform(db, SEPOL_TARGET_SELINUX);
|
||||
cil_set_policy_version(db, POLICYDB_VERSION_XPERMS_IOCTL);
|
||||
cil_set_attrs_expand_generated(db, 0);
|
||||
|
||||
// plat
|
||||
mmap_ro(SPLIT_PLAT_CIL, &addr, &size);
|
||||
VLOG("cil_add[%s]\n", SPLIT_PLAT_CIL);
|
||||
cil_add_file(db, SPLIT_PLAT_CIL, addr, size);
|
||||
munmap(addr, size);
|
||||
|
||||
// mapping
|
||||
char plat[10];
|
||||
int fd = open(SPLIT_NONPLAT_VER, O_RDONLY | O_CLOEXEC);
|
||||
plat[read(fd, plat, sizeof(plat)) - 1] = '\0';
|
||||
snprintf(path, sizeof(path), SPLIT_PLAT_MAPPING, plat);
|
||||
mmap_ro(path, &addr, &size);
|
||||
VLOG("cil_add[%s]\n", path);
|
||||
cil_add_file(db, path, addr, size);
|
||||
munmap(addr, size);
|
||||
close(fd);
|
||||
|
||||
// nonplat
|
||||
dir = opendir(NONPLAT_POLICY_DIR);
|
||||
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), NONPLAT_POLICY_DIR "%s", entry->d_name);
|
||||
mmap_ro(path, &addr, &size);
|
||||
VLOG("cil_add[%s]\n", path);
|
||||
cil_add_file(db, path, addr, size);
|
||||
munmap(addr, size);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
cil_compile(db);
|
||||
cil_build_policydb(db, &pdb);
|
||||
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];
|
||||
|
||||
// init the strings with different value
|
||||
sys_sha[0] = 0;
|
||||
ven_sha[0] = 1;
|
||||
|
||||
dir = opendir(NONPLAT_POLICY_DIR);
|
||||
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)) - 1] = '\0';
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
dir = opendir(PLAT_POLICY_DIR);
|
||||
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)) - 1] = '\0';
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
VLOG("sys_sha[%s]\nven_sha[%s]\n", sys_sha, ven_sha);
|
||||
return strcmp(sys_sha, ven_sha) == 0;
|
||||
}
|
||||
|
||||
static int patch_sepolicy() {
|
||||
if (access("/sepolicy", R_OK) == 0)
|
||||
load_policydb("/sepolicy");
|
||||
else if (access(SPLIT_PRECOMPILE, R_OK) == 0 && verify_precompiled())
|
||||
load_policydb(SPLIT_PRECOMPILE);
|
||||
else if (access(SPLIT_PLAT_CIL, R_OK) == 0)
|
||||
compile_cil();
|
||||
else
|
||||
return 1;
|
||||
|
||||
sepol_magisk_rules();
|
||||
dump_policydb("/sepolicy");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BUFSIZE (1 << 20)
|
||||
|
||||
static int unxz(const void *buf, size_t size, int fd) {
|
||||
lzma_stream strm = LZMA_STREAM_INIT;
|
||||
if (lzma_auto_decoder(&strm, UINT64_MAX, 0) != LZMA_OK)
|
||||
return 1;
|
||||
lzma_ret ret = 0;
|
||||
void *out = malloc(BUFSIZE);
|
||||
strm.next_in = buf;
|
||||
strm.avail_in = size;
|
||||
do {
|
||||
strm.next_out = out;
|
||||
strm.avail_out = BUFSIZE;
|
||||
ret = lzma_code(&strm, LZMA_RUN);
|
||||
write(fd, out, BUFSIZE - strm.avail_out);
|
||||
} while (strm.avail_out == 0 && ret == LZMA_OK);
|
||||
|
||||
free(out);
|
||||
lzma_end(&strm);
|
||||
|
||||
if (ret != LZMA_OK && ret != LZMA_STREAM_END)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_magisk(const char *path, mode_t mode) {
|
||||
unlink(path);
|
||||
int fd = creat(path, mode);
|
||||
int ret = unxz(magisk_dump, sizeof(magisk_dump), fd);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dump_magiskrc(const char *path, mode_t mode) {
|
||||
int fd = creat(path, mode);
|
||||
write(fd, magiskrc, sizeof(magiskrc));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void magisk_init_daemon() {
|
||||
setsid();
|
||||
|
||||
// Full patch
|
||||
sepol_allow("su", ALL, ALL, ALL);
|
||||
|
||||
// Wait till init cold boot done
|
||||
while (access("/dev/.coldboot_done", F_OK))
|
||||
usleep(1);
|
||||
|
||||
int null = open("/dev/null", O_RDWR | O_CLOEXEC);
|
||||
dup3(null, STDIN_FILENO, O_CLOEXEC);
|
||||
dup3(null, STDOUT_FILENO, O_CLOEXEC);
|
||||
dup3(null, STDERR_FILENO, O_CLOEXEC);
|
||||
close(null);
|
||||
|
||||
// Transit our context to su (mimic setcon)
|
||||
int fd, crap;
|
||||
fd = open("/proc/self/attr/current", O_WRONLY);
|
||||
write(fd, "u:r:su:s0", 9);
|
||||
close(fd);
|
||||
|
||||
// Dump full patch to kernel
|
||||
dump_policydb(SELINUX_LOAD);
|
||||
close(creat(PATCHDONE, 0));
|
||||
destroy_policydb();
|
||||
|
||||
// Keep Magisk daemon always alive
|
||||
while (1) {
|
||||
struct sockaddr_un sun;
|
||||
fd = setup_socket(&sun);
|
||||
while (connect(fd, (struct sockaddr*) &sun, sizeof(sun)))
|
||||
usleep(10000); /* Wait 10 ms after each try */
|
||||
|
||||
/* Should hold forever */
|
||||
read(fd, &crap, sizeof(crap));
|
||||
|
||||
/* If things went here, it means the other side of the socket is closed
|
||||
* We restart the daemon again */
|
||||
close(fd);
|
||||
if (fork_dont_care() == 0) {
|
||||
execv("/sbin/magisk", (char *[]) { "magisk", "--daemon", NULL } );
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
umask(0);
|
||||
|
||||
for (int i = 0; init_applet[i]; ++i) {
|
||||
if (strcmp(basename(argv[0]), init_applet[i]) == 0)
|
||||
return (*init_applet_main[i])(argc, argv);
|
||||
}
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "-x") == 0) {
|
||||
if (strcmp(argv[2], "magisk") == 0)
|
||||
return dump_magisk(argv[3], 0755);
|
||||
else if (strcmp(argv[2], "magiskrc") == 0)
|
||||
return dump_magiskrc(argv[3], 0755);
|
||||
}
|
||||
|
||||
// Prevent file descriptor confusion
|
||||
mknod("/null", S_IFCHR | 0666, makedev(1, 3));
|
||||
int null = open("/null", O_RDWR | O_CLOEXEC);
|
||||
unlink("/null");
|
||||
dup3(null, STDIN_FILENO, O_CLOEXEC);
|
||||
dup3(null, STDOUT_FILENO, O_CLOEXEC);
|
||||
dup3(null, STDERR_FILENO, O_CLOEXEC);
|
||||
if (null > STDERR_FILENO)
|
||||
close(null);
|
||||
|
||||
// Extract and link files
|
||||
mkdir("/overlay", 0000);
|
||||
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/magiskinit");
|
||||
|
||||
struct cmdline cmd;
|
||||
parse_cmdline(&cmd);
|
||||
|
||||
VLOG("cmdline: skip_initramfs=[%d] slot_suffix=[%s]\n", cmd.skip_initramfs, cmd.slot);
|
||||
|
||||
int root = open("/", O_RDONLY | O_CLOEXEC);
|
||||
|
||||
if (cmd.skip_initramfs) {
|
||||
// Exclude overlay folder
|
||||
excl_list = (char *[]) { "overlay", ".backup", NULL };
|
||||
// Clear rootfs
|
||||
frm_rf(root);
|
||||
|
||||
mkdir("/sys", 0755);
|
||||
xmount("sysfs", "/sys", "sysfs", 0, NULL);
|
||||
|
||||
char partname[32];
|
||||
snprintf(partname, sizeof(partname), "system%s", cmd.slot);
|
||||
|
||||
struct device dev;
|
||||
setup_block(&dev, partname);
|
||||
|
||||
mkdir("/system_root", 0755);
|
||||
xmount(dev.path, "/system_root", "ext4", MS_RDONLY, NULL);
|
||||
int system_root = open("/system_root", O_RDONLY | O_CLOEXEC);
|
||||
|
||||
// Exclude system folder
|
||||
excl_list = (char *[]) { "system", NULL };
|
||||
clone_dir(system_root, root);
|
||||
mkdir("/system", 0755);
|
||||
xmount("/system_root/system", "/system", NULL, MS_BIND, NULL);
|
||||
|
||||
snprintf(partname, sizeof(partname), "vendor%s", cmd.slot);
|
||||
|
||||
// We need to mount independent vendor partition
|
||||
if (setup_block(&dev, partname) == 0)
|
||||
xmount(dev.path, "/vendor", "ext4", MS_RDONLY, NULL);
|
||||
|
||||
close(system_root);
|
||||
} else {
|
||||
if (access("/ramdisk.cpio.xz", R_OK) == 0) {
|
||||
// High compression mode
|
||||
void *addr;
|
||||
size_t size;
|
||||
mmap_ro("/ramdisk.cpio.xz", &addr, &size);
|
||||
int fd = creat("/ramdisk.cpio", 0);
|
||||
unxz(addr, size, fd);
|
||||
munmap(addr, size);
|
||||
close(fd);
|
||||
struct vector v;
|
||||
vec_init(&v);
|
||||
parse_cpio(&v, "/ramdisk.cpio");
|
||||
excl_list = (char *[]) { "overlay", ".backup", NULL };
|
||||
frm_rf(root);
|
||||
chdir("/");
|
||||
cpio_extract_all(&v);
|
||||
cpio_vec_destroy(&v);
|
||||
} else {
|
||||
// Revert original init binary
|
||||
unlink("/init");
|
||||
link("/.backup/init", "/init");
|
||||
}
|
||||
}
|
||||
|
||||
int overlay = open("/overlay", O_RDONLY | O_CLOEXEC);
|
||||
|
||||
// Only patch rootfs if not intended to run in recovery
|
||||
if (access("/etc/recovery.fstab", F_OK) != 0) {
|
||||
mv_dir(overlay, root);
|
||||
|
||||
patch_ramdisk(root);
|
||||
if (patch_sepolicy()) {
|
||||
/* Non skip_initramfs devices using separate sepolicy
|
||||
* Mount /system and try to load again */
|
||||
xmount("sysfs", "/sys", "sysfs", 0, NULL);
|
||||
struct device dev;
|
||||
setup_block(&dev, "system");
|
||||
xmount(dev.path, "/system", "ext4", MS_RDONLY, NULL);
|
||||
// We need to mount independent vendor partition
|
||||
if (setup_block(&dev, "vendor") == 0)
|
||||
xmount(dev.path, "/vendor", "ext4", MS_RDONLY, NULL);
|
||||
|
||||
patch_sepolicy();
|
||||
|
||||
umount("/system");
|
||||
}
|
||||
|
||||
if (fork_dont_care() == 0) {
|
||||
strcpy(argv[0], "magiskinit");
|
||||
close(overlay);
|
||||
close(root);
|
||||
magisk_init_daemon();
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
close(overlay);
|
||||
close(root);
|
||||
umount("/vendor");
|
||||
rmdir("/overlay");
|
||||
|
||||
// Finally, give control back!
|
||||
execv("/init", argv);
|
||||
}
|
152
native/jni/core/socket.c
Normal file
152
native/jni/core/socket.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/* socket.c - All socket related operations
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "logging.h"
|
||||
#include "utils.h"
|
||||
#include "magisk.h"
|
||||
|
||||
/* Setup the address and return socket fd */
|
||||
int setup_socket(struct sockaddr_un *sun) {
|
||||
int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
memset(sun, 0, sizeof(*sun));
|
||||
sun->sun_family = AF_LOCAL;
|
||||
memcpy(sun->sun_path, REQUESTOR_DAEMON_PATH, sizeof(REQUESTOR_DAEMON_PATH) - 1);
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Receive a file descriptor from a Unix socket.
|
||||
* Contributed by @mkasick
|
||||
*
|
||||
* Returns the file descriptor on success, or -1 if a file
|
||||
* descriptor was not actually included in the message
|
||||
*
|
||||
* On error the function terminates by calling exit(-1)
|
||||
*/
|
||||
int recv_fd(int sockfd) {
|
||||
// Need to receive data from the message, otherwise don't care about it.
|
||||
char iovbuf;
|
||||
|
||||
struct iovec iov = {
|
||||
.iov_base = &iovbuf,
|
||||
.iov_len = 1,
|
||||
};
|
||||
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = cmsgbuf,
|
||||
.msg_controllen = sizeof(cmsgbuf),
|
||||
};
|
||||
|
||||
xrecvmsg(sockfd, &msg, MSG_WAITALL);
|
||||
|
||||
// Was a control message actually sent?
|
||||
switch (msg.msg_controllen) {
|
||||
case 0:
|
||||
// No, so the file descriptor was closed and won't be used.
|
||||
return -1;
|
||||
case sizeof(cmsgbuf):
|
||||
// Yes, grab the file descriptor from it.
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||
|
||||
if (cmsg == NULL ||
|
||||
cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
|
||||
cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
error:
|
||||
LOGE("unable to read fd");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return *(int *)CMSG_DATA(cmsg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a file descriptor through a Unix socket.
|
||||
* Contributed by @mkasick
|
||||
*
|
||||
* On error the function terminates by calling exit(-1)
|
||||
*
|
||||
* fd may be -1, in which case the dummy data is sent,
|
||||
* but no control message with the FD is sent.
|
||||
*/
|
||||
void send_fd(int sockfd, int fd) {
|
||||
// Need to send some data in the message, this will do.
|
||||
struct iovec iov = {
|
||||
.iov_base = "",
|
||||
.iov_len = 1,
|
||||
};
|
||||
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||
|
||||
if (fd != -1) {
|
||||
// Is the file descriptor actually open?
|
||||
if (fcntl(fd, F_GETFD) == -1) {
|
||||
if (errno != EBADF) {
|
||||
PLOGE("unable to send fd");
|
||||
}
|
||||
// It's closed, don't send a control message or sendmsg will EBADF.
|
||||
} else {
|
||||
// It's open, send the file descriptor in a control message.
|
||||
msg.msg_control = cmsgbuf;
|
||||
msg.msg_controllen = sizeof(cmsgbuf);
|
||||
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
|
||||
*(int *)CMSG_DATA(cmsg) = fd;
|
||||
}
|
||||
}
|
||||
|
||||
xsendmsg(sockfd, &msg, 0);
|
||||
}
|
||||
|
||||
int read_int(int fd) {
|
||||
int val;
|
||||
xxread(fd, &val, sizeof(int));
|
||||
return val;
|
||||
}
|
||||
|
||||
void write_int(int fd, int val) {
|
||||
if (fd < 0) return;
|
||||
xwrite(fd, &val, sizeof(int));
|
||||
}
|
||||
|
||||
char* read_string(int fd) {
|
||||
int len = read_int(fd);
|
||||
if (len > PATH_MAX || len < 0) {
|
||||
LOGE("invalid string length %d", len);
|
||||
exit(1);
|
||||
}
|
||||
char* val = xmalloc(sizeof(char) * (len + 1));
|
||||
xxread(fd, val, len);
|
||||
val[len] = '\0';
|
||||
return val;
|
||||
}
|
||||
|
||||
void write_string(int fd, const char* val) {
|
||||
if (fd < 0) return;
|
||||
int len = strlen(val);
|
||||
write_int(fd, len);
|
||||
xwrite(fd, val, len);
|
||||
}
|
158
native/jni/external/Android.mk
vendored
Normal file
158
native/jni/external/Android.mk
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
# libsqlite.so (stub)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:= libsqlite
|
||||
LOCAL_C_INCLUDES := jni/external/include
|
||||
LOCAL_SRC_FILES := stubs/sqlite3_stub.c
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# libselinux.so (stub)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:= libselinux
|
||||
LOCAL_C_INCLUDES := $(LIBSELINUX)
|
||||
LOCAL_SRC_FILES := stubs/selinux_stub.c
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# libfdt.a
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:= libfdt
|
||||
LOCAL_C_INCLUDES := $(LIBFDT)
|
||||
LOCAL_SRC_FILES := \
|
||||
dtc/libfdt/fdt.c \
|
||||
dtc/libfdt/fdt_addresses.c \
|
||||
dtc/libfdt/fdt_empty_tree.c \
|
||||
dtc/libfdt/fdt_overlay.c \
|
||||
dtc/libfdt/fdt_ro.c \
|
||||
dtc/libfdt/fdt_rw.c \
|
||||
dtc/libfdt/fdt_strerror.c \
|
||||
dtc/libfdt/fdt_sw.c \
|
||||
dtc/libfdt/fdt_wip.c
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# liblz4.a
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := liblz4
|
||||
LOCAL_C_INCLUDES += $(LIBLZ4)
|
||||
LOCAL_SRC_FILES := \
|
||||
lz4/lib/lz4.c \
|
||||
lz4/lib/lz4frame.c \
|
||||
lz4/lib/lz4hc.c \
|
||||
lz4/lib/xxhash.c
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# libbz2.a
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libbz2
|
||||
LOCAL_C_INCLUDES += $(LIBBZ2)
|
||||
LOCAL_SRC_FILES := \
|
||||
bzip2/blocksort.c \
|
||||
bzip2/huffman.c \
|
||||
bzip2/crctable.c \
|
||||
bzip2/randtable.c \
|
||||
bzip2/compress.c \
|
||||
bzip2/decompress.c \
|
||||
bzip2/bzlib.c
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# liblzma.a
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := liblzma
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(EXT_PATH)/include/xz_config \
|
||||
$(EXT_PATH)/xz/src/common \
|
||||
$(EXT_PATH)/xz/src/liblzma/api \
|
||||
$(EXT_PATH)/xz/src/liblzma/check \
|
||||
$(EXT_PATH)/xz/src/liblzma/common \
|
||||
$(EXT_PATH)/xz/src/liblzma/delta \
|
||||
$(EXT_PATH)/xz/src/liblzma/lz \
|
||||
$(EXT_PATH)/xz/src/liblzma/lzma \
|
||||
$(EXT_PATH)/xz/src/liblzma/rangecoder \
|
||||
$(EXT_PATH)/xz/src/liblzma/simple \
|
||||
$(EXT_PATH)/xz/src/liblzma
|
||||
LOCAL_SRC_FILES := \
|
||||
xz/src/common/tuklib_cpucores.c \
|
||||
xz/src/common/tuklib_exit.c \
|
||||
xz/src/common/tuklib_mbstr_fw.c \
|
||||
xz/src/common/tuklib_mbstr_width.c \
|
||||
xz/src/common/tuklib_open_stdxxx.c \
|
||||
xz/src/common/tuklib_physmem.c \
|
||||
xz/src/common/tuklib_progname.c \
|
||||
xz/src/liblzma/check/check.c \
|
||||
xz/src/liblzma/check/crc32_fast.c \
|
||||
xz/src/liblzma/check/crc32_table.c \
|
||||
xz/src/liblzma/check/crc64_fast.c \
|
||||
xz/src/liblzma/check/crc64_table.c \
|
||||
xz/src/liblzma/check/sha256.c \
|
||||
xz/src/liblzma/common/alone_decoder.c \
|
||||
xz/src/liblzma/common/alone_encoder.c \
|
||||
xz/src/liblzma/common/auto_decoder.c \
|
||||
xz/src/liblzma/common/block_buffer_decoder.c \
|
||||
xz/src/liblzma/common/block_buffer_encoder.c \
|
||||
xz/src/liblzma/common/block_decoder.c \
|
||||
xz/src/liblzma/common/block_encoder.c \
|
||||
xz/src/liblzma/common/block_header_decoder.c \
|
||||
xz/src/liblzma/common/block_header_encoder.c \
|
||||
xz/src/liblzma/common/block_util.c \
|
||||
xz/src/liblzma/common/common.c \
|
||||
xz/src/liblzma/common/easy_buffer_encoder.c \
|
||||
xz/src/liblzma/common/easy_decoder_memusage.c \
|
||||
xz/src/liblzma/common/easy_encoder.c \
|
||||
xz/src/liblzma/common/easy_encoder_memusage.c \
|
||||
xz/src/liblzma/common/easy_preset.c \
|
||||
xz/src/liblzma/common/filter_buffer_decoder.c \
|
||||
xz/src/liblzma/common/filter_buffer_encoder.c \
|
||||
xz/src/liblzma/common/filter_common.c \
|
||||
xz/src/liblzma/common/filter_decoder.c \
|
||||
xz/src/liblzma/common/filter_encoder.c \
|
||||
xz/src/liblzma/common/filter_flags_decoder.c \
|
||||
xz/src/liblzma/common/filter_flags_encoder.c \
|
||||
xz/src/liblzma/common/hardware_cputhreads.c \
|
||||
xz/src/liblzma/common/hardware_physmem.c \
|
||||
xz/src/liblzma/common/index.c \
|
||||
xz/src/liblzma/common/index_decoder.c \
|
||||
xz/src/liblzma/common/index_encoder.c \
|
||||
xz/src/liblzma/common/index_hash.c \
|
||||
xz/src/liblzma/common/outqueue.c \
|
||||
xz/src/liblzma/common/stream_buffer_decoder.c \
|
||||
xz/src/liblzma/common/stream_buffer_encoder.c \
|
||||
xz/src/liblzma/common/stream_decoder.c \
|
||||
xz/src/liblzma/common/stream_encoder.c \
|
||||
xz/src/liblzma/common/stream_encoder_mt.c \
|
||||
xz/src/liblzma/common/stream_flags_common.c \
|
||||
xz/src/liblzma/common/stream_flags_decoder.c \
|
||||
xz/src/liblzma/common/stream_flags_encoder.c \
|
||||
xz/src/liblzma/common/vli_decoder.c \
|
||||
xz/src/liblzma/common/vli_encoder.c \
|
||||
xz/src/liblzma/common/vli_size.c \
|
||||
xz/src/liblzma/delta/delta_common.c \
|
||||
xz/src/liblzma/delta/delta_decoder.c \
|
||||
xz/src/liblzma/delta/delta_encoder.c \
|
||||
xz/src/liblzma/lz/lz_decoder.c \
|
||||
xz/src/liblzma/lz/lz_encoder.c \
|
||||
xz/src/liblzma/lz/lz_encoder_mf.c \
|
||||
xz/src/liblzma/lzma/fastpos_table.c \
|
||||
xz/src/liblzma/lzma/fastpos_tablegen.c \
|
||||
xz/src/liblzma/lzma/lzma2_decoder.c \
|
||||
xz/src/liblzma/lzma/lzma2_encoder.c \
|
||||
xz/src/liblzma/lzma/lzma_decoder.c \
|
||||
xz/src/liblzma/lzma/lzma_encoder.c \
|
||||
xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c \
|
||||
xz/src/liblzma/lzma/lzma_encoder_optimum_normal.c \
|
||||
xz/src/liblzma/lzma/lzma_encoder_presets.c \
|
||||
xz/src/liblzma/rangecoder/price_table.c \
|
||||
xz/src/liblzma/rangecoder/price_tablegen.c \
|
||||
xz/src/liblzma/simple/arm.c \
|
||||
xz/src/liblzma/simple/armthumb.c \
|
||||
xz/src/liblzma/simple/ia64.c \
|
||||
xz/src/liblzma/simple/powerpc.c \
|
||||
xz/src/liblzma/simple/simple_coder.c \
|
||||
xz/src/liblzma/simple/simple_decoder.c \
|
||||
xz/src/liblzma/simple/simple_encoder.c \
|
||||
xz/src/liblzma/simple/sparc.c \
|
||||
xz/src/liblzma/simple/x86.c
|
||||
LOCAL_CFLAGS += -DHAVE_CONFIG_H -std=c99
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# libsepol.a
|
||||
include $(SE_PATH)/libsepol/Android.mk
|
1
native/jni/external/busybox
vendored
Submodule
1
native/jni/external/busybox
vendored
Submodule
Submodule native/jni/external/busybox added at e3a1a4d91f
1
native/jni/external/bzip2
vendored
Submodule
1
native/jni/external/bzip2
vendored
Submodule
Submodule native/jni/external/bzip2 added at 67d818584d
1
native/jni/external/dtc
vendored
Submodule
1
native/jni/external/dtc
vendored
Submodule
Submodule native/jni/external/dtc added at 22a65c5331
44
native/jni/external/include/sha1.h
vendored
Normal file
44
native/jni/external/include/sha1.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef SHA1_H
|
||||
#define SHA1_H
|
||||
|
||||
/*
|
||||
SHA-1 in C
|
||||
By Steve Reid <steve@edmweb.com>
|
||||
100% Public Domain
|
||||
*/
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t state[5];
|
||||
uint32_t count[2];
|
||||
unsigned char buffer[64];
|
||||
} SHA1_CTX;
|
||||
|
||||
void SHA1Transform(
|
||||
uint32_t state[5],
|
||||
const unsigned char buffer[64]
|
||||
);
|
||||
|
||||
void SHA1Init(
|
||||
SHA1_CTX * context
|
||||
);
|
||||
|
||||
void SHA1Update(
|
||||
SHA1_CTX * context,
|
||||
const unsigned char *data,
|
||||
uint32_t len
|
||||
);
|
||||
|
||||
void SHA1Final(
|
||||
unsigned char digest[20],
|
||||
SHA1_CTX * context
|
||||
);
|
||||
|
||||
void SHA1(
|
||||
char *hash_out,
|
||||
const char *str,
|
||||
int len);
|
||||
|
||||
#endif /* SHA1_H */
|
10491
native/jni/external/include/sqlite3.h
vendored
Normal file
10491
native/jni/external/include/sqlite3.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
498
native/jni/external/include/xz_config/config.h
vendored
Normal file
498
native/jni/external/include/xz_config/config.h
vendored
Normal file
@@ -0,0 +1,498 @@
|
||||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
/* #undef AC_APPLE_UNIVERSAL_BUILD */
|
||||
|
||||
/* How many MiB of RAM to assume if the real amount cannot be determined. */
|
||||
#define ASSUME_RAM 128
|
||||
|
||||
/* Define to 1 if translation of program messages to the user's native
|
||||
language is requested. */
|
||||
/* #undef ENABLE_NLS */
|
||||
|
||||
/* Define to 1 if bswap_16 is available. */
|
||||
#define HAVE_BSWAP_16 1
|
||||
|
||||
/* Define to 1 if bswap_32 is available. */
|
||||
#define HAVE_BSWAP_32 1
|
||||
|
||||
/* Define to 1 if bswap_64 is available. */
|
||||
#define HAVE_BSWAP_64 1
|
||||
|
||||
/* Define to 1 if you have the <byteswap.h> header file. */
|
||||
#define HAVE_BYTESWAP_H 1
|
||||
|
||||
/* Define to 1 if Capsicum is available. */
|
||||
/* #undef HAVE_CAPSICUM */
|
||||
|
||||
/* Define to 1 if the system has the type `CC_SHA256_CTX'. */
|
||||
/* #undef HAVE_CC_SHA256_CTX */
|
||||
|
||||
/* Define to 1 if you have the `CC_SHA256_Init' function. */
|
||||
/* #undef HAVE_CC_SHA256_INIT */
|
||||
|
||||
/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
|
||||
CoreFoundation framework. */
|
||||
/* #undef HAVE_CFLOCALECOPYCURRENT */
|
||||
|
||||
/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
|
||||
the CoreFoundation framework. */
|
||||
/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */
|
||||
|
||||
/* Define to 1 if crc32 integrity check is enabled. */
|
||||
#define HAVE_CHECK_CRC32 1
|
||||
|
||||
/* Define to 1 if crc64 integrity check is enabled. */
|
||||
#define HAVE_CHECK_CRC64 1
|
||||
|
||||
/* Define to 1 if sha256 integrity check is enabled. */
|
||||
#define HAVE_CHECK_SHA256 1
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
#define HAVE_CLOCK_GETTIME 1
|
||||
|
||||
/* Define to 1 if you have the <CommonCrypto/CommonDigest.h> header file. */
|
||||
/* #undef HAVE_COMMONCRYPTO_COMMONDIGEST_H */
|
||||
|
||||
/* Define if the GNU dcgettext() function is already present or preinstalled.
|
||||
*/
|
||||
/* #undef HAVE_DCGETTEXT */
|
||||
|
||||
/* Define to 1 if you have the declaration of `CLOCK_MONOTONIC', and to 0 if
|
||||
you don't. */
|
||||
#define HAVE_DECL_CLOCK_MONOTONIC 1
|
||||
|
||||
/* Define to 1 if you have the declaration of `program_invocation_name', and
|
||||
to 0 if you don't. */
|
||||
#define HAVE_DECL_PROGRAM_INVOCATION_NAME 0
|
||||
|
||||
/* Define to 1 if any of HAVE_DECODER_foo have been defined. */
|
||||
#define HAVE_DECODERS 1
|
||||
|
||||
/* Define to 1 if arm decoder is enabled. */
|
||||
#define HAVE_DECODER_ARM 1
|
||||
|
||||
/* Define to 1 if armthumb decoder is enabled. */
|
||||
#define HAVE_DECODER_ARMTHUMB 1
|
||||
|
||||
/* Define to 1 if delta decoder is enabled. */
|
||||
#define HAVE_DECODER_DELTA 1
|
||||
|
||||
/* Define to 1 if ia64 decoder is enabled. */
|
||||
#define HAVE_DECODER_IA64 1
|
||||
|
||||
/* Define to 1 if lzma1 decoder is enabled. */
|
||||
#define HAVE_DECODER_LZMA1 1
|
||||
|
||||
/* Define to 1 if lzma2 decoder is enabled. */
|
||||
#define HAVE_DECODER_LZMA2 1
|
||||
|
||||
/* Define to 1 if powerpc decoder is enabled. */
|
||||
#define HAVE_DECODER_POWERPC 1
|
||||
|
||||
/* Define to 1 if sparc decoder is enabled. */
|
||||
#define HAVE_DECODER_SPARC 1
|
||||
|
||||
/* Define to 1 if x86 decoder is enabled. */
|
||||
#define HAVE_DECODER_X86 1
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if any of HAVE_ENCODER_foo have been defined. */
|
||||
#define HAVE_ENCODERS 1
|
||||
|
||||
/* Define to 1 if arm encoder is enabled. */
|
||||
#define HAVE_ENCODER_ARM 1
|
||||
|
||||
/* Define to 1 if armthumb encoder is enabled. */
|
||||
#define HAVE_ENCODER_ARMTHUMB 1
|
||||
|
||||
/* Define to 1 if delta encoder is enabled. */
|
||||
#define HAVE_ENCODER_DELTA 1
|
||||
|
||||
/* Define to 1 if ia64 encoder is enabled. */
|
||||
#define HAVE_ENCODER_IA64 1
|
||||
|
||||
/* Define to 1 if lzma1 encoder is enabled. */
|
||||
#define HAVE_ENCODER_LZMA1 1
|
||||
|
||||
/* Define to 1 if lzma2 encoder is enabled. */
|
||||
#define HAVE_ENCODER_LZMA2 1
|
||||
|
||||
/* Define to 1 if powerpc encoder is enabled. */
|
||||
#define HAVE_ENCODER_POWERPC 1
|
||||
|
||||
/* Define to 1 if sparc encoder is enabled. */
|
||||
#define HAVE_ENCODER_SPARC 1
|
||||
|
||||
/* Define to 1 if x86 encoder is enabled. */
|
||||
#define HAVE_ENCODER_X86 1
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the `futimens' function. */
|
||||
#define HAVE_FUTIMENS 1
|
||||
|
||||
/* Define to 1 if you have the `futimes' function. */
|
||||
/* #undef HAVE_FUTIMES */
|
||||
|
||||
/* Define to 1 if you have the `futimesat' function. */
|
||||
/* #undef HAVE_FUTIMESAT */
|
||||
|
||||
/* Define to 1 if you have the <getopt.h> header file. */
|
||||
#define HAVE_GETOPT_H 1
|
||||
|
||||
/* Define to 1 if you have the `getopt_long' function. */
|
||||
#define HAVE_GETOPT_LONG 1
|
||||
|
||||
/* Define if the GNU gettext() function is already present or preinstalled. */
|
||||
/* #undef HAVE_GETTEXT */
|
||||
|
||||
/* Define if you have the iconv() function and it works. */
|
||||
/* #undef HAVE_ICONV */
|
||||
|
||||
/* Define to 1 if you have the <immintrin.h> header file. */
|
||||
/* #undef HAVE_IMMINTRIN_H */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
|
||||
#define HAVE_MBRTOWC 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 to enable bt2 match finder. */
|
||||
#define HAVE_MF_BT2 1
|
||||
|
||||
/* Define to 1 to enable bt3 match finder. */
|
||||
#define HAVE_MF_BT3 1
|
||||
|
||||
/* Define to 1 to enable bt4 match finder. */
|
||||
#define HAVE_MF_BT4 1
|
||||
|
||||
/* Define to 1 to enable hc3 match finder. */
|
||||
#define HAVE_MF_HC3 1
|
||||
|
||||
/* Define to 1 to enable hc4 match finder. */
|
||||
#define HAVE_MF_HC4 1
|
||||
|
||||
/* Define to 1 if you have the <minix/sha2.h> header file. */
|
||||
/* #undef HAVE_MINIX_SHA2_H */
|
||||
|
||||
/* Define to 1 if getopt.h declares extern int optreset. */
|
||||
#define HAVE_OPTRESET 1
|
||||
|
||||
/* Define to 1 if you have the `posix_fadvise' function. */
|
||||
#define HAVE_POSIX_FADVISE 1
|
||||
|
||||
/* Define to 1 if you have the `pthread_condattr_setclock' function. */
|
||||
#define HAVE_PTHREAD_CONDATTR_SETCLOCK 1
|
||||
|
||||
/* Have PTHREAD_PRIO_INHERIT. */
|
||||
/* #undef HAVE_PTHREAD_PRIO_INHERIT */
|
||||
|
||||
/* Define to 1 if you have the `SHA256Init' function. */
|
||||
/* #undef HAVE_SHA256INIT */
|
||||
|
||||
/* Define to 1 if the system has the type `SHA256_CTX'. */
|
||||
/* #undef HAVE_SHA256_CTX */
|
||||
|
||||
/* Define to 1 if you have the <sha256.h> header file. */
|
||||
/* #undef HAVE_SHA256_H */
|
||||
|
||||
/* Define to 1 if you have the `SHA256_Init' function. */
|
||||
/* #undef HAVE_SHA256_INIT */
|
||||
|
||||
/* Define to 1 if the system has the type `SHA2_CTX'. */
|
||||
/* #undef HAVE_SHA2_CTX */
|
||||
|
||||
/* Define to 1 if you have the <sha2.h> header file. */
|
||||
/* #undef HAVE_SHA2_H */
|
||||
|
||||
/* Define to 1 if optimizing for size. */
|
||||
/* #undef HAVE_SMALL */
|
||||
|
||||
/* Define to 1 if stdbool.h conforms to C99. */
|
||||
#define HAVE_STDBOOL_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if `st_atimensec' is a member of `struct stat'. */
|
||||
#define HAVE_STRUCT_STAT_ST_ATIMENSEC 1
|
||||
|
||||
/* Define to 1 if `st_atimespec.tv_nsec' is a member of `struct stat'. */
|
||||
/* #undef HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC */
|
||||
|
||||
/* Define to 1 if `st_atim.st__tim.tv_nsec' is a member of `struct stat'. */
|
||||
/* #undef HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC */
|
||||
|
||||
/* Define to 1 if `st_atim.tv_nsec' is a member of `struct stat'. */
|
||||
/* #undef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC */
|
||||
|
||||
/* Define to 1 if `st_uatime' is a member of `struct stat'. */
|
||||
/* #undef HAVE_STRUCT_STAT_ST_UATIME */
|
||||
|
||||
/* Define to 1 if you have the <sys/byteorder.h> header file. */
|
||||
/* #undef HAVE_SYS_BYTEORDER_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/capsicum.h> header file. */
|
||||
/* #undef HAVE_SYS_CAPSICUM_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/endian.h> header file. */
|
||||
/* #undef HAVE_SYS_ENDIAN_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if the system has the type `uintptr_t'. */
|
||||
#define HAVE_UINTPTR_T 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the `utime' function. */
|
||||
/* #undef HAVE_UTIME */
|
||||
|
||||
/* Define to 1 if you have the `utimes' function. */
|
||||
/* #undef HAVE_UTIMES */
|
||||
|
||||
/* Define to 1 or 0, depending whether the compiler supports simple visibility
|
||||
declarations. */
|
||||
#define HAVE_VISIBILITY 1
|
||||
|
||||
/* Define to 1 if you have the `wcwidth' function. */
|
||||
#define HAVE_WCWIDTH 1
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#define HAVE__BOOL 1
|
||||
|
||||
/* Define to 1 if _mm_movemask_epi8 is available. */
|
||||
/* #undef HAVE__MM_MOVEMASK_EPI8 */
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Define to 1 when using POSIX threads (pthreads). */
|
||||
#define MYTHREAD_POSIX 1
|
||||
|
||||
/* Define to 1 when using Windows Vista compatible threads. This uses features
|
||||
that are not available on Windows XP. */
|
||||
/* #undef MYTHREAD_VISTA */
|
||||
|
||||
/* Define to 1 when using Windows 95 (and thus XP) compatible threads. This
|
||||
avoids use of features that were added in Windows Vista. */
|
||||
/* #undef MYTHREAD_WIN95 */
|
||||
|
||||
/* Define to 1 to disable debugging code. */
|
||||
#define NDEBUG 1
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "xz"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "lasse.collin@tukaani.org"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "XZ Utils"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "XZ Utils 5.3.0alpha"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "xz"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL "http://tukaani.org/xz/"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "5.3.0alpha"
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
/* #undef PTHREAD_CREATE_JOINABLE */
|
||||
|
||||
/* The size of `size_t', as computed by sizeof. */
|
||||
#define SIZEOF_SIZE_T 4
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Define to 1 if the number of available CPU cores can be detected with
|
||||
cpuset(2). */
|
||||
/* #undef TUKLIB_CPUCORES_CPUSET */
|
||||
|
||||
/* Define to 1 if the number of available CPU cores can be detected with
|
||||
pstat_getdynamic(). */
|
||||
/* #undef TUKLIB_CPUCORES_PSTAT_GETDYNAMIC */
|
||||
|
||||
/* Define to 1 if the number of available CPU cores can be detected with
|
||||
sysconf(_SC_NPROCESSORS_ONLN) or sysconf(_SC_NPROC_ONLN). */
|
||||
#define TUKLIB_CPUCORES_SYSCONF 1
|
||||
|
||||
/* Define to 1 if the number of available CPU cores can be detected with
|
||||
sysctl(). */
|
||||
/* #undef TUKLIB_CPUCORES_SYSCTL */
|
||||
|
||||
/* Define to 1 if the system supports fast unaligned access to 16-bit and
|
||||
32-bit integers. */
|
||||
/* #undef TUKLIB_FAST_UNALIGNED_ACCESS */
|
||||
|
||||
/* Define to 1 if the amount of physical memory can be detected with
|
||||
_system_configuration.physmem. */
|
||||
/* #undef TUKLIB_PHYSMEM_AIX */
|
||||
|
||||
/* Define to 1 if the amount of physical memory can be detected with
|
||||
getinvent_r(). */
|
||||
/* #undef TUKLIB_PHYSMEM_GETINVENT_R */
|
||||
|
||||
/* Define to 1 if the amount of physical memory can be detected with
|
||||
getsysinfo(). */
|
||||
/* #undef TUKLIB_PHYSMEM_GETSYSINFO */
|
||||
|
||||
/* Define to 1 if the amount of physical memory can be detected with
|
||||
pstat_getstatic(). */
|
||||
/* #undef TUKLIB_PHYSMEM_PSTAT_GETSTATIC */
|
||||
|
||||
/* Define to 1 if the amount of physical memory can be detected with
|
||||
sysconf(_SC_PAGESIZE) and sysconf(_SC_PHYS_PAGES). */
|
||||
#define TUKLIB_PHYSMEM_SYSCONF 1
|
||||
|
||||
/* Define to 1 if the amount of physical memory can be detected with sysctl().
|
||||
*/
|
||||
/* #undef TUKLIB_PHYSMEM_SYSCTL */
|
||||
|
||||
/* Define to 1 if the amount of physical memory can be detected with Linux
|
||||
sysinfo(). */
|
||||
/* #undef TUKLIB_PHYSMEM_SYSINFO */
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# define _ALL_SOURCE 1
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# define _POSIX_PTHREAD_SEMANTICS 1
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# define _TANDEM_SOURCE 1
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# define __EXTENSIONS__ 1
|
||||
#endif
|
||||
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "5.3.0alpha"
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
/* # undef WORDS_BIGENDIAN */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Enable large inode numbers on Mac OS X 10.5. */
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
# define _DARWIN_USE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
/* #undef _FILE_OFFSET_BITS */
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
/* #undef _LARGE_FILES */
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
/* #undef _MINIX */
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
/* #undef _POSIX_1_SOURCE */
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
/* #undef _POSIX_SOURCE */
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
/* #undef _UINT32_T */
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
/* #undef _UINT64_T */
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
/* #undef _UINT8_T */
|
||||
|
||||
/* Define to rpl_ if the getopt replacement functions and variables should be
|
||||
used. */
|
||||
/* #undef __GETOPT_PREFIX */
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 32 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef int32_t */
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 64 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef int64_t */
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 16 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef uint16_t */
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 32 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef uint32_t */
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 64 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef uint64_t */
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 8 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
/* #undef uint8_t */
|
||||
|
||||
/* Define to the type of an unsigned integer type wide enough to hold a
|
||||
pointer, if such a type exists, and if the system does not define it. */
|
||||
/* #undef uintptr_t */
|
1
native/jni/external/lz4
vendored
Submodule
1
native/jni/external/lz4
vendored
Submodule
Submodule native/jni/external/lz4 added at c10863b98e
1
native/jni/external/selinux
vendored
Submodule
1
native/jni/external/selinux
vendored
Submodule
Submodule native/jni/external/selinux added at 8e849a5639
295
native/jni/external/sha1/sha1.c
vendored
Normal file
295
native/jni/external/sha1/sha1.c
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
SHA-1 in C
|
||||
By Steve Reid <steve@edmweb.com>
|
||||
100% Public Domain
|
||||
|
||||
Test Vectors (from FIPS PUB 180-1)
|
||||
"abc"
|
||||
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||
A million repetitions of "a"
|
||||
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||
*/
|
||||
|
||||
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
|
||||
/* #define SHA1HANDSOFF * Copies data before messing with it. */
|
||||
|
||||
#define SHA1HANDSOFF
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* for uint32_t */
|
||||
#include <stdint.h>
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
|
||||
/* blk0() and blk() perform the initial expand. */
|
||||
/* I got the idea of expanding during the round function from SSLeay */
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|
||||
|(rol(block->l[i],8)&0x00FF00FF))
|
||||
#elif BYTE_ORDER == BIG_ENDIAN
|
||||
#define blk0(i) block->l[i]
|
||||
#else
|
||||
#error "Endianness not defined!"
|
||||
#endif
|
||||
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
|
||||
^block->l[(i+2)&15]^block->l[i&15],1))
|
||||
|
||||
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
||||
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
||||
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
||||
|
||||
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
|
||||
void SHA1Transform(
|
||||
uint32_t state[5],
|
||||
const unsigned char buffer[64]
|
||||
)
|
||||
{
|
||||
uint32_t a, b, c, d, e;
|
||||
|
||||
typedef union
|
||||
{
|
||||
unsigned char c[64];
|
||||
uint32_t l[16];
|
||||
} CHAR64LONG16;
|
||||
|
||||
#ifdef SHA1HANDSOFF
|
||||
CHAR64LONG16 block[1]; /* use array to appear as a pointer */
|
||||
|
||||
memcpy(block, buffer, 64);
|
||||
#else
|
||||
/* The following had better never be used because it causes the
|
||||
* pointer-to-const buffer to be cast into a pointer to non-const.
|
||||
* And the result is written through. I threw a "const" in, hoping
|
||||
* this will cause a diagnostic.
|
||||
*/
|
||||
CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer;
|
||||
#endif
|
||||
/* Copy context->state[] to working vars */
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
R0(a, b, c, d, e, 0);
|
||||
R0(e, a, b, c, d, 1);
|
||||
R0(d, e, a, b, c, 2);
|
||||
R0(c, d, e, a, b, 3);
|
||||
R0(b, c, d, e, a, 4);
|
||||
R0(a, b, c, d, e, 5);
|
||||
R0(e, a, b, c, d, 6);
|
||||
R0(d, e, a, b, c, 7);
|
||||
R0(c, d, e, a, b, 8);
|
||||
R0(b, c, d, e, a, 9);
|
||||
R0(a, b, c, d, e, 10);
|
||||
R0(e, a, b, c, d, 11);
|
||||
R0(d, e, a, b, c, 12);
|
||||
R0(c, d, e, a, b, 13);
|
||||
R0(b, c, d, e, a, 14);
|
||||
R0(a, b, c, d, e, 15);
|
||||
R1(e, a, b, c, d, 16);
|
||||
R1(d, e, a, b, c, 17);
|
||||
R1(c, d, e, a, b, 18);
|
||||
R1(b, c, d, e, a, 19);
|
||||
R2(a, b, c, d, e, 20);
|
||||
R2(e, a, b, c, d, 21);
|
||||
R2(d, e, a, b, c, 22);
|
||||
R2(c, d, e, a, b, 23);
|
||||
R2(b, c, d, e, a, 24);
|
||||
R2(a, b, c, d, e, 25);
|
||||
R2(e, a, b, c, d, 26);
|
||||
R2(d, e, a, b, c, 27);
|
||||
R2(c, d, e, a, b, 28);
|
||||
R2(b, c, d, e, a, 29);
|
||||
R2(a, b, c, d, e, 30);
|
||||
R2(e, a, b, c, d, 31);
|
||||
R2(d, e, a, b, c, 32);
|
||||
R2(c, d, e, a, b, 33);
|
||||
R2(b, c, d, e, a, 34);
|
||||
R2(a, b, c, d, e, 35);
|
||||
R2(e, a, b, c, d, 36);
|
||||
R2(d, e, a, b, c, 37);
|
||||
R2(c, d, e, a, b, 38);
|
||||
R2(b, c, d, e, a, 39);
|
||||
R3(a, b, c, d, e, 40);
|
||||
R3(e, a, b, c, d, 41);
|
||||
R3(d, e, a, b, c, 42);
|
||||
R3(c, d, e, a, b, 43);
|
||||
R3(b, c, d, e, a, 44);
|
||||
R3(a, b, c, d, e, 45);
|
||||
R3(e, a, b, c, d, 46);
|
||||
R3(d, e, a, b, c, 47);
|
||||
R3(c, d, e, a, b, 48);
|
||||
R3(b, c, d, e, a, 49);
|
||||
R3(a, b, c, d, e, 50);
|
||||
R3(e, a, b, c, d, 51);
|
||||
R3(d, e, a, b, c, 52);
|
||||
R3(c, d, e, a, b, 53);
|
||||
R3(b, c, d, e, a, 54);
|
||||
R3(a, b, c, d, e, 55);
|
||||
R3(e, a, b, c, d, 56);
|
||||
R3(d, e, a, b, c, 57);
|
||||
R3(c, d, e, a, b, 58);
|
||||
R3(b, c, d, e, a, 59);
|
||||
R4(a, b, c, d, e, 60);
|
||||
R4(e, a, b, c, d, 61);
|
||||
R4(d, e, a, b, c, 62);
|
||||
R4(c, d, e, a, b, 63);
|
||||
R4(b, c, d, e, a, 64);
|
||||
R4(a, b, c, d, e, 65);
|
||||
R4(e, a, b, c, d, 66);
|
||||
R4(d, e, a, b, c, 67);
|
||||
R4(c, d, e, a, b, 68);
|
||||
R4(b, c, d, e, a, 69);
|
||||
R4(a, b, c, d, e, 70);
|
||||
R4(e, a, b, c, d, 71);
|
||||
R4(d, e, a, b, c, 72);
|
||||
R4(c, d, e, a, b, 73);
|
||||
R4(b, c, d, e, a, 74);
|
||||
R4(a, b, c, d, e, 75);
|
||||
R4(e, a, b, c, d, 76);
|
||||
R4(d, e, a, b, c, 77);
|
||||
R4(c, d, e, a, b, 78);
|
||||
R4(b, c, d, e, a, 79);
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
/* Wipe variables */
|
||||
a = b = c = d = e = 0;
|
||||
#ifdef SHA1HANDSOFF
|
||||
memset(block, '\0', sizeof(block));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* SHA1Init - Initialize new context */
|
||||
|
||||
void SHA1Init(
|
||||
SHA1_CTX * context
|
||||
)
|
||||
{
|
||||
/* SHA1 initialization constants */
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xEFCDAB89;
|
||||
context->state[2] = 0x98BADCFE;
|
||||
context->state[3] = 0x10325476;
|
||||
context->state[4] = 0xC3D2E1F0;
|
||||
context->count[0] = context->count[1] = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Run your data through this. */
|
||||
|
||||
void SHA1Update(
|
||||
SHA1_CTX * context,
|
||||
const unsigned char *data,
|
||||
uint32_t len
|
||||
)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
uint32_t j;
|
||||
|
||||
j = context->count[0];
|
||||
if ((context->count[0] += len << 3) < j)
|
||||
context->count[1]++;
|
||||
context->count[1] += (len >> 29);
|
||||
j = (j >> 3) & 63;
|
||||
if ((j + len) > 63)
|
||||
{
|
||||
memcpy(&context->buffer[j], data, (i = 64 - j));
|
||||
SHA1Transform(context->state, context->buffer);
|
||||
for (; i + 63 < len; i += 64)
|
||||
{
|
||||
SHA1Transform(context->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
memcpy(&context->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
|
||||
void SHA1Final(
|
||||
unsigned char digest[20],
|
||||
SHA1_CTX * context
|
||||
)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
unsigned char finalcount[8];
|
||||
|
||||
unsigned char c;
|
||||
|
||||
#if 0 /* untested "improvement" by DHR */
|
||||
/* Convert context->count to a sequence of bytes
|
||||
* in finalcount. Second element first, but
|
||||
* big-endian order within element.
|
||||
* But we do it all backwards.
|
||||
*/
|
||||
unsigned char *fcp = &finalcount[8];
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
uint32_t t = context->count[i];
|
||||
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 4; t >>= 8, j++)
|
||||
*--fcp = (unsigned char) t}
|
||||
#else
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */
|
||||
}
|
||||
#endif
|
||||
c = 0200;
|
||||
SHA1Update(context, &c, 1);
|
||||
while ((context->count[0] & 504) != 448)
|
||||
{
|
||||
c = 0000;
|
||||
SHA1Update(context, &c, 1);
|
||||
}
|
||||
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
|
||||
for (i = 0; i < 20; i++)
|
||||
{
|
||||
digest[i] = (unsigned char)
|
||||
((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
|
||||
}
|
||||
/* Wipe variables */
|
||||
memset(context, '\0', sizeof(*context));
|
||||
memset(&finalcount, '\0', sizeof(finalcount));
|
||||
}
|
||||
|
||||
void SHA1(
|
||||
char *hash_out,
|
||||
const char *str,
|
||||
int len)
|
||||
{
|
||||
SHA1_CTX ctx;
|
||||
unsigned int ii;
|
||||
|
||||
SHA1Init(&ctx);
|
||||
for (ii=0; ii<len; ii+=1)
|
||||
SHA1Update(&ctx, (const unsigned char*)str + ii, 1);
|
||||
SHA1Final((unsigned char *)hash_out, &ctx);
|
||||
hash_out[20] = '\0';
|
||||
}
|
356
native/jni/external/stubs/selinux_stub.c
vendored
Normal file
356
native/jni/external/stubs/selinux_stub.c
vendored
Normal file
@@ -0,0 +1,356 @@
|
||||
#include <stdbool.h>
|
||||
#include <selinux/avc.h>
|
||||
#include <selinux/context.h>
|
||||
#include <selinux/get_context_list.h>
|
||||
#include <selinux/get_default_type.h>
|
||||
#include <selinux/label.h>
|
||||
#include <selinux/restorecon.h>
|
||||
#include <selinux/selinux.h>
|
||||
int is_selinux_enabled(void) { return 0; }
|
||||
int is_selinux_mls_enabled(void) { return 0; }
|
||||
void freecon(char * con) { }
|
||||
void freeconary(char ** con) { }
|
||||
int getcon(char ** con) { return 0; }
|
||||
int getcon_raw(char ** con) { return 0; }
|
||||
int setcon(const char * con) { return 0; }
|
||||
int setcon_raw(const char * con) { return 0; }
|
||||
int getpidcon(pid_t pid, char ** con) { return 0; }
|
||||
int getpidcon_raw(pid_t pid, char ** con) { return 0; }
|
||||
int getprevcon(char ** con) { return 0; }
|
||||
int getprevcon_raw(char ** con) { return 0; }
|
||||
int getexeccon(char ** con) { return 0; }
|
||||
int getexeccon_raw(char ** con) { return 0; }
|
||||
int setexeccon(const char * con) { return 0; }
|
||||
int setexeccon_raw(const char * con) { return 0; }
|
||||
int getfscreatecon(char ** con) { return 0; }
|
||||
int getfscreatecon_raw(char ** con) { return 0; }
|
||||
int setfscreatecon(const char * context) { return 0; }
|
||||
int setfscreatecon_raw(const char * context) { return 0; }
|
||||
int getkeycreatecon(char ** con) { return 0; }
|
||||
int getkeycreatecon_raw(char ** con) { return 0; }
|
||||
int setkeycreatecon(const char * context) { return 0; }
|
||||
int setkeycreatecon_raw(const char * context) { return 0; }
|
||||
int getsockcreatecon(char ** con) { return 0; }
|
||||
int getsockcreatecon_raw(char ** con) { return 0; }
|
||||
int setsockcreatecon(const char * context) { return 0; }
|
||||
int setsockcreatecon_raw(const char * context) { return 0; }
|
||||
int getfilecon(const char *path, char ** con) { return 0; }
|
||||
int getfilecon_raw(const char *path, char ** con) { return 0; }
|
||||
int lgetfilecon(const char *path, char ** con) { return 0; }
|
||||
int lgetfilecon_raw(const char *path, char ** con) { return 0; }
|
||||
int fgetfilecon(int fd, char ** con) { return 0; }
|
||||
int fgetfilecon_raw(int fd, char ** con) { return 0; }
|
||||
int setfilecon(const char *path, const char * con) { return 0; }
|
||||
int setfilecon_raw(const char *path, const char * con) { return 0; }
|
||||
int lsetfilecon(const char *path, const char * con) { return 0; }
|
||||
int lsetfilecon_raw(const char *path, const char * con) { return 0; }
|
||||
int fsetfilecon(int fd, const char * con) { return 0; }
|
||||
int fsetfilecon_raw(int fd, const char * con) { return 0; }
|
||||
int getpeercon(int fd, char ** con) { return 0; }
|
||||
int getpeercon_raw(int fd, char ** con) { return 0; }
|
||||
void selinux_set_callback(int type, union selinux_callback cb) { }
|
||||
int security_compute_av(const char * scon,
|
||||
const char * tcon,
|
||||
security_class_t tclass,
|
||||
access_vector_t requested,
|
||||
struct av_decision *avd) { return 0; }
|
||||
int security_compute_av_raw(const char * scon,
|
||||
const char * tcon,
|
||||
security_class_t tclass,
|
||||
access_vector_t requested,
|
||||
struct av_decision *avd) { return 0; }
|
||||
int security_compute_av_flags(const char * scon,
|
||||
const char * tcon,
|
||||
security_class_t tclass,
|
||||
access_vector_t requested,
|
||||
struct av_decision *avd) { return 0; }
|
||||
int security_compute_av_flags_raw(const char * scon,
|
||||
const char * tcon,
|
||||
security_class_t tclass,
|
||||
access_vector_t requested,
|
||||
struct av_decision *avd) { return 0; }
|
||||
int security_compute_create(const char * scon,
|
||||
const char * tcon,
|
||||
security_class_t tclass,
|
||||
char ** newcon) { return 0; }
|
||||
int security_compute_create_raw(const char * scon,
|
||||
const char * tcon,
|
||||
security_class_t tclass,
|
||||
char ** newcon) { return 0; }
|
||||
int security_compute_create_name(const char * scon,
|
||||
const char * tcon,
|
||||
security_class_t tclass,
|
||||
const char *objname,
|
||||
char ** newcon) { return 0; }
|
||||
int security_compute_create_name_raw(const char * scon,
|
||||
const char * tcon,
|
||||
security_class_t tclass,
|
||||
const char *objname,
|
||||
char ** newcon) { return 0; }
|
||||
int security_compute_relabel(const char * scon,
|
||||
const char * tcon,
|
||||
security_class_t tclass,
|
||||
char ** newcon) { return 0; }
|
||||
int security_compute_relabel_raw(const char * scon,
|
||||
const char * tcon,
|
||||
security_class_t tclass,
|
||||
char ** newcon) { return 0; }
|
||||
int security_compute_member(const char * scon,
|
||||
const char * tcon,
|
||||
security_class_t tclass,
|
||||
char ** newcon) { return 0; }
|
||||
int security_compute_member_raw(const char * scon,
|
||||
const char * tcon,
|
||||
security_class_t tclass,
|
||||
char ** newcon) { return 0; }
|
||||
int security_compute_user(const char * scon,
|
||||
const char *username,
|
||||
char *** con) { return 0; }
|
||||
int security_compute_user_raw(const char * scon,
|
||||
const char *username,
|
||||
char *** con) { return 0; }
|
||||
int security_load_policy(void *data, size_t len) { return 0; }
|
||||
int security_get_initial_context(const char *name,
|
||||
char ** con) { return 0; }
|
||||
int security_get_initial_context_raw(const char *name,
|
||||
char ** con) { return 0; }
|
||||
int selinux_mkload_policy(int preservebools) { return 0; }
|
||||
int selinux_init_load_policy(int *enforce) { return 0; }
|
||||
int security_set_boolean_list(size_t boolcnt,
|
||||
SELboolean * boollist, int permanent) { return 0; }
|
||||
int security_load_booleans(char *path) { return 0; }
|
||||
int security_check_context(const char * con) { return 0; }
|
||||
int security_check_context_raw(const char * con) { return 0; }
|
||||
int security_canonicalize_context(const char * con,
|
||||
char ** canoncon) { return 0; }
|
||||
int security_canonicalize_context_raw(const char * con,
|
||||
char ** canoncon) { return 0; }
|
||||
int security_getenforce(void) { return 0; }
|
||||
int security_setenforce(int value) { return 0; }
|
||||
int security_deny_unknown(void) { return 0; }
|
||||
int security_disable(void) { return 0; }
|
||||
int security_policyvers(void) { return 0; }
|
||||
int security_get_boolean_names(char ***names, int *len) { return 0; }
|
||||
int security_get_boolean_pending(const char *name) { return 0; }
|
||||
int security_get_boolean_active(const char *name) { return 0; }
|
||||
int security_set_boolean(const char *name, int value) { return 0; }
|
||||
int security_commit_booleans(void) { return 0; }
|
||||
int selinux_set_mapping(struct security_class_mapping *map) { return 0; }
|
||||
security_class_t mode_to_security_class(mode_t mode) { return 0; }
|
||||
security_class_t string_to_security_class(const char *name) { return 0; }
|
||||
const char *security_class_to_string(security_class_t cls) { return 0; }
|
||||
const char *security_av_perm_to_string(security_class_t tclass,
|
||||
access_vector_t perm) { return 0; }
|
||||
access_vector_t string_to_av_perm(security_class_t tclass,
|
||||
const char *name) { return 0; }
|
||||
int security_av_string(security_class_t tclass,
|
||||
access_vector_t av, char **result) { return 0; }
|
||||
void print_access_vector(security_class_t tclass, access_vector_t av) { }
|
||||
void set_matchpathcon_printf(void (*f) (const char *fmt, ...)) { }
|
||||
void set_matchpathcon_invalidcon(int (*f) (const char *path,
|
||||
unsigned lineno,
|
||||
char *context)) { }
|
||||
void set_matchpathcon_canoncon(int (*f) (const char *path,
|
||||
unsigned lineno,
|
||||
char **context)) { }
|
||||
void set_matchpathcon_flags(unsigned int flags) { }
|
||||
int matchpathcon_init(const char *path) { return 0; }
|
||||
int matchpathcon_init_prefix(const char *path, const char *prefix) { return 0; }
|
||||
void matchpathcon_fini(void) { }
|
||||
int realpath_not_final(const char *name, char *resolved_path) { return 0; }
|
||||
int matchpathcon(const char *path,
|
||||
mode_t mode, char ** con) { return 0; }
|
||||
int matchpathcon_index(const char *path,
|
||||
mode_t mode, char ** con) { return 0; }
|
||||
int matchpathcon_filespec_add(ino_t ino, int specind, const char *file) { return 0; }
|
||||
void matchpathcon_filespec_destroy(void) { }
|
||||
void matchpathcon_filespec_eval(void) { }
|
||||
void matchpathcon_checkmatches(char *str) { }
|
||||
int matchmediacon(const char *media, char ** con) { return 0; }
|
||||
int selinux_getenforcemode(int *enforce) { return 0; }
|
||||
char *selinux_boolean_sub(const char *boolean_name) { return 0; }
|
||||
int selinux_getpolicytype(char **policytype) { return 0; }
|
||||
const char *selinux_policy_root(void) { return 0; }
|
||||
int selinux_set_policy_root(const char *rootpath) { return 0; }
|
||||
const char *selinux_current_policy_path(void) { return 0; }
|
||||
const char *selinux_binary_policy_path(void) { return 0; }
|
||||
const char *selinux_failsafe_context_path(void) { return 0; }
|
||||
const char *selinux_removable_context_path(void) { return 0; }
|
||||
const char *selinux_default_context_path(void) { return 0; }
|
||||
const char *selinux_user_contexts_path(void) { return 0; }
|
||||
const char *selinux_file_context_path(void) { return 0; }
|
||||
const char *selinux_file_context_homedir_path(void) { return 0; }
|
||||
const char *selinux_file_context_local_path(void) { return 0; }
|
||||
const char *selinux_file_context_subs_path(void) { return 0; }
|
||||
const char *selinux_file_context_subs_dist_path(void) { return 0; }
|
||||
const char *selinux_homedir_context_path(void) { return 0; }
|
||||
const char *selinux_media_context_path(void) { return 0; }
|
||||
const char *selinux_virtual_domain_context_path(void) { return 0; }
|
||||
const char *selinux_virtual_image_context_path(void) { return 0; }
|
||||
const char *selinux_lxc_contexts_path(void) { return 0; }
|
||||
const char *selinux_x_context_path(void) { return 0; }
|
||||
const char *selinux_sepgsql_context_path(void) { return 0; }
|
||||
const char *selinux_openrc_contexts_path(void) { return 0; }
|
||||
const char *selinux_openssh_contexts_path(void) { return 0; }
|
||||
const char *selinux_snapperd_contexts_path(void) { return 0; }
|
||||
const char *selinux_systemd_contexts_path(void) { return 0; }
|
||||
const char *selinux_contexts_path(void) { return 0; }
|
||||
const char *selinux_securetty_types_path(void) { return 0; }
|
||||
const char *selinux_booleans_subs_path(void) { return 0; }
|
||||
const char *selinux_booleans_path(void) { return 0; }
|
||||
const char *selinux_customizable_types_path(void) { return 0; }
|
||||
const char *selinux_users_path(void) { return 0; }
|
||||
const char *selinux_usersconf_path(void) { return 0; }
|
||||
const char *selinux_translations_path(void) { return 0; }
|
||||
const char *selinux_colors_path(void) { return 0; }
|
||||
const char *selinux_netfilter_context_path(void) { return 0; }
|
||||
const char *selinux_path(void) { return 0; }
|
||||
int selinux_check_access(const char * scon, const char * tcon, const char *tclass, const char *perm, void *auditdata) { return 0; }
|
||||
int selinux_check_passwd_access(access_vector_t requested) { return 0; }
|
||||
int checkPasswdAccess(access_vector_t requested) { return 0; }
|
||||
int selinux_check_securetty_context(const char * tty_context) { return 0; }
|
||||
void set_selinuxmnt(const char *mnt) { }
|
||||
int selinuxfs_exists(void) { return 0; }
|
||||
void fini_selinuxmnt(void) {}
|
||||
int setexecfilecon(const char *filename, const char *fallback_type) { return 0; }
|
||||
#ifndef DISABLE_RPM
|
||||
int rpm_execcon(unsigned int verified,
|
||||
const char *filename,
|
||||
char *const argv[], char *const envp[]) { return 0; }
|
||||
#endif
|
||||
int is_context_customizable(const char * scontext) { return 0; }
|
||||
int selinux_trans_to_raw_context(const char * trans,
|
||||
char ** rawp) { return 0; }
|
||||
int selinux_raw_to_trans_context(const char * raw,
|
||||
char ** transp) { return 0; }
|
||||
int selinux_raw_context_to_color(const char * raw,
|
||||
char **color_str) { return 0; }
|
||||
int getseuserbyname(const char *linuxuser, char **seuser, char **level) { return 0; }
|
||||
int getseuser(const char *username, const char *service,
|
||||
char **r_seuser, char **r_level) { return 0; }
|
||||
int selinux_file_context_cmp(const char * a,
|
||||
const char * b) { return 0; }
|
||||
int selinux_file_context_verify(const char *path, mode_t mode) { return 0; }
|
||||
int selinux_lsetfilecon_default(const char *path) { return 0; }
|
||||
void selinux_reset_config(void) { }
|
||||
int avc_sid_to_context(security_id_t sid, char ** ctx) { return 0; }
|
||||
int avc_sid_to_context_raw(security_id_t sid, char ** ctx) { return 0; }
|
||||
int avc_context_to_sid(const char * ctx, security_id_t * sid) { return 0; }
|
||||
int avc_context_to_sid_raw(const char * ctx, security_id_t * sid) { return 0; }
|
||||
int sidget(security_id_t sid) { return 0; }
|
||||
int sidput(security_id_t sid) { return 0; }
|
||||
int avc_get_initial_sid(const char *name, security_id_t * sid) { return 0; }
|
||||
int avc_init(const char *msgprefix,
|
||||
const struct avc_memory_callback *mem_callbacks,
|
||||
const struct avc_log_callback *log_callbacks,
|
||||
const struct avc_thread_callback *thread_callbacks,
|
||||
const struct avc_lock_callback *lock_callbacks) { return 0; }
|
||||
int avc_open(struct selinux_opt *opts, unsigned nopts) { return 0; }
|
||||
void avc_cleanup(void) { }
|
||||
int avc_reset(void) { return 0; }
|
||||
void avc_destroy(void) { }
|
||||
int avc_has_perm_noaudit(security_id_t ssid,
|
||||
security_id_t tsid,
|
||||
security_class_t tclass,
|
||||
access_vector_t requested,
|
||||
struct avc_entry_ref *aeref, struct av_decision *avd) { return 0; }
|
||||
int avc_has_perm(security_id_t ssid, security_id_t tsid,
|
||||
security_class_t tclass, access_vector_t requested,
|
||||
struct avc_entry_ref *aeref, void *auditdata) { return 0; }
|
||||
void avc_audit(security_id_t ssid, security_id_t tsid,
|
||||
security_class_t tclass, access_vector_t requested,
|
||||
struct av_decision *avd, int result, void *auditdata) { }
|
||||
int avc_compute_create(security_id_t ssid,
|
||||
security_id_t tsid,
|
||||
security_class_t tclass, security_id_t * newsid) { return 0; }
|
||||
int avc_compute_member(security_id_t ssid,
|
||||
security_id_t tsid,
|
||||
security_class_t tclass, security_id_t * newsid) { return 0; }
|
||||
int avc_add_callback(int (*callback)
|
||||
(uint32_t event, security_id_t ssid,
|
||||
security_id_t tsid, security_class_t tclass,
|
||||
access_vector_t perms,
|
||||
access_vector_t * out_retained),
|
||||
uint32_t events, security_id_t ssid,
|
||||
security_id_t tsid, security_class_t tclass,
|
||||
access_vector_t perms) { return 0; }
|
||||
void avc_cache_stats(struct avc_cache_stats *stats) { }
|
||||
void avc_av_stats(void) { }
|
||||
void avc_sid_stats(void) { }
|
||||
int avc_netlink_open(int blocking) { return 0; }
|
||||
void avc_netlink_loop(void) { }
|
||||
void avc_netlink_close(void) { }
|
||||
int avc_netlink_acquire_fd(void) { return 0; }
|
||||
void avc_netlink_release_fd(void) { }
|
||||
int avc_netlink_check_nb(void) { return 0; }
|
||||
int selinux_status_open(int fallback) { return 0; }
|
||||
void selinux_status_close(void) { }
|
||||
int selinux_status_updated(void) { return 0; }
|
||||
int selinux_status_getenforce(void) { return 0; }
|
||||
int selinux_status_policyload(void) { return 0; }
|
||||
int selinux_status_deny_unknown(void) { return 0; }
|
||||
context_t context_new(const char *s) { return 0; }
|
||||
char *context_str(context_t c) { return 0; }
|
||||
void context_free(context_t c) { }
|
||||
const char *context_type_get(context_t c) { return 0; }
|
||||
const char *context_range_get(context_t c) { return 0; }
|
||||
const char *context_role_get(context_t c) { return 0; }
|
||||
const char *context_user_get(context_t c) { return 0; }
|
||||
int context_type_set(context_t c, const char *s) { return 0; }
|
||||
int context_range_set(context_t c, const char *s) { return 0; }
|
||||
int context_role_set(context_t c, const char *s) { return 0; }
|
||||
int context_user_set(context_t c, const char *s) { return 0; }
|
||||
int get_ordered_context_list(const char *user,
|
||||
char * fromcon,
|
||||
char *** list) { return 0; }
|
||||
int get_ordered_context_list_with_level(const char *user,
|
||||
const char *level,
|
||||
char * fromcon,
|
||||
char *** list) { return 0; }
|
||||
int get_default_context(const char *user,
|
||||
char * fromcon,
|
||||
char ** newcon) { return 0; }
|
||||
int get_default_context_with_level(const char *user,
|
||||
const char *level,
|
||||
char * fromcon,
|
||||
char ** newcon) { return 0; }
|
||||
int get_default_context_with_role(const char *user,
|
||||
const char *role,
|
||||
char * fromcon,
|
||||
char ** newcon) { return 0; }
|
||||
int get_default_context_with_rolelevel(const char *user,
|
||||
const char *role,
|
||||
const char *level,
|
||||
char * fromcon,
|
||||
char ** newcon) { return 0; }
|
||||
int query_user_context(char ** list,
|
||||
char ** newcon) { return 0; }
|
||||
int manual_user_enter_context(const char *user,
|
||||
char ** newcon) { return 0; }
|
||||
const char *selinux_default_type_path(void) { return 0; }
|
||||
int get_default_type(const char *role, char **type) { return 0; }
|
||||
struct selabel_handle *selabel_open(unsigned int backend,
|
||||
const struct selinux_opt *opts,
|
||||
unsigned nopts) { return 0; }
|
||||
void selabel_close(struct selabel_handle *handle) { }
|
||||
int selabel_lookup(struct selabel_handle *handle, char **con,
|
||||
const char *key, int type) { return 0; }
|
||||
int selabel_lookup_raw(struct selabel_handle *handle, char **con,
|
||||
const char *key, int type) { return 0; }
|
||||
bool selabel_partial_match(struct selabel_handle *handle, const char *key) { return 0; }
|
||||
int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
|
||||
const char *key, const char **aliases, int type) { return 0; }
|
||||
int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
|
||||
const char *key, const char **aliases, int type) { return 0; }
|
||||
int selabel_digest(struct selabel_handle *rec,
|
||||
unsigned char **digest, size_t *digest_len,
|
||||
char ***specfiles, size_t *num_specfiles) { return 0; }
|
||||
void selabel_stats(struct selabel_handle *handle) { }
|
||||
int selinux_restorecon(const char *pathname,
|
||||
unsigned int restorecon_flags) { return 0; }
|
||||
struct selabel_handle *selinux_restorecon_default_handle(void) { return 0; }
|
||||
void selinux_restorecon_set_exclude_list(const char **exclude_list) { }
|
||||
int selinux_restorecon_set_alt_rootpath(const char *alt_rootpath) { return 0; }
|
||||
int selinux_restorecon_xattr(const char *pathname,
|
||||
unsigned int xattr_flags,
|
||||
struct dir_xattr ***xattr_list) { return 0; }
|
676
native/jni/external/stubs/sqlite3_stub.c
vendored
Normal file
676
native/jni/external/stubs/sqlite3_stub.c
vendored
Normal file
@@ -0,0 +1,676 @@
|
||||
#include "sqlite3.h"
|
||||
SQLITE_API const char *sqlite3_libversion(void) { return 0; }
|
||||
SQLITE_API const char *sqlite3_sourceid(void) { return 0; }
|
||||
SQLITE_API int sqlite3_libversion_number(void) { return 0; }
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
SQLITE_API int sqlite3_compileoption_used(const char *zOptName) { return 0; }
|
||||
SQLITE_API const char *sqlite3_compileoption_get(int N) { return 0; }
|
||||
#endif
|
||||
SQLITE_API int sqlite3_threadsafe(void) { return 0; }
|
||||
SQLITE_API int sqlite3_close(sqlite3 *db) { return 0; }
|
||||
SQLITE_API int sqlite3_close_v2(sqlite3 *db) { return 0; }
|
||||
SQLITE_API int sqlite3_exec(
|
||||
sqlite3 *db,
|
||||
const char *sql,
|
||||
int (*callback)(void*,int,char**,char**),
|
||||
void *v,
|
||||
char **errmsg
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_initialize(void) { return 0; }
|
||||
SQLITE_API int sqlite3_shutdown(void) { return 0; }
|
||||
SQLITE_API int sqlite3_os_init(void) { return 0; }
|
||||
SQLITE_API int sqlite3_os_end(void) { return 0; }
|
||||
SQLITE_API int sqlite3_config(int i, ...) { return 0; }
|
||||
SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...) { return 0; }
|
||||
SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff) { return 0; }
|
||||
SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3 *db) { return 0; }
|
||||
SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db,sqlite3_int64 i) { }
|
||||
SQLITE_API int sqlite3_changes(sqlite3 *db) { return 0; }
|
||||
SQLITE_API int sqlite3_total_changes(sqlite3 *db) { return 0; }
|
||||
SQLITE_API void sqlite3_interrupt(sqlite3 *db) { }
|
||||
SQLITE_API int sqlite3_complete(const char *sql) { return 0; }
|
||||
SQLITE_API int sqlite3_complete16(const void *sql) { return 0; }
|
||||
SQLITE_API int sqlite3_busy_handler(sqlite3 *db, int(*f) (void *v,int i), void* v) { return 0; }
|
||||
SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms) { return 0; }
|
||||
SQLITE_API int sqlite3_get_table(
|
||||
sqlite3 *db,
|
||||
const char *zSql,
|
||||
char ***pazResult,
|
||||
int *pnRow,
|
||||
int *pnColumn,
|
||||
char **pzErrmsg
|
||||
) { return 0; }
|
||||
SQLITE_API void sqlite3_free_table(char **result) { }
|
||||
SQLITE_API char *sqlite3_mprintf(const char* s,...) { return 0; }
|
||||
SQLITE_API char *sqlite3_vmprintf(const char* s, va_list v) { return 0; }
|
||||
SQLITE_API char *sqlite3_snprintf(int i, char* s, const char* st, ...) { return 0; }
|
||||
SQLITE_API char *sqlite3_vsnprintf(int i, char* s, const char* st, va_list v) { return 0; }
|
||||
SQLITE_API void *sqlite3_malloc(int i) { return 0; }
|
||||
SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 i) { return 0; }
|
||||
SQLITE_API void *sqlite3_realloc(void* v, int i) { return 0; }
|
||||
SQLITE_API void *sqlite3_realloc64(void* v, sqlite3_uint64 i) { return 0; }
|
||||
SQLITE_API void sqlite3_free(void* v) { }
|
||||
SQLITE_API sqlite3_uint64 sqlite3_msize(void* v) { return 0; }
|
||||
SQLITE_API sqlite3_int64 sqlite3_memory_used(void) { return 0; }
|
||||
SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag) { return 0; }
|
||||
SQLITE_API void sqlite3_randomness(int N, void *P) { }
|
||||
SQLITE_API int sqlite3_set_authorizer(
|
||||
sqlite3 *db,
|
||||
int (*xAuth)(void *v,int i,const char*,const char*,const char*,const char*),
|
||||
void *pUserData
|
||||
) { return 0; }
|
||||
SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3 *db,
|
||||
void(*xTrace)(void *v,const char*), void* v) { return 0; }
|
||||
SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3 *db,
|
||||
void(*xProfile)(void *v,const char*,sqlite3_uint64), void* v) { return 0; }
|
||||
SQLITE_API int sqlite3_trace_v2(
|
||||
sqlite3 *db,
|
||||
unsigned uMask,
|
||||
int(*xCallback)(unsigned,void *v,void *vv,void*),
|
||||
void *pCtx
|
||||
) { return 0; }
|
||||
SQLITE_API void sqlite3_progress_handler(sqlite3 *db, int i, int(*f)(void*), void* v) { }
|
||||
SQLITE_API int sqlite3_open(
|
||||
const char *filename,
|
||||
sqlite3 **ppDb
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_open16(
|
||||
const void *filename,
|
||||
sqlite3 **ppDb
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_open_v2(
|
||||
const char *filename,
|
||||
sqlite3 **ppDb,
|
||||
int flags,
|
||||
const char *zVfs
|
||||
) { return 0; }
|
||||
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam) { return 0; }
|
||||
SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault) { return 0; }
|
||||
SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char* s, const char* st, sqlite3_int64 i) { return 0; }
|
||||
SQLITE_API int sqlite3_errcode(sqlite3 *db) { return 0; }
|
||||
SQLITE_API int sqlite3_extended_errcode(sqlite3 *db) { return 0; }
|
||||
SQLITE_API const char *sqlite3_errmsg(sqlite3 *db) { return 0; }
|
||||
SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db) { return 0; }
|
||||
SQLITE_API const char *sqlite3_errstr(int i) { return 0; }
|
||||
SQLITE_API int sqlite3_limit(sqlite3 *db, int id, int newVal) { return 0; }
|
||||
SQLITE_API int sqlite3_prepare(
|
||||
sqlite3 *db,
|
||||
const char *zSql,
|
||||
int nByte,
|
||||
sqlite3_stmt **ppStmt,
|
||||
const char **pzTail
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_prepare_v2(
|
||||
sqlite3 *db,
|
||||
const char *zSql,
|
||||
int nByte,
|
||||
sqlite3_stmt **ppStmt,
|
||||
const char **pzTail
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_prepare16(
|
||||
sqlite3 *db,
|
||||
const void *zSql,
|
||||
int nByte,
|
||||
sqlite3_stmt **ppStmt,
|
||||
const void **pzTail
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_prepare16_v2(
|
||||
sqlite3 *db,
|
||||
const void *zSql,
|
||||
int nByte,
|
||||
sqlite3_stmt **ppStmt,
|
||||
const void **pzTail
|
||||
) { return 0; }
|
||||
SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt) { return 0; }
|
||||
SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt) { return 0; }
|
||||
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt) { return 0; }
|
||||
SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt* s) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_blob(sqlite3_stmt* s, int i, const void*v, int n, void(*f)(void*)) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt* s, int i, const void *v, sqlite3_uint64 ii,
|
||||
void(*f)(void*)) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_double(sqlite3_stmt* s, int i, double d) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_int(sqlite3_stmt* s, int i, int ii) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt* s, int i, sqlite3_int64 ii) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_null(sqlite3_stmt* s, int i) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_text(sqlite3_stmt* s,int i,const char* str, int ii, void(*f)(void*)) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_text16(sqlite3_stmt* s, int i, const void *v, int ii, void(*f)(void*)) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_text64(sqlite3_stmt* s, int i, const char* str, sqlite3_uint64 ii,
|
||||
void(*f)(void*), unsigned char encoding) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_value(sqlite3_stmt* s, int i, const sqlite3_value* v) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt* s, int i, int n) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt* s, int i, sqlite3_uint64 ii) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt* s) { return 0; }
|
||||
SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt* s, int i) { return 0; }
|
||||
SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt* s, const char *zName) { return 0; }
|
||||
SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt* s) { return 0; }
|
||||
SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt) { return 0; }
|
||||
SQLITE_API const char *sqlite3_column_name(sqlite3_stmt* s, int N) { return 0; }
|
||||
SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt* s, int N) { return 0; }
|
||||
SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt* s,int i) { return 0; }
|
||||
SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt* s,int i){ return 0; }
|
||||
SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt* s,int i) { return 0; }
|
||||
SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt* s,int i) { return 0; }
|
||||
SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt* s,int i) { return 0; }
|
||||
SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt* s,int i) { return 0; }
|
||||
SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt* s,int i) { return 0; }
|
||||
SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt* s,int i) { return 0; }
|
||||
SQLITE_API int sqlite3_step(sqlite3_stmt* s) { return 0; }
|
||||
SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt) { return 0; }
|
||||
SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt* s, int iCol) { return 0; }
|
||||
SQLITE_API int sqlite3_column_bytes(sqlite3_stmt* s, int iCol) { return 0; }
|
||||
SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt* s, int iCol) { return 0; }
|
||||
SQLITE_API double sqlite3_column_double(sqlite3_stmt* s, int iCol) { return 0; }
|
||||
SQLITE_API int sqlite3_column_int(sqlite3_stmt* s, int iCol) { return 0; }
|
||||
SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt* s, int iCol) { return 0; }
|
||||
SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt* s, int iCol) { return 0; }
|
||||
SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt* s, int iCol) { return 0; }
|
||||
SQLITE_API int sqlite3_column_type(sqlite3_stmt* s, int iCol) { return 0; }
|
||||
SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt* s, int iCol) { return 0; }
|
||||
SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt) { return 0; }
|
||||
SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt) { return 0; }
|
||||
SQLITE_API int sqlite3_create_function(
|
||||
sqlite3 *db,
|
||||
const char *zFunctionName,
|
||||
int nArg,
|
||||
int eTextRep,
|
||||
void *pApp,
|
||||
void (*xFunc)(sqlite3_context* c,int i,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context* c,int i,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context* c)
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_create_function16(
|
||||
sqlite3 *db,
|
||||
const void *zFunctionName,
|
||||
int nArg,
|
||||
int eTextRep,
|
||||
void *pApp,
|
||||
void (*xFunc)(sqlite3_context* c,int i,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context* c,int i,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context* c)
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_create_function_v2(
|
||||
sqlite3 *db,
|
||||
const char *zFunctionName,
|
||||
int nArg,
|
||||
int eTextRep,
|
||||
void *pApp,
|
||||
void (*xFunc)(sqlite3_context* c,int i,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context* c,int i,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context* c),
|
||||
void(*xDestroy)(void*)
|
||||
) { return 0; }
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context* c) { return 0; }
|
||||
SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt* s) { return 0; }
|
||||
SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt* s, sqlite3_stmt* ss) { return 0; }
|
||||
SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void) { return 0; }
|
||||
SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void) { }
|
||||
SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*f)(void *v,sqlite3_int64,int),
|
||||
void *v,sqlite3_int64 i) { return 0; }
|
||||
#endif
|
||||
SQLITE_API const void *sqlite3_value_blob(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API int sqlite3_value_bytes(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API int sqlite3_value_bytes16(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API double sqlite3_value_double(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API int sqlite3_value_int(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API const void *sqlite3_value_text16(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API const void *sqlite3_value_text16le(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API const void *sqlite3_value_text16be(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API int sqlite3_value_type(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API int sqlite3_value_numeric_type(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value* v) { return 0; }
|
||||
SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value* v) { return 0; }
|
||||
SQLITE_API void sqlite3_value_free(sqlite3_value* v) { }
|
||||
SQLITE_API void *sqlite3_aggregate_context(sqlite3_context* c, int nBytes) { return 0; }
|
||||
SQLITE_API void *sqlite3_user_data(sqlite3_context* c) { return 0; }
|
||||
SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context* c) { return 0; }
|
||||
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context* c, int N) { return 0; }
|
||||
SQLITE_API void sqlite3_set_auxdata(sqlite3_context* c, int N, void *v, void (*f)(void*)) { }
|
||||
SQLITE_API void sqlite3_result_blob(sqlite3_context* c, const void *v, int i, void(*f)(void*)) { }
|
||||
SQLITE_API void sqlite3_result_blob64(sqlite3_context* c,const void *v,
|
||||
sqlite3_uint64 i,void(*f)(void*)) { }
|
||||
SQLITE_API void sqlite3_result_double(sqlite3_context* c, double d) { }
|
||||
SQLITE_API void sqlite3_result_error(sqlite3_context* c, const char* s, int i) { }
|
||||
SQLITE_API void sqlite3_result_error16(sqlite3_context* c, const void *v, int i) { }
|
||||
SQLITE_API void sqlite3_result_error_toobig(sqlite3_context* c) { }
|
||||
SQLITE_API void sqlite3_result_error_nomem(sqlite3_context* c) { }
|
||||
SQLITE_API void sqlite3_result_error_code(sqlite3_context* c, int i) { }
|
||||
SQLITE_API void sqlite3_result_int(sqlite3_context* c, int i) { }
|
||||
SQLITE_API void sqlite3_result_int64(sqlite3_context* c, sqlite3_int64 i) { }
|
||||
SQLITE_API void sqlite3_result_null(sqlite3_context* c) { }
|
||||
SQLITE_API void sqlite3_result_text(sqlite3_context* c, const char* s, int i, void(*f)(void*)) { }
|
||||
SQLITE_API void sqlite3_result_text64(sqlite3_context* c, const char* s, sqlite3_uint64 i,
|
||||
void(*f)(void*), unsigned char encoding) { }
|
||||
SQLITE_API void sqlite3_result_text16(sqlite3_context* c, const void *v, int i, void(*f)(void*)) { }
|
||||
SQLITE_API void sqlite3_result_text16le(sqlite3_context* c, const void *v, int i,void(*f)(void*)) { }
|
||||
SQLITE_API void sqlite3_result_text16be(sqlite3_context* c, const void *v, int i,void(*f)(void*)) { }
|
||||
SQLITE_API void sqlite3_result_value(sqlite3_context* c, sqlite3_value* v) { }
|
||||
SQLITE_API void sqlite3_result_zeroblob(sqlite3_context* c, int n) { }
|
||||
SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context* c, sqlite3_uint64 n) { return 0; }
|
||||
SQLITE_API void sqlite3_result_subtype(sqlite3_context* c,unsigned int i) { }
|
||||
SQLITE_API int sqlite3_create_collation(
|
||||
sqlite3 *db,
|
||||
const char *zName,
|
||||
int eTextRep,
|
||||
void *pArg,
|
||||
int(*xCompare)(void *,int,const void *,int,const void*)
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_create_collation_v2(
|
||||
sqlite3 *db,
|
||||
const char *zName,
|
||||
int eTextRep,
|
||||
void *pArg,
|
||||
int(*xCompare)(void *,int,const void*,int,const void*),
|
||||
void(*xDestroy)(void*)
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_create_collation16(
|
||||
sqlite3 *db,
|
||||
const void *zName,
|
||||
int eTextRep,
|
||||
void *pArg,
|
||||
int(*xCompare)(void *,int,const void *,int,const void*)
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_collation_needed(
|
||||
sqlite3 *db,
|
||||
void *v,
|
||||
void(*f)(void *v,sqlite3 *db,int eTextRep,const char*)
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_collation_needed16(
|
||||
sqlite3 *db,
|
||||
void *v,
|
||||
void(*f)(void *v,sqlite3 *db,int eTextRep,const void*)
|
||||
) { return 0; }
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
SQLITE_API int sqlite3_key(
|
||||
sqlite3 *db,
|
||||
const void *pKey, int nKey
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_key_v2(
|
||||
sqlite3 *db,
|
||||
const char *zDbName,
|
||||
const void *pKey, int nKey
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_rekey(
|
||||
sqlite3 *db,
|
||||
const void *pKey, int nKey
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_rekey_v2(
|
||||
sqlite3 *db,
|
||||
const char *zDbName,
|
||||
const void *pKey, int nKey
|
||||
) { return 0; }
|
||||
SQLITE_API void sqlite3_activate_see(
|
||||
const char *zPassPhrase
|
||||
) { return 0; }
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_CEROD
|
||||
SQLITE_API void sqlite3_activate_cerod(
|
||||
const char *zPassPhrase
|
||||
) { return 0; }
|
||||
#endif
|
||||
SQLITE_API int sqlite3_sleep(int i) { return 0; }
|
||||
SQLITE_API int sqlite3_get_autocommit(sqlite3 *db) { return 0; }
|
||||
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *s) { return 0; }
|
||||
SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName) { return 0; }
|
||||
SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName) { return 0; }
|
||||
SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt) { return 0; }
|
||||
SQLITE_API void *sqlite3_commit_hook(sqlite3 *db, int(*f)(void*), void *v) { return 0; }
|
||||
SQLITE_API void *sqlite3_rollback_hook(sqlite3 *db, void(*f)(void *), void *v) { return 0; }
|
||||
SQLITE_API void *sqlite3_update_hook(
|
||||
sqlite3 *db,
|
||||
void(*f)(void *,int ,char const *,char const *,sqlite3_int64),
|
||||
void *v
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_enable_shared_cache(int i) { return 0; }
|
||||
SQLITE_API int sqlite3_release_memory(int i) { return 0; }
|
||||
SQLITE_API int sqlite3_db_release_memory(sqlite3 *db) { return 0; }
|
||||
SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N) { return 0; }
|
||||
SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N) { }
|
||||
SQLITE_API int sqlite3_table_column_metadata(
|
||||
sqlite3 *db,
|
||||
const char *zDbName,
|
||||
const char *zTableName,
|
||||
const char *zColumnName,
|
||||
char const **pzDataType,
|
||||
char const **pzCollSeq,
|
||||
int *pNotNull,
|
||||
int *pPrimaryKey,
|
||||
int *pAutoinc
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_load_extension(
|
||||
sqlite3 *db,
|
||||
const char *zFile,
|
||||
const char *zProc,
|
||||
char **pzErrMsg
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff) { return 0; }
|
||||
SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void)) { return 0; }
|
||||
SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void)) { return 0; }
|
||||
SQLITE_API void sqlite3_reset_auto_extension(void) { }
|
||||
SQLITE_API int sqlite3_create_module(
|
||||
sqlite3 *db,
|
||||
const char *zName,
|
||||
const sqlite3_module *p,
|
||||
void *pClientData
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_create_module_v2(
|
||||
sqlite3 *db,
|
||||
const char *zName,
|
||||
const sqlite3_module *p,
|
||||
void *pClientData,
|
||||
void(*xDestroy)(void*)
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zSQL) { return 0; }
|
||||
SQLITE_API int sqlite3_overload_function(sqlite3 *db, const char *zFuncName, int nArg) { return 0; }
|
||||
SQLITE_API int sqlite3_blob_open(
|
||||
sqlite3 *db,
|
||||
const char *zDb,
|
||||
const char *zTable,
|
||||
const char *zColumn,
|
||||
sqlite3_int64 iRow,
|
||||
int flags,
|
||||
sqlite3_blob **ppBlob
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *b, sqlite3_int64 i) { return 0; }
|
||||
SQLITE_API int sqlite3_blob_close(sqlite3_blob *b) { return 0; }
|
||||
SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *b) { return 0; }
|
||||
SQLITE_API int sqlite3_blob_read(sqlite3_blob *b, void *Z, int N, int iOffset) { return 0; }
|
||||
SQLITE_API int sqlite3_blob_write(sqlite3_blob *b, const void *z, int n, int iOffset) { return 0; }
|
||||
SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName) { return 0; }
|
||||
SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *v, int makeDflt) { return 0; }
|
||||
SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *v) { return 0; }
|
||||
SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int i) { return 0; }
|
||||
SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *m) { }
|
||||
SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *m) { }
|
||||
SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *m) { return 0; }
|
||||
SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *m) { }
|
||||
#ifndef NDEBUG
|
||||
SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *m) { return 0; }
|
||||
SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *m) { return 0; }
|
||||
#endif
|
||||
SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3* db) { return 0; }
|
||||
SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void* v) { return 0; }
|
||||
SQLITE_API int sqlite3_test_control(int op, ...) { return 0; }
|
||||
SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag) { return 0; }
|
||||
SQLITE_API int sqlite3_status64(
|
||||
int op,
|
||||
sqlite3_int64 *pCurrent,
|
||||
sqlite3_int64 *pHighwater,
|
||||
int resetFlag
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_db_status(sqlite3 *db, int op, int *pCur, int *pHiwtr, int resetFlg) { return 0; }
|
||||
SQLITE_API int sqlite3_stmt_status(sqlite3_stmt* s, int op,int resetFlg) { return 0; }
|
||||
SQLITE_API sqlite3_backup *sqlite3_backup_init(
|
||||
sqlite3 *pDest,
|
||||
const char *zDestName,
|
||||
sqlite3 *pSource,
|
||||
const char *zSourceName
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage) { return 0; }
|
||||
SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p) { return 0; }
|
||||
SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p) { return 0; }
|
||||
SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p) { return 0; }
|
||||
SQLITE_API int sqlite3_unlock_notify(
|
||||
sqlite3 *pBlocked,
|
||||
void (*xNotify)(void **apArg, int nArg),
|
||||
void *pNotifyArg
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_stricmp(const char *s, const char *ss) { return 0; }
|
||||
SQLITE_API int sqlite3_strnicmp(const char *s, const char *ss, int i) { return 0; }
|
||||
SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr) { return 0; }
|
||||
SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc) { return 0; }
|
||||
SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...) { }
|
||||
SQLITE_API void *sqlite3_wal_hook(
|
||||
sqlite3 *db,
|
||||
int(*f)(void *,sqlite3 *db,const char*,int i),
|
||||
void *v
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N) { return 0; }
|
||||
SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb) { return 0; }
|
||||
SQLITE_API int sqlite3_wal_checkpoint_v2(
|
||||
sqlite3 *db,
|
||||
const char *zDb,
|
||||
int eMode,
|
||||
int *pnLog,
|
||||
int *pnCkpt
|
||||
) { return 0; }
|
||||
#define SQLITE_CHECKPOINT_PASSIVE 0
|
||||
#define SQLITE_CHECKPOINT_FULL 1
|
||||
#define SQLITE_CHECKPOINT_RESTART 2
|
||||
#define SQLITE_CHECKPOINT_TRUNCATE 3
|
||||
SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...) { return 0; }
|
||||
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
|
||||
SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db) { return 0; }
|
||||
#define SQLITE_ROLLBACK 1
|
||||
#define SQLITE_FAIL 3
|
||||
#define SQLITE_REPLACE 5
|
||||
#define SQLITE_SCANSTAT_NLOOP 0
|
||||
#define SQLITE_SCANSTAT_NVISIT 1
|
||||
#define SQLITE_SCANSTAT_EST 2
|
||||
#define SQLITE_SCANSTAT_NAME 3
|
||||
#define SQLITE_SCANSTAT_EXPLAIN 4
|
||||
#define SQLITE_SCANSTAT_SELECTID 5
|
||||
SQLITE_API int sqlite3_stmt_scanstatus(
|
||||
sqlite3_stmt *pStmt,
|
||||
int idx,
|
||||
int iScanStatusOp,
|
||||
void *pOut
|
||||
) { return 0; }
|
||||
SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *s) { }
|
||||
SQLITE_API int sqlite3_db_cacheflush(sqlite3* db) { return 0; }
|
||||
#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
|
||||
SQLITE_API void *sqlite3_preupdate_hook(
|
||||
sqlite3 *db,
|
||||
void(*xPreUpdate)(
|
||||
void *pCtx,
|
||||
sqlite3 *db,
|
||||
int op,
|
||||
char const *zDb,
|
||||
char const *zName,
|
||||
sqlite3_int64 iKey1,
|
||||
sqlite3_int64 iKey2
|
||||
),
|
||||
void*
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int i, sqlite3_value **) { return 0; }
|
||||
SQLITE_API int sqlite3_preupdate_count(sqlite3 *) { return 0; }
|
||||
SQLITE_API int sqlite3_preupdate_depth(sqlite3 *) { return 0; }
|
||||
SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int i, sqlite3_value **) { return 0; }
|
||||
#endif
|
||||
SQLITE_API int sqlite3_system_errno(sqlite3 *db) { return 0; }
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
|
||||
sqlite3 *db,
|
||||
const char *zSchema,
|
||||
sqlite3_snapshot **ppSnapshot
|
||||
) { return 0; }
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
|
||||
sqlite3 *db,
|
||||
const char *zSchema,
|
||||
sqlite3_snapshot *pSnapshot
|
||||
) { return 0; }
|
||||
SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot* s) { }
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
|
||||
sqlite3_snapshot *p1,
|
||||
sqlite3_snapshot *p2
|
||||
) { return 0; }
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb) { return 0; }
|
||||
SQLITE_API int sqlite3_rtree_geometry_callback(
|
||||
sqlite3 *db,
|
||||
const char *zGeom,
|
||||
int (*xGeom)(sqlite3_rtree_geometry*, int i, sqlite3_rtree_dbl*,int*),
|
||||
void *pContext
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3_rtree_query_callback(
|
||||
sqlite3 *db,
|
||||
const char *zQueryFunc,
|
||||
int (*xQueryFunc)(sqlite3_rtree_query_info*),
|
||||
void *pContext,
|
||||
void (*xDestructor)(void*)
|
||||
) { return 0; }
|
||||
typedef struct sqlite3_session sqlite3_session;
|
||||
typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
|
||||
SQLITE_API int sqlite3session_create(
|
||||
sqlite3 *db,
|
||||
const char *zDb,
|
||||
sqlite3_session **ppSession
|
||||
) { return 0; }
|
||||
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession) { }
|
||||
SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable) { return 0; }
|
||||
SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect) { return 0; }
|
||||
SQLITE_API int sqlite3session_attach(
|
||||
sqlite3_session *pSession,
|
||||
const char *zTab
|
||||
) { return 0; }
|
||||
SQLITE_API void sqlite3session_table_filter(
|
||||
sqlite3_session *pSession,
|
||||
int(*xFilter)(
|
||||
void *pCtx,
|
||||
const char *zTab
|
||||
),
|
||||
void *pCtx
|
||||
) { }
|
||||
SQLITE_API int sqlite3session_changeset(
|
||||
sqlite3_session *pSession,
|
||||
int *pnChangeset,
|
||||
void **ppChangeset
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3session_diff(
|
||||
sqlite3_session *pSession,
|
||||
const char *zFromDb,
|
||||
const char *zTbl,
|
||||
char **pzErrMsg
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3session_patchset(
|
||||
sqlite3_session *pSession,
|
||||
int *pnPatchset,
|
||||
void **ppPatchset
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_start(
|
||||
sqlite3_changeset_iter **pp,
|
||||
int nChangeset,
|
||||
void *pChangeset
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_op(
|
||||
sqlite3_changeset_iter *pIter,
|
||||
const char **pzTab,
|
||||
int *pnCol,
|
||||
int *pOp,
|
||||
int *pbIndirect
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_pk(
|
||||
sqlite3_changeset_iter *pIter,
|
||||
unsigned char **pabPK,
|
||||
int *pnCol
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_old(
|
||||
sqlite3_changeset_iter *pIter,
|
||||
int iVal,
|
||||
sqlite3_value **ppValue
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_new(
|
||||
sqlite3_changeset_iter *pIter,
|
||||
int iVal,
|
||||
sqlite3_value **ppValue
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_conflict(
|
||||
sqlite3_changeset_iter *pIter,
|
||||
int iVal,
|
||||
sqlite3_value **ppValue
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_fk_conflicts(
|
||||
sqlite3_changeset_iter *pIter,
|
||||
int *pnOut
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_invert(
|
||||
int nIn, const void *pIn,
|
||||
int *pnOut, void **ppOut
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_concat(
|
||||
int nA,
|
||||
void *pA,
|
||||
int nB,
|
||||
void *pB,
|
||||
int *pnOut,
|
||||
void **ppOut
|
||||
) { return 0; }
|
||||
typedef struct sqlite3_changegroup sqlite3_changegroup;
|
||||
int sqlite3changegroup_new(sqlite3_changegroup **pp) { return 0; }
|
||||
int sqlite3changegroup_add(sqlite3_changegroup *c, int nData, void *pData) { return 0; }
|
||||
int sqlite3changegroup_output(
|
||||
sqlite3_changegroup *c,
|
||||
int *pnData,
|
||||
void **ppData
|
||||
) { return 0; }
|
||||
void sqlite3changegroup_delete(sqlite3_changegroup *c) { }
|
||||
SQLITE_API int sqlite3changeset_apply(
|
||||
sqlite3 *db,
|
||||
int nChangeset,
|
||||
void *pChangeset,
|
||||
int(*xFilter)(
|
||||
void *pCtx,
|
||||
const char *zTab
|
||||
),
|
||||
int(*xConflict)(
|
||||
void *pCtx,
|
||||
int eConflict,
|
||||
sqlite3_changeset_iter *p
|
||||
),
|
||||
void *pCtx
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_apply_strm(
|
||||
sqlite3 *db,
|
||||
int (*xInput)(void *pIn, void *pData, int *pnData),
|
||||
void *pIn,
|
||||
int(*xFilter)(
|
||||
void *pCtx,
|
||||
const char *zTab
|
||||
),
|
||||
int(*xConflict)(
|
||||
void *pCtx,
|
||||
int eConflict,
|
||||
sqlite3_changeset_iter *p
|
||||
),
|
||||
void *pCtx
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_concat_strm(
|
||||
int (*xInputA)(void *pIn, void *pData, int *pnData),
|
||||
void *pInA,
|
||||
int (*xInputB)(void *pIn, void *pData, int *pnData),
|
||||
void *pInB,
|
||||
int (*xOutput)(void *pOut, const void *pData, int nData),
|
||||
void *pOut
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_invert_strm(
|
||||
int (*xInput)(void *pIn, void *pData, int *pnData),
|
||||
void *pIn,
|
||||
int (*xOutput)(void *pOut, const void *pData, int nData),
|
||||
void *pOut
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3changeset_start_strm(
|
||||
sqlite3_changeset_iter **pp,
|
||||
int (*xInput)(void *pIn, void *pData, int *pnData),
|
||||
void *pIn
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3session_changeset_strm(
|
||||
sqlite3_session *pSession,
|
||||
int (*xOutput)(void *pOut, const void *pData, int nData),
|
||||
void *pOut
|
||||
) { return 0; }
|
||||
SQLITE_API int sqlite3session_patchset_strm(
|
||||
sqlite3_session *pSession,
|
||||
int (*xOutput)(void *pOut, const void *pData, int nData),
|
||||
void *pOut
|
||||
) { return 0; }
|
||||
int sqlite3changegroup_add_strm(sqlite3_changegroup *c,
|
||||
int (*xInput)(void *pIn, void *pData, int *pnData),
|
||||
void *pIn
|
||||
) { return 0; }
|
||||
int sqlite3changegroup_output_strm(sqlite3_changegroup *c,
|
||||
int (*xOutput)(void *pOut, const void *pData, int nData),
|
||||
void *pOut
|
||||
) { return 0; }
|
1
native/jni/external/xz
vendored
Submodule
1
native/jni/external/xz
vendored
Submodule
Submodule native/jni/external/xz added at 3d566cd519
60
native/jni/include/cpio.h
Normal file
60
native/jni/include/cpio.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef _CPIO_H_
|
||||
#define _CPIO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
typedef struct cpio_entry {
|
||||
// uint32_t ino;
|
||||
uint32_t mode;
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
// uint32_t nlink;
|
||||
// uint32_t mtime;
|
||||
uint32_t filesize;
|
||||
// uint32_t devmajor;
|
||||
// uint32_t devminor;
|
||||
// uint32_t rdevmajor;
|
||||
// uint32_t rdevminor;
|
||||
// uint32_t namesize;
|
||||
// uint32_t check;
|
||||
char *filename;
|
||||
void *data;
|
||||
int remove;
|
||||
} cpio_entry;
|
||||
|
||||
typedef struct cpio_newc_header {
|
||||
char magic[6];
|
||||
char ino[8];
|
||||
char mode[8];
|
||||
char uid[8];
|
||||
char gid[8];
|
||||
char nlink[8];
|
||||
char mtime[8];
|
||||
char filesize[8];
|
||||
char devmajor[8];
|
||||
char devminor[8];
|
||||
char rdevmajor[8];
|
||||
char rdevminor[8];
|
||||
char namesize[8];
|
||||
char check[8];
|
||||
} cpio_newc_header;
|
||||
|
||||
// Basic cpio functions
|
||||
void cpio_free(cpio_entry *e);
|
||||
int cpio_find(struct vector *v, const char *entry);
|
||||
int cpio_cmp(const void *a, const void *b);
|
||||
void parse_cpio(struct vector *v, const char *filename);
|
||||
void dump_cpio(struct vector *v, const char *filename);
|
||||
void cpio_vec_insert(struct vector *v, cpio_entry *n);
|
||||
void cpio_vec_destroy(struct vector *v);
|
||||
void cpio_rm(struct vector *v, int recursive, const char *entry);
|
||||
void cpio_mkdir(struct vector *v, mode_t mode, const char *entry);
|
||||
void cpio_ln(struct vector *v, const char *target, const char *entry);
|
||||
void cpio_add(struct vector *v, mode_t mode, const char *entry, const char *filename);
|
||||
int cpio_mv(struct vector *v, const char *from, const char *to);
|
||||
int cpio_extract(struct vector *v, const char *entry, const char *filename);
|
||||
void cpio_extract_all(struct vector *v);
|
||||
|
||||
#endif
|
83
native/jni/include/daemon.h
Normal file
83
native/jni/include/daemon.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* daemon.h - Utility functions for daemon-client communication
|
||||
*/
|
||||
|
||||
#ifndef _DAEMON_H_
|
||||
#define _DAEMON_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
extern int is_daemon_init, seperate_vendor;
|
||||
|
||||
// Commands require connecting to daemon
|
||||
typedef enum {
|
||||
DO_NOTHING = 0,
|
||||
LAUNCH_MAGISKHIDE,
|
||||
STOP_MAGISKHIDE,
|
||||
ADD_HIDELIST,
|
||||
RM_HIDELIST,
|
||||
LS_HIDELIST,
|
||||
SUPERUSER,
|
||||
CHECK_VERSION,
|
||||
CHECK_VERSION_CODE,
|
||||
POST_FS,
|
||||
POST_FS_DATA,
|
||||
LATE_START,
|
||||
TEST
|
||||
} client_request;
|
||||
|
||||
// Return codes for daemon
|
||||
typedef enum {
|
||||
DAEMON_ERROR = -1,
|
||||
DAEMON_SUCCESS = 0,
|
||||
ROOT_REQUIRED,
|
||||
HIDE_IS_ENABLED,
|
||||
HIDE_NOT_ENABLED,
|
||||
HIDE_ITEM_EXIST,
|
||||
HIDE_ITEM_NOT_EXIST,
|
||||
} daemon_response;
|
||||
|
||||
// daemon.c
|
||||
|
||||
void start_daemon();
|
||||
int connect_daemon();
|
||||
void auto_start_magiskhide();
|
||||
void daemon_init();
|
||||
|
||||
// socket.c
|
||||
|
||||
int setup_socket(struct sockaddr_un *sun);
|
||||
int recv_fd(int sockfd);
|
||||
void send_fd(int sockfd, int fd);
|
||||
int read_int(int fd);
|
||||
void write_int(int fd, int val);
|
||||
char* read_string(int fd);
|
||||
void write_string(int fd, const char* val);
|
||||
|
||||
/***************
|
||||
* Boot Stages *
|
||||
***************/
|
||||
|
||||
void post_fs(int client);
|
||||
void post_fs_data(int client);
|
||||
void late_start(int client);
|
||||
void fix_filecon();
|
||||
|
||||
/**************
|
||||
* MagiskHide *
|
||||
**************/
|
||||
|
||||
void launch_magiskhide(int client);
|
||||
void stop_magiskhide(int client);
|
||||
void add_hide_list(int client);
|
||||
void rm_hide_list(int client);
|
||||
void ls_hide_list(int client);
|
||||
|
||||
/*************
|
||||
* Superuser *
|
||||
*************/
|
||||
|
||||
void su_daemon_receiver(int client, struct ucred *credential);
|
||||
|
||||
#endif
|
43
native/jni/include/list.h
Normal file
43
native/jni/include/list.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* list.h - Double link list implementation
|
||||
*/
|
||||
|
||||
#ifndef _LIST_H_
|
||||
#define _LIST_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next;
|
||||
struct list_head *prev;
|
||||
};
|
||||
|
||||
void init_list_head(struct list_head *head);
|
||||
void list_insert(struct list_head *pos, struct list_head *node);
|
||||
void list_insert_end(struct list_head *head, struct list_head *node);
|
||||
struct list_head *list_pop(struct list_head *pos);
|
||||
struct list_head *list_pop_end(struct list_head *head);
|
||||
|
||||
#define list_entry(pos, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (pos); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
|
||||
#define list_for_each(ptr, head, type, member) \
|
||||
ptr = list_entry((head)->next, type, member); \
|
||||
for (struct list_head *__ = (head)->next; __ != (head); __ = __->next, ptr = list_entry(__, type, member))
|
||||
|
||||
#define list_for_each_r(ptr, head, type, member) \
|
||||
ptr = list_entry((head)->prev, type, member); \
|
||||
for (struct list_head *__ = (head)->prev; __ != (head); __ = __->prev, ptr = list_entry(__, type, member))
|
||||
|
||||
#define list_destory(head, type, member, func) ({ \
|
||||
struct list_head *node = head->next; \
|
||||
while(node != head) { \
|
||||
node = node->next; \
|
||||
if (func) func(list_entry(node->prev, line_list, pos)); \
|
||||
free(list_entry(node->prev, line_list, pos)); \
|
||||
} \
|
||||
head->next = head; \
|
||||
head->prev = head; \
|
||||
})
|
||||
|
||||
#endif
|
86
native/jni/include/logging.h
Normal file
86
native/jni/include/logging.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* logging.h - Error handling and logging
|
||||
*/
|
||||
|
||||
#ifndef _LOGGING_H_
|
||||
#define _LOGGING_H_
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define str(a) #a
|
||||
#define xstr(a) str(a)
|
||||
|
||||
/**************
|
||||
* No logging *
|
||||
**************/
|
||||
|
||||
#define LOGD(...)
|
||||
#define LOGI(...)
|
||||
#define LOGW(...)
|
||||
#define LOGE(...)
|
||||
#define PLOGE(...)
|
||||
|
||||
/******************
|
||||
* Daemon logging *
|
||||
******************/
|
||||
|
||||
#ifdef IS_DAEMON
|
||||
|
||||
#undef LOGI
|
||||
#undef LOGW
|
||||
#undef LOGE
|
||||
#undef PLOGE
|
||||
|
||||
#include <pthread.h>
|
||||
#include <android/log.h>
|
||||
|
||||
#define LOG_TAG "Magisk"
|
||||
|
||||
#ifdef MAGISK_DEBUG
|
||||
#undef LOGD
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#endif
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
#define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno))
|
||||
|
||||
enum {
|
||||
HIDE_EVENT,
|
||||
LOG_EVENT,
|
||||
DEBUG_EVENT
|
||||
};
|
||||
|
||||
struct log_listener {
|
||||
int fd;
|
||||
int (*filter) (const char*);
|
||||
};
|
||||
|
||||
extern struct log_listener log_events[];
|
||||
|
||||
void monitor_logs();
|
||||
void start_debug_full_log();
|
||||
void stop_debug_full_log();
|
||||
void start_debug_log();
|
||||
|
||||
#endif
|
||||
|
||||
/********************
|
||||
* Tools Log & Exit *
|
||||
********************/
|
||||
|
||||
#ifdef XWRAP_EXIT
|
||||
|
||||
#undef LOGE
|
||||
#undef PLOGE
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define LOGE(...) { fprintf(stderr, __VA_ARGS__); exit(1); }
|
||||
#define PLOGE(fmt, args...) { fprintf(stderr, fmt " failed with %d: %s\n\n", ##args, errno, strerror(errno)); exit(1); }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // _LOGGING_H_
|
74
native/jni/include/magisk.h
Normal file
74
native/jni/include/magisk.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* magisk.h - Top header
|
||||
*/
|
||||
|
||||
#ifndef _MAGISK_H_
|
||||
#define _MAGISK_H_
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
#define MAGISK_VER_STR xstr(MAGISK_VERSION) ":MAGISK"
|
||||
#define REQUESTOR_DAEMON_PATH "\0MAGISK"
|
||||
|
||||
#ifndef ARG_MAX
|
||||
#define ARG_MAX 4096
|
||||
#endif
|
||||
|
||||
#define LOGFILE "/cache/magisk.log"
|
||||
#define DEBUG_LOG "/data/adb/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"
|
||||
#define MAGISKTMP "/sbin/.core"
|
||||
#define MIRRDIR MAGISKTMP "/mirror"
|
||||
#define BBPATH MAGISKTMP "/busybox"
|
||||
#define MOUNTPOINT MAGISKTMP "/img"
|
||||
#define COREDIR MOUNTPOINT "/.core"
|
||||
#define HOSTSFILE COREDIR "/hosts"
|
||||
#define HIDELIST COREDIR "/hidelist"
|
||||
#define MAINIMG "/data/adb/magisk.img"
|
||||
#define DATABIN "/data/adb/magisk"
|
||||
#define MANAGERAPK DATABIN "/magisk.apk"
|
||||
#define MAGISKRC "/init.magisk.rc"
|
||||
|
||||
|
||||
// selinuxfs paths
|
||||
#define SELINUX_PATH "/sys/fs/selinux/"
|
||||
#define SELINUX_ENFORCE SELINUX_PATH "enforce"
|
||||
#define SELINUX_POLICY SELINUX_PATH "policy"
|
||||
#define SELINUX_LOAD SELINUX_PATH "load"
|
||||
|
||||
// split policy paths
|
||||
#define PLAT_POLICY_DIR "/system/etc/selinux/"
|
||||
#define NONPLAT_POLICY_DIR "/vendor/etc/selinux/"
|
||||
#define SPLIT_PLAT_CIL PLAT_POLICY_DIR "plat_sepolicy.cil"
|
||||
#define SPLIT_PLAT_MAPPING PLAT_POLICY_DIR "mapping/%s.cil"
|
||||
#define SPLIT_PRECOMPILE NONPLAT_POLICY_DIR "precompiled_sepolicy"
|
||||
#define SPLIT_NONPLAT_VER NONPLAT_POLICY_DIR "plat_sepolicy_vers.txt"
|
||||
|
||||
#define MAGISKHIDE_PROP "persist.magisk.hide"
|
||||
|
||||
extern char *argv0; /* For changing process name */
|
||||
|
||||
#define applet ((char *[]) { "su", "resetprop", "magiskhide", NULL })
|
||||
#define init_applet ((char *[]) { "magiskpolicy", "supolicy", NULL })
|
||||
|
||||
extern int (*applet_main[]) (int, char *[]), (*init_applet_main[]) (int, char *[]);
|
||||
|
||||
int create_links(const char *bin, const char *path);
|
||||
|
||||
// Multi-call entrypoints
|
||||
int magiskhide_main(int argc, char *argv[]);
|
||||
int magiskpolicy_main(int argc, char *argv[]);
|
||||
int su_client_main(int argc, char *argv[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int resetprop_main(int argc, char *argv[]);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
44
native/jni/include/magiskrc.h
Normal file
44
native/jni/include/magiskrc.h
Normal file
@@ -0,0 +1,44 @@
|
||||
const char magiskrc[] =
|
||||
|
||||
// Triggers
|
||||
|
||||
"on post-fs\n"
|
||||
" start logd\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"
|
||||
" rm /dev/.magisk.unblock\n"
|
||||
"\n"
|
||||
|
||||
// Services
|
||||
|
||||
"service magisk_daemon /sbin/magisk --daemon\n"
|
||||
" user root\n"
|
||||
" seclabel u:r:su:s0\n"
|
||||
" oneshot\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"
|
||||
;
|
25
native/jni/include/resetprop.h
Normal file
25
native/jni/include/resetprop.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/* resetprop.h - API for resetprop
|
||||
*/
|
||||
|
||||
#ifndef _RESETPROP_H_
|
||||
#define _RESETPROP_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int prop_exist(const char *name);
|
||||
int setprop(const char *name, const char *value);
|
||||
int setprop2(const char *name, const char *value, const int trigger);
|
||||
char *getprop(const char *name);
|
||||
char *getprop2(const char *name, int persist);
|
||||
int deleteprop(const char *name);
|
||||
int deleteprop2(const char *name, const int persist);
|
||||
int read_prop_file(const char* filename, const int trigger);
|
||||
void getprop_all(void (*callback)(const char*, const char*));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
151
native/jni/include/utils.h
Normal file
151
native/jni/include/utils.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/* util.h - Header for all utility functions
|
||||
*/
|
||||
|
||||
#ifndef _UTILS_H_
|
||||
#define _UTILS_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
#define UID_SHELL (get_shell_uid())
|
||||
#define UID_ROOT 0
|
||||
#define UID_SYSTEM (get_system_uid())
|
||||
#define UID_RADIO (get_radio_uid())
|
||||
|
||||
// xwrap.c
|
||||
|
||||
FILE *xfopen(const char *pathname, const char *mode);
|
||||
FILE *xfdopen(int fd, const char *mode);
|
||||
#define GET_MACRO(_1, _2, _3, NAME, ...) NAME
|
||||
#define xopen(...) GET_MACRO(__VA_ARGS__, xopen3, xopen2)(__VA_ARGS__)
|
||||
int xopen2(const char *pathname, int flags);
|
||||
int xopen3(const char *pathname, int flags, mode_t mode);
|
||||
int xopenat(int dirfd, const char *pathname, int flags);
|
||||
ssize_t xwrite(int fd, const void *buf, size_t count);
|
||||
ssize_t xread(int fd, void *buf, size_t count);
|
||||
ssize_t xxread(int fd, void *buf, size_t count);
|
||||
int xpipe2(int pipefd[2], int flags);
|
||||
int xsetns(int fd, int nstype);
|
||||
DIR *xopendir(const char *name);
|
||||
DIR *xfdopendir(int fd);
|
||||
struct dirent *xreaddir(DIR *dirp);
|
||||
pid_t xsetsid();
|
||||
int xsocket(int domain, int type, int protocol);
|
||||
int xbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int xconnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int xlisten(int sockfd, int backlog);
|
||||
int xaccept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
|
||||
void *xmalloc(size_t size);
|
||||
void *xcalloc(size_t nmemb, size_t size);
|
||||
void *xrealloc(void *ptr, size_t size);
|
||||
ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags);
|
||||
ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags);
|
||||
int xpthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||
void *(*start_routine) (void *), void *arg);
|
||||
int xsocketpair(int domain, int type, int protocol, int sv[2]);
|
||||
int xstat(const char *pathname, struct stat *buf);
|
||||
int xlstat(const char *pathname, struct stat *buf);
|
||||
int xdup2(int oldfd, int newfd);
|
||||
ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz);
|
||||
ssize_t xreadlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);
|
||||
int xsymlink(const char *target, const char *linkpath);
|
||||
int xmount(const char *source, const char *target,
|
||||
const char *filesystemtype, unsigned long mountflags,
|
||||
const void *data);
|
||||
int xumount(const char *target);
|
||||
int xumount2(const char *target, int flags);
|
||||
int xrename(const char *oldpath, const char *newpath);
|
||||
int xmkdir(const char *pathname, mode_t mode);
|
||||
int xmkdirs(const char *pathname, mode_t mode);
|
||||
int xmkdirat(int dirfd, const char *pathname, mode_t mode);
|
||||
void *xmmap(void *addr, size_t length, int prot, int flags,
|
||||
int fd, off_t offset);
|
||||
ssize_t xsendfile(int out_fd, int in_fd, off_t *offset, size_t count);
|
||||
pid_t xfork();
|
||||
|
||||
// misc.c
|
||||
|
||||
#define quit_signals ((int []) { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 })
|
||||
|
||||
unsigned get_shell_uid();
|
||||
unsigned get_system_uid();
|
||||
unsigned get_radio_uid();
|
||||
int check_data();
|
||||
int file_to_vector(const char* filename, struct vector *v);
|
||||
int vector_to_file(const char* filename, struct vector *v);
|
||||
ssize_t fdgets(char *buf, size_t size, int fd);
|
||||
void ps(void (*func)(int));
|
||||
void ps_filter_proc_name(const char *filter, void (*func)(int));
|
||||
void unlock_blocks();
|
||||
void setup_sighandlers(void (*handler)(int));
|
||||
int exec_command(int err, int *fd, void (*setupenv)(struct vector*), const char *argv0, ...);
|
||||
int exec_command_sync(char *const argv0, ...);
|
||||
int bind_mount(const char *from, const char *to);
|
||||
void get_client_cred(int fd, struct ucred *cred);
|
||||
int switch_mnt_ns(int pid);
|
||||
int fork_dont_care();
|
||||
void wait_till_exists(const char *target);
|
||||
|
||||
// file.c
|
||||
|
||||
extern char **excl_list;
|
||||
|
||||
struct file_attr {
|
||||
struct stat st;
|
||||
char con[128];
|
||||
};
|
||||
|
||||
int fd_getpath(int fd, char *path, size_t size);
|
||||
int mkdirs(const char *pathname, mode_t mode);
|
||||
void in_order_walk(int dirfd, void (*callback)(int, struct dirent*));
|
||||
void rm_rf(const char *path);
|
||||
void frm_rf(int dirfd);
|
||||
void mv_f(const char *source, const char *destination);
|
||||
void mv_dir(int src, int dest);
|
||||
void cp_afc(const char *source, const char *destination);
|
||||
void clone_dir(int src, int dest);
|
||||
int getattr(const char *path, struct file_attr *a);
|
||||
int getattrat(int dirfd, const char *pathname, struct file_attr *a);
|
||||
int fgetattr(int fd, struct file_attr *a);
|
||||
int setattr(const char *path, struct file_attr *a);
|
||||
int setattrat(int dirfd, const char *pathname, struct file_attr *a);
|
||||
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);
|
||||
int mmap_ro(const char *filename, void **buf, size_t *size);
|
||||
int mmap_rw(const char *filename, void **buf, size_t *size);
|
||||
void fd_full_read(int fd, void **buf, size_t *size);
|
||||
void full_read(const char *filename, void **buf, size_t *size);
|
||||
void full_read_at(int dirfd, const char *filename, void **buf, size_t *size);
|
||||
void stream_full_read(int fd, void **buf, size_t *size);
|
||||
void write_zero(int fd, size_t size);
|
||||
void mem_align(size_t *pos, size_t align);
|
||||
void file_align(int fd, size_t align, int out);
|
||||
|
||||
// img.c
|
||||
|
||||
#define round_size(a) ((((a) / 32) + 2) * 32)
|
||||
#define SOURCE_TMP "/dev/source"
|
||||
#define TARGET_TMP "/dev/target"
|
||||
|
||||
int create_img(const char *img, int size);
|
||||
int get_img_size(const char *img, int *used, int *total);
|
||||
int resize_img(const char *img, int size);
|
||||
char *mount_image(const char *img, const char *target);
|
||||
void umount_image(const char *target, const char *device);
|
||||
int merge_img(const char *source, const char *target);
|
||||
void trim_img(const char *img);
|
||||
|
||||
// pattern.c
|
||||
|
||||
void patch_init_rc(void **buf, size_t *size);
|
||||
int patch_verity(void **buf, uint32_t *size, int patch);
|
||||
void patch_encryption(void **buf, uint32_t *size);
|
||||
|
||||
#endif
|
37
native/jni/include/vector.h
Normal file
37
native/jni/include/vector.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* vector.h - A simple vector implementation in c
|
||||
*/
|
||||
|
||||
#ifndef _VECTOR_H_
|
||||
#define _VECTOR_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct vector {
|
||||
unsigned size;
|
||||
unsigned cap;
|
||||
void **data;
|
||||
};
|
||||
|
||||
void vec_init(struct vector *v);
|
||||
void vec_push_back(struct vector *v, void *p);
|
||||
void *vec_pop_back(struct vector *v);
|
||||
void vec_sort(struct vector *v, int (*compar)(const void *, const void *));
|
||||
void vec_destroy(struct vector *v);
|
||||
void vec_deep_destroy(struct vector *v);
|
||||
struct vector *vec_dup(struct vector *v);
|
||||
|
||||
#define vec_size(v) (v)->size
|
||||
#define vec_cap(v) (v)->cap
|
||||
#define vec_entry(v) (v)->data
|
||||
/* Usage: vec_for_each(vector *v, void *e) */
|
||||
#define vec_for_each(v, e) \
|
||||
e = v ? (v)->data[0] : NULL; \
|
||||
for (int _ = 0; v && _ < (v)->size; ++_, e = (v)->data[_])
|
||||
|
||||
#define vec_for_each_r(v, e) \
|
||||
e = (v && (v)->size > 0) ? (v)->data[(v)->size - 1] : NULL; \
|
||||
for (int _ = ((int) (v)->size) - 1; v && _ >= 0; --_, e = (v)->data[_])
|
||||
|
||||
#define vec_cur(v) vec_entry(v)[_]
|
||||
|
||||
#endif
|
308
native/jni/magiskboot/bootimg.c
Normal file
308
native/jni/magiskboot/bootimg.c
Normal file
@@ -0,0 +1,308 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "bootimg.h"
|
||||
#include "magiskboot.h"
|
||||
#include "utils.h"
|
||||
#include "logging.h"
|
||||
|
||||
#define INSUF_BLOCK_RET 2
|
||||
#define CHROMEOS_RET 3
|
||||
#define ELF32_RET 4
|
||||
#define ELF64_RET 5
|
||||
|
||||
static void dump(void *buf, size_t size, const char *filename) {
|
||||
int fd = creat(filename, 0644);
|
||||
xwrite(fd, buf, size);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static size_t restore(const char *filename, int fd) {
|
||||
int ifd = xopen(filename, O_RDONLY);
|
||||
size_t size = lseek(ifd, 0, SEEK_END);
|
||||
lseek(ifd, 0, SEEK_SET);
|
||||
xsendfile(fd, ifd, NULL, size);
|
||||
close(ifd);
|
||||
return size;
|
||||
}
|
||||
|
||||
static void restore_buf(int fd, const void *buf, size_t size) {
|
||||
xwrite(fd, buf, size);
|
||||
}
|
||||
|
||||
static void print_hdr(const boot_img_hdr *hdr) {
|
||||
fprintf(stderr, "KERNEL [%d] @ 0x%08x\n", hdr->kernel_size, hdr->kernel_addr);
|
||||
fprintf(stderr, "RAMDISK [%d] @ 0x%08x\n", hdr->ramdisk_size, hdr->ramdisk_addr);
|
||||
fprintf(stderr, "SECOND [%d] @ 0x%08x\n", hdr->second_size, hdr->second_addr);
|
||||
fprintf(stderr, "EXTRA [%d] @ 0x%08x\n", hdr->extra_size, hdr->tags_addr);
|
||||
fprintf(stderr, "PAGESIZE [%d]\n", hdr->page_size);
|
||||
if (hdr->os_version != 0) {
|
||||
int a,b,c,y,m = 0;
|
||||
int os_version, os_patch_level;
|
||||
os_version = hdr->os_version >> 11;
|
||||
os_patch_level = hdr->os_version & 0x7ff;
|
||||
|
||||
a = (os_version >> 14) & 0x7f;
|
||||
b = (os_version >> 7) & 0x7f;
|
||||
c = os_version & 0x7f;
|
||||
fprintf(stderr, "OS_VERSION [%d.%d.%d]\n", a, b, c);
|
||||
|
||||
y = (os_patch_level >> 4) + 2000;
|
||||
m = os_patch_level & 0xf;
|
||||
fprintf(stderr, "PATCH_LEVEL [%d-%02d]\n", y, m);
|
||||
}
|
||||
fprintf(stderr, "NAME [%s]\n", hdr->name);
|
||||
fprintf(stderr, "CMDLINE [%s]\n", hdr->cmdline);
|
||||
}
|
||||
|
||||
int parse_img(const char *image, boot_img *boot) {
|
||||
memset(boot, 0, sizeof(*boot));
|
||||
int is_blk = mmap_ro(image, &boot->map_addr, &boot->map_size);
|
||||
|
||||
// Parse image
|
||||
fprintf(stderr, "Parsing boot image: [%s]\n", image);
|
||||
for (void *head = boot->map_addr; head < boot->map_addr + boot->map_size; head += 256) {
|
||||
size_t pos = 0;
|
||||
|
||||
switch (check_type(head)) {
|
||||
case CHROMEOS:
|
||||
// The caller should know it's chromeos, as it needs additional signing
|
||||
boot->flags |= CHROMEOS_FLAG;
|
||||
continue;
|
||||
case ELF32:
|
||||
exit(ELF32_RET);
|
||||
case ELF64:
|
||||
exit(ELF64_RET);
|
||||
case AOSP:
|
||||
// Read the header
|
||||
memcpy(&boot->hdr, head + pos, sizeof(boot->hdr));
|
||||
pos += boot->hdr.page_size;
|
||||
|
||||
print_hdr(&boot->hdr);
|
||||
|
||||
boot->kernel = head + pos;
|
||||
pos += boot->hdr.kernel_size;
|
||||
mem_align(&pos, boot->hdr.page_size);
|
||||
|
||||
boot->ramdisk = head + pos;
|
||||
pos += boot->hdr.ramdisk_size;
|
||||
mem_align(&pos, boot->hdr.page_size);
|
||||
|
||||
if (boot->hdr.second_size) {
|
||||
boot->second = head + pos;
|
||||
pos += boot->hdr.second_size;
|
||||
mem_align(&pos, boot->hdr.page_size);
|
||||
}
|
||||
|
||||
if (boot->hdr.extra_size) {
|
||||
boot->extra = head + pos;
|
||||
pos += boot->hdr.extra_size;
|
||||
mem_align(&pos, boot->hdr.page_size);
|
||||
}
|
||||
|
||||
if (pos < boot->map_size) {
|
||||
boot->tail = head + pos;
|
||||
boot->tail_size = boot->map_size - pos;
|
||||
}
|
||||
|
||||
// Search for dtb in kernel
|
||||
for (uint32_t i = 0; i < boot->hdr.kernel_size; ++i) {
|
||||
if (memcmp(boot->kernel + i, DTB_MAGIC, 4) == 0) {
|
||||
boot->dtb = boot->kernel + i;
|
||||
boot->dt_size = boot->hdr.kernel_size - i;
|
||||
boot->hdr.kernel_size = i;
|
||||
fprintf(stderr, "DTB [%u]\n", boot->dt_size);
|
||||
}
|
||||
}
|
||||
|
||||
boot->ramdisk_type = check_type(boot->ramdisk);
|
||||
boot->kernel_type = check_type(boot->kernel);
|
||||
|
||||
// Check MTK
|
||||
if (boot->kernel_type == MTK) {
|
||||
fprintf(stderr, "MTK_KERNEL_HDR [512]\n");
|
||||
boot->flags |= MTK_KERNEL;
|
||||
memcpy(&boot->mtk_kernel_hdr, boot->kernel, sizeof(mtk_hdr));
|
||||
boot->kernel += 512;
|
||||
boot->hdr.kernel_size -= 512;
|
||||
boot->kernel_type = check_type(boot->kernel);
|
||||
}
|
||||
if (boot->ramdisk_type == MTK) {
|
||||
fprintf(stderr, "MTK_RAMDISK_HDR [512]\n");
|
||||
boot->flags |= MTK_RAMDISK;
|
||||
memcpy(&boot->mtk_ramdisk_hdr, boot->ramdisk, sizeof(mtk_hdr));
|
||||
boot->ramdisk += 512;
|
||||
boot->hdr.ramdisk_size -= 512;
|
||||
boot->ramdisk_type = check_type(boot->ramdisk);
|
||||
}
|
||||
|
||||
char fmt[16];
|
||||
|
||||
get_type_name(boot->kernel_type, fmt);
|
||||
fprintf(stderr, "KERNEL_FMT [%s]\n", fmt);
|
||||
get_type_name(boot->ramdisk_type, fmt);
|
||||
fprintf(stderr, "RAMDISK_FMT [%s]\n", fmt);
|
||||
|
||||
return boot->flags & CHROMEOS_FLAG ? CHROMEOS_RET :
|
||||
((is_blk && boot->tail_size < 500 * 1024) ? INSUF_BLOCK_RET : 0);
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
LOGE("No boot image magic found!\n");
|
||||
}
|
||||
|
||||
void unpack(const char* image) {
|
||||
boot_img boot;
|
||||
int ret = parse_img(image, &boot);
|
||||
int fd;
|
||||
|
||||
// Dump kernel
|
||||
if (COMPRESSED(boot.kernel_type)) {
|
||||
fd = creat(KERNEL_FILE, 0644);
|
||||
decomp(boot.kernel_type, fd, boot.kernel, boot.hdr.kernel_size);
|
||||
close(fd);
|
||||
} else {
|
||||
dump(boot.kernel, boot.hdr.kernel_size, KERNEL_FILE);
|
||||
}
|
||||
|
||||
if (boot.dt_size) {
|
||||
// Dump dtb
|
||||
dump(boot.dtb, boot.dt_size, DTB_FILE);
|
||||
}
|
||||
|
||||
// Dump ramdisk
|
||||
if (COMPRESSED(boot.ramdisk_type)) {
|
||||
fd = creat(RAMDISK_FILE, 0644);
|
||||
decomp(boot.ramdisk_type, fd, boot.ramdisk, boot.hdr.ramdisk_size);
|
||||
close(fd);
|
||||
} else {
|
||||
dump(boot.ramdisk, boot.hdr.ramdisk_size, RAMDISK_FILE ".raw");
|
||||
LOGE("Unknown ramdisk format! Dumped to %s\n", RAMDISK_FILE ".raw");
|
||||
}
|
||||
|
||||
if (boot.hdr.second_size) {
|
||||
// Dump second
|
||||
dump(boot.second, boot.hdr.second_size, SECOND_FILE);
|
||||
}
|
||||
|
||||
if (boot.hdr.extra_size) {
|
||||
// Dump extra
|
||||
dump(boot.extra, boot.hdr.extra_size, EXTRA_FILE);
|
||||
}
|
||||
|
||||
munmap(boot.map_addr, boot.map_size);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
void repack(const char* orig_image, const char* out_image) {
|
||||
boot_img boot;
|
||||
|
||||
// There are possible two MTK headers
|
||||
size_t mtk_kernel_off, mtk_ramdisk_off;
|
||||
|
||||
// Parse original image
|
||||
parse_img(orig_image, &boot);
|
||||
|
||||
fprintf(stderr, "Repack to boot image: [%s]\n", out_image);
|
||||
|
||||
// Create new image
|
||||
int fd = creat(out_image, 0644);
|
||||
|
||||
// Skip a page for header
|
||||
write_zero(fd, boot.hdr.page_size);
|
||||
|
||||
if (boot.flags & MTK_KERNEL) {
|
||||
// Record position and skip MTK header
|
||||
mtk_kernel_off = lseek(fd, 0, SEEK_CUR);
|
||||
write_zero(fd, 512);
|
||||
}
|
||||
if (COMPRESSED(boot.kernel_type)) {
|
||||
size_t raw_size;
|
||||
void *kernel_raw;
|
||||
mmap_ro(KERNEL_FILE, &kernel_raw, &raw_size);
|
||||
boot.hdr.kernel_size = comp(boot.kernel_type, fd, kernel_raw, raw_size);
|
||||
munmap(kernel_raw, raw_size);
|
||||
} else {
|
||||
boot.hdr.kernel_size = restore(KERNEL_FILE, fd);
|
||||
}
|
||||
// Restore dtb
|
||||
if (boot.dt_size && access(DTB_FILE, R_OK) == 0) {
|
||||
boot.hdr.kernel_size += restore(DTB_FILE, fd);
|
||||
}
|
||||
file_align(fd, boot.hdr.page_size, 1);
|
||||
|
||||
if (boot.flags & MTK_RAMDISK) {
|
||||
// Record position and skip MTK header
|
||||
mtk_ramdisk_off = lseek(fd, 0, SEEK_CUR);
|
||||
write_zero(fd, 512);
|
||||
}
|
||||
if (access(RAMDISK_FILE, R_OK) == 0) {
|
||||
// If we found raw cpio, compress to original format
|
||||
size_t cpio_size;
|
||||
void *cpio;
|
||||
mmap_ro(RAMDISK_FILE, &cpio, &cpio_size);
|
||||
boot.hdr.ramdisk_size = comp(boot.ramdisk_type, fd, cpio, cpio_size);
|
||||
munmap(cpio, cpio_size);
|
||||
} else {
|
||||
// Find compressed ramdisk
|
||||
char name[PATH_MAX];
|
||||
int found = 0;
|
||||
for (int i = 0; SUP_EXT_LIST[i]; ++i) {
|
||||
sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]);
|
||||
if (access(name, R_OK) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
LOGE("No ramdisk exists!\n");
|
||||
boot.hdr.ramdisk_size = restore(name, fd);
|
||||
}
|
||||
file_align(fd, boot.hdr.page_size, 1);
|
||||
|
||||
// Restore second
|
||||
if (boot.hdr.second_size && access(SECOND_FILE, R_OK) == 0) {
|
||||
boot.hdr.second_size = restore(SECOND_FILE, fd);
|
||||
file_align(fd, boot.hdr.page_size, 1);
|
||||
}
|
||||
|
||||
// Restore extra
|
||||
if (boot.hdr.extra_size && access(EXTRA_FILE, R_OK) == 0) {
|
||||
boot.hdr.extra_size = restore(EXTRA_FILE, fd);
|
||||
file_align(fd, boot.hdr.page_size, 1);
|
||||
}
|
||||
|
||||
// Check tail info, currently only for LG Bump and Samsung SEANDROIDENFORCE
|
||||
if (boot.tail_size >= 16) {
|
||||
if (memcmp(boot.tail, "SEANDROIDENFORCE", 16) == 0 ||
|
||||
memcmp(boot.tail, LG_BUMP_MAGIC, 16) == 0 ) {
|
||||
restore_buf(fd, boot.tail, 16);
|
||||
}
|
||||
}
|
||||
|
||||
// Write MTK headers back
|
||||
if (boot.flags & MTK_KERNEL) {
|
||||
lseek(fd, mtk_kernel_off, SEEK_SET);
|
||||
boot.mtk_kernel_hdr.size = boot.hdr.kernel_size;
|
||||
boot.hdr.kernel_size += 512;
|
||||
restore_buf(fd, &boot.mtk_kernel_hdr, sizeof(mtk_hdr));
|
||||
}
|
||||
if (boot.flags & MTK_RAMDISK) {
|
||||
lseek(fd, mtk_ramdisk_off, SEEK_SET);
|
||||
boot.mtk_ramdisk_hdr.size = boot.hdr.ramdisk_size;
|
||||
boot.hdr.ramdisk_size += 512;
|
||||
restore_buf(fd, &boot.mtk_ramdisk_hdr, sizeof(mtk_hdr));
|
||||
}
|
||||
// Main header
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
restore_buf(fd, &boot.hdr, sizeof(boot.hdr));
|
||||
|
||||
// Print new image info
|
||||
print_hdr(&boot.hdr);
|
||||
|
||||
munmap(boot.map_addr, boot.map_size);
|
||||
close(fd);
|
||||
}
|
127
native/jni/magiskboot/bootimg.h
Normal file
127
native/jni/magiskboot/bootimg.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/* tools/mkbootimg/bootimg.h
|
||||
**
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "types.h"
|
||||
|
||||
#ifndef _BOOT_IMAGE_H_
|
||||
#define _BOOT_IMAGE_H_
|
||||
|
||||
typedef struct boot_img_hdr boot_img_hdr;
|
||||
|
||||
#define BOOT_MAGIC "ANDROID!"
|
||||
#define BOOT_MAGIC_SIZE 8
|
||||
#define BOOT_NAME_SIZE 16
|
||||
#define BOOT_ARGS_SIZE 512
|
||||
#define BOOT_EXTRA_ARGS_SIZE 1024
|
||||
|
||||
struct boot_img_hdr
|
||||
{
|
||||
uint8_t magic[BOOT_MAGIC_SIZE];
|
||||
|
||||
uint32_t kernel_size; /* size in bytes */
|
||||
uint32_t kernel_addr; /* physical load addr */
|
||||
|
||||
uint32_t ramdisk_size; /* size in bytes */
|
||||
uint32_t ramdisk_addr; /* physical load addr */
|
||||
|
||||
uint32_t second_size; /* size in bytes */
|
||||
uint32_t second_addr; /* physical load addr */
|
||||
|
||||
uint32_t tags_addr; /* physical addr for kernel tags */
|
||||
uint32_t page_size; /* flash page size we assume */
|
||||
uint32_t extra_size; /* extra blob size in bytes */
|
||||
|
||||
/* operating system version and security patch level; for
|
||||
* version "A.B.C" and patch level "Y-M-D":
|
||||
* ver = A << 14 | B << 7 | C (7 bits for each of A, B, C)
|
||||
* lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M)
|
||||
* os_version = ver << 11 | lvl */
|
||||
uint32_t os_version;
|
||||
|
||||
uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
|
||||
|
||||
uint8_t cmdline[BOOT_ARGS_SIZE];
|
||||
|
||||
uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
|
||||
|
||||
/* Supplemental command line data; kept here to maintain
|
||||
* binary compatibility with older versions of mkbootimg */
|
||||
uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
** +-----------------+
|
||||
** | boot header | 1 page
|
||||
** +-----------------+
|
||||
** | kernel | n pages
|
||||
** +-----------------+
|
||||
** | ramdisk | m pages
|
||||
** +-----------------+
|
||||
** | second stage | o pages
|
||||
** +-----------------+
|
||||
** | extra blobs | p pages
|
||||
** +-----------------+
|
||||
**
|
||||
** n = (kernel_size + page_size - 1) / page_size
|
||||
** m = (ramdisk_size + page_size - 1) / page_size
|
||||
** o = (second_size + page_size - 1) / page_size
|
||||
** p = (extra_size + page_size - 1) / page_size
|
||||
**
|
||||
** 0. all entities are page_size aligned in flash
|
||||
** 1. kernel and ramdisk are required (size != 0)
|
||||
** 2. second is optional (second_size == 0 -> no second)
|
||||
** 3. load each element (kernel, ramdisk, second) at
|
||||
** the specified physical address (kernel_addr, etc)
|
||||
** 4. prepare tags at tag_addr. kernel_args[] is
|
||||
** appended to the kernel commandline in the tags.
|
||||
** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
|
||||
** 6. if second_size != 0: jump to second_addr
|
||||
** else: jump to kernel_addr
|
||||
*/
|
||||
|
||||
typedef struct mtk_hdr {
|
||||
uint8_t magic[4]; /* MTK magic */
|
||||
uint32_t size; /* Size of the content */
|
||||
uint8_t name[32]; /* The type of the header */
|
||||
} mtk_hdr;
|
||||
|
||||
// Flags
|
||||
#define MTK_KERNEL 0x1
|
||||
#define MTK_RAMDISK 0x2
|
||||
#define CHROMEOS_FLAG 0x4
|
||||
|
||||
typedef struct boot_img {
|
||||
size_t map_size;
|
||||
uint32_t dt_size;
|
||||
size_t tail_size;
|
||||
uint8_t flags;
|
||||
file_t kernel_type, ramdisk_type;
|
||||
|
||||
boot_img_hdr hdr;
|
||||
mtk_hdr mtk_kernel_hdr, mtk_ramdisk_hdr;
|
||||
|
||||
void *map_addr;
|
||||
void *kernel;
|
||||
void *dtb;
|
||||
void *ramdisk;
|
||||
void *second;
|
||||
void *extra;
|
||||
void *tail;
|
||||
} boot_img;
|
||||
|
||||
#endif
|
512
native/jni/magiskboot/compress.c
Normal file
512
native/jni/magiskboot/compress.c
Normal file
@@ -0,0 +1,512 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <zlib.h>
|
||||
#include <lzma.h>
|
||||
#include <lz4.h>
|
||||
#include <lz4frame.h>
|
||||
#include <lz4hc.h>
|
||||
#include <bzlib.h>
|
||||
|
||||
#include "magiskboot.h"
|
||||
#include "logging.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define CHUNK 0x40000
|
||||
|
||||
// Mode: 0 = decode; 1 = encode
|
||||
size_t gzip(int mode, int fd, const void *buf, size_t size) {
|
||||
size_t ret = 0, have, total = 0;
|
||||
z_stream strm;
|
||||
unsigned char out[CHUNK];
|
||||
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ret = inflateInit2(&strm, 15 | 16);
|
||||
break;
|
||||
case 1:
|
||||
ret = deflateInit2(&strm, 9, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != Z_OK)
|
||||
LOGE("Unable to init zlib stream\n");
|
||||
|
||||
strm.next_in = (void *) buf;
|
||||
strm.avail_in = size;
|
||||
|
||||
do {
|
||||
strm.avail_out = CHUNK;
|
||||
strm.next_out = out;
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ret = inflate(&strm, Z_FINISH);
|
||||
break;
|
||||
case 1:
|
||||
ret = deflate(&strm, Z_FINISH);
|
||||
break;
|
||||
}
|
||||
if (ret == Z_STREAM_ERROR)
|
||||
LOGE("Error when running gzip\n");
|
||||
have = CHUNK - strm.avail_out;
|
||||
total += xwrite(fd, out, have);
|
||||
} while (strm.avail_out == 0);
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
inflateEnd(&strm);
|
||||
break;
|
||||
case 1:
|
||||
deflateEnd(&strm);
|
||||
break;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
// Mode: 0 = decode xz/lzma; 1 = encode xz; 2 = encode lzma
|
||||
size_t lzma(int mode, int fd, const void *buf, size_t size) {
|
||||
size_t have, total = 0;
|
||||
lzma_ret ret = 0;
|
||||
lzma_stream strm = LZMA_STREAM_INIT;
|
||||
lzma_options_lzma opt;
|
||||
unsigned char out[CHUNK];
|
||||
|
||||
// Initialize preset
|
||||
lzma_lzma_preset(&opt, 9);
|
||||
lzma_filter filters[] = {
|
||||
{ .id = LZMA_FILTER_LZMA2, .options = &opt },
|
||||
{ .id = LZMA_VLI_UNKNOWN, .options = NULL },
|
||||
};
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ret = lzma_auto_decoder(&strm, UINT64_MAX, 0);
|
||||
break;
|
||||
case 1:
|
||||
ret = lzma_stream_encoder(&strm, filters, LZMA_CHECK_CRC32);
|
||||
break;
|
||||
case 2:
|
||||
ret = lzma_alone_encoder(&strm, &opt);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (ret != LZMA_OK)
|
||||
LOGE("Unable to init lzma stream\n");
|
||||
|
||||
strm.next_in = buf;
|
||||
strm.avail_in = size;
|
||||
|
||||
do {
|
||||
strm.avail_out = CHUNK;
|
||||
strm.next_out = out;
|
||||
ret = lzma_code(&strm, LZMA_FINISH);
|
||||
if (ret != LZMA_OK && ret != LZMA_STREAM_END)
|
||||
LOGE("LZMA error %d!\n", ret);
|
||||
have = CHUNK - strm.avail_out;
|
||||
total += xwrite(fd, out, have);
|
||||
} while (strm.avail_out == 0);
|
||||
|
||||
lzma_end(&strm);
|
||||
return total;
|
||||
}
|
||||
|
||||
// Mode: 0 = decode; 1 = encode
|
||||
size_t lz4(int mode, int fd, const void *buf, size_t size) {
|
||||
LZ4F_decompressionContext_t dctx;
|
||||
LZ4F_compressionContext_t cctx;
|
||||
LZ4F_frameInfo_t info;
|
||||
|
||||
size_t blockSize, outCapacity, avail_in, ret = 0, pos = 0, total = 0;
|
||||
size_t have, read;
|
||||
void *out = NULL;
|
||||
|
||||
// Initialize context
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ret = LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION);
|
||||
break;
|
||||
case 1:
|
||||
ret = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION);
|
||||
break;
|
||||
}
|
||||
|
||||
if (LZ4F_isError(ret))
|
||||
LOGE("Context creation error: %s\n", LZ4F_getErrorName(ret));
|
||||
|
||||
// Allocate out buffer
|
||||
blockSize = 1 << 22;
|
||||
switch(mode) {
|
||||
case 0:
|
||||
// Read header
|
||||
read = blockSize;
|
||||
ret = LZ4F_getFrameInfo(dctx, &info, buf, &read);
|
||||
if (LZ4F_isError(ret))
|
||||
LOGE("LZ4F_getFrameInfo error: %s\n", LZ4F_getErrorName(ret));
|
||||
switch (info.blockSizeID) {
|
||||
case LZ4F_default:
|
||||
case LZ4F_max64KB: outCapacity = 1 << 16; break;
|
||||
case LZ4F_max256KB: outCapacity = 1 << 18; break;
|
||||
case LZ4F_max1MB: outCapacity = 1 << 20; break;
|
||||
case LZ4F_max4MB: outCapacity = 1 << 22; break;
|
||||
default:
|
||||
LOGE("Impossible unless more block sizes are allowed\n");
|
||||
}
|
||||
pos += read;
|
||||
break;
|
||||
case 1:
|
||||
outCapacity = LZ4F_compressFrameBound(blockSize, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
out = xmalloc(outCapacity);
|
||||
|
||||
// Write header
|
||||
if (mode == 1) {
|
||||
LZ4F_preferences_t prefs;
|
||||
memset(&prefs, 0, sizeof(prefs));
|
||||
prefs.autoFlush = 1;
|
||||
prefs.compressionLevel = 9;
|
||||
prefs.frameInfo.blockMode = 1;
|
||||
prefs.frameInfo.blockSizeID = 7;
|
||||
prefs.frameInfo.contentChecksumFlag = 1;
|
||||
have = ret = LZ4F_compressBegin(cctx, out, size, &prefs);
|
||||
if (LZ4F_isError(ret))
|
||||
LOGE("Failed to start compression: error %s\n", LZ4F_getErrorName(ret));
|
||||
total += xwrite(fd, out, have);
|
||||
}
|
||||
|
||||
do {
|
||||
if (pos + blockSize >= size) {
|
||||
avail_in = size - pos;
|
||||
} else {
|
||||
avail_in = blockSize;
|
||||
}
|
||||
|
||||
do {
|
||||
switch(mode) {
|
||||
case 0:
|
||||
have = outCapacity;
|
||||
read = avail_in;
|
||||
ret = LZ4F_decompress(dctx, out, &have, buf + pos, &read, NULL);
|
||||
break;
|
||||
case 1:
|
||||
read = avail_in;
|
||||
have = ret = LZ4F_compressUpdate(cctx, out, outCapacity, buf + pos, avail_in, NULL);
|
||||
break;
|
||||
}
|
||||
if (LZ4F_isError(ret))
|
||||
LOGE("LZ4 coding error: %s\n", LZ4F_getErrorName(ret));
|
||||
|
||||
total += xwrite(fd, out, have);
|
||||
// Update status
|
||||
pos += read;
|
||||
avail_in -= read;
|
||||
} while(avail_in != 0 && ret != 0);
|
||||
|
||||
} while(pos < size && ret != 0);
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
LZ4F_freeDecompressionContext(dctx);
|
||||
break;
|
||||
case 1:
|
||||
have = ret = LZ4F_compressEnd(cctx, out, outCapacity, NULL);
|
||||
if (LZ4F_isError(ret))
|
||||
LOGE("Failed to end compression: error %s\n", LZ4F_getErrorName(ret));
|
||||
|
||||
total += xwrite(fd, out, have);
|
||||
|
||||
LZ4F_freeCompressionContext(cctx);
|
||||
break;
|
||||
}
|
||||
|
||||
free(out);
|
||||
return total;
|
||||
}
|
||||
|
||||
// Mode: 0 = decode; 1 = encode
|
||||
size_t bzip2(int mode, int fd, const void* buf, size_t size) {
|
||||
size_t ret = 0, have, total = 0;
|
||||
bz_stream strm;
|
||||
char out[CHUNK];
|
||||
|
||||
strm.bzalloc = NULL;
|
||||
strm.bzfree = NULL;
|
||||
strm.opaque = NULL;
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ret = BZ2_bzDecompressInit(&strm, 0, 0);
|
||||
break;
|
||||
case 1:
|
||||
ret = BZ2_bzCompressInit(&strm, 9, 0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != BZ_OK)
|
||||
LOGE("Unable to init bzlib stream\n");
|
||||
|
||||
strm.next_in = (void *) buf;
|
||||
strm.avail_in = size;
|
||||
|
||||
do {
|
||||
strm.avail_out = CHUNK;
|
||||
strm.next_out = out;
|
||||
switch(mode) {
|
||||
case 0:
|
||||
ret = BZ2_bzDecompress(&strm);
|
||||
break;
|
||||
case 1:
|
||||
ret = BZ2_bzCompress(&strm, BZ_FINISH);
|
||||
break;
|
||||
}
|
||||
have = CHUNK - strm.avail_out;
|
||||
total += xwrite(fd, out, have);
|
||||
} while (strm.avail_out == 0);
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
BZ2_bzDecompressEnd(&strm);
|
||||
break;
|
||||
case 1:
|
||||
BZ2_bzCompressEnd(&strm);
|
||||
break;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
#define LZ4_LEGACY_BLOCKSIZE 0x800000
|
||||
|
||||
// Mode: 0 = decode; 1 = encode
|
||||
size_t lz4_legacy(int mode, int fd, const void* buf, size_t size) {
|
||||
size_t pos = 0;
|
||||
int have;
|
||||
char *out;
|
||||
unsigned block_size, insize, total = 0;
|
||||
|
||||
switch(mode) {
|
||||
case 0:
|
||||
out = xmalloc(LZ4_LEGACY_BLOCKSIZE);
|
||||
// Skip magic
|
||||
pos += 4;
|
||||
break;
|
||||
case 1:
|
||||
out = xmalloc(LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE));
|
||||
// Write magic
|
||||
total += xwrite(fd, "\x02\x21\x4c\x18", 4);
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
switch(mode) {
|
||||
case 0:
|
||||
// Read block size
|
||||
block_size = *(unsigned *)(buf + pos);
|
||||
pos += 4;
|
||||
if (block_size > LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE))
|
||||
goto done;
|
||||
have = LZ4_decompress_safe(buf + pos, out, block_size, LZ4_LEGACY_BLOCKSIZE);
|
||||
if (have < 0)
|
||||
LOGE("Cannot decode lz4_legacy block\n");
|
||||
pos += block_size;
|
||||
break;
|
||||
case 1:
|
||||
if (pos + LZ4_LEGACY_BLOCKSIZE >= size)
|
||||
insize = size - pos;
|
||||
else
|
||||
insize = LZ4_LEGACY_BLOCKSIZE;
|
||||
have = LZ4_compress_HC(buf + pos, out, insize, LZ4_COMPRESSBOUND(LZ4_LEGACY_BLOCKSIZE), 9);
|
||||
if (have == 0)
|
||||
LOGE("lz4_legacy compression error\n");
|
||||
pos += insize;
|
||||
// Write block size
|
||||
total += xwrite(fd, &have, sizeof(have));
|
||||
break;
|
||||
}
|
||||
// Write main data
|
||||
total += xwrite(fd, out, have);
|
||||
} while(pos < size);
|
||||
|
||||
done:
|
||||
if (mode == 1) {
|
||||
// Append original size to output
|
||||
unsigned uncomp = size;
|
||||
xwrite(fd, &uncomp, sizeof(uncomp));
|
||||
}
|
||||
free(out);
|
||||
return total;
|
||||
}
|
||||
|
||||
long long decomp(file_t type, int to, const void *from, size_t size) {
|
||||
switch (type) {
|
||||
case GZIP:
|
||||
return gzip(0, to, from, size);
|
||||
case XZ:
|
||||
return lzma(0, to, from, size);
|
||||
case LZMA:
|
||||
return lzma(0, to, from, size);
|
||||
case BZIP2:
|
||||
return bzip2(0, to, from, size);
|
||||
case LZ4:
|
||||
return lz4(0, to, from, size);
|
||||
case LZ4_LEGACY:
|
||||
return lz4_legacy(0, to, from, size);
|
||||
default:
|
||||
// Unsupported
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
long long comp(file_t type, int to, const void *from, size_t size) {
|
||||
switch (type) {
|
||||
case GZIP:
|
||||
return gzip(1, to, from, size);
|
||||
case XZ:
|
||||
return lzma(1, to, from, size);
|
||||
case LZMA:
|
||||
return lzma(2, to, from, size);
|
||||
case BZIP2:
|
||||
return bzip2(1, to, from, size);
|
||||
case LZ4:
|
||||
return lz4(1, to, from, size);
|
||||
case LZ4_LEGACY:
|
||||
return lz4_legacy(1, to, from, size);
|
||||
default:
|
||||
// Unsupported
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Below are utility functions for commandline
|
||||
*/
|
||||
|
||||
void decomp_file(char *from, const char *to) {
|
||||
int strip = 1;
|
||||
void *file;
|
||||
size_t size = 0;
|
||||
if (strcmp(from, "-") == 0)
|
||||
stream_full_read(STDIN_FILENO, &file, &size);
|
||||
else
|
||||
mmap_ro(from, &file, &size);
|
||||
file_t type = check_type(file);
|
||||
char *ext;
|
||||
ext = strrchr(from, '.');
|
||||
if (to == NULL)
|
||||
to = from;
|
||||
if (ext != NULL) {
|
||||
// Strip out a matched file extension
|
||||
switch (type) {
|
||||
case GZIP:
|
||||
if (strcmp(ext, ".gz") != 0)
|
||||
strip = 0;
|
||||
break;
|
||||
case XZ:
|
||||
if (strcmp(ext, ".xz") != 0)
|
||||
strip = 0;
|
||||
break;
|
||||
case LZMA:
|
||||
if (strcmp(ext, ".lzma") != 0)
|
||||
strip = 0;
|
||||
break;
|
||||
case BZIP2:
|
||||
if (strcmp(ext, ".bz2") != 0)
|
||||
strip = 0;
|
||||
break;
|
||||
case LZ4_LEGACY:
|
||||
case LZ4:
|
||||
if (strcmp(ext, ".lz4") != 0)
|
||||
strip = 0;
|
||||
break;
|
||||
default:
|
||||
LOGE("Provided file \'%s\' is not a supported archive format\n", from);
|
||||
}
|
||||
if (strip)
|
||||
*ext = '\0';
|
||||
}
|
||||
|
||||
int fd;
|
||||
|
||||
if (strcmp(to, "-") == 0) {
|
||||
fd = STDOUT_FILENO;
|
||||
} else {
|
||||
fd = creat(to, 0644);
|
||||
fprintf(stderr, "Decompressing to [%s]\n", to);
|
||||
}
|
||||
|
||||
decomp(type, fd, file, size);
|
||||
close(fd);
|
||||
if (to == from && ext != NULL) {
|
||||
*ext = '.';
|
||||
unlink(from);
|
||||
}
|
||||
if (strcmp(from, "-") == 0)
|
||||
free(file);
|
||||
else
|
||||
munmap(file, size);
|
||||
}
|
||||
|
||||
void comp_file(const char *method, const char *from, const char *to) {
|
||||
file_t type;
|
||||
char *ext, dest[PATH_MAX];
|
||||
if (strcmp(method, "gzip") == 0) {
|
||||
type = GZIP;
|
||||
ext = "gz";
|
||||
} else if (strcmp(method, "xz") == 0) {
|
||||
type = XZ;
|
||||
ext = "xz";
|
||||
} else if (strcmp(method, "lzma") == 0) {
|
||||
type = LZMA;
|
||||
ext = "lzma";
|
||||
} else if (strcmp(method, "lz4") == 0) {
|
||||
type = LZ4;
|
||||
ext = "lz4";
|
||||
} else if (strcmp(method, "lz4_legacy") == 0) {
|
||||
type = LZ4_LEGACY;
|
||||
ext = "lz4";
|
||||
} else if (strcmp(method, "bzip2") == 0) {
|
||||
type = BZIP2;
|
||||
ext = "bz2";
|
||||
} else {
|
||||
fprintf(stderr, "Only support following methods: ");
|
||||
for (int i = 0; SUP_LIST[i]; ++i)
|
||||
fprintf(stderr, "%s ", SUP_LIST[i]);
|
||||
fprintf(stderr, "\n");
|
||||
exit(1);
|
||||
}
|
||||
void *file;
|
||||
size_t size;
|
||||
if (strcmp(from, "-") == 0)
|
||||
stream_full_read(STDIN_FILENO, &file, &size);
|
||||
else
|
||||
mmap_ro(from, &file, &size);
|
||||
if (to == NULL) {
|
||||
if (strcmp(from, "-") == 0)
|
||||
strcpy(dest, "-");
|
||||
else
|
||||
snprintf(dest, sizeof(dest), "%s.%s", from, ext);
|
||||
} else
|
||||
strcpy(dest, to);
|
||||
int fd;
|
||||
if (strcmp(dest, "-") == 0) {
|
||||
fd = STDOUT_FILENO;
|
||||
} else {
|
||||
fd = creat(dest, 0644);
|
||||
fprintf(stderr, "Compressing to [%s]\n", dest);
|
||||
}
|
||||
comp(type, fd, file, size);
|
||||
close(fd);
|
||||
if (strcmp(from, "-") == 0)
|
||||
free(file);
|
||||
else
|
||||
munmap(file, size);
|
||||
if (to == NULL)
|
||||
unlink(from);
|
||||
}
|
||||
|
111
native/jni/magiskboot/dtb.c
Normal file
111
native/jni/magiskboot/dtb.c
Normal file
@@ -0,0 +1,111 @@
|
||||
#include <libfdt.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "magiskboot.h"
|
||||
#include "utils.h"
|
||||
|
||||
static void print_props(const void *fdt, int node, int depth) {
|
||||
int prop;
|
||||
fdt_for_each_property_offset(prop, fdt, node) {
|
||||
for (int i = 0; i < depth; ++i) printf(" ");
|
||||
printf(" ");
|
||||
int size;
|
||||
const char *name;
|
||||
const char *value = fdt_getprop_by_offset(fdt, prop, &name, &size);
|
||||
printf("[%s]: [%s]\n", name, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_subnode(const void *fdt, int parent, int depth) {
|
||||
int node;
|
||||
fdt_for_each_subnode(node, fdt, parent) {
|
||||
for (int i = 0; i < depth; ++i) printf(" ");
|
||||
printf("#%d: %s\n", node, fdt_get_name(fdt, node, NULL));
|
||||
print_props(fdt, node, depth);
|
||||
print_subnode(fdt, node, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int find_fstab(const void *fdt, int parent) {
|
||||
int node, fstab;
|
||||
fdt_for_each_subnode(node, fdt, parent) {
|
||||
if (strcmp(fdt_get_name(fdt, node, NULL), "fstab") == 0)
|
||||
return node;
|
||||
fstab = find_fstab(fdt, node);
|
||||
if (fstab != -1)
|
||||
return fstab;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void dtb_dump(const char *file) {
|
||||
size_t size ;
|
||||
void *dtb, *fdt;
|
||||
fprintf(stderr, "Loading dtbs from [%s]\n", file);
|
||||
mmap_ro(file, &dtb, &size);
|
||||
// Loop through all the dtbs
|
||||
int dtb_num = 0;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (memcmp(dtb + i, DTB_MAGIC, 4) == 0) {
|
||||
fdt = dtb + i;
|
||||
fprintf(stderr, "Dumping dtb.%04d\n", dtb_num++);
|
||||
print_subnode(fdt, 0, 0);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
munmap(dtb, size);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void dtb_patch(const char *file, int patch) {
|
||||
size_t size ;
|
||||
void *dtb, *fdt;
|
||||
fprintf(stderr, "Loading dtbs from [%s]\n", file);
|
||||
if (patch)
|
||||
mmap_rw(file, &dtb, &size);
|
||||
else
|
||||
mmap_ro(file, &dtb, &size);
|
||||
// Loop through all the dtbs
|
||||
int dtb_num = 0, found = 0;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (memcmp(dtb + i, DTB_MAGIC, 4) == 0) {
|
||||
fdt = dtb + i;
|
||||
int fstab = find_fstab(fdt, 0);
|
||||
if (fstab > 0) {
|
||||
fprintf(stderr, "Found fstab in dtb.%04d\n", dtb_num++);
|
||||
int block;
|
||||
fdt_for_each_subnode(block, fdt, fstab) {
|
||||
fprintf(stderr, "Found block [%s] in fstab\n", fdt_get_name(fdt, block, NULL));
|
||||
uint32_t value_size;
|
||||
void *value = (void *) fdt_getprop(fdt, block, "fsmgr_flags", &value_size);
|
||||
if (patch) {
|
||||
void *dup = xmalloc(value_size);
|
||||
memcpy(dup, value, value_size);
|
||||
memset(value, 0, value_size);
|
||||
found |= patch_verity(&dup, &value_size, 1);
|
||||
memcpy(value, dup, value_size);
|
||||
free(dup);
|
||||
} else {
|
||||
found |= patch_verity(&value, &value_size, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
munmap(dtb, size);
|
||||
exit(!found);
|
||||
}
|
||||
|
||||
int dtb_commands(const char *cmd, int argc, char *argv[]) {
|
||||
if (argc == 0) return 1;
|
||||
if (strcmp(cmd, "dump") == 0)
|
||||
dtb_dump(argv[0]);
|
||||
else if (strcmp(cmd, "patch") == 0)
|
||||
dtb_patch(argv[0], 1);
|
||||
else if (strcmp(cmd, "test") == 0)
|
||||
dtb_patch(argv[0], 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
38
native/jni/magiskboot/hexpatch.c
Normal file
38
native/jni/magiskboot/hexpatch.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "magiskboot.h"
|
||||
#include "utils.h"
|
||||
|
||||
static void hex2byte(const char *hex, unsigned char *str) {
|
||||
char high, low;
|
||||
for (int i = 0, length = strlen(hex); i < length; i += 2) {
|
||||
high = toupper(hex[i]) - '0';
|
||||
low = toupper(hex[i + 1]) - '0';
|
||||
str[i / 2] = ((high > 9 ? high - 7 : high) << 4) + (low > 9 ? low - 7 : low);
|
||||
}
|
||||
}
|
||||
|
||||
void hexpatch(const char *image, const char *from, const char *to) {
|
||||
int patternsize = strlen(from) / 2, patchsize = strlen(to) / 2;
|
||||
size_t filesize;
|
||||
void *file, *pattern, *patch;
|
||||
mmap_rw(image, &file, &filesize);
|
||||
pattern = xmalloc(patternsize);
|
||||
patch = xmalloc(patchsize);
|
||||
hex2byte(from, pattern);
|
||||
hex2byte(to, patch);
|
||||
for (size_t i = 0; filesize > 0 && i < filesize - patternsize; ++i) {
|
||||
if (memcmp(file + i, pattern, patternsize) == 0) {
|
||||
fprintf(stderr, "Patch @ %08X [%s]->[%s]\n", (unsigned) i, from, to);
|
||||
memset(file + i, 0, patternsize);
|
||||
memcpy(file + i, patch, patchsize);
|
||||
i += patternsize - 1;
|
||||
}
|
||||
}
|
||||
munmap(file, filesize);
|
||||
free(pattern);
|
||||
free(patch);
|
||||
}
|
35
native/jni/magiskboot/magiskboot.h
Normal file
35
native/jni/magiskboot/magiskboot.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef _MAGISKBOOT_H_
|
||||
#define _MAGISKBOOT_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "logging.h"
|
||||
#include "bootimg.h"
|
||||
|
||||
#define KERNEL_FILE "kernel"
|
||||
#define RAMDISK_FILE "ramdisk.cpio"
|
||||
#define SECOND_FILE "second"
|
||||
#define EXTRA_FILE "extra"
|
||||
#define DTB_FILE "dtb"
|
||||
#define NEW_BOOT "new-boot.img"
|
||||
|
||||
// Main entries
|
||||
void unpack(const char *image);
|
||||
void repack(const char* orig_image, const char* out_image);
|
||||
void hexpatch(const char *image, const char *from, const char *to);
|
||||
int parse_img(const char *image, boot_img *boot);
|
||||
int cpio_commands(int argc, char *argv[]);
|
||||
void comp_file(const char *method, const char *from, const char *to);
|
||||
void decomp_file(char *from, const char *to);
|
||||
int dtb_commands(const char *cmd, int argc, char *argv[]);
|
||||
|
||||
// Compressions
|
||||
size_t gzip(int mode, int fd, const void *buf, size_t size);
|
||||
size_t lzma(int mode, int fd, const void *buf, size_t size);
|
||||
size_t lz4(int mode, int fd, const void *buf, size_t size);
|
||||
size_t bzip2(int mode, int fd, const void *buf, size_t size);
|
||||
size_t lz4_legacy(int mode, int fd, const void *buf, size_t size);
|
||||
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);
|
||||
|
||||
#endif
|
166
native/jni/magiskboot/main.c
Normal file
166
native/jni/magiskboot/main.c
Normal file
@@ -0,0 +1,166 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "magiskboot.h"
|
||||
#include "utils.h"
|
||||
#include "sha1.h"
|
||||
|
||||
/********************
|
||||
Patch Boot Image
|
||||
*********************/
|
||||
|
||||
static void usage(char *arg0) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s <action> [args...]\n"
|
||||
"\n"
|
||||
"Supported actions:\n"
|
||||
" --parse <bootimg>\n"
|
||||
" Parse <bootimg> only, do not unpack. Return values: \n"
|
||||
" 0:OK 1:error 2:insufficient boot partition size\n"
|
||||
" 3:chromeos 4:ELF32 5:ELF64\n"
|
||||
"\n"
|
||||
" --unpack <bootimg>\n"
|
||||
" Unpack <bootimg> to kernel, ramdisk.cpio, (second), (dtb), (extra) into\n"
|
||||
" the current directory. Return value is the same as --parse\n"
|
||||
"\n"
|
||||
" --repack <origbootimg> [outbootimg]\n"
|
||||
" Repack kernel, ramdisk.cpio[.ext], second, dtb... from current directory\n"
|
||||
" to [outbootimg], or new-boot.img if not specified.\n"
|
||||
" It will compress ramdisk.cpio with the same method used in <origbootimg>,\n"
|
||||
" or attempt to find ramdisk.cpio.[ext], and repack directly with the\n"
|
||||
" compressed ramdisk file\n"
|
||||
"\n"
|
||||
" --hexpatch <file> <hexpattern1> <hexpattern2>\n"
|
||||
" Search <hexpattern1> in <file>, and replace with <hexpattern2>\n"
|
||||
"\n"
|
||||
" --cpio <incpio> [commands...]\n"
|
||||
" Do cpio commands to <incpio> (modifications are done directly)\n"
|
||||
" Each command is a single argument, use quotes if necessary\n"
|
||||
" Supported commands:\n"
|
||||
" rm [-r] ENTRY\n"
|
||||
" Remove ENTRY, specify [-r] to remove recursively\n"
|
||||
" mkdir MODE ENTRY\n"
|
||||
" Create directory ENTRY in permissions MODE\n"
|
||||
" ln TARGET ENTRY\n"
|
||||
" Create a symlink to TARGET with the name ENTRY\n"
|
||||
" mv SOURCE DEST\n"
|
||||
" Move SOURCE to DEST\n"
|
||||
" add MODE ENTRY INFILE\n"
|
||||
" Add INFILE as ENTRY in permissions MODE; replaces ENTRY if exists\n"
|
||||
" extract [ENTRY OUT]\n"
|
||||
" Extract ENTRY to OUT, or extract all entries to current directory\n"
|
||||
" test\n"
|
||||
" Test the current cpio's patch status\n"
|
||||
" Return value: 0/stock 1/Magisk 2/other (phh, SuperSU, Xposed)\n"
|
||||
" patch KEEPVERITY KEEPFORCEENCRYPT\n"
|
||||
" Ramdisk patches. KEEP**** are boolean values\n"
|
||||
" backup ORIG [SHA1]\n"
|
||||
" Create ramdisk backups from ORIG\n"
|
||||
" SHA1 of stock boot image is optional\n"
|
||||
" restore\n"
|
||||
" Restore ramdisk from ramdisk backup stored within incpio\n"
|
||||
" magisk ORIG HIGHCOMP KEEPVERITY KEEPFORCEENCRYPT [SHA1]\n"
|
||||
" Do Magisk patches and backups all in one step\n"
|
||||
" Create ramdisk backups from ORIG\n"
|
||||
" HIGHCOMP, KEEP**** are boolean values\n"
|
||||
" SHA1 of stock boot image is optional\n"
|
||||
" sha1\n"
|
||||
" Print stock boot SHA1 if previously stored\n"
|
||||
"\n"
|
||||
" --dtb-<cmd> <dtb>\n"
|
||||
" Do dtb related cmds to <dtb> (modifications are done directly)\n"
|
||||
" Supported commands:\n"
|
||||
" dump\n"
|
||||
" Dump all contents from dtb for debugging\n"
|
||||
" test\n"
|
||||
" Check if fstab has verity/avb flags\n"
|
||||
" Return value: 0/no flags 1/flag exists\n"
|
||||
" patch\n"
|
||||
" Search for fstab and remove verity/avb\n"
|
||||
"\n"
|
||||
" --compress[=method] <infile> [outfile]\n"
|
||||
" Compress <infile> with [method] (default: gzip), optionally to [outfile]\n"
|
||||
" <infile>/[outfile] can be '-' to be STDIN/STDOUT\n"
|
||||
" Supported methods: "
|
||||
, arg0);
|
||||
for (int i = 0; SUP_LIST[i]; ++i)
|
||||
fprintf(stderr, "%s ", SUP_LIST[i]);
|
||||
fprintf(stderr,
|
||||
"\n\n"
|
||||
" --decompress <infile> [outfile]\n"
|
||||
" Detect method and decompress <infile>, optionally to [outfile]\n"
|
||||
" <infile>/[outfile] can be '-' to be STDIN/STDOUT\n"
|
||||
" Supported methods: ");
|
||||
for (int i = 0; SUP_LIST[i]; ++i)
|
||||
fprintf(stderr, "%s ", SUP_LIST[i]);
|
||||
fprintf(stderr,
|
||||
"\n\n"
|
||||
" --sha1 <file>\n"
|
||||
" Print the SHA1 checksum for <file>\n"
|
||||
"\n"
|
||||
" --cleanup\n"
|
||||
" Cleanup the current working directory\n"
|
||||
"\n");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
fprintf(stderr, "MagiskBoot v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) - Boot Image Modification Tool\n");
|
||||
|
||||
umask(0);
|
||||
if (argc > 1 && strcmp(argv[1], "--cleanup") == 0) {
|
||||
fprintf(stderr, "Cleaning up...\n");
|
||||
char name[PATH_MAX];
|
||||
unlink(KERNEL_FILE);
|
||||
unlink(RAMDISK_FILE);
|
||||
unlink(RAMDISK_FILE ".raw");
|
||||
unlink(SECOND_FILE);
|
||||
unlink(DTB_FILE);
|
||||
unlink(EXTRA_FILE);
|
||||
for (int i = 0; SUP_EXT_LIST[i]; ++i) {
|
||||
sprintf(name, "%s.%s", RAMDISK_FILE, SUP_EXT_LIST[i]);
|
||||
unlink(name);
|
||||
}
|
||||
} else if (argc > 2 && strcmp(argv[1], "--sha1") == 0) {
|
||||
char sha1[21], *buf;
|
||||
size_t size;
|
||||
mmap_ro(argv[2], (void **) &buf, &size);
|
||||
SHA1(sha1, buf, size);
|
||||
for (int i = 0; i < 20; ++i)
|
||||
printf("%02x", sha1[i]);
|
||||
printf("\n");
|
||||
munmap(buf, size);
|
||||
} else if (argc > 2 && strcmp(argv[1], "--parse") == 0) {
|
||||
boot_img boot;
|
||||
exit(parse_img(argv[2], &boot));
|
||||
} else if (argc > 2 && strcmp(argv[1], "--unpack") == 0) {
|
||||
unpack(argv[2]);
|
||||
} else if (argc > 2 && strcmp(argv[1], "--repack") == 0) {
|
||||
repack(argv[2], argc > 3 ? argv[3] : NEW_BOOT);
|
||||
} else if (argc > 2 && strcmp(argv[1], "--decompress") == 0) {
|
||||
decomp_file(argv[2], argc > 3 ? argv[3] : NULL);
|
||||
} else if (argc > 2 && strncmp(argv[1], "--compress", 10) == 0) {
|
||||
char *method;
|
||||
method = strchr(argv[1], '=');
|
||||
if (method == NULL) method = "gzip";
|
||||
else method++;
|
||||
comp_file(method, argv[2], argc > 3 ? argv[3] : NULL);
|
||||
} else if (argc > 4 && strcmp(argv[1], "--hexpatch") == 0) {
|
||||
hexpatch(argv[2], argv[3], argv[4]);
|
||||
} else if (argc > 2 && strcmp(argv[1], "--cpio") == 0) {
|
||||
if (cpio_commands(argc - 2, argv + 2)) usage(argv[0]);
|
||||
} else if (argc > 2 && strncmp(argv[1], "--dtb", 5) == 0) {
|
||||
char *cmd = argv[1] + 5;
|
||||
if (*cmd == '\0') usage(argv[0]);
|
||||
else ++cmd;
|
||||
if (dtb_commands(cmd, argc - 2, argv + 2)) usage(argv[0]);
|
||||
} else {
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
335
native/jni/magiskboot/ramdisk.c
Normal file
335
native/jni/magiskboot/ramdisk.c
Normal file
@@ -0,0 +1,335 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <utils.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "magiskboot.h"
|
||||
#include "cpio.h"
|
||||
|
||||
static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) {
|
||||
fprintf(stderr, "Patch with flag KEEPVERITY=[%s] KEEPFORCEENCRYPT=[%s]\n",
|
||||
keepverity ? "true" : "false", keepforceencrypt ? "true" : "false");
|
||||
cpio_entry *e;
|
||||
vec_for_each(v, e) {
|
||||
if (!e) continue;
|
||||
if (!keepverity) {
|
||||
if (strncmp(e->filename, ".backup", 7) && strstr(e->filename, "fstab") && S_ISREG(e->mode)) {
|
||||
patch_verity(&e->data, &e->filesize, 1);
|
||||
} else if (strcmp(e->filename, "verity_key") == 0) {
|
||||
fprintf(stderr, "Remove [verity_key]\n");
|
||||
cpio_free(e);
|
||||
vec_cur(v) = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!keepforceencrypt) {
|
||||
if (strstr(e->filename, "fstab") != NULL && S_ISREG(e->mode)) {
|
||||
patch_encryption(&e->data, &e->filesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define STOCK_BOOT 0x0
|
||||
#define MAGISK_PATCH 0x1
|
||||
#define OTHER_PATCH 0x2
|
||||
|
||||
static int cpio_test(struct vector *v) {
|
||||
const char *OTHER_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", "boot/sbin/launch_daemonsu.sh", NULL };
|
||||
const char *MAGISK_LIST[] = { ".backup/.magisk", "init.magisk.rc", "overlay/init.magisk.rc", NULL };
|
||||
|
||||
for (int i = 0; OTHER_LIST[i]; ++i)
|
||||
if (cpio_find(v, OTHER_LIST[i]) > 0)
|
||||
return OTHER_PATCH;
|
||||
|
||||
for (int i = 0; MAGISK_LIST[i]; ++i)
|
||||
if (cpio_find(v, MAGISK_LIST[i]) > 0)
|
||||
return MAGISK_PATCH;
|
||||
|
||||
return STOCK_BOOT;
|
||||
}
|
||||
|
||||
static char *cpio_sha1(struct vector *v) {
|
||||
cpio_entry *e;
|
||||
char sha1[41];
|
||||
vec_for_each(v, e) {
|
||||
if (!e) continue;
|
||||
if (strcmp(e->filename, "init.magisk.rc") == 0
|
||||
|| strcmp(e->filename, "overlay/init.magisk.rc") == 0) {
|
||||
for (void *pos = e->data; pos < e->data + e->filesize; pos = strchr(pos + 1, '\n') + 1) {
|
||||
if (memcmp(pos, "# STOCKSHA1=", 12) == 0) {
|
||||
pos += 12;
|
||||
memcpy(sha1, pos, 40);
|
||||
sha1[40] = '\0';
|
||||
return strdup(sha1);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(e->filename, ".backup/.sha1") == 0) {
|
||||
return e->data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cpio_backup(struct vector *v, struct vector *bak, const char *orig, const char *sha1) {
|
||||
struct vector o_body, *o = &o_body;
|
||||
cpio_entry *m, *n, *rem, *cksm;
|
||||
char buf[PATH_MAX];
|
||||
int res, backup;
|
||||
|
||||
m = xcalloc(sizeof(*m), 1);
|
||||
m->filename = strdup(".backup");
|
||||
m->mode = S_IFDIR;
|
||||
vec_push_back(bak, m);
|
||||
|
||||
rem = xcalloc(sizeof(*rem), 1);
|
||||
rem->filename = strdup(".backup/.rmlist");
|
||||
rem->mode = S_IFREG;
|
||||
|
||||
if (sha1) {
|
||||
fprintf(stderr, "Save SHA1: [%s] -> [.backup/.sha1]\n", sha1);
|
||||
cksm = xcalloc(sizeof(*cksm), 1);
|
||||
vec_push_back(bak, cksm);
|
||||
cksm->filename = strdup(".backup/.sha1");
|
||||
cksm->mode = S_IFREG;
|
||||
cksm->data = strdup(sha1);
|
||||
cksm->filesize = strlen(sha1) + 1;
|
||||
}
|
||||
|
||||
vec_init(o);
|
||||
parse_cpio(o, orig);
|
||||
// Remove possible backups in original ramdisk
|
||||
cpio_rm(o, 1, ".backup");
|
||||
cpio_rm(v, 1, ".backup");
|
||||
|
||||
// Sort both vectors before comparing
|
||||
vec_sort(o, cpio_cmp);
|
||||
vec_sort(v, cpio_cmp);
|
||||
|
||||
// Start comparing
|
||||
size_t i = 0, j = 0;
|
||||
while(i != vec_size(o) || j != vec_size(v)) {
|
||||
backup = 0;
|
||||
if (i != vec_size(o) && j != vec_size(v)) {
|
||||
m = vec_entry(o)[i];
|
||||
n = vec_entry(v)[j];
|
||||
res = strcmp(m->filename, n->filename);
|
||||
} else if (i == vec_size(o)) {
|
||||
n = vec_entry(v)[j];
|
||||
res = 1;
|
||||
} else if (j == vec_size(v)) {
|
||||
m = vec_entry(o)[i];
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
// Something is missing in new ramdisk, backup!
|
||||
++i;
|
||||
backup = 1;
|
||||
fprintf(stderr, "Backup missing entry: ");
|
||||
} else if (res == 0) {
|
||||
++i; ++j;
|
||||
if (m->filesize == n->filesize && memcmp(m->data, n->data, m->filesize) == 0)
|
||||
continue;
|
||||
// Not the same!
|
||||
backup = 1;
|
||||
fprintf(stderr, "Backup mismatch entry: ");
|
||||
} else {
|
||||
// Something new in ramdisk, record in rem
|
||||
++j;
|
||||
rem->data = xrealloc(rem->data, rem->filesize + strlen(n->filename) + 1);
|
||||
memcpy(rem->data + rem->filesize, n->filename, strlen(n->filename) + 1);
|
||||
rem->filesize += strlen(n->filename) + 1;
|
||||
fprintf(stderr, "Record new entry: [%s] -> [.backup/.rmlist]\n", n->filename);
|
||||
}
|
||||
if (backup) {
|
||||
sprintf(buf, ".backup/%s", m->filename);
|
||||
fprintf(stderr, "[%s] -> [%s]\n", m->filename, buf);
|
||||
free(m->filename);
|
||||
m->filename = strdup(buf);
|
||||
vec_push_back(bak, m);
|
||||
// NULL the original entry, so it won't be freed
|
||||
vec_entry(o)[i - 1] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (rem->filesize)
|
||||
vec_push_back(bak, rem);
|
||||
else
|
||||
cpio_free(rem);
|
||||
|
||||
// Cleanup
|
||||
cpio_vec_destroy(o);
|
||||
}
|
||||
|
||||
static void cpio_restore(struct vector *v) {
|
||||
cpio_entry *e;
|
||||
vec_for_each(v, e) {
|
||||
if (!e) continue;
|
||||
if (strncmp(e->filename, ".backup", 7) == 0) {
|
||||
if (e->filename[7] == '\0') continue;
|
||||
if (e->filename[8] == '.') {
|
||||
if (strcmp(e->filename, ".backup/.rmlist") == 0) {
|
||||
for (int pos = 0; pos < e->filesize; pos += strlen(e->data + pos) + 1)
|
||||
cpio_rm(v, 0, e->data + pos);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
fprintf(stderr, "Restore [%s] -> [%s]\n", e->filename, e->filename + 8);
|
||||
vec_cur(v) = NULL;
|
||||
char *new_name = strdup(e->filename + 8);
|
||||
free(e->filename);
|
||||
e->filename = new_name;
|
||||
cpio_vec_insert(v, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Some known stuff we can remove
|
||||
cpio_rm(v, 1, ".backup");
|
||||
cpio_rm(v, 1, "overlay");
|
||||
cpio_rm(v, 0, "sbin/magic_mask.sh");
|
||||
cpio_rm(v, 0, "init.magisk.rc");
|
||||
cpio_rm(v, 0, "magisk");
|
||||
cpio_rm(v, 0, "ramdisk-recovery.xz");
|
||||
}
|
||||
|
||||
static void restore_high_compress(struct vector *v, const char *incpio) {
|
||||
// Check if the ramdisk is in high compression mode
|
||||
if (cpio_extract(v, "ramdisk.cpio.xz", incpio) == 0) {
|
||||
void *xz;
|
||||
size_t size;
|
||||
full_read(incpio, &xz, &size);
|
||||
int fd = creat(incpio, 0644);
|
||||
lzma(0, fd, xz, size);
|
||||
close(fd);
|
||||
free(xz);
|
||||
cpio_rm(v, 0, "ramdisk.cpio.xz");
|
||||
cpio_rm(v, 0, "init");
|
||||
struct vector vv;
|
||||
vec_init(&vv);
|
||||
parse_cpio(&vv, incpio);
|
||||
cpio_entry *e;
|
||||
vec_for_each(&vv, e)
|
||||
vec_push_back(v, e);
|
||||
vec_destroy(&vv);
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_high_compress(struct vector *v, struct vector *b, const char *incpio) {
|
||||
cpio_entry *init, *magiskinit;
|
||||
|
||||
// Swap magiskinit with original init
|
||||
int i = cpio_find(b, ".backup/init"), j = cpio_find(v, "init");
|
||||
init = vec_entry(b)[i];
|
||||
magiskinit = vec_entry(v)[j];
|
||||
free(init->filename);
|
||||
init->filename = strdup("init");
|
||||
vec_entry(v)[j] = init;
|
||||
vec_entry(b)[i] = NULL;
|
||||
|
||||
dump_cpio(v, incpio);
|
||||
cpio_vec_destroy(v);
|
||||
void *cpio;
|
||||
size_t size;
|
||||
full_read(incpio, &cpio, &size);
|
||||
int fd = creat(incpio, 0644);
|
||||
lzma(1, fd, cpio, size);
|
||||
close(fd);
|
||||
free(cpio);
|
||||
vec_init(v);
|
||||
vec_push_back(v, magiskinit);
|
||||
cpio_add(v, 0, "ramdisk.cpio.xz", incpio);
|
||||
}
|
||||
|
||||
int cpio_commands(int argc, char *argv[]) {
|
||||
char *incpio = argv[0];
|
||||
++argv;
|
||||
--argc;
|
||||
|
||||
struct vector v;
|
||||
vec_init(&v);
|
||||
parse_cpio(&v, incpio);
|
||||
|
||||
int cmdc;
|
||||
char *cmdv[6];
|
||||
|
||||
while (argc) {
|
||||
cmdc = 0;
|
||||
for (char *tok = strtok(argv[0], " "); tok; tok = strtok(NULL, " "))
|
||||
cmdv[cmdc++] = tok;
|
||||
|
||||
if (strcmp(cmdv[0], "test") == 0) {
|
||||
exit(cpio_test(&v));
|
||||
} else if (strcmp(cmdv[0], "restore") == 0) {
|
||||
restore_high_compress(&v, incpio);
|
||||
cpio_restore(&v);
|
||||
} else if (strcmp(cmdv[0], "sha1") == 0) {
|
||||
char *sha1 = cpio_sha1(&v);
|
||||
if (sha1)
|
||||
printf("%s\n", sha1);
|
||||
return 0;
|
||||
} else if (cmdc >= 2 && strcmp(cmdv[0], "backup") == 0) {
|
||||
struct vector back;
|
||||
vec_init(&back);
|
||||
cpio_backup(&v, &back, cmdv[1], cmdc > 2 ? cmdv[2] : NULL);
|
||||
cpio_entry *e;
|
||||
vec_for_each(&back, e)
|
||||
if (e) vec_push_back(&v, e);
|
||||
vec_destroy(&back);
|
||||
} else if (cmdc >= 5 && strcmp(cmdv[0], "magisk") == 0) {
|
||||
cpio_patch(&v, strcmp(cmdv[3], "true") == 0, strcmp(cmdv[4], "true") == 0);
|
||||
|
||||
struct vector back;
|
||||
vec_init(&back);
|
||||
cpio_backup(&v, &back, cmdv[1], cmdc > 5 ? cmdv[5] : NULL);
|
||||
|
||||
cpio_entry *e;
|
||||
e = xcalloc(sizeof(*e), 1);
|
||||
e->filename = strdup(".backup/.magisk");
|
||||
e->mode = S_IFREG;
|
||||
e->data = xmalloc(50);
|
||||
snprintf(e->data, 50, "KEEPVERITY=%s\nKEEPFORCEENCRYPT=%s\n", cmdv[3], cmdv[4]);
|
||||
e->filesize = strlen(e->data) + 1;
|
||||
vec_push_back(&back, e);
|
||||
|
||||
// Enable high compression mode
|
||||
if (strcmp(cmdv[2], "true") == 0)
|
||||
enable_high_compress(&v, &back, incpio);
|
||||
|
||||
vec_for_each(&back, e)
|
||||
if (e) vec_push_back(&v, e);
|
||||
vec_destroy(&back);
|
||||
} else if (cmdc >= 2 && strcmp(cmdv[0], "rm") == 0) {
|
||||
int recur = cmdc > 2 && strcmp(cmdv[1], "-r") == 0;
|
||||
cpio_rm(&v, recur, cmdv[1 + recur]);
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "mv") == 0) {
|
||||
cpio_mv(&v, cmdv[1], cmdv[2]);
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "patch") == 0) {
|
||||
cpio_patch(&v, strcmp(cmdv[1], "true") == 0, strcmp(cmdv[2], "true") == 0);
|
||||
} else if (strcmp(cmdv[0], "extract") == 0) {
|
||||
if (cmdc == 3) {
|
||||
return cpio_extract(&v, cmdv[1], cmdv[2]);
|
||||
} else {
|
||||
cpio_extract_all(&v);
|
||||
return 0;
|
||||
}
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "mkdir") == 0) {
|
||||
cpio_mkdir(&v, strtoul(cmdv[1], NULL, 8), cmdv[2]);
|
||||
} else if (cmdc == 3 && strcmp(cmdv[0], "ln") == 0) {
|
||||
cpio_ln(&v, cmdv[1], cmdv[2]);
|
||||
} else if (cmdc == 4 && strcmp(cmdv[0], "add") == 0) {
|
||||
cpio_add(&v, strtoul(cmdv[1], NULL, 8), cmdv[2], cmdv[3]);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
|
||||
dump_cpio(&v, incpio);
|
||||
cpio_vec_destroy(&v);
|
||||
return 0;
|
||||
}
|
79
native/jni/magiskboot/types.c
Normal file
79
native/jni/magiskboot/types.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "bootimg.h"
|
||||
#include "types.h"
|
||||
|
||||
file_t check_type(const void *buf) {
|
||||
if (memcmp(buf, CHROMEOS_MAGIC, 8) == 0) {
|
||||
return CHROMEOS;
|
||||
} else if (memcmp(buf, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) {
|
||||
return AOSP;
|
||||
} else if (memcmp(buf, ELF32_MAGIC, 5) == 0) {
|
||||
return ELF32;
|
||||
} else if (memcmp(buf, ELF64_MAGIC, 5) == 0) {
|
||||
return ELF64;
|
||||
} else if (memcmp(buf, GZIP_MAGIC, 4) == 0) {
|
||||
return GZIP;
|
||||
} else if (memcmp(buf, LZOP_MAGIC, 9) == 0) {
|
||||
return LZOP;
|
||||
} else if (memcmp(buf, XZ_MAGIC, 6) == 0) {
|
||||
return XZ;
|
||||
} else if (memcmp(buf, "\x5d\x00\x00", 3) == 0
|
||||
&& (((char *)buf)[12] == '\xff' || ((char *)buf)[12] == '\x00')) {
|
||||
return LZMA;
|
||||
} else if (memcmp(buf, BZIP_MAGIC, 3) == 0) {
|
||||
return BZIP2;
|
||||
} else if (memcmp(buf, LZ4_MAGIC, 4) == 0) {
|
||||
return LZ4;
|
||||
} else if (memcmp(buf, LZ4_LEG_MAGIC, 4) == 0) {
|
||||
return LZ4_LEGACY;
|
||||
} else if (memcmp(buf, MTK_MAGIC, 4) == 0) {
|
||||
return MTK;
|
||||
} else if (memcmp(buf, DTB_MAGIC, 4) == 0) {
|
||||
return DTB;
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void get_type_name(file_t type, char *name) {
|
||||
char *s;
|
||||
switch (type) {
|
||||
case CHROMEOS:
|
||||
s = "chromeos";
|
||||
break;
|
||||
case AOSP:
|
||||
s = "aosp";
|
||||
break;
|
||||
case GZIP:
|
||||
s = "gzip";
|
||||
break;
|
||||
case LZOP:
|
||||
s = "lzop";
|
||||
break;
|
||||
case XZ:
|
||||
s = "xz";
|
||||
break;
|
||||
case LZMA:
|
||||
s = "lzma";
|
||||
break;
|
||||
case BZIP2:
|
||||
s = "bzip2";
|
||||
break;
|
||||
case LZ4:
|
||||
s = "lz4";
|
||||
break;
|
||||
case LZ4_LEGACY:
|
||||
s = "lz4_legacy";
|
||||
break;
|
||||
case MTK:
|
||||
s = "mtk";
|
||||
break;
|
||||
case DTB:
|
||||
s = "dtb";
|
||||
break;
|
||||
default:
|
||||
s = "raw";
|
||||
}
|
||||
strcpy(name, s);
|
||||
}
|
42
native/jni/magiskboot/types.h
Normal file
42
native/jni/magiskboot/types.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef _TYPES_H_
|
||||
#define _TYPES_H_
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN,
|
||||
CHROMEOS,
|
||||
AOSP,
|
||||
ELF32,
|
||||
ELF64,
|
||||
GZIP,
|
||||
LZOP,
|
||||
XZ,
|
||||
LZMA,
|
||||
BZIP2,
|
||||
LZ4,
|
||||
LZ4_LEGACY,
|
||||
MTK,
|
||||
DTB
|
||||
} file_t;
|
||||
|
||||
#define COMPRESSED(type) (type >= GZIP && type <= LZ4_LEGACY)
|
||||
|
||||
#define CHROMEOS_MAGIC "CHROMEOS"
|
||||
#define ELF32_MAGIC "\x7f""ELF\x01"
|
||||
#define ELF64_MAGIC "\x7f""ELF\x02"
|
||||
#define GZIP_MAGIC "\x1f\x8b\x08\x00"
|
||||
#define LZOP_MAGIC "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a"
|
||||
#define XZ_MAGIC "\xfd""7zXZ\x00"
|
||||
#define BZIP_MAGIC "BZh"
|
||||
#define LZ4_MAGIC "\x04\x22\x4d\x18"
|
||||
#define LZ4_LEG_MAGIC "\x02\x21\x4c\x18"
|
||||
#define MTK_MAGIC "\x88\x16\x88\x58"
|
||||
#define DTB_MAGIC "\xd0\x0d\xfe\xed"
|
||||
#define LG_BUMP_MAGIC "\x41\xa9\xe4\x67\x74\x4d\x1d\x1b\xa4\x29\xf2\xec\xea\x65\x52\x79"
|
||||
|
||||
#define SUP_LIST ((char *[]) { "gzip", "xz", "lzma", "bzip2", "lz4", "lz4_legacy", NULL })
|
||||
#define SUP_EXT_LIST ((char *[]) { "gz", "xz", "lzma", "bz2", "lz4", "lz4", NULL })
|
||||
|
||||
file_t check_type(const void *buf);
|
||||
void get_type_name(file_t type, char *name);
|
||||
|
||||
#endif
|
213
native/jni/magiskhide/hide_utils.c
Normal file
213
native/jni/magiskhide/hide_utils.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/* hide_utils.c - Some utility functions for MagiskHide
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
#include "resetprop.h"
|
||||
#include "magiskhide.h"
|
||||
#include "daemon.h"
|
||||
|
||||
static char *prop_key[] =
|
||||
{ "ro.boot.verifiedbootstate", "ro.boot.flash.locked", "ro.boot.veritymode", "ro.boot.warranty_bit", "ro.warranty_bit",
|
||||
"ro.debuggable", "ro.secure", "ro.build.type", "ro.build.tags", "ro.build.selinux", NULL };
|
||||
|
||||
static char *prop_value[] =
|
||||
{ "green", "1", "enforcing", "0", "0", "0", "1", "user", "release-keys", "0", NULL };
|
||||
|
||||
static int mocked = 0;
|
||||
|
||||
void manage_selinux() {
|
||||
if (mocked) return;
|
||||
char val[1];
|
||||
int fd = xopen(SELINUX_ENFORCE, O_RDONLY);
|
||||
xxread(fd, val, 1);
|
||||
close(fd);
|
||||
// Permissive
|
||||
if (val[0] == '0') {
|
||||
LOGI("hide_daemon: Permissive detected, hide the state\n");
|
||||
|
||||
chmod(SELINUX_ENFORCE, 0640);
|
||||
chmod(SELINUX_POLICY, 0440);
|
||||
mocked = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void hide_sensitive_props() {
|
||||
LOGI("hide_utils: Hiding sensitive props\n");
|
||||
|
||||
// Hide all sensitive props
|
||||
char *value;
|
||||
for (int i = 0; prop_key[i]; ++i) {
|
||||
value = getprop(prop_key[i]);
|
||||
if (value) {
|
||||
if (strcmp(value, prop_value[i]) != 0)
|
||||
setprop2(prop_key[i], prop_value[i], 0);
|
||||
free(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rm_magisk_prop(const char *name, const char *value) {
|
||||
if (strstr(name, "magisk")) {
|
||||
deleteprop2(name, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void clean_magisk_props() {
|
||||
LOGD("hide_utils: Cleaning magisk props\n");
|
||||
getprop_all(rm_magisk_prop);
|
||||
}
|
||||
|
||||
int add_list(char *proc) {
|
||||
if (!hideEnabled) {
|
||||
free(proc);
|
||||
return HIDE_NOT_ENABLED;
|
||||
}
|
||||
|
||||
char *line;
|
||||
struct vector *new_list = xmalloc(sizeof(*new_list));
|
||||
if (new_list == NULL)
|
||||
return DAEMON_ERROR;
|
||||
vec_init(new_list);
|
||||
|
||||
vec_for_each(hide_list, line) {
|
||||
// They should be unique
|
||||
if (strcmp(line, proc) == 0) {
|
||||
free(proc);
|
||||
vec_destroy(new_list);
|
||||
free(new_list);
|
||||
return HIDE_ITEM_EXIST;
|
||||
}
|
||||
vec_push_back(new_list, line);
|
||||
}
|
||||
|
||||
vec_push_back(new_list, proc);
|
||||
LOGI("hide_list add: [%s]\n", proc);
|
||||
ps_filter_proc_name(proc, kill_proc);
|
||||
|
||||
// Critical region
|
||||
pthread_mutex_lock(&hide_lock);
|
||||
vec_destroy(hide_list);
|
||||
free(hide_list);
|
||||
hide_list = new_list;
|
||||
pthread_mutex_unlock(&hide_lock);
|
||||
|
||||
pthread_mutex_lock(&file_lock);
|
||||
vector_to_file(HIDELIST, hide_list); // Do not complain if file not found
|
||||
pthread_mutex_unlock(&file_lock);
|
||||
return DAEMON_SUCCESS;
|
||||
}
|
||||
|
||||
int rm_list(char *proc) {
|
||||
if (!hideEnabled) {
|
||||
free(proc);
|
||||
return HIDE_NOT_ENABLED;
|
||||
}
|
||||
|
||||
daemon_response ret = DAEMON_ERROR;
|
||||
char *line;
|
||||
int do_rm = 0;
|
||||
struct vector *new_list = xmalloc(sizeof(*new_list));
|
||||
if (new_list == NULL)
|
||||
goto error;
|
||||
vec_init(new_list);
|
||||
|
||||
vec_for_each(hide_list, line) {
|
||||
if (strcmp(line, proc) == 0) {
|
||||
free(proc);
|
||||
proc = line;
|
||||
do_rm = 1;
|
||||
continue;
|
||||
}
|
||||
vec_push_back(new_list, line);
|
||||
}
|
||||
|
||||
if (do_rm) {
|
||||
LOGI("hide_list rm: [%s]\n", proc);
|
||||
ps_filter_proc_name(proc, kill_proc);
|
||||
// Critical region
|
||||
pthread_mutex_lock(&hide_lock);
|
||||
vec_destroy(hide_list);
|
||||
free(hide_list);
|
||||
hide_list = new_list;
|
||||
pthread_mutex_unlock(&hide_lock);
|
||||
|
||||
ret = DAEMON_SUCCESS;
|
||||
pthread_mutex_lock(&file_lock);
|
||||
vector_to_file(HIDELIST, hide_list); // Do not complain if file not found
|
||||
pthread_mutex_unlock(&file_lock);
|
||||
} else {
|
||||
ret = HIDE_ITEM_NOT_EXIST;
|
||||
vec_destroy(new_list);
|
||||
free(new_list);
|
||||
}
|
||||
|
||||
error:
|
||||
free(proc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int init_list() {
|
||||
LOGD("hide_list: initialize...\n");
|
||||
if ((hide_list = xmalloc(sizeof(*hide_list))) == NULL)
|
||||
return 1;
|
||||
vec_init(hide_list);
|
||||
|
||||
// Might error if file doesn't exist, no need to report
|
||||
file_to_vector(HIDELIST, hide_list);
|
||||
|
||||
char *line;
|
||||
vec_for_each(hide_list, line) {
|
||||
LOGI("hide_list: [%s]\n", line);
|
||||
ps_filter_proc_name(line, kill_proc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int destroy_list() {
|
||||
char *line;
|
||||
vec_for_each(hide_list, line) {
|
||||
ps_filter_proc_name(line, kill_proc);
|
||||
}
|
||||
vec_deep_destroy(hide_list);
|
||||
free(hide_list);
|
||||
hide_list = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void add_hide_list(int client) {
|
||||
char *proc = read_string(client);
|
||||
// ack
|
||||
write_int(client, add_list(proc));
|
||||
close(client);
|
||||
}
|
||||
|
||||
void rm_hide_list(int client) {
|
||||
char *proc = read_string(client);
|
||||
// ack
|
||||
write_int(client, rm_list(proc));
|
||||
close(client);
|
||||
}
|
||||
|
||||
void ls_hide_list(int client) {
|
||||
if (!hideEnabled) {
|
||||
write_int(client, HIDE_NOT_ENABLED);
|
||||
return;
|
||||
}
|
||||
write_int(client, DAEMON_SUCCESS);
|
||||
write_int(client, vec_size(hide_list));
|
||||
char *s;
|
||||
vec_for_each(hide_list, s) {
|
||||
write_string(client, s);
|
||||
}
|
||||
close(client);
|
||||
}
|
167
native/jni/magiskhide/magiskhide.c
Normal file
167
native/jni/magiskhide/magiskhide.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/* magiskhide.c - initialize the environment for Magiskhide
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
#include "magiskhide.h"
|
||||
#include "daemon.h"
|
||||
#include "resetprop.h"
|
||||
|
||||
struct vector *hide_list = NULL;
|
||||
|
||||
int hideEnabled = 0;
|
||||
static pthread_t proc_monitor_thread;
|
||||
pthread_mutex_t hide_lock, file_lock;
|
||||
|
||||
void kill_proc(int pid) {
|
||||
kill(pid, SIGTERM);
|
||||
}
|
||||
|
||||
static void usage(char *arg0) {
|
||||
fprintf(stderr,
|
||||
"MagiskHide v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu) - Hide Magisk!\n\n"
|
||||
"Usage: %s [--options [arguments...] ]\n\n"
|
||||
"Options:\n"
|
||||
" --enable Start magiskhide\n"
|
||||
" --disable Stop magiskhide\n"
|
||||
" --add PROCESS Add PROCESS to the hide list\n"
|
||||
" --rm PROCESS Remove PROCESS from the hide list\n"
|
||||
" --ls Print out the current hide list\n"
|
||||
, arg0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void launch_magiskhide(int client) {
|
||||
if (hideEnabled) {
|
||||
if (client > 0) {
|
||||
write_int(client, HIDE_IS_ENABLED);
|
||||
close(client);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
hideEnabled = 1;
|
||||
LOGI("* Starting MagiskHide\n");
|
||||
|
||||
deleteprop2(MAGISKHIDE_PROP, 1);
|
||||
|
||||
hide_sensitive_props();
|
||||
|
||||
// Initialize the mutex lock
|
||||
pthread_mutex_init(&hide_lock, NULL);
|
||||
pthread_mutex_init(&file_lock, NULL);
|
||||
|
||||
// Initialize the hide list
|
||||
if (init_list())
|
||||
goto error;
|
||||
|
||||
// Add SafetyNet by default
|
||||
add_list(strdup("com.google.android.gms.unstable"));
|
||||
|
||||
if (client > 0) {
|
||||
write_int(client, DAEMON_SUCCESS);
|
||||
close(client);
|
||||
}
|
||||
|
||||
// Get thread reference
|
||||
proc_monitor_thread = pthread_self();
|
||||
// Start monitoring
|
||||
proc_monitor();
|
||||
return;
|
||||
|
||||
error:
|
||||
hideEnabled = 0;
|
||||
if (client > 0) {
|
||||
write_int(client, DAEMON_ERROR);
|
||||
close(client);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void stop_magiskhide(int client) {
|
||||
if (!hideEnabled) {
|
||||
write_int(client, HIDE_NOT_ENABLED);
|
||||
close(client);
|
||||
return;
|
||||
}
|
||||
|
||||
LOGI("* Stopping MagiskHide\n");
|
||||
|
||||
hideEnabled = 0;
|
||||
setprop(MAGISKHIDE_PROP, "0");
|
||||
// Remove without actually removing persist props
|
||||
deleteprop2(MAGISKHIDE_PROP, 0);
|
||||
pthread_kill(proc_monitor_thread, TERM_THREAD);
|
||||
|
||||
write_int(client, DAEMON_SUCCESS);
|
||||
close(client);
|
||||
}
|
||||
|
||||
int magiskhide_main(int argc, char *argv[]) {
|
||||
if (argc < 2) {
|
||||
usage(argv[0]);
|
||||
}
|
||||
client_request req = DO_NOTHING;
|
||||
if (strcmp(argv[1], "--enable") == 0) {
|
||||
req = LAUNCH_MAGISKHIDE;
|
||||
} else if (strcmp(argv[1], "--disable") == 0) {
|
||||
req = STOP_MAGISKHIDE;
|
||||
} else if (strcmp(argv[1], "--add") == 0 && argc > 2) {
|
||||
req = ADD_HIDELIST;
|
||||
} else if (strcmp(argv[1], "--rm") == 0 && argc > 2) {
|
||||
req = RM_HIDELIST;
|
||||
} else if (strcmp(argv[1], "--ls") == 0) {
|
||||
req = LS_HIDELIST;
|
||||
} else {
|
||||
usage(argv[0]);
|
||||
}
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, req);
|
||||
if (req == ADD_HIDELIST || req == RM_HIDELIST) {
|
||||
write_string(fd, argv[2]);
|
||||
}
|
||||
daemon_response code = read_int(fd);
|
||||
switch (code) {
|
||||
case DAEMON_ERROR:
|
||||
fprintf(stderr, "Error occured in daemon...\n");
|
||||
return code;
|
||||
case DAEMON_SUCCESS:
|
||||
break;
|
||||
case ROOT_REQUIRED:
|
||||
fprintf(stderr, "Root is required for this operation\n");
|
||||
return code;
|
||||
case HIDE_NOT_ENABLED:
|
||||
fprintf(stderr, "Magisk hide is not enabled yet\n");
|
||||
return code;
|
||||
case HIDE_IS_ENABLED:
|
||||
fprintf(stderr, "Magisk hide is already enabled\n");
|
||||
return code;
|
||||
case HIDE_ITEM_EXIST:
|
||||
fprintf(stderr, "Process [%s] already exists in hide list\n", argv[2]);
|
||||
return code;
|
||||
case HIDE_ITEM_NOT_EXIST:
|
||||
fprintf(stderr, "Process [%s] does not exist in hide list\n", argv[2]);
|
||||
return code;
|
||||
}
|
||||
|
||||
if (req == LS_HIDELIST) {
|
||||
int argc = read_int(fd);
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
char *s = read_string(fd);
|
||||
printf("%s\n", s);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
30
native/jni/magiskhide/magiskhide.h
Normal file
30
native/jni/magiskhide/magiskhide.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef MAGISK_HIDE_H
|
||||
#define MAGISK_HIDE_H
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#define TERM_THREAD SIGUSR1
|
||||
#define HIDE_DONE SIGUSR2
|
||||
|
||||
// Kill process
|
||||
void kill_proc(int pid);
|
||||
|
||||
// Process monitor
|
||||
void proc_monitor();
|
||||
|
||||
// Utility functions
|
||||
void manage_selinux();
|
||||
void hide_sensitive_props();
|
||||
void clean_magisk_props();
|
||||
|
||||
// List managements
|
||||
int add_list(char *proc);
|
||||
int rm_list(char *proc);
|
||||
int init_list();
|
||||
int destroy_list();
|
||||
|
||||
extern int hideEnabled;
|
||||
extern struct vector *hide_list;
|
||||
extern pthread_mutex_t hide_lock, file_lock;
|
||||
|
||||
#endif
|
265
native/jni/magiskhide/proc_monitor.c
Normal file
265
native/jni/magiskhide/proc_monitor.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/* proc_monitor.c - Monitor am_proc_start events and unmount
|
||||
*
|
||||
* We monitor the logcat am_proc_start events. When a target starts up,
|
||||
* we pause it ASAP, and fork a new process to join its mount namespace
|
||||
* and do all the unmounting/mocking
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
#include "magiskhide.h"
|
||||
|
||||
static char init_ns[32], zygote_ns[2][32], cache_block[256];
|
||||
static int hide_queue = 0, zygote_num, has_cache = 1, pipefd[2] = { -1, -1 };
|
||||
|
||||
// Workaround for the lack of pthread_cancel
|
||||
static void term_thread(int sig) {
|
||||
LOGD("proc_monitor: running cleanup\n");
|
||||
destroy_list();
|
||||
hideEnabled = 0;
|
||||
// Unregister listener
|
||||
log_events[HIDE_EVENT].fd = -1;
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
pipefd[0] = pipefd[1] = -1;
|
||||
pthread_mutex_destroy(&hide_lock);
|
||||
pthread_mutex_destroy(&file_lock);
|
||||
LOGD("proc_monitor: terminating...\n");
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
static void hide_done(int sig) {
|
||||
--hide_queue;
|
||||
if (hide_queue == 0) {
|
||||
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
|
||||
xsymlink(DATABIN, "/data/magisk");
|
||||
xsymlink(MAINIMG, "/data/magisk.img");
|
||||
xsymlink(MOUNTPOINT, "/magisk");
|
||||
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int read_namespace(const int pid, char* target, const size_t size) {
|
||||
char path[32];
|
||||
snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
|
||||
if (access(path, R_OK) == -1)
|
||||
return 1;
|
||||
xreadlink(path, target, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void store_zygote_ns(int pid) {
|
||||
if (zygote_num == 2) return;
|
||||
do {
|
||||
usleep(500);
|
||||
read_namespace(pid, zygote_ns[zygote_num], 32);
|
||||
} while (strcmp(zygote_ns[zygote_num], init_ns) == 0);
|
||||
++zygote_num;
|
||||
}
|
||||
|
||||
static void lazy_unmount(const char* mountpoint) {
|
||||
if (umount2(mountpoint, MNT_DETACH) != -1)
|
||||
LOGD("hide_daemon: Unmounted (%s)\n", mountpoint);
|
||||
}
|
||||
|
||||
static void hide_daemon(int pid, int ppid) {
|
||||
LOGD("hide_daemon: start unmount for pid=[%d]\n", pid);
|
||||
strcpy(argv0, "hide_daemon");
|
||||
|
||||
char *line, buffer[PATH_MAX];
|
||||
struct vector mount_list;
|
||||
|
||||
manage_selinux();
|
||||
clean_magisk_props();
|
||||
|
||||
if (switch_mnt_ns(pid))
|
||||
goto exit;
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
|
||||
vec_init(&mount_list);
|
||||
file_to_vector(buffer, &mount_list);
|
||||
|
||||
// Find the cache block name if not found yet
|
||||
if (has_cache && cache_block[0] == '\0') {
|
||||
vec_for_each(&mount_list, line) {
|
||||
if (strstr(line, " /cache ")) {
|
||||
sscanf(line, "%256s", cache_block);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (strlen(cache_block) == 0)
|
||||
has_cache = 0;
|
||||
}
|
||||
|
||||
// Unmout cache mounts
|
||||
if (has_cache) {
|
||||
vec_for_each(&mount_list, line) {
|
||||
if (strstr(line, cache_block) && (strstr(line, " /system/") || strstr(line, " /vendor/"))) {
|
||||
sscanf(line, "%*s %4096s", buffer);
|
||||
lazy_unmount(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unmount dummy skeletons, /sbin links
|
||||
vec_for_each(&mount_list, line) {
|
||||
if (strstr(line, "tmpfs /system") || strstr(line, "tmpfs /vendor") || strstr(line, "tmpfs /sbin")) {
|
||||
sscanf(line, "%*s %4096s", buffer);
|
||||
lazy_unmount(buffer);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
vec_destroy(&mount_list);
|
||||
|
||||
// Re-read mount infos
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
|
||||
vec_init(&mount_list);
|
||||
file_to_vector(buffer, &mount_list);
|
||||
|
||||
// Unmount any loop mounts
|
||||
vec_for_each(&mount_list, line) {
|
||||
if (strstr(line, "/dev/block/loop")) {
|
||||
sscanf(line, "%*s %4096s", buffer);
|
||||
lazy_unmount(buffer);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
|
||||
exit:
|
||||
// Send resume signal
|
||||
kill(pid, SIGCONT);
|
||||
// Free up memory
|
||||
vec_destroy(&mount_list);
|
||||
// Wait a while and link it back
|
||||
sleep(10);
|
||||
kill(ppid, HIDE_DONE);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
void proc_monitor() {
|
||||
// Unblock user signals
|
||||
sigset_t block_set;
|
||||
sigemptyset(&block_set);
|
||||
sigaddset(&block_set, TERM_THREAD);
|
||||
sigaddset(&block_set, HIDE_DONE);
|
||||
pthread_sigmask(SIG_UNBLOCK, &block_set, NULL);
|
||||
|
||||
// Register the cancel signal
|
||||
struct sigaction act;
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_handler = term_thread;
|
||||
sigaction(TERM_THREAD, &act, NULL);
|
||||
act.sa_handler = hide_done;
|
||||
sigaction(HIDE_DONE, &act, NULL);
|
||||
|
||||
cache_block[0] = '\0';
|
||||
|
||||
// Get the mount namespace of init
|
||||
if (read_namespace(1, init_ns, 32)) {
|
||||
LOGE("proc_monitor: Your kernel doesn't support mount namespace :(\n");
|
||||
term_thread(TERM_THREAD);
|
||||
}
|
||||
LOGI("proc_monitor: init ns=%s\n", init_ns);
|
||||
|
||||
// Get the mount namespace of zygote
|
||||
zygote_num = 0;
|
||||
while(!zygote_num) {
|
||||
// Check zygote every 10 ms
|
||||
usleep(10000);
|
||||
ps_filter_proc_name("zygote", store_zygote_ns);
|
||||
}
|
||||
ps_filter_proc_name("zygote64", store_zygote_ns);
|
||||
|
||||
switch(zygote_num) {
|
||||
case 1:
|
||||
LOGI("proc_monitor: zygote ns=%s\n", zygote_ns[0]);
|
||||
break;
|
||||
case 2:
|
||||
LOGI("proc_monitor: zygote ns=%s zygote64 ns=%s\n", zygote_ns[0], zygote_ns[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
// Register our listener to logcat monitor
|
||||
xpipe2(pipefd, O_CLOEXEC);
|
||||
log_events[HIDE_EVENT].fd = pipefd[1];
|
||||
|
||||
for (char *log, *line;; free(log)) {
|
||||
if (read(pipefd[0], &log, sizeof(log)) != sizeof(log)) {
|
||||
/* It might be interrupted */
|
||||
log = NULL;
|
||||
continue;
|
||||
}
|
||||
char *ss = strchr(log, '[');
|
||||
int pid, ret, comma = 0;
|
||||
char *pos = ss, processName[256], ns[32];
|
||||
|
||||
while(1) {
|
||||
pos = strchr(pos, ',');
|
||||
if(pos == NULL)
|
||||
break;
|
||||
pos[0] = ' ';
|
||||
++comma;
|
||||
}
|
||||
|
||||
if (comma == 6)
|
||||
ret = sscanf(ss, "[%*d %d %*d %*d %256s", &pid, processName);
|
||||
else
|
||||
ret = sscanf(ss, "[%*d %d %*d %256s", &pid, processName);
|
||||
|
||||
if(ret != 2)
|
||||
continue;
|
||||
|
||||
// Critical region
|
||||
pthread_mutex_lock(&hide_lock);
|
||||
vec_for_each(hide_list, line) {
|
||||
if (strcmp(processName, line) == 0) {
|
||||
while(1) {
|
||||
ret = 1;
|
||||
for (int i = 0; i < zygote_num; ++i) {
|
||||
read_namespace(pid, ns, sizeof(ns));
|
||||
if (strcmp(ns, zygote_ns[i]) == 0) {
|
||||
usleep(50);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret) break;
|
||||
}
|
||||
|
||||
// Send pause signal ASAP
|
||||
if (kill(pid, SIGSTOP) == -1) continue;
|
||||
|
||||
LOGI("proc_monitor: %s (PID=%d ns=%s)\n", processName, pid, ns);
|
||||
|
||||
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
|
||||
unlink("/magisk");
|
||||
unlink("/data/magisk");
|
||||
unlink("/data/magisk.img");
|
||||
unlink(MAGISKRC);
|
||||
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
|
||||
++hide_queue;
|
||||
|
||||
/*
|
||||
* The setns system call do not support multithread processes
|
||||
* We have to fork a new process, setns, then do the unmounts
|
||||
*/
|
||||
int selfpid = getpid();
|
||||
if (fork_dont_care() == 0)
|
||||
hide_daemon(pid, selfpid);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&hide_lock);
|
||||
}
|
||||
}
|
1
native/jni/magiskpolicy
Submodule
1
native/jni/magiskpolicy
Submodule
Submodule native/jni/magiskpolicy added at 2f4062a923
43
native/jni/resetprop/ErrnoRestorer.h
Normal file
43
native/jni/resetprop/ErrnoRestorer.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ERRNO_RESTORER_H
|
||||
#define ERRNO_RESTORER_H
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "bionic_macros.h"
|
||||
|
||||
class ErrnoRestorer {
|
||||
public:
|
||||
explicit ErrnoRestorer() : saved_errno_(errno) {
|
||||
}
|
||||
|
||||
~ErrnoRestorer() {
|
||||
errno = saved_errno_;
|
||||
}
|
||||
|
||||
void override(int new_errno) {
|
||||
saved_errno_ = new_errno;
|
||||
}
|
||||
|
||||
private:
|
||||
int saved_errno_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ErrnoRestorer);
|
||||
};
|
||||
|
||||
#endif // ERRNO_RESTORER_H
|
144
native/jni/resetprop/_system_properties.h
Normal file
144
native/jni/resetprop/_system_properties.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SYS__SYSTEM_PROPERTIES_H
|
||||
#define _INCLUDE_SYS__SYSTEM_PROPERTIES_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
|
||||
#error you should #include <sys/system_properties.h> instead
|
||||
#endif
|
||||
|
||||
// #include <sys/system_properties.h>
|
||||
#include "system_properties.h"
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define PROP_SERVICE_NAME "property_service"
|
||||
#define PROP_FILENAME "/dev/__properties__"
|
||||
|
||||
#define PROP_MSG_SETPROP 1
|
||||
#define PROP_MSG_SETPROP2 0x00020001
|
||||
|
||||
#define PROP_SUCCESS 0
|
||||
#define PROP_ERROR_READ_CMD 0x0004
|
||||
#define PROP_ERROR_READ_DATA 0x0008
|
||||
#define PROP_ERROR_READ_ONLY_PROPERTY 0x000B
|
||||
#define PROP_ERROR_INVALID_NAME 0x0010
|
||||
#define PROP_ERROR_INVALID_VALUE 0x0014
|
||||
#define PROP_ERROR_PERMISSION_DENIED 0x0018
|
||||
#define PROP_ERROR_INVALID_CMD 0x001B
|
||||
#define PROP_ERROR_HANDLE_CONTROL_MESSAGE 0x0020
|
||||
#define PROP_ERROR_SET_FAILED 0x0024
|
||||
|
||||
/*
|
||||
** Map the property area from the specified filename. This
|
||||
** method is for testing only.
|
||||
*/
|
||||
int __system_property_set_filename2(const char *filename);
|
||||
|
||||
/*
|
||||
** Initialize the area to be used to store properties. Can
|
||||
** only be done by a single process that has write access to
|
||||
** the property area.
|
||||
*/
|
||||
int __system_property_area_init2();
|
||||
|
||||
/* Read the global serial number of the system properties
|
||||
**
|
||||
** Called to predict if a series of cached __system_property_find
|
||||
** objects will have seen __system_property_serial values change.
|
||||
** But also aids the converse, as changes in the global serial can
|
||||
** also be used to predict if a failed __system_property_find
|
||||
** could in-turn now find a new object; thus preventing the
|
||||
** cycles of effort to poll __system_property_find.
|
||||
**
|
||||
** Typically called at beginning of a cache cycle to signal if _any_ possible
|
||||
** changes have occurred since last. If there is, one may check each individual
|
||||
** __system_property_serial to confirm dirty, or __system_property_find
|
||||
** to check if the property now exists. If a call to __system_property_add
|
||||
** or __system_property_update has completed between two calls to
|
||||
** __system_property_area_serial then the second call will return a larger
|
||||
** value than the first call. Beware of race conditions as changes to the
|
||||
** properties are not atomic, the main value of this call is to determine
|
||||
** whether the expensive __system_property_find is worth retrying to see if
|
||||
** a property now exists.
|
||||
**
|
||||
** Returns the serial number on success, -1 on error.
|
||||
*/
|
||||
uint32_t __system_property_area_serial2();
|
||||
|
||||
/* Add a new system property. Can only be done by a single
|
||||
** process that has write access to the property area, and
|
||||
** that process must handle sequencing to ensure the property
|
||||
** does not already exist and that only one property is added
|
||||
** or updated at a time.
|
||||
**
|
||||
** Returns 0 on success, -1 if the property area is full.
|
||||
*/
|
||||
int __system_property_add2(const char *name, unsigned int namelen, const char *value, unsigned int valuelen);
|
||||
|
||||
/* Delete a new system property. Added in resetprop
|
||||
**
|
||||
** Returns 0 on success, -1 if the property area is full.
|
||||
*/
|
||||
int __system_property_del(const char *name);
|
||||
|
||||
/* Update the value of a system property returned by
|
||||
** __system_property_find. Can only be done by a single process
|
||||
** that has write access to the property area, and that process
|
||||
** must handle sequencing to ensure that only one property is
|
||||
** updated at a time.
|
||||
**
|
||||
** Returns 0 on success, -1 if the parameters are incorrect.
|
||||
*/
|
||||
int __system_property_update2(prop_info *pi, const char *value, unsigned int len);
|
||||
|
||||
/* Read the serial number of a system property returned by
|
||||
** __system_property_find.
|
||||
**
|
||||
** Returns the serial number on success, -1 on error.
|
||||
*/
|
||||
uint32_t __system_property_serial2(const prop_info* pi);
|
||||
|
||||
/* Initialize the system properties area in read only mode.
|
||||
* Should be done by all processes that need to read system
|
||||
* properties.
|
||||
*
|
||||
* Returns 0 on success, -1 otherwise.
|
||||
*/
|
||||
int __system_properties_init2();
|
||||
|
||||
/* Deprecated: use __system_property_wait instead. */
|
||||
uint32_t __system_property_wait_any2(uint32_t old_serial);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
77
native/jni/resetprop/bionic_futex.h
Normal file
77
native/jni/resetprop/bionic_futex.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _BIONIC_FUTEX_H
|
||||
#define _BIONIC_FUTEX_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <linux/futex.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct timespec;
|
||||
|
||||
static inline __always_inline int __futex(volatile void* ftx, int op, int value,
|
||||
const struct timespec* timeout,
|
||||
int bitset) {
|
||||
// Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.
|
||||
int saved_errno = errno;
|
||||
int result = syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset);
|
||||
if (__predict_false(result == -1)) {
|
||||
result = -errno;
|
||||
errno = saved_errno;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int __futex_wake(volatile void* ftx, int count) {
|
||||
return __futex(ftx, FUTEX_WAKE, count, NULL, 0);
|
||||
}
|
||||
|
||||
static inline int __futex_wake_ex(volatile void* ftx, bool shared, int count) {
|
||||
return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL, 0);
|
||||
}
|
||||
|
||||
static inline int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) {
|
||||
return __futex(ftx, FUTEX_WAIT, value, timeout, 0);
|
||||
}
|
||||
|
||||
static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value,
|
||||
bool use_realtime_clock, const struct timespec* abs_timeout) {
|
||||
return __futex(ftx, (shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE) |
|
||||
(use_realtime_clock ? FUTEX_CLOCK_REALTIME : 0), value, abs_timeout,
|
||||
FUTEX_BITSET_MATCH_ANY);
|
||||
}
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _BIONIC_FUTEX_H */
|
79
native/jni/resetprop/bionic_lock.h
Normal file
79
native/jni/resetprop/bionic_lock.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _BIONIC_LOCK_H
|
||||
#define _BIONIC_LOCK_H
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include "bionic_futex.h"
|
||||
#include "bionic_macros.h"
|
||||
|
||||
// Lock is used in places like pthread_rwlock_t, which can be initialized without calling
|
||||
// an initialization function. So make sure Lock can be initialized by setting its memory to 0.
|
||||
class Lock {
|
||||
private:
|
||||
enum LockState {
|
||||
Unlocked = 0,
|
||||
LockedWithoutWaiter,
|
||||
LockedWithWaiter,
|
||||
};
|
||||
_Atomic(LockState) state;
|
||||
bool process_shared;
|
||||
|
||||
public:
|
||||
void init(bool process_shared) {
|
||||
atomic_init(&state, Unlocked);
|
||||
this->process_shared = process_shared;
|
||||
}
|
||||
|
||||
bool trylock() {
|
||||
LockState old_state = Unlocked;
|
||||
return __predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
|
||||
LockedWithoutWaiter, memory_order_acquire, memory_order_relaxed));
|
||||
}
|
||||
|
||||
void lock() {
|
||||
LockState old_state = Unlocked;
|
||||
if (__predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
|
||||
LockedWithoutWaiter, memory_order_acquire, memory_order_relaxed))) {
|
||||
return;
|
||||
}
|
||||
while (atomic_exchange_explicit(&state, LockedWithWaiter, memory_order_acquire) != Unlocked) {
|
||||
// TODO: As the critical section is brief, it is a better choice to spin a few times befor sleeping.
|
||||
__futex_wait_ex(&state, process_shared, LockedWithWaiter, false, nullptr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
if (atomic_exchange_explicit(&state, Unlocked, memory_order_release) == LockedWithWaiter) {
|
||||
__futex_wake_ex(&state, process_shared, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _BIONIC_LOCK_H
|
69
native/jni/resetprop/bionic_macros.h
Normal file
69
native/jni/resetprop/bionic_macros.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _BIONIC_MACROS_H_
|
||||
#define _BIONIC_MACROS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Frameworks OpenGL code currently leaks this header and allows
|
||||
// collisions with other declarations, e.g., from libnativehelper.
|
||||
// TODO: Remove once cleaned up. b/18334516
|
||||
#if !defined(DISALLOW_COPY_AND_ASSIGN)
|
||||
// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions.
|
||||
// It goes in the private: declarations in a class.
|
||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&) = delete; \
|
||||
void operator=(const TypeName&) = delete
|
||||
#endif // !defined(DISALLOW_COPY_AND_ASSIGN)
|
||||
|
||||
// A macro to disallow all the implicit constructors, namely the
|
||||
// default constructor, copy constructor and operator= functions.
|
||||
//
|
||||
// This should be used in the private: declarations for a class
|
||||
// that wants to prevent anyone from instantiating it. This is
|
||||
// especially useful for classes containing only static methods.
|
||||
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
|
||||
TypeName() = delete; \
|
||||
DISALLOW_COPY_AND_ASSIGN(TypeName)
|
||||
|
||||
#define BIONIC_ALIGN(value, alignment) \
|
||||
(((value) + (alignment) - 1) & ~((alignment) - 1))
|
||||
|
||||
#define BIONIC_ROUND_UP_POWER_OF_2(value) \
|
||||
((sizeof(value) == 8) \
|
||||
? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
|
||||
: (1UL << (32 - __builtin_clz(static_cast<unsigned int>(value)))))
|
||||
|
||||
static constexpr uintptr_t align_down(uintptr_t p, size_t align) {
|
||||
return p & ~(align - 1);
|
||||
}
|
||||
|
||||
static constexpr uintptr_t align_up(uintptr_t p, size_t align) {
|
||||
return (p + align - 1) & ~(align - 1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T* align_down(T* p, size_t align) {
|
||||
return reinterpret_cast<T*>(align_down(reinterpret_cast<uintptr_t>(p), align));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T* align_up(T* p, size_t align) {
|
||||
return reinterpret_cast<T*>(align_up(reinterpret_cast<uintptr_t>(p), align));
|
||||
}
|
||||
|
||||
#endif // _BIONIC_MACROS_H_
|
407
native/jni/resetprop/resetprop.cpp
Normal file
407
native/jni/resetprop/resetprop.cpp
Normal file
@@ -0,0 +1,407 @@
|
||||
/* resetprop.cpp - Manipulate any system props
|
||||
*
|
||||
* Copyright 2016 nkk71 <nkk71x@gmail.com>
|
||||
* Copyright 2016 topjohnwu <topjohnwu@gmail.com>
|
||||
*
|
||||
* Info:
|
||||
*
|
||||
* all changes are in
|
||||
*
|
||||
* bionic/libc/bionic/system_properties.cpp
|
||||
*
|
||||
* Functions that need to be patched/added in system_properties.cpp
|
||||
*
|
||||
* int __system_properties_init2()
|
||||
* on android 7, first tear down the everything then let it initialize again:
|
||||
* if (initialized) {
|
||||
* //list_foreach(contexts, [](context_node* l) { l->reset_access(); });
|
||||
* //return 0;
|
||||
* free_and_unmap_contexts();
|
||||
* initialized = false;
|
||||
* }
|
||||
*
|
||||
*
|
||||
* static prop_area* map_prop_area(const char* filename, bool is_legacy)
|
||||
* we dont want this read only so change: 'O_RDONLY' to 'O_RDWR'
|
||||
*
|
||||
* static prop_area* map_fd_ro(const int fd)
|
||||
* we dont want this read only so change: 'PROT_READ' to 'PROT_READ | PROT_WRITE'
|
||||
*
|
||||
*
|
||||
* Copy the code of prop_info *prop_area::find_property, and modify to delete props
|
||||
* const prop_info *prop_area::find_property_and_del(prop_bt *const trie, const char *name)
|
||||
* {
|
||||
* ...
|
||||
* ... Do not alloc a new prop_bt here, remove all code involve alloc_if_needed
|
||||
* ...
|
||||
*
|
||||
* if (prop_offset != 0) {
|
||||
* atomic_store_explicit(¤t->prop, 0, memory_order_release); // Add this line to nullify the prop entry
|
||||
* return to_prop_info(¤t->prop);
|
||||
* } else {
|
||||
*
|
||||
* ....
|
||||
* }
|
||||
*
|
||||
*
|
||||
* by patching just those functions directly, all other functions should be ok
|
||||
* as is.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
|
||||
#include "_system_properties.h"
|
||||
#include "system_properties.h"
|
||||
|
||||
#include "magisk.h"
|
||||
#include "resetprop.h"
|
||||
extern "C" {
|
||||
#include "vector.h"
|
||||
}
|
||||
|
||||
#define PRINT_D(...) { LOGD(__VA_ARGS__); if (verbose) fprintf(stderr, __VA_ARGS__); }
|
||||
#define PRINT_E(...) { LOGE(__VA_ARGS__); fprintf(stderr, __VA_ARGS__); }
|
||||
#define PERSISTENT_PROPERTY_DIR "/data/property"
|
||||
|
||||
static int verbose = 0;
|
||||
|
||||
static int check_legal_property_name(const char *name) {
|
||||
int namelen = strlen(name);
|
||||
|
||||
if (namelen < 1) goto illegal;
|
||||
if (name[0] == '.') goto illegal;
|
||||
if (name[namelen - 1] == '.') goto illegal;
|
||||
|
||||
/* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */
|
||||
/* Don't allow ".." to appear in a property name */
|
||||
for (size_t i = 0; i < namelen; i++) {
|
||||
if (name[i] == '.') {
|
||||
// i=0 is guaranteed to never have a dot. See above.
|
||||
if (name[i-1] == '.') goto illegal;
|
||||
continue;
|
||||
}
|
||||
if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') continue;
|
||||
if (name[i] >= 'a' && name[i] <= 'z') continue;
|
||||
if (name[i] >= 'A' && name[i] <= 'Z') continue;
|
||||
if (name[i] >= '0' && name[i] <= '9') continue;
|
||||
goto illegal;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
illegal:
|
||||
PRINT_E("Illegal property name: [%s]\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int usage(char* arg0) {
|
||||
fprintf(stderr,
|
||||
"resetprop v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu & nkk71) - System Props Modification Tool\n\n"
|
||||
"Usage: %s [flags] [options...]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h, --help show this message\n"
|
||||
" (no arguments) print all properties\n"
|
||||
" NAME get property\n"
|
||||
" NAME VALUE set property entry NAME with VALUE\n"
|
||||
" --file FILE load props from FILE\n"
|
||||
" --delete NAME delete property\n"
|
||||
"\n"
|
||||
"Flags:\n"
|
||||
" -v print verbose output to stderr\n"
|
||||
" -n set properties without init triggers\n"
|
||||
" only affects setprop\n"
|
||||
" -p access actual persist storage\n"
|
||||
" only affects getprop and deleteprop\n"
|
||||
"\n"
|
||||
|
||||
, arg0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int init_resetprop() {
|
||||
if (__system_properties_init2()) {
|
||||
PRINT_E("resetprop: Initialize error\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prop_exist(const char *name) {
|
||||
if (init_resetprop()) return 0;
|
||||
return __system_property_find2(name) != NULL;
|
||||
}
|
||||
|
||||
static void read_prop_info(void* cookie, const char *name, const char *value, uint32_t serial) {
|
||||
strcpy((char *) cookie, value);
|
||||
}
|
||||
|
||||
|
||||
char *getprop(const char *name) {
|
||||
return getprop2(name, 0);
|
||||
}
|
||||
|
||||
// Get prop by name, return string (should free manually!)
|
||||
char *getprop2(const char *name, int persist) {
|
||||
if (check_legal_property_name(name))
|
||||
return NULL;
|
||||
char value[PROP_VALUE_MAX];
|
||||
if (init_resetprop()) return NULL;
|
||||
const prop_info *pi = __system_property_find2(name);
|
||||
if (pi == NULL) {
|
||||
if (persist && strncmp(name, "persist.", 8) == 0) {
|
||||
// Try to read from file
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, sizeof(path), PERSISTENT_PROPERTY_DIR "/%s", name);
|
||||
int fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) goto no_prop;
|
||||
PRINT_D("resetprop: read prop from [%s]\n", path);
|
||||
size_t len = read(fd, value, sizeof(value));
|
||||
value[len] = '\0'; // Null terminate the read value
|
||||
} else {
|
||||
no_prop:
|
||||
PRINT_D("resetprop: prop [%s] does not exist\n", name);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
__system_property_read_callback2(pi, read_prop_info, value);
|
||||
}
|
||||
PRINT_D("resetprop: getprop [%s]: [%s]\n", name, value);
|
||||
return strdup(value);
|
||||
}
|
||||
|
||||
struct wrapper {
|
||||
void (*func)(const char *, const char *);
|
||||
};
|
||||
|
||||
static void cb_wrapper(void* cookie, const char *name, const char *value, uint32_t serial) {
|
||||
((wrapper *) cookie)->func(name, value);
|
||||
}
|
||||
|
||||
static void prop_foreach_cb(const prop_info* pi, void* cookie) {
|
||||
__system_property_read_callback2(pi, cb_wrapper, cookie);
|
||||
}
|
||||
|
||||
class property {
|
||||
public:
|
||||
property(const char *n, const char *v) {
|
||||
name = strdup(n);
|
||||
value = strdup(v);
|
||||
}
|
||||
~property() {
|
||||
free((void *)name);
|
||||
free((void *)value);
|
||||
}
|
||||
const char *name;
|
||||
const char *value;
|
||||
};
|
||||
|
||||
vector prop_list;
|
||||
|
||||
static int prop_cmp(const void *p1, const void *p2) {
|
||||
return strcmp(((property *) p1)->name, ((property *) p2)->name);
|
||||
}
|
||||
|
||||
static void print_all_props_cb(const char *name, const char *value) {
|
||||
vec_push_back(&prop_list, new property(name, value));
|
||||
}
|
||||
|
||||
static void print_all_props(int persist) {
|
||||
void *p;
|
||||
vec_init(&prop_list);
|
||||
getprop_all(print_all_props_cb);
|
||||
if (persist) {
|
||||
// Check all persist props in data
|
||||
DIR *dir = opendir(PERSISTENT_PROPERTY_DIR);
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 )
|
||||
continue;
|
||||
int found = 0;
|
||||
vec_for_each(&prop_list, p) {
|
||||
if (strcmp(((property *) p)->name, entry->d_name) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
vec_push_back(&prop_list, new property(entry->d_name, getprop2(entry->d_name, 1)));
|
||||
}
|
||||
}
|
||||
vec_sort(&prop_list, prop_cmp);
|
||||
vec_for_each(&prop_list, p) {
|
||||
printf("[%s]: [%s]\n", ((property *) p)->name, ((property *) p)->value);
|
||||
delete((property *) p);
|
||||
}
|
||||
vec_destroy(&prop_list);
|
||||
}
|
||||
|
||||
void getprop_all(void (*callback)(const char*, const char*)) {
|
||||
if (init_resetprop()) return;
|
||||
struct wrapper wrap = {
|
||||
.func = callback
|
||||
};
|
||||
__system_property_foreach2(prop_foreach_cb, &wrap);
|
||||
}
|
||||
|
||||
int setprop(const char *name, const char *value) {
|
||||
return setprop2(name, value, 1);
|
||||
}
|
||||
|
||||
int setprop2(const char *name, const char *value, const int trigger) {
|
||||
if (check_legal_property_name(name))
|
||||
return 1;
|
||||
if (init_resetprop()) return -1;
|
||||
int ret;
|
||||
|
||||
prop_info *pi = (prop_info*) __system_property_find2(name);
|
||||
if (pi != NULL) {
|
||||
if (trigger) {
|
||||
if (strncmp(name, "ro.", 3) == 0) deleteprop(name);
|
||||
ret = __system_property_set2(name, value);
|
||||
} else {
|
||||
ret = __system_property_update2(pi, value, strlen(value));
|
||||
}
|
||||
} else {
|
||||
PRINT_D("resetprop: New prop [%s]\n", name);
|
||||
if (trigger) {
|
||||
ret = __system_property_set2(name, value);
|
||||
} else {
|
||||
ret = __system_property_add2(name, strlen(name), value, strlen(value));
|
||||
}
|
||||
}
|
||||
|
||||
PRINT_D("resetprop: setprop [%s]: [%s] by %s\n", name, value,
|
||||
trigger ? "property_service" : "modifing prop data structure");
|
||||
|
||||
if (ret)
|
||||
PRINT_E("resetprop: setprop error\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int deleteprop(const char *name) {
|
||||
return deleteprop2(name, 1);
|
||||
}
|
||||
|
||||
int deleteprop2(const char *name, const int persist) {
|
||||
if (check_legal_property_name(name))
|
||||
return 1;
|
||||
if (init_resetprop()) return -1;
|
||||
char path[PATH_MAX];
|
||||
path[0] = '\0';
|
||||
PRINT_D("resetprop: deleteprop [%s]\n", name);
|
||||
if (persist && strncmp(name, "persist.", 8) == 0)
|
||||
snprintf(path, sizeof(path), PERSISTENT_PROPERTY_DIR "/%s", name);
|
||||
return __system_property_del(name) && unlink(path);
|
||||
}
|
||||
|
||||
int read_prop_file(const char* filename, const int trigger) {
|
||||
if (init_resetprop()) return -1;
|
||||
PRINT_D("resetprop: Load prop file [%s]\n", filename);
|
||||
FILE *fp = fopen(filename, "r");
|
||||
if (fp == NULL) {
|
||||
PRINT_E("Cannot open [%s]\n", filename);
|
||||
return 1;
|
||||
}
|
||||
char *line = NULL, *pch;
|
||||
size_t len;
|
||||
ssize_t read;
|
||||
int comment = 0, i;
|
||||
while ((read = getline(&line, &len, fp)) != -1) {
|
||||
// Remove the trailing newline
|
||||
if (line[read - 1] == '\n') {
|
||||
line[read - 1] = '\0';
|
||||
--read;
|
||||
}
|
||||
comment = 0;
|
||||
for (i = 0; i < read; ++i) {
|
||||
// Ignore starting spaces
|
||||
if (line[i] == ' ') continue;
|
||||
else {
|
||||
// A line starting with # is ignored
|
||||
if (line[i] == '#') comment = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (comment) continue;
|
||||
pch = strchr(line, '=');
|
||||
// Ignore ivalid formats
|
||||
if ( ((pch == NULL) || (i >= (pch - line))) || (pch >= line + read - 1) ) continue;
|
||||
// Separate the string
|
||||
*pch = '\0';
|
||||
setprop2(line + i, pch + 1, trigger);
|
||||
}
|
||||
free(line);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int resetprop_main(int argc, char *argv[]) {
|
||||
int trigger = 1, persist = 0;
|
||||
char *argv0 = argv[0], *prop;
|
||||
|
||||
--argc;
|
||||
++argv;
|
||||
|
||||
// Parse flags and -- options
|
||||
while (argc && argv[0][0] == '-') {
|
||||
for (int idx = 1; 1; ++idx) {
|
||||
switch (argv[0][idx]) {
|
||||
case '-':
|
||||
if (strcmp(argv[0], "--file") == 0 && argc == 2) {
|
||||
return read_prop_file(argv[1], trigger);
|
||||
} else if (strcmp(argv[0], "--delete") == 0 && argc == 2) {
|
||||
return deleteprop2(argv[1], persist);
|
||||
} else if (strcmp(argv[0], "--help") == 0) {
|
||||
goto usage;
|
||||
}
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
continue;
|
||||
case 'p':
|
||||
persist = 1;
|
||||
continue;
|
||||
case 'n':
|
||||
trigger = 0;
|
||||
continue;
|
||||
case '\0':
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage:
|
||||
return usage(argv0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
|
||||
switch (argc) {
|
||||
case 0:
|
||||
print_all_props(persist);
|
||||
return 0;
|
||||
case 1:
|
||||
prop = getprop2(argv[0], persist);
|
||||
if (prop == NULL) return 1;
|
||||
printf("%s\n", prop);
|
||||
free(prop);
|
||||
return 0;
|
||||
case 2:
|
||||
return setprop2(argv[0], argv[1], trigger);
|
||||
default:
|
||||
usage(argv0);
|
||||
return 1;
|
||||
}
|
||||
}
|
1559
native/jni/resetprop/system_properties.cpp
Normal file
1559
native/jni/resetprop/system_properties.cpp
Normal file
File diff suppressed because it is too large
Load Diff
100
native/jni/resetprop/system_properties.h
Normal file
100
native/jni/resetprop/system_properties.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SYS_SYSTEM_PROPERTIES_H
|
||||
#define _INCLUDE_SYS_SYSTEM_PROPERTIES_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
typedef struct prop_info prop_info;
|
||||
|
||||
#define PROP_VALUE_MAX 92
|
||||
|
||||
/*
|
||||
* Sets system property `key` to `value`, creating the system property if it doesn't already exist.
|
||||
*/
|
||||
int __system_property_set2(const char* key, const char* value);
|
||||
|
||||
/*
|
||||
* Returns a `prop_info` corresponding system property `name`, or nullptr if it doesn't exist.
|
||||
* Use __system_property_read_callback to query the current value.
|
||||
*
|
||||
* Property lookup is expensive, so it can be useful to cache the result of this function.
|
||||
*/
|
||||
const prop_info* __system_property_find2(const char* name);
|
||||
|
||||
/*
|
||||
* Calls `callback` with a consistent trio of name, value, and serial number for property `pi`.
|
||||
*/
|
||||
void __system_property_read_callback2(const prop_info *pi,
|
||||
void (*callback)(void* cookie, const char *name, const char *value, uint32_t serial),
|
||||
void* cookie);
|
||||
|
||||
/*
|
||||
* Passes a `prop_info` for each system property to the provided
|
||||
* callback. Use __system_property_read_callback() to read the value.
|
||||
*
|
||||
* This method is for inspecting and debugging the property system, and not generally useful.
|
||||
*/
|
||||
int __system_property_foreach2(void (*propfn)(const prop_info* pi, void* cookie), void* cookie);
|
||||
|
||||
/*
|
||||
* Waits for the specific system property identified by `pi` to be updated
|
||||
* past `old_serial`. Waits no longer than `relative_timeout`, or forever
|
||||
* if `relaive_timeout` is null.
|
||||
*
|
||||
* If `pi` is null, waits for the global serial number instead.
|
||||
*
|
||||
* If you don't know the current serial, use 0.
|
||||
*
|
||||
* Returns true and updates `*new_serial_ptr` on success, or false if the call
|
||||
* timed out.
|
||||
*/
|
||||
struct timespec;
|
||||
bool __system_property_wait2(const prop_info* pi,
|
||||
uint32_t old_serial,
|
||||
uint32_t* new_serial_ptr,
|
||||
const struct timespec* relative_timeout);
|
||||
|
||||
/* Deprecated. In Android O and above, there's no limit on property name length. */
|
||||
#define PROP_NAME_MAX 32
|
||||
/* Deprecated. Use __system_property_read_callback instead. */
|
||||
int __system_property_read2(const prop_info* pi, char* name, char* value);
|
||||
/* Deprecated. Use __system_property_read_callback instead. */
|
||||
int __system_property_get2(const char* name, char* value);
|
||||
/* Deprecated. Use __system_property_foreach instead. */
|
||||
const prop_info* __system_property_find_nth2(unsigned n);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
1
native/jni/su
Submodule
1
native/jni/su
Submodule
Submodule native/jni/su added at ed5dd827e9
256
native/jni/utils/cpio.c
Normal file
256
native/jni/utils/cpio.c
Normal file
@@ -0,0 +1,256 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "cpio.h"
|
||||
#include "logging.h"
|
||||
#include "utils.h"
|
||||
|
||||
static uint32_t x8u(char *hex) {
|
||||
uint32_t val, inpos = 8, outpos;
|
||||
char pattern[6];
|
||||
|
||||
while (*hex == '0') {
|
||||
hex++;
|
||||
if (!--inpos) return 0;
|
||||
}
|
||||
// Because scanf gratuitously treats %*X differently than printf does.
|
||||
sprintf(pattern, "%%%dx%%n", inpos);
|
||||
sscanf(hex, pattern, &val, &outpos);
|
||||
if (inpos != outpos) LOGE("bad cpio header\n");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void cpio_free(cpio_entry *e) {
|
||||
if (e) {
|
||||
free(e->filename);
|
||||
free(e->data);
|
||||
free(e);
|
||||
}
|
||||
}
|
||||
|
||||
int cpio_find(struct vector *v, const char *entry) {
|
||||
cpio_entry *e;
|
||||
vec_for_each(v, e) {
|
||||
if (!e) continue;
|
||||
if (strcmp(e->filename, entry) == 0)
|
||||
return _;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cpio_cmp(const void *a, const void *b) {
|
||||
return strcmp(((cpio_entry *) a)->filename, ((cpio_entry *) b)->filename);
|
||||
}
|
||||
|
||||
void cpio_vec_insert(struct vector *v, cpio_entry *n) {
|
||||
int i = cpio_find(v, n->filename);
|
||||
if (i > 0) {
|
||||
// Replace, then all is done
|
||||
cpio_free(vec_entry(v)[i]);
|
||||
vec_entry(v)[i] = n;
|
||||
return;
|
||||
}
|
||||
vec_push_back(v, n);
|
||||
}
|
||||
|
||||
// Parse cpio file to a vector of cpio_entry
|
||||
void parse_cpio(struct vector *v, const char *filename) {
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) return;
|
||||
fprintf(stderr, "Loading cpio: [%s]\n", filename);
|
||||
cpio_newc_header header;
|
||||
cpio_entry *f;
|
||||
while(xxread(fd, &header, 110) != -1) {
|
||||
f = xcalloc(sizeof(*f), 1);
|
||||
// f->ino = x8u(header.ino);
|
||||
f->mode = x8u(header.mode);
|
||||
f->uid = x8u(header.uid);
|
||||
f->gid = x8u(header.gid);
|
||||
// f->nlink = x8u(header.nlink);
|
||||
// f->mtime = x8u(header.mtime);
|
||||
f->filesize = x8u(header.filesize);
|
||||
// f->devmajor = x8u(header.devmajor);
|
||||
// f->devminor = x8u(header.devminor);
|
||||
// f->rdevmajor = x8u(header.rdevmajor);
|
||||
// f->rdevminor = x8u(header.rdevminor);
|
||||
uint32_t namesize = x8u(header.namesize);
|
||||
// f->check = x8u(header.check);
|
||||
f->filename = xmalloc(namesize);
|
||||
xxread(fd, f->filename, namesize);
|
||||
file_align(fd, 4, 0);
|
||||
if (strcmp(f->filename, ".") == 0 || strcmp(f->filename, "..") == 0) {
|
||||
cpio_free(f);
|
||||
continue;
|
||||
}
|
||||
if (strcmp(f->filename, "TRAILER!!!") == 0) {
|
||||
cpio_free(f);
|
||||
break;
|
||||
}
|
||||
if (f->filesize) {
|
||||
f->data = xmalloc(f->filesize);
|
||||
xxread(fd, f->data, f->filesize);
|
||||
file_align(fd, 4, 0);
|
||||
}
|
||||
vec_push_back(v, f);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void dump_cpio(struct vector *v, const char *filename) {
|
||||
fprintf(stderr, "Dump cpio: [%s]\n", filename);
|
||||
unsigned inode = 300000;
|
||||
char header[111];
|
||||
// Sort by name
|
||||
vec_sort(v, cpio_cmp);
|
||||
cpio_entry *e;
|
||||
int fd = creat(filename, 0644);
|
||||
vec_for_each(v, e) {
|
||||
sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
|
||||
inode++, // e->ino
|
||||
e->mode,
|
||||
e->uid,
|
||||
e->gid,
|
||||
1, // e->nlink
|
||||
0, // e->mtime
|
||||
e->filesize,
|
||||
0, // e->devmajor
|
||||
0, // e->devminor
|
||||
0, // e->rdevmajor
|
||||
0, // e->rdevminor
|
||||
(uint32_t) strlen(e->filename) + 1,
|
||||
0 // e->check
|
||||
);
|
||||
xwrite(fd, header, 110);
|
||||
xwrite(fd, e->filename, strlen(e->filename) + 1);
|
||||
file_align(fd, 4, 1);
|
||||
if (e->filesize) {
|
||||
xwrite(fd, e->data, e->filesize);
|
||||
file_align(fd, 4, 1);
|
||||
}
|
||||
}
|
||||
// Write trailer
|
||||
sprintf(header, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x", inode++, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 11, 0);
|
||||
xwrite(fd, header, 110);
|
||||
xwrite(fd, "TRAILER!!!\0", 11);
|
||||
file_align(fd, 4, 1);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void cpio_vec_destroy(struct vector *v) {
|
||||
// Free each cpio_entry
|
||||
cpio_entry *e;
|
||||
vec_for_each(v, e)
|
||||
cpio_free(e);
|
||||
vec_destroy(v);
|
||||
}
|
||||
|
||||
void cpio_rm(struct vector *v, int recursive, const char *entry) {
|
||||
cpio_entry *e;
|
||||
size_t len = strlen(entry);
|
||||
vec_for_each(v, e) {
|
||||
if (!e) continue;
|
||||
if (strncmp(e->filename, entry, len) == 0) {
|
||||
if ((recursive && e->filename[len] == '/') || e->filename[len] == '\0') {
|
||||
fprintf(stderr, "Remove [%s]\n", e->filename);
|
||||
cpio_free(e);
|
||||
vec_cur(v) = NULL;
|
||||
if (!recursive) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cpio_mkdir(struct vector *v, mode_t mode, const char *entry) {
|
||||
cpio_entry *e = xcalloc(sizeof(*e), 1);
|
||||
e->mode = S_IFDIR | mode;
|
||||
e->filename = strdup(entry);
|
||||
cpio_vec_insert(v, e);
|
||||
fprintf(stderr, "Create directory [%s] (%04o)\n",entry, mode);
|
||||
}
|
||||
|
||||
void cpio_ln(struct vector *v, const char *target, const char *entry) {
|
||||
cpio_entry *e = xcalloc(sizeof(*e), 1);
|
||||
e->mode = S_IFLNK;
|
||||
e->filename = strdup(entry);
|
||||
e->filesize = strlen(target);
|
||||
e->data = strdup(target);
|
||||
cpio_vec_insert(v, e);
|
||||
fprintf(stderr, "Create symlink [%s] -> [%s]\n", entry, target);
|
||||
}
|
||||
|
||||
void cpio_add(struct vector *v, mode_t mode, const char *entry, const char *filename) {
|
||||
int fd = xopen(filename, O_RDONLY);
|
||||
cpio_entry *e = xcalloc(sizeof(*e), 1);
|
||||
e->mode = S_IFREG | mode;
|
||||
e->filename = strdup(entry);
|
||||
e->filesize = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
e->data = xmalloc(e->filesize);
|
||||
xxread(fd, e->data, e->filesize);
|
||||
close(fd);
|
||||
cpio_vec_insert(v, e);
|
||||
fprintf(stderr, "Add entry [%s] (%04o)\n", entry, mode);
|
||||
}
|
||||
|
||||
int cpio_mv(struct vector *v, const char *from, const char *to) {
|
||||
struct cpio_entry *e;
|
||||
int f = cpio_find(v, from), t = cpio_find(v, to);
|
||||
if (f > 0) {
|
||||
if (t > 0) {
|
||||
cpio_free(vec_entry(v)[t]);
|
||||
vec_entry(v)[t] = NULL;
|
||||
}
|
||||
e = vec_entry(v)[f];
|
||||
free(e->filename);
|
||||
e->filename = strdup(to);
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "Cannot find entry %s\n", from);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cpio_extract(struct vector *v, const char *entry, const char *filename) {
|
||||
int i = cpio_find(v, entry);
|
||||
if (i > 0) {
|
||||
cpio_entry *e = vec_entry(v)[i];
|
||||
fprintf(stderr, "Extracting [%s] to [%s]\n", entry, filename);
|
||||
if (S_ISREG(e->mode)) {
|
||||
int fd = creat(filename, e->mode & 0777);
|
||||
xwrite(fd, e->data, e->filesize);
|
||||
fchown(fd, e->uid, e->gid);
|
||||
close(fd);
|
||||
} else if (S_ISLNK(e->mode)) {
|
||||
char *target = xcalloc(e->filesize + 1, 1);
|
||||
memcpy(target, e->data, e->filesize);
|
||||
unlink(filename);
|
||||
symlink(target, filename);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "Cannot find the file entry [%s]\n", entry);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cpio_extract_all(struct vector *v) {
|
||||
cpio_entry *e;
|
||||
vec_for_each(v, e) {
|
||||
if (!e) continue;
|
||||
fprintf(stderr, "Extracting [%s]\n", e->filename);
|
||||
unlink(e->filename);
|
||||
rmdir(e->filename);
|
||||
if (S_ISDIR(e->mode)) {
|
||||
mkdir(e->filename, e->mode & 0777);
|
||||
} else if (S_ISREG(e->mode)) {
|
||||
int fd = creat(e->filename, e->mode & 0777);
|
||||
xwrite(fd, e->data, e->filesize);
|
||||
fchown(fd, e->uid, e->gid);
|
||||
close(fd);
|
||||
} else if (S_ISLNK(e->mode)) {
|
||||
char *target = xcalloc(e->filesize + 1, 1);
|
||||
memcpy(target, e->data, e->filesize);
|
||||
symlink(target, e->filename);
|
||||
}
|
||||
}
|
||||
}
|
447
native/jni/utils/file.c
Normal file
447
native/jni/utils/file.c
Normal file
@@ -0,0 +1,447 @@
|
||||
/* file.c - Contains all files related utilities
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/mman.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#ifdef SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
char **excl_list = NULL;
|
||||
|
||||
static int is_excl(const char *name) {
|
||||
if (excl_list)
|
||||
for (int i = 0; excl_list[i]; ++i)
|
||||
if (strcmp(name, excl_list[i]) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_getpath(int fd, char *path, size_t size) {
|
||||
snprintf(path, size, "/proc/self/fd/%d", fd);
|
||||
if (xreadlink(path, path, size) == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mkdirs(const char *pathname, mode_t mode) {
|
||||
char *path = strdup(pathname), *p;
|
||||
errno = 0;
|
||||
for (p = path + 1; *p; ++p) {
|
||||
if (*p == '/') {
|
||||
*p = '\0';
|
||||
if (mkdir(path, mode) == -1) {
|
||||
if (errno != EEXIST)
|
||||
return -1;
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
if (mkdir(path, mode) == -1) {
|
||||
if (errno != EEXIST)
|
||||
return -1;
|
||||
}
|
||||
free(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void in_order_walk(int dirfd, void (*callback)(int, struct dirent*)) {
|
||||
struct dirent *entry;
|
||||
int newfd;
|
||||
DIR *dir = fdopendir(dirfd);
|
||||
if (dir == NULL) return;
|
||||
|
||||
while ((entry = xreaddir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
if (is_excl(entry->d_name))
|
||||
continue;
|
||||
if (entry->d_type == DT_DIR) {
|
||||
newfd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
in_order_walk(newfd, callback);
|
||||
close(newfd);
|
||||
}
|
||||
callback(dirfd, entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void rm_cb(int dirfd, struct dirent *entry) {
|
||||
switch (entry->d_type) {
|
||||
case DT_DIR:
|
||||
unlinkat(dirfd, entry->d_name, AT_REMOVEDIR);
|
||||
break;
|
||||
default:
|
||||
unlinkat(dirfd, entry->d_name, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void rm_rf(const char *path) {
|
||||
int fd = open(path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
|
||||
if (fd >= 0) {
|
||||
frm_rf(fd);
|
||||
close(fd);
|
||||
}
|
||||
remove(path);
|
||||
}
|
||||
|
||||
void frm_rf(int dirfd) {
|
||||
in_order_walk(dirfd, rm_cb);
|
||||
}
|
||||
|
||||
/* This will only on the same file system */
|
||||
void mv_f(const char *source, const char *destination) {
|
||||
struct stat st;
|
||||
xlstat(source, &st);
|
||||
int src, dest;
|
||||
struct file_attr a;
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
xmkdirs(destination, st.st_mode & 0777);
|
||||
src = xopen(source, O_RDONLY | O_CLOEXEC);
|
||||
dest = xopen(destination, O_RDONLY | O_CLOEXEC);
|
||||
fclone_attr(src, dest);
|
||||
mv_dir(src, dest);
|
||||
close(src);
|
||||
close(dest);
|
||||
} else{
|
||||
getattr(source, &a);
|
||||
xrename(source, destination);
|
||||
setattr(destination, &a);
|
||||
}
|
||||
rmdir(source);
|
||||
}
|
||||
|
||||
/* This will only on the same file system */
|
||||
void mv_dir(int src, int dest) {
|
||||
struct dirent *entry;
|
||||
DIR *dir;
|
||||
int newsrc, newdest;
|
||||
struct file_attr a;
|
||||
|
||||
dir = xfdopendir(src);
|
||||
while ((entry = xreaddir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
if (is_excl(entry->d_name))
|
||||
continue;
|
||||
getattrat(src, entry->d_name, &a);
|
||||
switch (entry->d_type) {
|
||||
case DT_DIR:
|
||||
xmkdirat(dest, entry->d_name, a.st.st_mode & 0777);
|
||||
newsrc = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
newdest = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
fsetattr(newdest, &a);
|
||||
mv_dir(newsrc, newdest);
|
||||
close(newsrc);
|
||||
close(newdest);
|
||||
unlinkat(src, entry->d_name, AT_REMOVEDIR);
|
||||
break;
|
||||
case DT_LNK:
|
||||
case DT_REG:
|
||||
renameat(src, entry->d_name, dest, entry->d_name);
|
||||
setattrat(dest, entry->d_name, &a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cp_afc(const char *source, const char *destination) {
|
||||
int src, dest;
|
||||
struct file_attr a;
|
||||
getattr(source, &a);
|
||||
|
||||
if (S_ISDIR(a.st.st_mode)) {
|
||||
xmkdirs(destination, a.st.st_mode & 0777);
|
||||
src = xopen(source, O_RDONLY | O_CLOEXEC);
|
||||
dest = xopen(destination, O_RDONLY | O_CLOEXEC);
|
||||
fsetattr(dest, &a);
|
||||
clone_dir(src, dest);
|
||||
close(src);
|
||||
close(dest);
|
||||
} else{
|
||||
unlink(destination);
|
||||
if (S_ISREG(a.st.st_mode)) {
|
||||
src = xopen(source, O_RDONLY);
|
||||
dest = xopen(destination, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
xsendfile(dest, src, NULL, a.st.st_size);
|
||||
fsetattr(src, &a);
|
||||
close(src);
|
||||
close(dest);
|
||||
} else if (S_ISLNK(a.st.st_mode)) {
|
||||
char buf[PATH_MAX];
|
||||
xreadlink(source, buf, sizeof(buf));
|
||||
xsymlink(buf, destination);
|
||||
setattr(destination, &a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clone_dir(int src, int dest) {
|
||||
struct dirent *entry;
|
||||
DIR *dir;
|
||||
int srcfd, destfd, newsrc, newdest;
|
||||
char buf[PATH_MAX];
|
||||
struct file_attr a;
|
||||
|
||||
dir = xfdopendir(src);
|
||||
while ((entry = xreaddir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
if (is_excl(entry->d_name))
|
||||
continue;
|
||||
getattrat(src, entry->d_name, &a);
|
||||
switch (entry->d_type) {
|
||||
case DT_DIR:
|
||||
xmkdirat(dest, entry->d_name, a.st.st_mode & 0777);
|
||||
setattrat(dest, entry->d_name, &a);
|
||||
newsrc = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
newdest = xopenat(dest, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
clone_dir(newsrc, newdest);
|
||||
close(newsrc);
|
||||
close(newdest);
|
||||
break;
|
||||
case DT_REG:
|
||||
destfd = xopenat(dest, entry->d_name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC);
|
||||
srcfd = xopenat(src, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
xsendfile(destfd, srcfd, 0, a.st.st_size);
|
||||
fsetattr(destfd, &a);
|
||||
close(destfd);
|
||||
close(srcfd);
|
||||
break;
|
||||
case DT_LNK:
|
||||
xreadlinkat(src, entry->d_name, buf, sizeof(buf));
|
||||
symlinkat(buf, dest, entry->d_name);
|
||||
setattrat(dest, entry->d_name, &a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getattr(const char *path, struct file_attr *a) {
|
||||
if (xlstat(path, &a->st) == -1)
|
||||
return -1;
|
||||
#ifdef SELINUX
|
||||
char *con = "";
|
||||
if (lgetfilecon(path, &con) == -1)
|
||||
return -1;
|
||||
strcpy(a->con, con);
|
||||
freecon(con);
|
||||
#else
|
||||
a->con[0] = '\0';
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getattrat(int dirfd, const char *pathname, struct file_attr *a) {
|
||||
int fd = xopenat(dirfd, pathname, O_PATH | O_NOFOLLOW | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
int ret = fgetattr(fd, a);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fgetattr(int fd, struct file_attr *a) {
|
||||
#ifdef SELINUX
|
||||
char path[PATH_MAX];
|
||||
fd_getpath(fd, path, sizeof(path));
|
||||
return getattr(path, a);
|
||||
#else
|
||||
if (fstat(fd, &a->st) == -1)
|
||||
return -1;
|
||||
a->con[0] = '\0';
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int setattr(const char *path, struct file_attr *a) {
|
||||
if (chmod(path, a->st.st_mode & 0777) < 0)
|
||||
return -1;
|
||||
if (chown(path, a->st.st_uid, a->st.st_gid) < 0)
|
||||
return -1;
|
||||
#ifdef SELINUX
|
||||
if (strlen(a->con) && lsetfilecon(path, a->con) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setattrat(int dirfd, const char *pathname, struct file_attr *a) {
|
||||
int fd = xopenat(dirfd, pathname, O_PATH | O_NOFOLLOW | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
int ret = fsetattr(fd, a);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fsetattr(int fd, struct file_attr *a) {
|
||||
#ifdef SELINUX
|
||||
char path[PATH_MAX];
|
||||
fd_getpath(fd, path, sizeof(path));
|
||||
return setattr(path, a);
|
||||
#else
|
||||
if (fchmod(fd, a->st.st_mode & 0777) < 0)
|
||||
return -1;
|
||||
if (fchown(fd, a->st.st_uid, a->st.st_gid) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void clone_attr(const char *source, const char *target) {
|
||||
struct file_attr a;
|
||||
getattr(source, &a);
|
||||
setattr(target, &a);
|
||||
}
|
||||
|
||||
void fclone_attr(const int sourcefd, const int targetfd) {
|
||||
struct file_attr a;
|
||||
fgetattr(sourcefd, &a);
|
||||
fsetattr(targetfd, &a);
|
||||
}
|
||||
|
||||
#ifdef SELINUX
|
||||
|
||||
#define UNLABEL_CON "u:object_r:unlabeled:s0"
|
||||
#define SYSTEM_CON "u:object_r:system_file:s0"
|
||||
|
||||
void restorecon(int dirfd, int force) {
|
||||
struct dirent *entry;
|
||||
DIR *dir;
|
||||
int fd;
|
||||
char path[PATH_MAX], *con;
|
||||
|
||||
fd_getpath(dirfd, path, sizeof(path));
|
||||
lgetfilecon(path, &con);
|
||||
if (force || strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0)
|
||||
lsetfilecon(path, SYSTEM_CON);
|
||||
freecon(con);
|
||||
|
||||
dir = xfdopendir(dirfd);
|
||||
while ((entry = xreaddir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
if (entry->d_type == DT_DIR) {
|
||||
fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
restorecon(fd, force);
|
||||
} else {
|
||||
fd = xopenat(dirfd, entry->d_name, O_PATH | O_NOFOLLOW | O_CLOEXEC);
|
||||
fd_getpath(fd, path, sizeof(path));
|
||||
lgetfilecon(path, &con);
|
||||
if (force || strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0)
|
||||
lsetfilecon(path, SYSTEM_CON);
|
||||
freecon(con);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SELINUX
|
||||
|
||||
static int _mmap(int rw, const char *filename, void **buf, size_t *size) {
|
||||
struct stat st;
|
||||
int fd = xopen(filename, rw ? O_RDWR : O_RDONLY);
|
||||
fstat(fd, &st);
|
||||
if (S_ISBLK(st.st_mode))
|
||||
ioctl(fd, BLKGETSIZE64, size);
|
||||
else
|
||||
*size = st.st_size;
|
||||
*buf = *size > 0 ? xmmap(NULL, *size, PROT_READ | (rw ? PROT_WRITE : 0), MAP_SHARED, fd, 0) : NULL;
|
||||
close(fd);
|
||||
return S_ISBLK(st.st_mode);
|
||||
}
|
||||
|
||||
int mmap_ro(const char *filename, void **buf, size_t *size) {
|
||||
return _mmap(0, filename, buf, size);
|
||||
}
|
||||
|
||||
int mmap_rw(const char *filename, void **buf, size_t *size) {
|
||||
return _mmap(1, filename, buf, size);
|
||||
}
|
||||
|
||||
void fd_full_read(int fd, void **buf, size_t *size) {
|
||||
*size = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
*buf = xmalloc(*size);
|
||||
xxread(fd, *buf, *size);
|
||||
}
|
||||
|
||||
void full_read(const char *filename, void **buf, size_t *size) {
|
||||
int fd = xopen(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
*buf = NULL;
|
||||
*size = 0;
|
||||
return;
|
||||
}
|
||||
fd_full_read(fd, buf, size);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void full_read_at(int dirfd, const char *filename, void **buf, size_t *size) {
|
||||
int fd = xopenat(dirfd, filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
*buf = NULL;
|
||||
*size = 0;
|
||||
return;
|
||||
}
|
||||
fd_full_read(fd, buf, size);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void stream_full_read(int fd, void **buf, size_t *size) {
|
||||
size_t cap = 1 << 20;
|
||||
uint8_t tmp[1 << 20];
|
||||
*buf = xmalloc(cap);
|
||||
ssize_t read;
|
||||
*size = 0;
|
||||
while (1) {
|
||||
read = xread(fd, tmp, sizeof(tmp));
|
||||
if (read <= 0)
|
||||
break;
|
||||
if (*size + read > cap) {
|
||||
cap *= 2;
|
||||
*buf = realloc(*buf, cap);
|
||||
}
|
||||
memcpy(*buf + *size, tmp, read);
|
||||
*size += read;
|
||||
}
|
||||
}
|
||||
|
||||
void write_zero(int fd, size_t size) {
|
||||
size_t pos = lseek(fd, 0, SEEK_CUR);
|
||||
ftruncate(fd, pos + size);
|
||||
lseek(fd, pos + size, SEEK_SET);
|
||||
}
|
||||
|
||||
void mem_align(size_t *pos, size_t align) {
|
||||
size_t mask = align - 1;
|
||||
if (*pos & mask) {
|
||||
*pos += align - (*pos & mask);
|
||||
}
|
||||
}
|
||||
|
||||
void file_align(int fd, size_t align, int out) {
|
||||
size_t pos = lseek(fd, 0, SEEK_CUR);
|
||||
size_t mask = align - 1;
|
||||
size_t off;
|
||||
if (pos & mask) {
|
||||
off = align - (pos & mask);
|
||||
if (out) {
|
||||
write_zero(fd, off);
|
||||
} else {
|
||||
lseek(fd, pos + off, SEEK_SET);
|
||||
}
|
||||
}
|
||||
}
|
233
native/jni/utils/img.c
Normal file
233
native/jni/utils/img.c
Normal file
@@ -0,0 +1,233 @@
|
||||
/* img.c - All image related functions
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mount.h>
|
||||
#include <linux/loop.h>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
|
||||
static int e2fsck(const char *img) {
|
||||
// Check and repair ext4 image
|
||||
char buffer[128];
|
||||
int pid, fd = -1;
|
||||
pid = exec_command(1, &fd, NULL, "e2fsck", "-yf", img, NULL);
|
||||
if (pid < 0)
|
||||
return 1;
|
||||
while (fdgets(buffer, sizeof(buffer), fd))
|
||||
LOGD("magisk_img: %s", buffer);
|
||||
waitpid(pid, NULL, 0);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *loopsetup(const char *img) {
|
||||
char device[20];
|
||||
struct loop_info64 info;
|
||||
int i, lfd, ffd;
|
||||
memset(&info, 0, sizeof(info));
|
||||
// First get an empty loop device
|
||||
for (i = 0; i <= 7; ++i) {
|
||||
sprintf(device, "/dev/block/loop%d", i);
|
||||
lfd = xopen(device, O_RDWR);
|
||||
if (ioctl(lfd, LOOP_GET_STATUS64, &info) == -1)
|
||||
break;
|
||||
close(lfd);
|
||||
}
|
||||
if (i == 8) return NULL;
|
||||
ffd = xopen(img, O_RDWR);
|
||||
if (ioctl(lfd, LOOP_SET_FD, ffd) == -1)
|
||||
return NULL;
|
||||
strcpy((char *) info.lo_file_name, img);
|
||||
ioctl(lfd, LOOP_SET_STATUS64, &info);
|
||||
close(lfd);
|
||||
close(ffd);
|
||||
return strdup(device);
|
||||
}
|
||||
|
||||
int create_img(const char *img, int size) {
|
||||
if (size == 128) /* WTF...? */
|
||||
size = 132;
|
||||
unlink(img);
|
||||
LOGI("Create %s with size %dM\n", img, size);
|
||||
int ret;
|
||||
|
||||
char buffer[16];
|
||||
snprintf(buffer, sizeof(buffer), "%dM", size);
|
||||
ret = exec_command_sync("make_ext4fs", "-l", buffer, img, NULL);
|
||||
if (ret < 0)
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_img_size(const char *img, int *used, int *total) {
|
||||
if (access(img, R_OK) == -1)
|
||||
return 1;
|
||||
char buffer[PATH_MAX];
|
||||
int pid, fd = -1, status = 1;
|
||||
pid = exec_command(1, &fd, NULL, "e2fsck", "-n", img, NULL);
|
||||
if (pid < 0)
|
||||
return 1;
|
||||
while (fdgets(buffer, sizeof(buffer), fd)) {
|
||||
if (strstr(buffer, img)) {
|
||||
char *tok = strtok(buffer, ",");
|
||||
while(tok != NULL) {
|
||||
if (strstr(tok, "blocks")) {
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
tok = strtok(NULL, ",");
|
||||
}
|
||||
if (status) continue;
|
||||
sscanf(tok, "%d/%d", used, total);
|
||||
*used = *used / 256 + 1;
|
||||
*total /= 256;
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
waitpid(pid, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int resize_img(const char *img, int size) {
|
||||
LOGI("Resize %s to %dM\n", img, size);
|
||||
if (e2fsck(img))
|
||||
return 1;
|
||||
char buffer[128];
|
||||
int pid, fd = -1, used, total;
|
||||
snprintf(buffer, sizeof(buffer), "%dM", size);
|
||||
pid = exec_command(1, &fd, NULL, "resize2fs", img, buffer, NULL);
|
||||
if (pid < 0)
|
||||
return 1;
|
||||
while (fdgets(buffer, sizeof(buffer), fd))
|
||||
LOGD("magisk_img: %s", buffer);
|
||||
close(fd);
|
||||
waitpid(pid, NULL, 0);
|
||||
|
||||
// Double check our image size
|
||||
get_img_size(img, &used, &total);
|
||||
if (total != size) {
|
||||
// Sammy crap occurs or resize2fs failed, lets create a new image!
|
||||
char *dir = dirname(img);
|
||||
snprintf(buffer, sizeof(buffer), "%s/tmp.img", dir);
|
||||
create_img(buffer, size);
|
||||
char *s_loop, *t_loop;
|
||||
s_loop = mount_image(img, SOURCE_TMP);
|
||||
if (s_loop == NULL) return 1;
|
||||
t_loop = mount_image(buffer, TARGET_TMP);
|
||||
if (t_loop == NULL) return 1;
|
||||
|
||||
cp_afc(SOURCE_TMP, TARGET_TMP);
|
||||
umount_image(SOURCE_TMP, s_loop);
|
||||
umount_image(TARGET_TMP, t_loop);
|
||||
rmdir(SOURCE_TMP);
|
||||
rmdir(TARGET_TMP);
|
||||
free(s_loop);
|
||||
free(t_loop);
|
||||
rename(buffer, img);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *mount_image(const char *img, const char *target) {
|
||||
if (access(img, F_OK) == -1)
|
||||
return NULL;
|
||||
if (access(target, F_OK) == -1) {
|
||||
if (xmkdirs(target, 0755) == -1) {
|
||||
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
|
||||
xmkdirs(target, 0755);
|
||||
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (e2fsck(img))
|
||||
return NULL;
|
||||
|
||||
char *device = loopsetup(img);
|
||||
if (device)
|
||||
xmount(device, target, "ext4", 0, NULL);
|
||||
return device;
|
||||
}
|
||||
|
||||
void umount_image(const char *target, const char *device) {
|
||||
xumount(target);
|
||||
int fd = xopen(device, O_RDWR);
|
||||
ioctl(fd, LOOP_CLR_FD);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int merge_img(const char *source, const char *target) {
|
||||
if (access(source, F_OK) == -1)
|
||||
return 0;
|
||||
LOGI("* Merging %s -> %s\n", source, target);
|
||||
if (access(target, F_OK) == -1) {
|
||||
xrename(source, target);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char buffer[PATH_MAX];
|
||||
|
||||
// resize target to worst case
|
||||
int s_used, s_total, t_used, t_total, n_total;
|
||||
get_img_size(source, &s_used, &s_total);
|
||||
get_img_size(target, &t_used, &t_total);
|
||||
n_total = round_size(s_used + t_used);
|
||||
if (n_total > t_total)
|
||||
resize_img(target, n_total);
|
||||
|
||||
xmkdir(SOURCE_TMP, 0755);
|
||||
xmkdir(TARGET_TMP, 0755);
|
||||
char *s_loop, *t_loop;
|
||||
s_loop = mount_image(source, SOURCE_TMP);
|
||||
if (s_loop == NULL) return 1;
|
||||
t_loop = mount_image(target, TARGET_TMP);
|
||||
if (t_loop == NULL) return 1;
|
||||
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
if (!(dir = xopendir(SOURCE_TMP)))
|
||||
return 1;
|
||||
while ((entry = xreaddir(dir))) {
|
||||
if (entry->d_type == DT_DIR) {
|
||||
if (strcmp(entry->d_name, ".") == 0 ||
|
||||
strcmp(entry->d_name, "..") == 0 ||
|
||||
strcmp(entry->d_name, ".core") == 0 ||
|
||||
strcmp(entry->d_name, "lost+found") == 0)
|
||||
continue;
|
||||
// Cleanup old module if exists
|
||||
snprintf(buffer, sizeof(buffer), "%s/%s", TARGET_TMP, entry->d_name);
|
||||
if (access(buffer, F_OK) == 0) {
|
||||
LOGI("Upgrade module: %s\n", entry->d_name);
|
||||
rm_rf(buffer);
|
||||
} else {
|
||||
LOGI("New module: %s\n", entry->d_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
cp_afc(SOURCE_TMP, TARGET_TMP);
|
||||
|
||||
// Unmount all loop devices
|
||||
umount_image(SOURCE_TMP, s_loop);
|
||||
umount_image(TARGET_TMP, t_loop);
|
||||
rmdir(SOURCE_TMP);
|
||||
rmdir(TARGET_TMP);
|
||||
free(s_loop);
|
||||
free(t_loop);
|
||||
unlink(source);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void trim_img(const char *img) {
|
||||
int used, total, new_size;
|
||||
get_img_size(img, &used, &total);
|
||||
new_size = round_size(used);
|
||||
if (new_size != total)
|
||||
resize_img(img, new_size);
|
||||
}
|
39
native/jni/utils/list.c
Normal file
39
native/jni/utils/list.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* list.h - Double link list implementation
|
||||
*/
|
||||
|
||||
#include "list.h"
|
||||
|
||||
void init_list_head(struct list_head *head) {
|
||||
head->next = head;
|
||||
head->prev = head;
|
||||
}
|
||||
|
||||
void list_insert(struct list_head *pos, struct list_head *node) {
|
||||
// First construct our new node
|
||||
node->next = pos->next;
|
||||
node->prev = pos;
|
||||
// Maintain the list
|
||||
pos->next->prev = node;
|
||||
pos->next = node;
|
||||
}
|
||||
|
||||
void list_insert_end(struct list_head *head, struct list_head *node) {
|
||||
list_insert(head->prev, node);
|
||||
}
|
||||
|
||||
struct list_head *list_pop(struct list_head *pos) {
|
||||
struct list_head *ret;
|
||||
ret = pos->prev;
|
||||
// Maintain the list
|
||||
pos->prev->next = pos->next;
|
||||
pos->next->prev = pos->prev;
|
||||
// Remove references
|
||||
pos->next = pos;
|
||||
pos->prev = pos;
|
||||
// Return the previous node in the list
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct list_head *list_pop_end(struct list_head *head) {
|
||||
return list_pop(head->prev);
|
||||
}
|
343
native/jni/utils/misc.c
Normal file
343
native/jni/utils/misc.c
Normal file
@@ -0,0 +1,343 @@
|
||||
/* misc.c - Store all functions that are unable to be catagorized clearly
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/inotify.h>
|
||||
|
||||
#include "logging.h"
|
||||
#include "utils.h"
|
||||
#include "resetprop.h"
|
||||
|
||||
unsigned get_shell_uid() {
|
||||
struct passwd* ppwd = getpwnam("shell");
|
||||
if (NULL == ppwd)
|
||||
return 2000;
|
||||
|
||||
return ppwd->pw_uid;
|
||||
}
|
||||
|
||||
unsigned get_system_uid() {
|
||||
struct passwd* ppwd = getpwnam("system");
|
||||
if (NULL == ppwd)
|
||||
return 1000;
|
||||
|
||||
return ppwd->pw_uid;
|
||||
}
|
||||
|
||||
unsigned get_radio_uid() {
|
||||
struct passwd* ppwd = getpwnam("radio");
|
||||
if (NULL == ppwd)
|
||||
return 1001;
|
||||
|
||||
return ppwd->pw_uid;
|
||||
}
|
||||
|
||||
int check_data() {
|
||||
struct vector v;
|
||||
vec_init(&v);
|
||||
file_to_vector("/proc/mounts", &v);
|
||||
char *line, *crypto;
|
||||
int mnt = 0;
|
||||
vec_for_each(&v, line) {
|
||||
if (strstr(line, " /data ")) {
|
||||
if (strstr(line, "tmpfs") == NULL)
|
||||
mnt = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
vec_deep_destroy(&v);
|
||||
// /data is mounted and not tmpfs and data is unencrypted or vold is started
|
||||
return mnt && (((crypto = getprop("ro.crypto.state")) && strcmp(crypto, "unencrypted") == 0)
|
||||
|| getprop("init.svc.vold"));
|
||||
}
|
||||
|
||||
/* All the string should be freed manually!! */
|
||||
int file_to_vector(const char* filename, struct vector *v) {
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t read;
|
||||
|
||||
FILE *fp = xfopen(filename, "r");
|
||||
if (fp == NULL)
|
||||
return 1;
|
||||
|
||||
while ((read = getline(&line, &len, fp)) != -1) {
|
||||
// Remove end newline
|
||||
if (line[read - 1] == '\n')
|
||||
line[read - 1] = '\0';
|
||||
vec_push_back(v, line);
|
||||
line = NULL;
|
||||
}
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vector_to_file(const char *filename, struct vector *v) {
|
||||
FILE *fp = xfopen(filename, "w");
|
||||
if (fp == NULL)
|
||||
return 1;
|
||||
char *line;
|
||||
vec_for_each(v, line) {
|
||||
fprintf(fp, "%s\n", line);
|
||||
}
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if the string only contains digits */
|
||||
static int is_num(const char *s) {
|
||||
int len = strlen(s);
|
||||
for (int i = 0; i < len; ++i)
|
||||
if (s[i] < '0' || s[i] > '9')
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read a whole line from file descriptor */
|
||||
ssize_t fdgets(char *buf, const size_t size, int fd) {
|
||||
ssize_t len = 0;
|
||||
buf[0] = '\0';
|
||||
while (len < size - 1) {
|
||||
int ret = read(fd, buf + len, 1);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
if (ret == 0)
|
||||
break;
|
||||
if (buf[len] == '\0' || buf[len++] == '\n') {
|
||||
buf[len] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf[size - 1] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Call func for each process */
|
||||
void ps(void (*func)(int)) {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
if (!(dir = xopendir("/proc")))
|
||||
return;
|
||||
|
||||
while ((entry = xreaddir(dir))) {
|
||||
if (entry->d_type == DT_DIR) {
|
||||
if (is_num(entry->d_name))
|
||||
func(atoi(entry->d_name));
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
// Internal usage
|
||||
static void (*ps_filter_cb)(int);
|
||||
static const char *ps_filter_pattern;
|
||||
static void proc_name_filter(int pid) {
|
||||
char buf[64];
|
||||
int fd;
|
||||
snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
|
||||
if (access(buf, R_OK) == -1 || (fd = xopen(buf, O_RDONLY)) == -1)
|
||||
return;
|
||||
if (fdgets(buf, sizeof(buf), fd) == 0) {
|
||||
snprintf(buf, sizeof(buf), "/proc/%d/comm", pid);
|
||||
close(fd);
|
||||
if (access(buf, R_OK) == -1 || (fd = xopen(buf, O_RDONLY)) == -1)
|
||||
return;
|
||||
fdgets(buf, sizeof(buf), fd);
|
||||
}
|
||||
if (strcmp(buf, ps_filter_pattern) == 0) {
|
||||
ps_filter_cb(pid);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* Call func with process name filtered with pattern */
|
||||
void ps_filter_proc_name(const char *pattern, void (*func)(int)) {
|
||||
ps_filter_cb = func;
|
||||
ps_filter_pattern = ((pattern == NULL) ? "" : pattern);
|
||||
ps(proc_name_filter);
|
||||
}
|
||||
|
||||
void unlock_blocks() {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
int fd, dev, OFF = 0;
|
||||
|
||||
if ((dev = xopen("/dev/block", O_RDONLY | O_CLOEXEC)) < 0)
|
||||
return;
|
||||
dir = xfdopendir(dev);
|
||||
|
||||
while((entry = readdir(dir))) {
|
||||
if (entry->d_type == DT_BLK) {
|
||||
if ((fd = openat(dev, entry->d_name, O_RDONLY)) < 0)
|
||||
continue;
|
||||
if (ioctl(fd, BLKROSET, &OFF) == -1)
|
||||
PLOGE("unlock %s", entry->d_name);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
close(dev);
|
||||
}
|
||||
|
||||
void setup_sighandlers(void (*handler)(int)) {
|
||||
struct sigaction act;
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_handler = handler;
|
||||
for (int i = 0; quit_signals[i]; ++i) {
|
||||
sigaction(quit_signals[i], &act, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fd == NULL -> Ignore output
|
||||
*fd < 0 -> Open pipe and set *fd to the read end
|
||||
*fd >= 0 -> STDOUT (or STDERR) will be redirected to *fd
|
||||
*cb -> A callback function which runs after fork
|
||||
*/
|
||||
static int v_exec_command(int err, int *fd, void (*setupenv)(struct vector*), const char *argv0, va_list argv) {
|
||||
int pipefd[2], writeEnd = -1;
|
||||
|
||||
if (fd) {
|
||||
if (*fd < 0) {
|
||||
if (xpipe2(pipefd, O_CLOEXEC) == -1)
|
||||
return -1;
|
||||
writeEnd = pipefd[1];
|
||||
} else {
|
||||
writeEnd = *fd;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect va_list into vector
|
||||
struct vector args;
|
||||
vec_init(&args);
|
||||
vec_push_back(&args, strdup(argv0));
|
||||
for (void *arg = va_arg(argv, void*); arg; arg = va_arg(argv, void*))
|
||||
vec_push_back(&args, strdup(arg));
|
||||
vec_push_back(&args, NULL);
|
||||
|
||||
// Setup environment
|
||||
char *const *envp;
|
||||
struct vector env;
|
||||
vec_init(&env);
|
||||
if (setupenv) {
|
||||
setupenv(&env);
|
||||
envp = (char **) vec_entry(&env);
|
||||
} else {
|
||||
extern char **environ;
|
||||
envp = environ;
|
||||
}
|
||||
|
||||
int pid = xfork();
|
||||
if (pid != 0) {
|
||||
if (fd && *fd < 0) {
|
||||
// Give the read end and close write end
|
||||
*fd = pipefd[0];
|
||||
close(pipefd[1]);
|
||||
}
|
||||
vec_deep_destroy(&args);
|
||||
vec_deep_destroy(&env);
|
||||
return pid;
|
||||
}
|
||||
|
||||
if (fd) {
|
||||
xdup2(writeEnd, STDOUT_FILENO);
|
||||
if (err) xdup2(writeEnd, STDERR_FILENO);
|
||||
}
|
||||
|
||||
execvpe(argv0, (char **) vec_entry(&args), envp);
|
||||
PLOGE("execvpe");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int exec_command_sync(char *const argv0, ...) {
|
||||
va_list argv;
|
||||
va_start(argv, argv0);
|
||||
int pid, status;
|
||||
pid = v_exec_command(0, NULL, NULL, argv0, argv);
|
||||
va_end(argv);
|
||||
if (pid < 0)
|
||||
return pid;
|
||||
waitpid(pid, &status, 0);
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
int exec_command(int err, int *fd, void (*setupenv)(struct vector*), const char *argv0, ...) {
|
||||
va_list argv;
|
||||
va_start(argv, argv0);
|
||||
int pid = v_exec_command(err, fd, setupenv, argv0, argv);
|
||||
va_end(argv);
|
||||
return pid;
|
||||
}
|
||||
|
||||
int bind_mount(const char *from, const char *to) {
|
||||
int ret = xmount(from, to, NULL, MS_BIND, NULL);
|
||||
#ifdef MAGISK_DEBUG
|
||||
LOGI("bind_mount: %s <- %s\n", to, from);
|
||||
#else
|
||||
LOGI("bind_mount: %s\n", to);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void get_client_cred(int fd, struct ucred *cred) {
|
||||
socklen_t ucred_length = sizeof(*cred);
|
||||
if(getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &ucred_length))
|
||||
PLOGE("getsockopt");
|
||||
}
|
||||
|
||||
int switch_mnt_ns(int pid) {
|
||||
char mnt[32];
|
||||
snprintf(mnt, sizeof(mnt), "/proc/%d/ns/mnt", pid);
|
||||
if(access(mnt, R_OK) == -1) return 1; // Maybe process died..
|
||||
|
||||
int fd, ret;
|
||||
fd = xopen(mnt, O_RDONLY);
|
||||
if (fd < 0) return 1;
|
||||
// Switch to its namespace
|
||||
ret = xsetns(fd, 0);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fork_dont_care() {
|
||||
int pid = xfork();
|
||||
if (pid) {
|
||||
waitpid(pid, NULL, 0);
|
||||
return pid;
|
||||
} else if ((pid = xfork())) {
|
||||
exit(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wait_till_exists(const char *target) {
|
||||
if (access(target, F_OK) == 0)
|
||||
return;
|
||||
int fd = inotify_init();
|
||||
char *dir = dirname(target);
|
||||
char crap[PATH_MAX];
|
||||
inotify_add_watch(fd, dir, IN_CREATE);
|
||||
while (1) {
|
||||
struct inotify_event event;
|
||||
read(fd, &event, sizeof(event));
|
||||
read(fd, crap, event.len);
|
||||
if (access(target, F_OK) == 0)
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
}
|
99
native/jni/utils/pattern.c
Normal file
99
native/jni/utils/pattern.c
Normal file
@@ -0,0 +1,99 @@
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
static int check_verity_pattern(const char *s) {
|
||||
int skip = 0;
|
||||
if (s[0] == ',') ++skip;
|
||||
if (strncmp(s + skip, "verify", 6) == 0)
|
||||
skip += 6;
|
||||
else if (strncmp(s + skip, "avb", 3) == 0)
|
||||
skip += 3;
|
||||
else
|
||||
return -1;
|
||||
|
||||
if (s[skip] == '=') {
|
||||
while (s[skip] != '\0' && s[skip] != ' ' && s[skip] != '\n' && s[skip] != ',') ++skip;
|
||||
}
|
||||
return skip;
|
||||
}
|
||||
|
||||
static int check_encryption_pattern(const char *s) {
|
||||
const char *encrypt_list[] = { "forceencrypt", "forcefdeorfbe", NULL };
|
||||
for (int i = 0 ; encrypt_list[i]; ++i) {
|
||||
int len = strlen(encrypt_list[i]);
|
||||
if (strncmp(s, encrypt_list[i], len) == 0)
|
||||
return len;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void patch_init_rc(void **buf, size_t *size) {
|
||||
int injected = 0;
|
||||
char *new_data = malloc(*size + 23);
|
||||
char *old_data = *buf;
|
||||
size_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';
|
||||
}
|
||||
|
||||
free(*buf);
|
||||
*size = pos;
|
||||
*buf = new_data;
|
||||
}
|
||||
|
||||
int patch_verity(void **buf, uint32_t *size, int patch) {
|
||||
int skip, src_size = *size;
|
||||
char *src = *buf, *patched = patch ? xcalloc(src_size, 1) : NULL;
|
||||
for (int read = 0, write = 0; read < src_size; ++read, ++write) {
|
||||
if ((skip = check_verity_pattern(src + read)) > 0) {
|
||||
if (!patch)
|
||||
return 1;
|
||||
fprintf(stderr, "Remove pattern [%.*s]\n", skip, src + read);
|
||||
read += skip;
|
||||
*size -= skip;
|
||||
}
|
||||
if (patch)
|
||||
patched[write] = src[read];
|
||||
}
|
||||
if (patch) {
|
||||
free(*buf);
|
||||
*buf = patched;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void patch_encryption(void **buf, uint32_t *size) {
|
||||
int skip, src_size = *size;
|
||||
char *src = *buf, *patched = xcalloc(src_size, 1);
|
||||
for (int read = 0, write = 0; read < src_size; ++read, ++write) {
|
||||
if ((skip = check_encryption_pattern(src + read)) > 0) {
|
||||
fprintf(stderr, "Replace pattern [%.*s] with [encryptable]\n", skip, src + read);
|
||||
memcpy(patched + read, "encryptable", 11);
|
||||
read += skip;
|
||||
write += 11;
|
||||
*size -= (skip - 11);
|
||||
}
|
||||
patched[write] = src[read];
|
||||
}
|
||||
free(*buf);
|
||||
*buf = patched;
|
||||
}
|
||||
|
||||
|
83
native/jni/utils/vector.c
Normal file
83
native/jni/utils/vector.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/* vector.c - A simple vector implementation in c
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
void vec_init(struct vector *v) {
|
||||
if (v == NULL) return;
|
||||
vec_size(v) = 0;
|
||||
vec_cap(v) = 1;
|
||||
vec_entry(v) = malloc(sizeof(void*));
|
||||
}
|
||||
|
||||
void vec_push_back(struct vector *v, void *p) {
|
||||
if (v == NULL) return;
|
||||
if (vec_size(v) == vec_cap(v)) {
|
||||
vec_cap(v) *= 2;
|
||||
vec_entry(v) = realloc(vec_entry(v), sizeof(void*) * vec_cap(v));
|
||||
}
|
||||
vec_entry(v)[vec_size(v)] = p;
|
||||
++vec_size(v);
|
||||
}
|
||||
|
||||
void *vec_pop_back(struct vector *v) {
|
||||
void *ret = vec_entry(v)[vec_size(v) - 1];
|
||||
--vec_size(v);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int (*cmp)(const void *, const void *);
|
||||
|
||||
static int vec_comp(const void *a, const void *b) {
|
||||
void *aa = *((void **)a), *bb = *((void **)b);
|
||||
if (aa == NULL && bb == NULL) return 0;
|
||||
else if (aa == NULL) return 1;
|
||||
else if (bb == NULL) return -1;
|
||||
else return cmp ? cmp(aa, bb) : 0;
|
||||
}
|
||||
|
||||
void vec_sort(struct vector *v, int (*compar)(const void *, const void *)) {
|
||||
if (v == NULL) return;
|
||||
cmp = compar;
|
||||
qsort(vec_entry(v), vec_size(v), sizeof(void*), vec_comp);
|
||||
void *e;
|
||||
vec_for_each_r(v, e) {
|
||||
if (e) break;
|
||||
--vec_size(v);
|
||||
}
|
||||
}
|
||||
|
||||
/* Will cleanup only the vector itself
|
||||
* use in cases when each element requires special cleanup
|
||||
*/
|
||||
void vec_destroy(struct vector *v) {
|
||||
if (v == NULL) return;
|
||||
vec_size(v) = 0;
|
||||
vec_cap(v) = 0;
|
||||
free(vec_entry(v));
|
||||
vec_entry(v) = NULL; // Prevent double destroy segfault
|
||||
}
|
||||
|
||||
/* Will cleanup each element AND the vector itself
|
||||
* Shall be the general case
|
||||
*/
|
||||
void vec_deep_destroy(struct vector *v) {
|
||||
if (v == NULL) return;
|
||||
void *e;
|
||||
vec_for_each(v, e) {
|
||||
free(e);
|
||||
}
|
||||
vec_destroy(v);
|
||||
}
|
||||
|
||||
struct vector *vec_dup(struct vector *v) {
|
||||
struct vector *ret = malloc(sizeof(*ret));
|
||||
vec_size(ret) = vec_size(v);
|
||||
vec_cap(ret) = vec_cap(v);
|
||||
vec_entry(v) = malloc(sizeof(void*) * vec_cap(ret));
|
||||
memcpy(vec_entry(ret), vec_entry(v), sizeof(void*) * vec_cap(ret));
|
||||
return ret;
|
||||
}
|
357
native/jni/utils/xwrap.c
Normal file
357
native/jni/utils/xwrap.c
Normal file
@@ -0,0 +1,357 @@
|
||||
/* xwrap.c - wrappers around existing library functions.
|
||||
*
|
||||
* Functions with the x prefix are wrappers that either succeed or log the
|
||||
* error message. They usually have the same arguments and return value
|
||||
* as the function they wrap.
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/sendfile.h>
|
||||
|
||||
#include "logging.h"
|
||||
#include "utils.h"
|
||||
|
||||
FILE *xfopen(const char *pathname, const char *mode) {
|
||||
FILE *fp = fopen(pathname, mode);
|
||||
if (fp == NULL) {
|
||||
PLOGE("fopen: %s", pathname);
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
FILE *xfdopen(int fd, const char *mode) {
|
||||
FILE *fp = fdopen(fd, mode);
|
||||
if (fp == NULL) {
|
||||
PLOGE("fopen");
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
int xopen2(const char *pathname, int flags) {
|
||||
int fd = open(pathname, flags);
|
||||
if (fd < 0) {
|
||||
PLOGE("open: %s", pathname);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int xopen3(const char *pathname, int flags, mode_t mode) {
|
||||
int fd = open(pathname, flags, mode);
|
||||
if (fd < 0) {
|
||||
PLOGE("open: %s", pathname);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int xopenat(int dirfd, const char *pathname, int flags) {
|
||||
int fd = openat(dirfd, pathname, flags);
|
||||
if (fd < 0) {
|
||||
PLOGE("openat: %s", pathname);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
ssize_t xwrite(int fd, const void *buf, size_t count) {
|
||||
int ret = write(fd, buf, count);
|
||||
if (count != ret) {
|
||||
PLOGE("write");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Read error other than EOF
|
||||
ssize_t xread(int fd, void *buf, size_t count) {
|
||||
int ret = read(fd, buf, count);
|
||||
if (ret < 0) {
|
||||
PLOGE("read");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Read exact same size as count
|
||||
ssize_t xxread(int fd, void *buf, size_t count) {
|
||||
int ret = read(fd, buf, count);
|
||||
if (count != ret) {
|
||||
PLOGE("read");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xpipe2(int pipefd[2], int flags) {
|
||||
int ret = pipe2(pipefd, flags);
|
||||
if (ret == -1) {
|
||||
PLOGE("pipe2");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xsetns(int fd, int nstype) {
|
||||
int ret = setns(fd, nstype);
|
||||
if (ret == -1) {
|
||||
PLOGE("setns");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
DIR *xopendir(const char *name) {
|
||||
DIR *d = opendir(name);
|
||||
if (d == NULL) {
|
||||
PLOGE("opendir: %s", name);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
DIR *xfdopendir(int fd) {
|
||||
DIR *d = fdopendir(fd);
|
||||
if (d == NULL) {
|
||||
PLOGE("fdopendir");
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
struct dirent *xreaddir(DIR *dirp) {
|
||||
errno = 0;
|
||||
struct dirent *e = readdir(dirp);
|
||||
if (errno && e == NULL) {
|
||||
PLOGE("readdir");
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
pid_t xsetsid() {
|
||||
pid_t pid = setsid();
|
||||
if (pid == -1) {
|
||||
PLOGE("setsid");
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
int xsocket(int domain, int type, int protocol) {
|
||||
int fd = socket(domain, type, protocol);
|
||||
if (fd == -1) {
|
||||
PLOGE("socket");
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int xbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
int ret = bind(sockfd, addr, addrlen);
|
||||
if (ret == -1) {
|
||||
PLOGE("bind");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xlisten(int sockfd, int backlog) {
|
||||
int ret = listen(sockfd, backlog);
|
||||
if (ret == -1) {
|
||||
PLOGE("listen");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xaccept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) {
|
||||
int fd = accept4(sockfd, addr, addrlen, flags);
|
||||
if (fd == -1) {
|
||||
PLOGE("accept");
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void *xmalloc(size_t size) {
|
||||
void *p = malloc(size);
|
||||
if (p == NULL) {
|
||||
PLOGE("malloc");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *xcalloc(size_t nmemb, size_t size) {
|
||||
void *p = calloc(nmemb, size);
|
||||
if (p == NULL) {
|
||||
PLOGE("calloc");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *xrealloc(void *ptr, size_t size) {
|
||||
void *p = realloc(ptr, size);
|
||||
if (p == NULL) {
|
||||
PLOGE("realloc");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags) {
|
||||
int sent = sendmsg(sockfd, msg, flags);
|
||||
if (sent == -1) {
|
||||
PLOGE("sendmsg");
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) {
|
||||
int rec = recvmsg(sockfd, msg, flags);
|
||||
if (rec == -1) {
|
||||
PLOGE("recvmsg");
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
||||
int xpthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||
void *(*start_routine) (void *), void *arg) {
|
||||
errno = pthread_create(thread, attr, start_routine, arg);
|
||||
if (errno) {
|
||||
PLOGE("pthread_create");
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
|
||||
int xstat(const char *pathname, struct stat *buf) {
|
||||
int ret = stat(pathname, buf);
|
||||
if (ret == -1) {
|
||||
PLOGE("stat %s", pathname);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xlstat(const char *pathname, struct stat *buf) {
|
||||
int ret = lstat(pathname, buf);
|
||||
if (ret == -1) {
|
||||
PLOGE("lstat %s", pathname);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xdup2(int oldfd, int newfd) {
|
||||
int ret = dup2(oldfd, newfd);
|
||||
if (ret == -1) {
|
||||
PLOGE("dup2");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t xreadlink(const char *pathname, char *buf, size_t bufsiz) {
|
||||
ssize_t ret = readlink(pathname, buf, bufsiz);
|
||||
if (ret == -1) {
|
||||
PLOGE("readlink %s", pathname);
|
||||
} else {
|
||||
buf[ret] = '\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t xreadlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) {
|
||||
ssize_t ret = readlinkat(dirfd, pathname, buf, bufsiz);
|
||||
if (ret == -1) {
|
||||
PLOGE("readlinkat %s", pathname);
|
||||
} else {
|
||||
buf[ret] = '\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xsymlink(const char *target, const char *linkpath) {
|
||||
int ret = symlink(target, linkpath);
|
||||
if (ret == -1) {
|
||||
PLOGE("symlink %s->%s", target, linkpath);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmount(const char *source, const char *target,
|
||||
const char *filesystemtype, unsigned long mountflags,
|
||||
const void *data) {
|
||||
int ret = mount(source, target, filesystemtype, MS_SILENT | mountflags, data);
|
||||
if (ret == -1) {
|
||||
PLOGE("mount %s->%s", source, target);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xumount(const char *target) {
|
||||
int ret = umount(target);
|
||||
if (ret == -1) {
|
||||
PLOGE("umount %s", target);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xumount2(const char *target, int flags) {
|
||||
int ret = umount2(target, flags);
|
||||
if (ret == -1) {
|
||||
PLOGE("umount2 %s", target);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xrename(const char *oldpath, const char *newpath) {
|
||||
int ret = rename(oldpath, newpath);
|
||||
if (ret == -1) {
|
||||
PLOGE("rename %s->%s", oldpath, newpath);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmkdir(const char *pathname, mode_t mode) {
|
||||
int ret = mkdir(pathname, mode);
|
||||
if (ret == -1 && errno != EEXIST) {
|
||||
PLOGE("mkdir %s %u", pathname, mode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmkdirs(const char *pathname, mode_t mode) {
|
||||
int ret = mkdirs(pathname, mode);
|
||||
if (ret == -1) {
|
||||
PLOGE("mkdirs %s", pathname);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmkdirat(int dirfd, const char *pathname, mode_t mode) {
|
||||
int ret = mkdirat(dirfd, pathname, mode);
|
||||
if (ret == -1 && errno != EEXIST) {
|
||||
PLOGE("mkdirat %s %u", pathname, mode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *xmmap(void *addr, size_t length, int prot, int flags,
|
||||
int fd, off_t offset) {
|
||||
void *ret = mmap(addr, length, prot, flags, fd, offset);
|
||||
if (ret == MAP_FAILED) {
|
||||
PLOGE("mmap");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t xsendfile(int out_fd, int in_fd, off_t *offset, size_t count) {
|
||||
ssize_t ret = sendfile(out_fd, in_fd, offset, count);
|
||||
if (count != ret) {
|
||||
PLOGE("sendfile");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
pid_t xfork() {
|
||||
int ret = fork();
|
||||
if (ret == -1) {
|
||||
PLOGE("fork");
|
||||
}
|
||||
return ret;
|
||||
}
|
1
native/src/main/AndroidManifest.xml
Normal file
1
native/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest package="com.topjohnwu.core.magisk" />
|
Reference in New Issue
Block a user