Compare commits

..

43 Commits
v15.4 ... v16.4

Author SHA1 Message Date
topjohnwu
3a9a3ed184 Bump Magisk Manager version 2018-04-29 15:20:41 +08:00
topjohnwu
88fae36b8a Hide sub-services of apps for hiding
Close #383
2018-04-29 15:10:35 +08:00
topjohnwu
fc9d4034a9 Fix installation in custom recoveries 2018-04-29 14:04:18 +08:00
topjohnwu
cecc0b932d Remove some traits 2018-04-29 12:34:36 +08:00
topjohnwu
0faed7159c Add invincible mode back 2018-04-29 12:17:28 +08:00
topjohnwu
fb491cfdcf Add Protobuf support to resetprop 2018-04-29 01:20:48 +08:00
topjohnwu
fc706dcb40 Bump busybox to 1.28.3 2018-04-22 14:28:16 +08:00
topjohnwu
a2c1b024f3 Use 32-bit binaries only 2018-04-22 14:13:27 +08:00
Frieder Bluemle
3d865394d7 Update Gradle wrapper to 4.6 2018-04-22 03:09:02 +08:00
topjohnwu
76ef1d0d86 Cleanup sepolicy rules 2018-04-22 03:06:40 +08:00
topjohnwu
9484ec0c17 Massive refactoring
Remove post-fs mode
2018-04-22 02:16:56 +08:00
topjohnwu
614c552e55 Improve daemon startup 2018-04-21 20:16:59 +08:00
topjohnwu
7db3d84ba2 Forgot to update the default file secontext 2018-04-21 13:20:42 +08:00
topjohnwu
87f6018468 Massive sepolicy refactor 2018-04-15 03:18:18 +08:00
topjohnwu
9194c50590 Update build.gradle 2018-04-15 03:17:28 +08:00
topjohnwu
7ff45974c6 Upstream selinux 2018-04-14 17:18:29 +08:00
topjohnwu
2533a4fc4a Fix APK installation on Android P 2018-04-08 03:22:22 +08:00
topjohnwu
42284c5efb Test logcat instead of checking logd 2018-04-08 02:12:40 +08:00
topjohnwu
7d7686da33 Update Magisk Manager 2018-03-28 15:23:55 +08:00
topjohnwu
65e455ef0b Update Android gradle plugin 2018-03-28 02:43:03 +08:00
topjohnwu
ac05e2f2e2 Fix tail size calculation
Close #381
2018-03-27 00:45:18 +08:00
topjohnwu
787f7b3035 Remove backwards compatibility symlinks
These links cause magiskhide unable to work ideally and add complications. I think I gave enough time for migration
2018-03-27 00:35:59 +08:00
topjohnwu
31bd642b80 Update to busybox 1.28.2 2018-03-26 22:12:04 +08:00
topjohnwu
f0bac6b154 Resetprop small refactor 2018-03-26 21:21:48 +08:00
topjohnwu
cc7e74ca11 Cleanup build.gradle 2018-03-26 03:53:06 +08:00
topjohnwu
e8a44646b8 Update Magisk Manager 2018-03-18 12:34:07 +08:00
topjohnwu
ae97d011ae Change MagiskHide state if logd is disabled 2018-03-18 12:17:10 +08:00
imswebra
1b7657a374 tips.md Grammar Fix 2018-03-18 12:16:57 +08:00
topjohnwu
5665e04014 Force using system binaries 2018-03-17 21:42:42 +08:00
topjohnwu
bb70385a42 Update Magisk Manager 2018-03-11 08:37:13 +08:00
topjohnwu
9855877b03 Update rules for Android P 2018-03-11 08:36:20 +08:00
topjohnwu
76c9188fae Android P renamed nonplat_properties 2018-03-11 02:53:57 +08:00
topjohnwu
e4e5269836 Android P have no make_ext4fs, use mke2fs as fallback 2018-03-11 02:52:24 +08:00
topjohnwu
9e737df534 Update high compression mode detection logic 2018-03-10 15:55:55 +08:00
Shaka Huang
0b3192c4d5 Check dtb even if kernel is not available
By the flow of unpacking boot image of Chrome OS there will be no kernel file but an dtb image. In that case the dtb image won’t be added when repacking boot image.

Signed-off-by: Shaka Huang <shakalaca@gmail.com>
2018-03-03 20:57:55 +08:00
Shaka Huang
968e6237bd Fix error parsing MTK boot.img
Should be copy & paste error:

1. boot->r_fmt should be re-checked instead of boot->k_fmt once MTK header was found in ramdisk.

2. ramdisk_size should be restored instead of kernel_size when uncompressed ramdisk was found.

3. Correct header of ramdisk

Signed-off-by: Shaka Huang <shakalaca@gmail.com>
2018-03-03 20:57:37 +08:00
worstperson
d780b5a0e4 Add support for the Nook Tablet, Acclaim
Also changed occurences of NOOK with NOOKHD
2018-03-03 20:55:44 +08:00
worstperson
3e48427eaf Add support for the new NOOK_MAGIC
The new cmdline value that's been in use since Marshmallow
2018-03-03 20:55:44 +08:00
worstperson
31360c34ed Set NOOK_PRE_HEADER_SZ from 0xFFFFF to 0x100000
All applicable Nook HD/HD+ roms are using this offset
2018-03-03 20:55:44 +08:00
topjohnwu
e9624e2304 Update submodules 2018-02-22 02:49:54 +08:00
topjohnwu
9c6e64f47d Workaround compiler optimization bug 2018-02-21 14:44:24 +08:00
topjohnwu
0afa601551 Fix F2FS manager crashing 2018-02-20 05:15:06 +08:00
topjohnwu
a94fa81195 Support non skip_initramfs device with slot suffix 2018-02-14 00:57:52 +08:00
51 changed files with 1002 additions and 845 deletions

3
.gitmodules vendored
View File

@@ -25,3 +25,6 @@
[submodule "xz"]
path = native/jni/external/xz
url = https://github.com/xz-mirror/xz.git
[submodule "nanopb"]
path = native/jni/external/nanopb
url = https://github.com/nanopb/nanopb.git

2
app

Submodule app updated: c840a30c30...15ed3e52f2

View File

@@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.android.tools.build:gradle:3.1.2'
// NOTE: Do not place your application dependencies here; they belong
@@ -19,9 +19,16 @@ allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
ext {
compileSdkVersion = 27
buildToolsVersion = "28.0.0-rc1"
supportLibVersion = "27.1.1"
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@@ -93,7 +93,7 @@ def build_binary(args):
error('Build Magisk binary failed!')
print('')
for arch in ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']:
for arch in ['armeabi-v7a', 'x86']:
mkdir_p(os.path.join('out', arch))
with open(os.path.join('out', arch, 'dump.h'), 'w') as dump:
dump.write('#include "stdlib.h"\n')
@@ -110,7 +110,7 @@ def build_binary(args):
error('Build Magisk binary failed!')
print('')
for arch in ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']:
for arch in ['armeabi-v7a', 'x86']:
for binary in ['magiskinit', 'magiskboot', 'b64xz', 'busybox']:
try:
mv(os.path.join('native', 'libs', arch, binary), os.path.join('out', arch, binary))
@@ -120,6 +120,7 @@ def build_binary(args):
def build_apk(args):
header('* Building Magisk Manager')
mkdir(os.path.join('app', 'src', 'main', 'assets'))
for script in ['magisk_uninstaller.sh', 'util_functions.sh']:
source = os.path.join('scripts', script)
target = os.path.join('app', 'src', 'main', 'assets', script)
@@ -233,7 +234,7 @@ def zip_main(args):
zip_with_msg(zipf, source, target)
# Binaries
for lib_dir, zip_dir in [('arm64-v8a', 'arm64'), ('armeabi-v7a', 'arm'), ('x86', 'x86'), ('x86_64', 'x64')]:
for lib_dir, zip_dir in [('armeabi-v7a', 'arm'), ('x86', 'x86')]:
for binary in ['magiskinit', 'magiskboot']:
source = os.path.join('out', lib_dir, binary)
target = os.path.join(zip_dir, binary)
@@ -260,7 +261,7 @@ def zip_main(args):
zipf.writestr(target, util_func)
# addon.d.sh
source = os.path.join('scripts', 'addon.d.sh')
target = os.path.join('addon.d', '99-magisk.sh')
target = os.path.join('common', '99-magisk.sh')
zip_with_msg(zipf, source, target)
# Prebuilts
@@ -290,7 +291,7 @@ def zip_uninstaller(args):
zip_with_msg(zipf, source, target)
# Binaries
for lib_dir, zip_dir in [('arm64-v8a', 'arm64'), ('armeabi-v7a', 'arm'), ('x86', 'x86'), ('x86_64', 'x64')]:
for lib_dir, zip_dir in [('armeabi-v7a', 'arm'), ('x86', 'x86')]:
source = os.path.join('out', lib_dir, 'magiskboot')
target = os.path.join(zip_dir, 'magiskboot')
zip_with_msg(zipf, source, target)

View File

@@ -1,7 +1,7 @@
# Tips and Tricks
## OTA Installation Tips
Magisk do modifications systemless-ly, which means applying official OTAs is much simpler. Here I provide a few tutorials for several different kind of devices to apply OTAs and preserve Magisk after the installation if possible.
Magisk does modifications systemless-ly, which means applying official OTAs is much simpler. Here I provide a few tutorials for several different kind of devices to apply OTAs and preserve Magisk after the installation if possible.
**This tutorial is only for Magisk v14.1+**
@@ -50,4 +50,4 @@ If you decide to start by installing Magisk without touching your recovery parti
How to remove a file systemless-ly? To actually make the file **disappear** is complicated (possible, not worth the effort). **Replacing it with a dummy file should be good enough**! Create an empty file with the same name and place it in the same path within a module, it shall replace your target file with a dummy file.
## Remove Folders
Same as mentioned above, actually making the folder to **disappear** is not worth the effort. **Replacing it with an empty folder should be good enough**! A handy trick for module developers using [Magisk Module Template](https://github.com/topjohnwu/magisk-module-template) is to add the folder you want to remove into the `REPLACE` list within `config.sh`. If your module doesn't provide a correspond folder, it will create an empty folder, and automatically add `.replace` into the empty folder so the dummy folder will properly replace the one in `/system`.
Same as mentioned above, actually making the folder to **disappear** is not worth the effort. **Replacing it with an empty folder should be good enough**! A handy trick for module developers using [Magisk Module Template](https://github.com/topjohnwu/magisk-module-template) is to add the folder you want to remove into the `REPLACE` list within `config.sh`. If your module doesn't provide a correspond folder, it will create an empty folder, and automatically add `.replace` into the empty folder so the dummy folder will properly replace the one in `/system`.

Binary file not shown.

View File

@@ -1,6 +1,5 @@
#Mon Dec 04 11:24:34 CST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

100
gradlew vendored
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
##############################################################################
##
@@ -6,42 +6,6 @@
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@@ -60,6 +24,46 @@ cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -85,7 +89,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -150,11 +154,19 @@ if $cygwin ; then
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
APP_ARGS=$(save "$@")
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

14
gradlew.bat vendored
View File

@@ -8,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,10 +46,9 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line

View File

@@ -1,7 +1,8 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
externalNativeBuild {
ndkBuild {

View File

@@ -9,6 +9,7 @@ LIBLZMA := $(EXT_PATH)/xz/src/liblzma/api
LIBLZ4 := $(EXT_PATH)/lz4/lib
LIBBZ2 := $(EXT_PATH)/bzip2
LIBFDT := $(EXT_PATH)/dtc/libfdt
LIBNANOPB := $(EXT_PATH)/nanopb
UTIL_SRC := utils/cpio.c \
utils/file.c \
utils/img.c \
@@ -28,11 +29,13 @@ ifneq "$(or $(PRECOMPILE), $(GRADLE))" ""
include $(CLEAR_VARS)
LOCAL_MODULE := magisk
LOCAL_SHARED_LIBRARIES := libsqlite libselinux
LOCAL_STATIC_LIBRARIES := libnanopb
LOCAL_C_INCLUDES := \
jni/include \
jni/magiskpolicy \
$(EXT_PATH)/include \
$(LIBSELINUX)
$(LIBSELINUX) \
$(LIBNANOPB)
LOCAL_SRC_FILES := \
core/magisk.c \
@@ -43,7 +46,8 @@ LOCAL_SRC_FILES := \
magiskhide/magiskhide.c \
magiskhide/proc_monitor.c \
magiskhide/hide_utils.c \
resetprop/resetprop.cpp \
resetprop/persist_props.c \
resetprop/resetprop.c \
resetprop/system_properties.cpp \
su/su.c \
su/activity.c \
@@ -74,7 +78,6 @@ LOCAL_C_INCLUDES := \
LOCAL_SRC_FILES := \
core/magiskinit.c \
core/socket.c \
magiskpolicy/api.c \
magiskpolicy/magiskpolicy.c \
magiskpolicy/rules.c \
@@ -110,10 +113,8 @@ LOCAL_CFLAGS := -DXWRAP_EXIT
LOCAL_LDLIBS := -lz
include $(BUILD_EXECUTABLE)
# 32-bit static binaries
# 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
@@ -125,8 +126,6 @@ include $(BUILD_EXECUTABLE)
# Busybox
include jni/external/busybox/Android.mk
endif
endif
endif
# Precompile
endif

View File

@@ -1,4 +1,4 @@
APP_ABI := x86 x86_64 armeabi-v7a arm64-v8a
APP_ABI := x86 armeabi-v7a
APP_PLATFORM := android-21
APP_CFLAGS := $(MAGISK_FLAGS) -std=gnu99
APP_CPPFLAGS := -std=c++11

View File

@@ -19,6 +19,7 @@
#include "utils.h"
#include "daemon.h"
#include "resetprop.h"
#include "magiskpolicy.h"
static char *buf, *buf2;
static struct vector module_list;
@@ -124,15 +125,6 @@ static void bb_setenv(struct vector *v) {
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 *
***********/
@@ -359,7 +351,7 @@ static void simple_mount(const char *path) {
DIR *dir;
struct dirent *entry;
snprintf(buf, PATH_MAX, "%s%s", CACHEMOUNT, path);
snprintf(buf, PATH_MAX, "%s%s", SIMPLEMOUNT, path);
if (!(dir = opendir(buf)))
return;
@@ -377,7 +369,7 @@ static void simple_mount(const char *path) {
free(new_path);
} else if (entry->d_type == DT_REG) {
// Actual file path
snprintf(buf, PATH_MAX, "%s%s", CACHEMOUNT, buf2);
snprintf(buf, PATH_MAX, "%s%s", SIMPLEMOUNT, buf2);
// Clone all attributes
clone_attr(buf2, buf);
// Finally, mount the file
@@ -460,7 +452,7 @@ static int prepare_img() {
void fix_filecon() {
int dirfd = xopen(MOUNTPOINT, O_RDONLY | O_CLOEXEC);
restorecon(dirfd, 0);
restorecon(dirfd);
close(dirfd);
}
@@ -473,15 +465,13 @@ static void unblock_boot_process() {
pthread_exit(NULL);
}
void post_fs(int client) {
LOGI("** post-fs mode running\n");
// ack
write_int(client, 0);
close(client);
void startup() {
if (!check_data())
return;
// Uninstall or core only mode
// uninstaller or core-only mode
if (access(UNINSTALLER, F_OK) == 0 || access(DISABLEFILE, F_OK) == 0)
goto unblock;
goto initialize;
// Allocate buffer
buf = xmalloc(PATH_MAX);
@@ -490,32 +480,152 @@ void post_fs(int client) {
simple_mount("/system");
simple_mount("/vendor");
unblock:
unblock_boot_process();
}
initialize:
LOGI("** Initializing Magisk\n");
void post_fs_data(int client) {
// ack
write_int(client, 0);
close(client);
if (!is_daemon_init && !check_data())
goto unblock;
// Unlock all blocks for rw
unlock_blocks();
// Start the debug log
start_debug_full_log();
// 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);
}
LOGI("** post-fs-data mode running\n");
// Migration
rm_rf("/data/magisk");
unlink("/data/magisk.img");
unlink("/data/magisk_debug.log");
xmkdir("/data/adb", 0700);
chmod("/data/adb", 0700);
// Allocate buffer
if (buf == NULL) buf = xmalloc(PATH_MAX);
if (buf2 == NULL) buf2 = xmalloc(PATH_MAX);
vec_init(&module_list);
LOGI("* Creating /sbin overlay");
DIR *dir;
struct dirent *entry;
int root, sbin, fd;
char buf[PATH_MAX];
void *magisk, *init;
size_t magisk_size, init_size;
// Initialize
if (!is_daemon_init)
daemon_init();
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
// uninstaller
// Remove some traits of Magisk
unlink("/init.magisk.rc");
// Create hardlink mirror of /sbin to /root
mkdir("/root", 0750);
full_read("/sbin/magisk", &magisk, &magisk_size);
unlink("/sbin/magisk");
full_read("/sbin/magiskinit", &init, &init_size);
unlink("/sbin/magiskinit");
root = xopen("/root", O_RDONLY | O_CLOEXEC);
sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC);
link_dir(sbin, root);
close(sbin);
// Mount the /sbin tmpfs overlay
xmount("tmpfs", "/sbin", "tmpfs", 0, NULL);
chmod("/sbin", 0755);
setfilecon("/sbin", "u:object_r:rootfs:s0");
sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC);
// Setup magisk symlinks
fd = creat("/sbin/magisk", 0755);
xwrite(fd, magisk, magisk_size);
close(fd);
free(magisk);
setfilecon("/sbin/magisk", "u:object_r:"SEPOL_FILE_DOMAIN":s0");
for (int i = 0; applet[i]; ++i) {
snprintf(buf, PATH_MAX, "/sbin/%s", applet[i]);
xsymlink("/sbin/magisk", buf);
}
// Setup magiskinit symlinks
fd = creat("/sbin/magiskinit", 0755);
xwrite(fd, init, init_size);
close(fd);
free(init);
setfilecon("/sbin/magiskinit", "u:object_r:"SEPOL_FILE_DOMAIN":s0");
for (int i = 0; init_applet[i]; ++i) {
snprintf(buf, PATH_MAX, "/sbin/%s", init_applet[i]);
xsymlink("/sbin/magiskinit", buf);
}
// Create symlinks pointing back to /root
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);
symlinkat(buf, sbin, entry->d_name);
}
close(sbin);
close(root);
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", MIRRDIR "/system", buf);
#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", MIRRDIR "/vendor", buf);
#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 "/vendor", MIRRDIR "/system/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");
// uninstall
if (access(UNINSTALLER, F_OK) == 0) {
close(open(UNBLOCKFILE, O_RDONLY | O_CREAT));
setenv("BOOTMODE", "true", 1);
@@ -523,6 +633,28 @@ void post_fs_data(int client) {
return;
}
// Start post-fs-data mode
execv("/sbin/magisk", (char *[]) { "magisk", "--post-fs-data", NULL });
}
void post_fs_data(int client) {
// ack
write_int(client, 0);
close(client);
// Start the debug log
start_debug_full_log();
LOGI("** post-fs-data mode running\n");
xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL);
full_patch_pid = exec_command(0, NULL, NULL, "/sbin/magiskpolicy", "--live", "allow "SEPOL_PROC_DOMAIN" * * *", NULL);
// Allocate buffer
buf = xmalloc(PATH_MAX);
buf2 = xmalloc(PATH_MAX);
vec_init(&module_list);
// Merge, trim, mount magisk.img, which will also travel through the modules
// After this, it will create the module list
if (prepare_img())
@@ -614,8 +746,6 @@ core_only:
}
auto_start_magiskhide();
unblock:
unblock_boot_process();
}
@@ -630,8 +760,7 @@ void late_start(int client) {
if (buf2 == NULL) buf2 = xmalloc(PATH_MAX);
// Wait till the full patch is done
wait_till_exists(PATCHDONE);
unlink(PATCHDONE);
waitpid(full_patch_pid, NULL, 0);
// Run scripts after full patch, most reliable way to run scripts
LOGI("* Running service.d scripts\n");
@@ -648,14 +777,13 @@ 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");
setfilecon("/data/magisk.apk", "u:object_r:"SEPOL_FILE_DOMAIN":s0");
while (1) {
sleep(5);
LOGD("apk_install: attempting to install APK");
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);
pid = exec_command(1, &apk_res, NULL,
"/system/bin/pm", "install", "-r", "/data/magisk.apk", NULL);
if (pid != -1) {
int err = 0;
while (fdgets(buf, PATH_MAX, apk_res) > 0) {

View File

@@ -19,8 +19,10 @@
#include "utils.h"
#include "daemon.h"
#include "resetprop.h"
#include "magiskpolicy.h"
int is_daemon_init = 0, seperate_vendor = 0;
int seperate_vendor = 0;
int full_patch_pid;
static void *request_handler(void *args) {
int client = *((int *) args);
@@ -36,7 +38,6 @@ static void *request_handler(void *args) {
case ADD_HIDELIST:
case RM_HIDELIST:
case LS_HIDELIST:
case POST_FS:
case POST_FS_DATA:
case LATE_START:
if (credential.uid != 0) {
@@ -75,9 +76,6 @@ static void *request_handler(void *args) {
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;
@@ -96,6 +94,30 @@ static void *start_magisk_hide(void *args) {
return NULL;
}
static void daemon_saver() {
int fd, val;
struct sockaddr_un sun;
// Change process name
strcpy(argv0, "magisk_saver");
while (1) {
fd = setup_socket(&sun);
while(connect(fd, (struct sockaddr*) &sun, sizeof(sun)))
usleep(10000);
write_int(fd, DO_NOTHING);
// Should hold forever unless the other side is closed
read(fd, &val, sizeof(int));
// If it came here, the daemon is terminated
close(fd);
if (fork_dont_care() == 0)
start_daemon(0);
}
}
void auto_start_magiskhide() {
char *hide_prop = getprop2(MAGISKHIDE_PROP, 1);
if (hide_prop == NULL || strcmp(hide_prop, "0") != 0) {
@@ -106,151 +128,18 @@ void auto_start_magiskhide() {
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];
char magisk_name[10], init_name[10];
// 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);
link_dir(sbin, root);
unlink("/sbin/magisk");
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);
}
gen_rand_str(magisk_name, sizeof(magisk_name));
snprintf(buf, PATH_MAX, "/root/%s", magisk_name);
unlink("/sbin/magisk");
rename("/root/magisk", buf);
xsymlink(buf, "/sbin/magisk");
for (int i = 0; applet[i]; ++i) {
snprintf(buf2, PATH_MAX, "/sbin/%s", applet[i]);
xsymlink(buf, buf2);
}
gen_rand_str(init_name, sizeof(init_name));
snprintf(buf, PATH_MAX, "/root/%s", init_name);
unlink("/sbin/magiskinit");
rename("/root/magiskinit", buf);
for (int i = 0; init_applet[i]; ++i) {
snprintf(buf2, PATH_MAX, "/sbin/%s", init_applet[i]);
xsymlink(buf, 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", MIRRDIR "/system", buf);
#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", MIRRDIR "/vendor", buf);
#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 "/vendor", MIRRDIR "/system/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() {
void start_daemon(int post_fs_data) {
setsid();
setcon("u:r:su:s0");
umask(0);
setcon("u:r:"SEPOL_PROC_DOMAIN":s0");
int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC);
xdup2(fd, STDIN_FILENO);
xdup2(fd, STDOUT_FILENO);
xdup2(fd, STDERR_FILENO);
close(fd);
if (post_fs_data && fork_dont_care() == 0)
daemon_saver();
// Block user signals
sigset_t block_set;
sigemptyset(&block_set);
@@ -268,22 +157,17 @@ void start_daemon() {
// Start the log monitor
monitor_logs();
if ((is_daemon_init = (access(MAGISKTMP, F_OK) == 0))) {
if (!post_fs_data && (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();
}
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();
strcpy(argv0, "magiskd");
// Loop forever to listen for requests
while(1) {
@@ -297,7 +181,7 @@ void start_daemon() {
}
/* Connect the daemon, and return a socketfd */
int connect_daemon() {
int connect_daemon(int post_fs_data) {
struct sockaddr_un sun;
int fd = setup_socket(&sun);
if (connect(fd, (struct sockaddr*) &sun, sizeof(sun))) {
@@ -308,10 +192,10 @@ int connect_daemon() {
exit(1);
}
if (xfork() == 0) {
if (fork_dont_care() == 0) {
LOGD("client: connect fail, try launching new daemon process\n");
close(fd);
start_daemon();
start_daemon(post_fs_data);
}
while (connect(fd, (struct sockaddr*) &sun, sizeof(sun)))

View File

@@ -14,8 +14,7 @@
#include "utils.h"
#include "resetprop.h"
extern int is_daemon_init;
int logd = 0;
int loggable = 1;
static int am_proc_start_filter(const char *log) {
return strstr(log, "am_proc_start") != NULL;
@@ -49,15 +48,16 @@ struct log_listener log_events[] = {
static int debug_log_pid = -1, debug_log_fd = -1;
#endif
static void check_logd() {
char *prop = getprop("init.svc.logd");
if (prop != NULL) {
free(prop);
logd = 1;
} else {
LOGD("log_monitor: logd not started, disable logging");
logd = 0;
static void test_logcat() {
int log_fd = -1, log_pid;
char buf[1];
log_pid = exec_command(0, &log_fd, NULL, "logcat", NULL);
if (read(log_fd, buf, sizeof(buf)) != sizeof(buf)) {
loggable = 0;
LOGD("log_monitor: cannot read from logcat, disable logging");
}
kill(log_pid, SIGTERM);
waitpid(log_pid, NULL, 0);
}
static void *logger_thread(void *args) {
@@ -67,7 +67,7 @@ static void *logger_thread(void *args) {
LOGD("log_monitor: logger start");
while (1) {
if (!logd) {
if (!loggable) {
// Disable all services
for (int i = 0; i < (sizeof(log_events) / sizeof(struct log_listener)); ++i) {
close(log_events[i].fd);
@@ -98,7 +98,7 @@ static void *logger_thread(void *args) {
// Clear buffer before restart
exec_command_sync("logcat", "-b", "events", "-b", "main", "-c", NULL);
check_logd();
test_logcat();
}
// Should never be here, but well...
@@ -106,38 +106,20 @@ static void *logger_thread(void *args) {
}
static void *magisk_log_thread(void *args) {
// Buffer logs before we have data access
struct vector logs;
vec_init(&logs);
FILE *log = xfopen(LOGFILE, "w");
setbuf(log, NULL);
int pipefd[2];
if (xpipe2(pipefd, O_CLOEXEC) == -1)
return NULL;
LOGD("log_monitor: magisk log dumper start");
// Register our listener
log_events[LOG_EVENT].fd = pipefd[1];
LOGD("log_monitor: magisk log dumper start");
for (char *line; xxread(pipefd[0], &line, sizeof(line)) > 0; free(line))
fprintf(log, "%s", line);
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;
}
@@ -163,9 +145,9 @@ static void *debug_magisk_log_thread(void *args) {
void monitor_logs() {
pthread_t thread;
check_logd();
test_logcat();
if (logd) {
if (loggable) {
// Start log file dumper before monitor
xpthread_create(&thread, NULL, magisk_log_thread, NULL);
pthread_detach(thread);
@@ -178,7 +160,7 @@ void monitor_logs() {
void start_debug_full_log() {
#ifdef MAGISK_DEBUG
if (logd) {
if (loggable) {
// 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);
@@ -201,7 +183,7 @@ void stop_debug_full_log() {
void start_debug_log() {
#ifdef MAGISK_DEBUG
if (logd) {
if (loggable) {
pthread_t thread;
// Start debug thread
xpthread_create(&thread, NULL, debug_magisk_log_thread, NULL);

View File

@@ -47,13 +47,14 @@ static void usage() {
" --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"
" --daemon manually start magisk daemon\n"
" --[init trigger] start service for init trigger\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"
"Supported init triggers:\n"
" startup, post-fs-data, service\n"
"\n"
"Supported applets:\n"
, argv0, argv0);
@@ -65,6 +66,7 @@ static void usage() {
}
int main(int argc, char *argv[]) {
umask(0);
argv0 = argv[0];
if (strcmp(basename(argv[0]), "magisk") == 0) {
if (argc < 2) usage();
@@ -72,14 +74,14 @@ int main(int argc, char *argv[]) {
printf("%s (%d)\n", MAGISK_VER_STR, MAGISK_VER_CODE);
return 0;
} else if (strcmp(argv[1], "-v") == 0) {
int fd = connect_daemon();
int fd = connect_daemon(0);
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();
int fd = connect_daemon(0);
write_int(fd, CHECK_VERSION_CODE);
printf("%d\n", read_int(fd));
return 0;
@@ -144,19 +146,18 @@ int main(int argc, char *argv[]) {
clone_attr(argv[2], argv[3]);
return 0;
} else if (strcmp(argv[1], "--daemon") == 0) {
if (xfork() == 0)
start_daemon();
int fd = connect_daemon(0);
close(fd);
return 0;
} else if (strcmp(argv[1], "--startup") == 0) {
startup();
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();
int fd = connect_daemon(1);
write_int(fd, POST_FS_DATA);
return read_int(fd);
} else if (strcmp(argv[1], "--service") == 0) {
int fd = connect_daemon();
int fd = connect_daemon(0);
write_int(fd, LATE_START);
return read_int(fd);
} else {

View File

@@ -55,12 +55,11 @@
extern policydb_t *policydb;
int (*init_applet_main[]) (int, char *[]) = { magiskpolicy_main, magiskpolicy_main, NULL };
static int keepverity = 0, keepencrypt = 0;
static char RAND_SOCKET_NAME[sizeof(SOCKET_NAME)];
static int SOCKET_OFF = -1;
struct cmdline {
int skip_initramfs;
char skip_initramfs;
char slot[3];
};
@@ -74,8 +73,7 @@ struct device {
static void parse_cmdline(struct cmdline *cmd) {
// cleanup
cmd->skip_initramfs = 0;
cmd->slot[0] = '\0';
memset(cmd, 0, sizeof(&cmd));
char cmdline[4096];
mkdir("/proc", 0555);
@@ -89,11 +87,13 @@ static void parse_cmdline(struct cmdline *cmd) {
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);
sscanf(tok, "androidboot.slot=%c", cmd->slot + 1);
} else if (strcmp(tok, "skip_initramfs") == 0) {
cmd->skip_initramfs = 1;
}
}
VLOG("cmdline: skip_initramfs[%d] slot[%s]\n", cmd->skip_initramfs, cmd->slot);
}
static void parse_device(struct device *dev, char *uevent) {
@@ -148,24 +148,7 @@ static int setup_block(struct device *dev, const char *partname) {
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 = (uint32_t) _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) {
static void patch_ramdisk() {
void *addr;
size_t size;
mmap_rw("/init", &addr, &size);
@@ -183,25 +166,6 @@ static void patch_ramdisk(int root) {
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) {
@@ -386,55 +350,6 @@ static void patch_socket_name(const char *path) {
munmap(buf, size);
}
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);
if (null > STDERR_FILENO)
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);
memcpy(sun.sun_path + 1, RAND_SOCKET_NAME, sizeof(SOCKET_NAME));
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);
@@ -460,118 +375,114 @@ int main(int argc, char *argv[]) {
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");
patch_socket_name("/overlay/sbin/magisk");
// Backup self
link("/init", "/init.bak");
struct cmdline cmd;
parse_cmdline(&cmd);
VLOG("cmdline: skip_initramfs=[%d] slot_suffix=[%s]\n", cmd.skip_initramfs, cmd.slot);
/* ***********
* Initialize
* ***********/
int root = open("/", O_RDONLY | O_CLOEXEC);
if (cmd.skip_initramfs) {
// Exclude overlay folder
excl_list = (char *[]) { "overlay", ".backup", NULL };
// Clear rootfs
excl_list = (char *[]) { "overlay", ".backup", "init.bak", NULL };
frm_rf(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");
}
/* ************
* Early Mount
* ************/
// If skip_initramfs or using split policies, we need early mount
if (cmd.skip_initramfs || access("/sepolicy", R_OK) != 0) {
char partname[32];
struct device dev;
// Mount sysfs
mkdir("/sys", 0755);
xmount("sysfs", "/sys", "sysfs", 0, NULL);
char partname[32];
// Mount system
snprintf(partname, sizeof(partname), "system%s", cmd.slot);
struct device dev;
setup_block(&dev, partname);
if (cmd.skip_initramfs) {
mkdir("/system_root", 0755);
xmount(dev.path, "/system_root", "ext4", MS_RDONLY, NULL);
int system_root = open("/system_root", O_RDONLY | O_CLOEXEC);
mkdir("/system_root", 0755);
xmount(dev.path, "/system_root", "ext4", MS_RDONLY, NULL);
int system_root = open("/system_root", O_RDONLY | O_CLOEXEC);
// Clone rootfs except /system
excl_list = (char *[]) { "system", NULL };
clone_dir(system_root, root);
close(system_root);
// 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);
mkdir("/system", 0755);
xmount("/system_root/system", "/system", NULL, MS_BIND, NULL);
} else {
xmount(dev.path, "/system", "ext4", MS_RDONLY, NULL);
}
// Mount vendor
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");
}
}
/* *************
* Patch rootfs
* *************/
// Only patch rootfs if not intended to run in recovery
if (access("/etc/recovery.fstab", F_OK) != 0) {
int overlay = open("/overlay", O_RDONLY | O_CLOEXEC);
mv_dir(overlay, root);
int fd;
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");
// Handle ramdisk overlays
fd = open("/overlay", O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
mv_dir(fd, root);
close(fd);
rmdir("/overlay");
}
close(overlay);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
patch_ramdisk();
patch_sepolicy();
if (fork_dont_care() == 0) {
strcpy(argv[0], "magiskinit");
close(root);
magisk_init_daemon();
}
// Dump binaries
dump_magiskrc("/init.magisk.rc", 0750);
dump_magisk("/sbin/magisk", 0755);
patch_socket_name("/sbin/magisk");
rename("/init.bak", "/sbin/magiskinit");
}
// Clean up
close(root);
if (!cmd.skip_initramfs)
umount("/system");
umount("/vendor");
rmdir("/overlay");
// Finally, give control back!
execv("/init", argv);

View File

@@ -8,13 +8,15 @@
#include "utils.h"
#include "magisk.h"
static char socket_name[] = SOCKET_NAME; /* Workaround compiler bug pre NDK r13 */
/* 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;
sun->sun_path[0] = '\0';
memcpy(sun->sun_path + 1, SOCKET_NAME, sizeof(SOCKET_NAME));
memcpy(sun->sun_path + 1, socket_name, sizeof(SOCKET_NAME));
return fd;
}

View File

@@ -28,6 +28,16 @@ LOCAL_SRC_FILES := \
mincrypt/sha256.c
include $(BUILD_STATIC_LIBRARY)
# libnanopb.a
include $(CLEAR_VARS)
LOCAL_MODULE:= libnanopb
LOCAL_C_INCLUDES := $(LIBNANOPB)
LOCAL_SRC_FILES := \
nanopb/pb_common.c \
nanopb/pb_decode.c \
nanopb/pb_encode.c
include $(BUILD_STATIC_LIBRARY)
# libfdt.a
include $(CLEAR_VARS)
LOCAL_MODULE:= libfdt

1
native/jni/external/nanopb vendored Submodule

View File

@@ -8,7 +8,9 @@
#include <sys/un.h>
#include <sys/socket.h>
extern int is_daemon_init, seperate_vendor;
extern int is_daemon_init;
extern int seperate_vendor;
extern int full_patch_pid;
// Commands require connecting to daemon
enum {
@@ -16,7 +18,6 @@ enum {
SUPERUSER,
CHECK_VERSION,
CHECK_VERSION_CODE,
POST_FS,
POST_FS_DATA,
LATE_START,
LAUNCH_MAGISKHIDE,
@@ -31,7 +32,7 @@ enum {
DAEMON_ERROR = -1,
DAEMON_SUCCESS = 0,
ROOT_REQUIRED,
LOGD_DISABLED,
LOGCAT_DISABLED,
HIDE_IS_ENABLED,
HIDE_NOT_ENABLED,
HIDE_ITEM_EXIST,
@@ -40,10 +41,9 @@ enum {
// daemon.c
void start_daemon();
int connect_daemon();
void start_daemon(int post_fs_data);
int connect_daemon(int post_fs_data);
void auto_start_magiskhide();
void daemon_init();
// socket.c
@@ -59,7 +59,7 @@ void write_string(int fd, const char* val);
* Boot Stages *
***************/
void post_fs(int client);
void startup();
void post_fs_data(int client);
void late_start(int client);
void fix_filecon();

View File

@@ -58,7 +58,7 @@ struct log_listener {
};
extern struct log_listener log_events[];
extern int logd;
extern int loggable;
void monitor_logs();
void start_debug_full_log();

View File

@@ -14,12 +14,9 @@
#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"
@@ -27,8 +24,12 @@
#define COREDIR MOUNTPOINT "/.core"
#define HOSTSFILE COREDIR "/hosts"
#define HIDELIST COREDIR "/hidelist"
#define MAINIMG "/data/adb/magisk.img"
#define DATABIN "/data/adb/magisk"
#define SECURE_DIR "/data/adb/"
#define MAINIMG SECURE_DIR "magisk.img"
#define DATABIN SECURE_DIR "magisk"
#define MAGISKDB SECURE_DIR "magisk.db"
#define SIMPLEMOUNT SECURE_DIR "magisk_simple"
#define DEBUG_LOG SECURE_DIR "magisk_debug.log"
#define MANAGERAPK DATABIN "/magisk.apk"
#define MAGISKRC "/init.magisk.rc"
@@ -62,13 +63,6 @@ int create_links(const char *bin, const char *path);
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

View File

@@ -1,17 +1,17 @@
#include "magiskpolicy.h"
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"
" start magisk_startup\n"
" wait /dev/.magisk.unblock 10\n"
" rm /dev/.magisk.unblock\n"
"\n"
@@ -20,25 +20,19 @@ const char magiskrc[] =
"service magisk_daemon /sbin/magisk --daemon\n"
" user root\n"
" seclabel u:r:su:s0\n"
" seclabel u:r:"SEPOL_PROC_DOMAIN":s0\n"
" oneshot\n"
"\n"
"service magisk_pfs /sbin/magisk --post-fs\n"
"service magisk_startup /sbin/magisk --startup\n"
" user root\n"
" seclabel u:r:su:s0\n"
" seclabel u:r:"SEPOL_PROC_DOMAIN":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"
"service magisk_service /sbin/magisk --service\n"
" class late_start\n"
" user root\n"
" seclabel u:r:su:s0\n"
" seclabel u:r:"SEPOL_PROC_DOMAIN":s0\n"
" oneshot\n"
;

View File

@@ -4,10 +4,6 @@
#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);
@@ -16,10 +12,6 @@ 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
void getprop_all(void (*callback)(const char *, const char *, void *), void *cookie);
#endif

View File

@@ -122,7 +122,7 @@ 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);
void restorecon(int dirfd);
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);

View File

@@ -124,10 +124,16 @@ int parse_img(const char *image, boot_img *boot) {
fprintf(stderr, "PXA_BOOT_HDR\n");
boot->hdr = malloc(sizeof(pxa_boot_img_hdr));
memcpy(boot->hdr, head, sizeof(pxa_boot_img_hdr));
} else if (memcmp(((boot_img_hdr*) head)->cmdline, NOOK_MAGIC, 12) == 0) {
boot->flags |= NOOK_FLAG;
fprintf(stderr, "NOOK_GREEN_LOADER\n");
head += NOOK_PRE_HEADER_SZ - 1;
} else if (memcmp(((boot_img_hdr*) head)->cmdline, NOOKHD_MAGIC, 12) == 0
|| memcmp(((boot_img_hdr*) head)->cmdline, NOOKHD_NEW_MAGIC, 26) == 0) {
boot->flags |= NOOKHD_FLAG;
fprintf(stderr, "NOOKHD_GREEN_LOADER\n");
head += NOOKHD_PRE_HEADER_SZ - 1;
continue;
} else if (memcmp(((boot_img_hdr*) head)->name, ACCLAIM_MAGIC, 10) == 0) {
boot->flags |= ACCLAIM_FLAG;
fprintf(stderr, "ACCLAIM_BAUWKSBOOT\n");
head += ACCLAIM_PRE_HEADER_SZ - 1;
continue;
} else {
boot->hdr = malloc(sizeof(boot_img_hdr));
@@ -162,7 +168,7 @@ int parse_img(const char *image, boot_img *boot) {
if (pos < boot->map_size) {
boot->tail = head + pos;
boot->tail_size = boot->map_size - pos;
boot->tail_size = boot->map_size - (boot->tail - boot->map_addr);
}
// Check tail info, currently only for LG Bump and Samsung SEANDROIDENFORCE
@@ -202,12 +208,12 @@ int parse_img(const char *image, boot_img *boot) {
fprintf(stderr, "MTK_RAMDISK_HDR\n");
boot->flags |= MTK_RAMDISK;
boot->r_hdr = malloc(sizeof(mtk_hdr));
memcpy(boot->r_hdr, boot->kernel, sizeof(mtk_hdr));
memcpy(boot->r_hdr, boot->ramdisk, sizeof(mtk_hdr));
fprintf(stderr, "RAMDISK [%u]\n", boot->r_hdr->size);
fprintf(stderr, "NAME [%s]\n", boot->r_hdr->name);
boot->ramdisk += 512;
lheader(boot, ramdisk_size, -= 512);
boot->k_fmt = check_fmt(boot->ramdisk, header(boot, ramdisk_size));
boot->r_fmt = check_fmt(boot->ramdisk, header(boot, ramdisk_size));
}
char fmt[16];
@@ -288,8 +294,10 @@ void repack(const char* orig_image, const char* out_image) {
} else if (boot.flags & BLOB_FLAG) {
// Skip blob header
write_zero(fd, sizeof(blob_hdr));
} else if (boot.flags & NOOK_FLAG) {
restore_buf(fd, boot.map_addr, NOOK_PRE_HEADER_SZ);
} else if (boot.flags & NOOKHD_FLAG) {
restore_buf(fd, boot.map_addr, NOOKHD_PRE_HEADER_SZ);
} else if (boot.flags & ACCLAIM_FLAG) {
restore_buf(fd, boot.map_addr, ACCLAIM_PRE_HEADER_SZ);
}
// Skip a page for header
@@ -312,13 +320,14 @@ void repack(const char* orig_image, const char* out_image) {
} else {
lheader(&boot, kernel_size, = restore(KERNEL_FILE, fd));
}
// dtb
if (access(DTB_FILE, R_OK) == 0) {
lheader(&boot, kernel_size, += restore(DTB_FILE, fd));
}
file_align();
}
// dtb
if (access(DTB_FILE, R_OK) == 0) {
lheader(&boot, kernel_size, += restore(DTB_FILE, fd));
}
file_align();
// ramdisk
ramdisk_off = lseek(fd, 0, SEEK_CUR);
if (boot.flags & MTK_RAMDISK) {
@@ -333,7 +342,7 @@ void repack(const char* orig_image, const char* out_image) {
lheader(&boot, ramdisk_size, = comp(boot.r_fmt, fd, cpio, cpio_size));
munmap(cpio, cpio_size);
} else {
lheader(&boot, kernel_size, = restore(KERNEL_FILE, fd));
lheader(&boot, ramdisk_size, = restore(RAMDISK_FILE, fd));
}
file_align();
}

View File

@@ -130,7 +130,8 @@ typedef struct blob_hdr {
#define LG_BUMP_FLAG 0x0040
#define SHA256_FLAG 0x0080
#define BLOB_FLAG 0x0100
#define NOOK_FLAG 0x0200
#define NOOKHD_FLAG 0x0200
#define ACCLAIM_FLAG 0x0400
typedef struct boot_img {
// Memory map of the whole image

View File

@@ -38,8 +38,11 @@ typedef enum {
#define DHTB_MAGIC "\x44\x48\x54\x42\x01\x00\x00\x00"
#define SEANDROID_MAGIC "SEANDROIDENFORCE"
#define TEGRABLOB_MAGIC "-SIGNED-BY-SIGNBLOB-"
#define NOOK_MAGIC "Green Loader"
#define NOOK_PRE_HEADER_SZ 1048575
#define NOOKHD_MAGIC "Green Loader"
#define NOOKHD_NEW_MAGIC "eMMC boot.img+secondloader"
#define NOOKHD_PRE_HEADER_SZ 1048576
#define ACCLAIM_MAGIC "BauwksBoot"
#define ACCLAIM_PRE_HEADER_SZ 262144
#define SUP_LIST ((char *[]) { "gzip", "xz", "lzma", "bzip2", "lz4", "lz4_legacy", NULL })
#define SUP_EXT_LIST ((char *[]) { "gz", "xz", "lzma", "bz2", "lz4", "lz4", NULL })

View File

@@ -34,18 +34,22 @@ static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) {
#define STOCK_BOOT 0x0
#define MAGISK_PATCH 0x1
#define OTHER_PATCH 0x2
#define HIGH_COMPRESS 0x2
#define OTHER_PATCH 0x3
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)
if (cpio_find(v, OTHER_LIST[i]) >= 0)
return OTHER_PATCH;
if (cpio_find(v, "ramdisk.cpio.xz") >= 0)
return HIGH_COMPRESS;
for (int i = 0; MAGISK_LIST[i]; ++i)
if (cpio_find(v, MAGISK_LIST[i]) > 0)
if (cpio_find(v, MAGISK_LIST[i]) >= 0)
return MAGISK_PATCH;
return STOCK_BOOT;

View File

@@ -56,7 +56,7 @@ void hide_sensitive_props() {
}
}
static void rm_magisk_prop(const char *name, const char *value) {
static void rm_magisk_prop(const char *name, const char *value, void *v) {
if (strstr(name, "magisk")) {
deleteprop2(name, 0);
}
@@ -64,7 +64,7 @@ static void rm_magisk_prop(const char *name, const char *value) {
void clean_magisk_props() {
LOGD("hide_utils: Cleaning magisk props\n");
getprop_all(rm_magisk_prop);
getprop_all(rm_magisk_prop, NULL);
}
int add_list(char *proc) {

View File

@@ -49,11 +49,14 @@ void launch_magiskhide(int client) {
return;
}
if (!logd) {
if (!loggable) {
if (client > 0) {
write_int(client, LOGD_DISABLED);
write_int(client, LOGCAT_DISABLED);
close(client);
}
setprop(MAGISKHIDE_PROP, "0");
// Remove without actually removing persist props
deleteprop2(MAGISKHIDE_PROP, 0);
return;
}
@@ -132,7 +135,7 @@ int magiskhide_main(int argc, char *argv[]) {
} else {
usage(argv[0]);
}
int fd = connect_daemon();
int fd = connect_daemon(0);
write_int(fd, req);
if (req == ADD_HIDELIST || req == RM_HIDELIST) {
write_string(fd, argv[2]);
@@ -144,14 +147,14 @@ int magiskhide_main(int argc, char *argv[]) {
case ROOT_REQUIRED:
fprintf(stderr, "Root is required for this operation\n");
return code;
case LOGD_DISABLED:
fprintf(stderr, "Logd is not running, cannot run logcat\n");
case LOGCAT_DISABLED:
fprintf(stderr, "Logcat is disabled, cannot start MagiskHide\n");
return (code);
case HIDE_NOT_ENABLED:
fprintf(stderr, "Magisk hide is not enabled yet\n");
fprintf(stderr, "MagiskHide is not enabled yet\n");
return code;
case HIDE_IS_ENABLED:
fprintf(stderr, "Magisk hide is already enabled\n");
fprintf(stderr, "MagiskHide is already enabled\n");
return code;
case HIDE_ITEM_EXIST:
fprintf(stderr, "Process [%s] already exists in hide list\n", argv[2]);

View File

@@ -4,7 +4,6 @@
#include <pthread.h>
#define TERM_THREAD SIGUSR1
#define HIDE_DONE SIGUSR2
// Kill process
void kill_proc(int pid);

View File

@@ -20,7 +20,7 @@
#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 };
static int zygote_num, has_cache = 1, pipefd[2] = { -1, -1 };
// Workaround for the lack of pthread_cancel
static void term_thread(int sig) {
@@ -38,17 +38,6 @@ static void term_thread(int sig) {
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);
@@ -72,7 +61,7 @@ static void lazy_unmount(const char* mountpoint) {
LOGD("hide_daemon: Unmounted (%s)\n", mountpoint);
}
static void hide_daemon(int pid, int ppid) {
static void hide_daemon(int pid) {
LOGD("hide_daemon: start unmount for pid=[%d]\n", pid);
strcpy(argv0, "hide_daemon");
@@ -140,9 +129,6 @@ exit:
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);
}
@@ -151,7 +137,6 @@ void proc_monitor() {
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
@@ -159,8 +144,6 @@ void proc_monitor() {
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';
@@ -219,6 +202,11 @@ void proc_monitor() {
if(ret != 2)
continue;
// Allow hiding sub-services of applications
char *colon = strchr(processName, ':');
if (colon)
*colon = '\0';
// Critical region
pthread_mutex_lock(&hide_lock);
vec_for_each(hide_list, line) {
@@ -239,23 +227,17 @@ void proc_monitor() {
// Send pause signal ASAP
if (kill(pid, SIGSTOP) == -1) continue;
// Restore the colon so we can log the actual process name
if (colon)
*colon = ':';
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);
hide_daemon(pid);
break;
}

View File

@@ -0,0 +1,31 @@
/* resetprop.h - Internal struct definitions
*/
#ifndef MAGISK_PROPS_H
#define MAGISK_PROPS_H
#include "system_properties.h"
#include "logging.h"
extern int prop_verbose;
#define PRINT_D(...) { LOGD(__VA_ARGS__); if (prop_verbose) fprintf(stderr, __VA_ARGS__); }
#define PRINT_E(...) { LOGE(__VA_ARGS__); fprintf(stderr, __VA_ARGS__); }
struct prop_t {
char *name;
char value[PROP_VALUE_MAX];
};
struct read_cb_t {
void (*func)(const char *name, const char *value, void *cookie);
void *cookie;
};
char *persist_getprop(const char *name);
void persist_getprop_all(struct read_cb_t *read_cb);
bool persist_deleteprop(const char *name);
void collect_props(const char *name, const char *value, void *prop_list);
#endif //MAGISK_PROPS_H

View File

@@ -0,0 +1,252 @@
#include <stdbool.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <pb.h>
#include <pb_decode.h>
#include <pb_encode.h>
#include "_resetprop.h"
#include "utils.h"
#include "vector.h"
#define PERSISTENT_PROPERTY_DIR "/data/property"
/* ***********************************************************************
* Auto generated header and constant definitions compiled from
* android/platform/system/core/master/init/persistent_properties.proto
* using Nanopb's protoc
* Nanopb: https://github.com/nanopb/nanopb
* ***********************************************************************/
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.1 at Sun Apr 22 14:36:22 2018. */
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Struct definitions */
typedef struct _PersistentProperties {
pb_callback_t properties;
/* @@protoc_insertion_point(struct:PersistentProperties) */
} PersistentProperties;
typedef struct _PersistentProperties_PersistentPropertyRecord {
pb_callback_t name;
bool has_value;
char value[92];
/* @@protoc_insertion_point(struct:PersistentProperties_PersistentPropertyRecord) */
} PersistentProperties_PersistentPropertyRecord;
/* Default values for struct fields */
/* Initializer values for message structs */
#define PersistentProperties_init_default {{{NULL}, NULL}}
#define PersistentProperties_PersistentPropertyRecord_init_default {{{NULL}, NULL}, false, ""}
#define PersistentProperties_init_zero {{{NULL}, NULL}}
#define PersistentProperties_PersistentPropertyRecord_init_zero {{{NULL}, NULL}, false, ""}
/* Field tags (for use in manual encoding/decoding) */
#define PersistentProperties_properties_tag 1
#define PersistentProperties_PersistentPropertyRecord_name_tag 1
#define PersistentProperties_PersistentPropertyRecord_value_tag 2
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.3.9.1 at Sun Apr 22 14:36:22 2018. */
/* Struct field encoding specification for nanopb */
const pb_field_t PersistentProperties_PersistentPropertyRecord_fields[3] = {
PB_FIELD( 1, STRING , OPTIONAL, CALLBACK, FIRST, PersistentProperties_PersistentPropertyRecord, name, name, 0),
PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, PersistentProperties_PersistentPropertyRecord, value, name, 0),
PB_LAST_FIELD
};
const pb_field_t PersistentProperties_fields[2] = {
PB_FIELD( 1, MESSAGE , REPEATED, CALLBACK, FIRST, PersistentProperties, properties, properties, &PersistentProperties_PersistentPropertyRecord_fields),
PB_LAST_FIELD
};
/* Maximum encoded size of messages (where known) */
/* PersistentProperties_size depends on runtime parameters */
/* PersistentProperties_PersistentPropertyRecord_size depends on runtime parameters */
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define PROPS_MESSAGES \
#endif
/* @@protoc_insertion_point(eof) */
/* ***************************
* End of auto generated code
* ***************************/
static bool name_decode(pb_istream_t *stream, const pb_field_t *field, void **arg) {
uint8_t *name = xmalloc(stream->bytes_left + 1);
name[stream->bytes_left] = '\0';
if (!pb_read(stream, name, stream->bytes_left))
return false;
*arg = name;
return true;
}
static bool name_encode(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
return pb_encode_tag_for_field(stream, field) && pb_encode_string(stream, *arg, strlen(*arg));
}
static bool prop_decode(pb_istream_t *stream, const pb_field_t *field, void **arg) {
PersistentProperties_PersistentPropertyRecord prop = {};
prop.name.funcs.decode = name_decode;
if (!pb_decode(stream, PersistentProperties_PersistentPropertyRecord_fields, &prop))
return false;
struct read_cb_t *read_cb = *arg;
read_cb->func(prop.name.arg, prop.value, read_cb->cookie);
return true;
}
static bool prop_encode(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
PersistentProperties_PersistentPropertyRecord prop = {};
prop.name.funcs.encode = name_encode;
prop.has_value = true;
struct vector *v = *arg;
struct prop_t *e;
vec_for_each(v, e) {
if (e == NULL)
continue;
if (!pb_encode_tag_for_field(stream, field))
return false;
prop.name.arg = e->name;
strcpy(prop.value, e->value);
if (!pb_encode_submessage(stream, PersistentProperties_PersistentPropertyRecord_fields, &prop))
return false;
free(e->name);
free(e);
}
return true;
}
static bool write_callback(pb_ostream_t *stream, const uint8_t *buf, size_t count) {
int fd = (intptr_t)stream->state;
return xwrite(fd, buf, count) == count;
}
static pb_ostream_t create_ostream(const char *filename) {
int fd = creat(filename, 0644);
pb_ostream_t o = {&write_callback, (void*)(intptr_t)fd, SIZE_MAX, 0};
return o;
}
static void pb_getprop_cb(const char *name, const char *value, void *v) {
struct prop_t *prop = v;
if (prop->name && strcmp(name, prop->name) == 0) {
strcpy(prop->value, value);
prop->name = NULL;
}
}
void persist_getprop_all(struct read_cb_t *read_cb) {
if (access(PERSISTENT_PROPERTY_DIR "/persistent_properties", R_OK) == 0) {
PRINT_D("resetprop: decode with protobuf from [" PERSISTENT_PROPERTY_DIR "/persistent_properties]\n");
PersistentProperties props = PersistentProperties_init_zero;
props.properties.funcs.decode = prop_decode;
props.properties.arg = read_cb;
uint8_t *buf;
size_t size;
mmap_ro(PERSISTENT_PROPERTY_DIR "/persistent_properties", (void **) &buf, &size);
pb_istream_t stream = pb_istream_from_buffer(buf, size);
pb_decode(&stream, PersistentProperties_fields, &props);
munmap(buf, size);
} else {
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;
char *value = persist_getprop(entry->d_name);
if (value) {
read_cb->func(strdup(entry->d_name), value, read_cb->cookie);
free(value);
}
}
}
}
char *persist_getprop(const char *name) {
struct prop_t prop;
prop.name = (char *) name;
if (access(PERSISTENT_PROPERTY_DIR "/persistent_properties", R_OK) == 0) {
struct read_cb_t read_cb = {
.func = pb_getprop_cb,
.cookie = &prop
};
persist_getprop_all(&read_cb);
if (prop.name)
return NULL;
} else {
// 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)
return NULL;
PRINT_D("resetprop: read prop from [%s]\n", path);
prop.value[read(fd, prop.value, sizeof(PROP_VALUE_MAX))] = '\0'; // Null terminate the read value
close(fd);
}
return strdup(prop.value);
}
bool persist_deleteprop(const char *name) {
if (access(PERSISTENT_PROPERTY_DIR "/persistent_properties", R_OK) == 0) {
struct vector v;
vec_init(&v);
struct read_cb_t read_cb = {
.func = collect_props,
.cookie = &v
};
persist_getprop_all(&read_cb);
struct prop_t *p;
bool reencode = false;
vec_for_each(&v, p) {
if (strcmp(p->name, name) == 0) {
// Remove the prop from the list
free(p->name);
free(p);
vec_cur(&v) = NULL;
reencode = true;
break;
}
}
if (reencode) {
// Dump the props back
PersistentProperties props = PersistentProperties_init_zero;
pb_ostream_t ostream = create_ostream(PERSISTENT_PROPERTY_DIR "/persistent_properties.tmp");
props.properties.funcs.encode = prop_encode;
props.properties.arg = &v;
PRINT_D("resetprop: encode with protobuf to [" PERSISTENT_PROPERTY_DIR "/persistent_properties.tmp]\n");
if (!pb_encode(&ostream, PersistentProperties_fields, &props))
return false;
clone_attr(PERSISTENT_PROPERTY_DIR "/persistent_properties", PERSISTENT_PROPERTY_DIR "/persistent_properties.tmp");
rename(PERSISTENT_PROPERTY_DIR "/persistent_properties.tmp", PERSISTENT_PROPERTY_DIR "/persistent_properties");
}
vec_destroy(&v);
return reencode;
} else {
char path[PATH_MAX];
snprintf(path, sizeof(path), PERSISTENT_PROPERTY_DIR "/%s", name);
if (unlink(path) == 0) {
PRINT_D("resetprop: unlink [%s]\n", path);
return true;
}
}
return false;
}

View File

@@ -2,52 +2,6 @@
*
* 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(&current->prop, 0, memory_order_release); // Add this line to nullify the prop entry
* return to_prop_info(&current->prop);
* } else {
*
* ....
* }
*
*
* by patching just those functions directly, all other functions should be ok
* as is.
*
*
*/
#include <stdio.h>
@@ -65,15 +19,11 @@
#include "magisk.h"
#include "resetprop.h"
extern "C" {
#include "_resetprop.h"
#include "vector.h"
}
#include "utils.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;
int prop_verbose = 0;
static int check_legal_property_name(const char *name) {
int namelen = strlen(name);
@@ -129,6 +79,49 @@ static int usage(char* arg0) {
return 1;
}
// The callback passes to __system_property_read_callback2, actually runs the callback in read_cb
static void callback_wrapper(void *read_cb, const char *name, const char *value, uint32_t serial) {
((struct read_cb_t *) read_cb)->func(name, value, ((struct read_cb_t *) read_cb)->cookie);
}
/* **********************************
* Callback functions for read_cb_t
* **********************************/
void collect_props(const char *name, const char *value, void *prop_list) {
struct prop_t *p = (struct prop_t *) xmalloc(sizeof(*p));
p->name = strdup(name);
strcpy(p->value, value);
vec_push_back(prop_list, p);
}
static void collect_unique_props(const char *name, const char *value, void *prop_list) {
struct vector *v = prop_list;
struct prop_t *p;
bool uniq = true;
vec_for_each(v, p) {
if (strcmp(name, p->name) == 0) {
uniq = 0;
break;
}
}
if (uniq)
collect_props(name, value, prop_list);
}
static void store_prop_value(const char *name, const char *value, void *dst) {
strcpy(dst, value);
}
static void prop_foreach_cb(const prop_info* pi, void* read_cb) {
__system_property_read_callback2(pi, callback_wrapper, read_cb);
}
// Comparision function used to sort prop vectors
static int prop_cmp(const void *p1, const void *p2) {
return strcmp(((struct prop_t *) p1)->name, ((struct prop_t *) p2)->name);
}
static int init_resetprop() {
if (__system_properties_init2()) {
PRINT_E("resetprop: Initialize error\n");
@@ -137,16 +130,36 @@ static int init_resetprop() {
return 0;
}
static void print_props(int persist) {
struct prop_t *p;
struct vector prop_list;
vec_init(&prop_list);
getprop_all(collect_props, &prop_list);
if (persist) {
struct read_cb_t read_cb = {
.func = collect_unique_props,
.cookie = &prop_list
};
persist_getprop_all(&read_cb);
}
vec_sort(&prop_list, prop_cmp);
vec_for_each(&prop_list, p) {
printf("[%s]: [%s]\n", p->name, p->value);
free(p->name);
free(p);
}
vec_destroy(&prop_list);
}
/* **************************************************
* Implementations of functions in resetprop.h (APIs)
* **************************************************/
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);
}
@@ -155,103 +168,35 @@ char *getprop(const char *name) {
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:
char *value = persist_getprop(name);
if (value)
return value;
}
PRINT_D("resetprop: prop [%s] does not exist\n", name);
return NULL;
}
} else {
__system_property_read_callback2(pi, read_prop_info, value);
char value[PROP_VALUE_MAX];
struct read_cb_t read_cb = {
.func = store_prop_value,
.cookie = value
};
__system_property_read_callback2(pi, callback_wrapper, &read_cb);
PRINT_D("resetprop: getprop [%s]: [%s]\n", name, value);
return strdup(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*)) {
void getprop_all(void (*callback)(const char *, const char *, void *), void *cookie) {
if (init_resetprop()) return;
struct wrapper wrap = {
.func = callback
struct read_cb_t read_cb = {
.func = callback,
.cookie = cookie
};
__system_property_foreach2(prop_foreach_cb, &wrap);
__system_property_foreach2(prop_foreach_cb, &read_cb);
}
int setprop(const char *name, const char *value) {
@@ -294,7 +239,7 @@ int deleteprop(const char *name) {
return deleteprop2(name, 1);
}
int deleteprop2(const char *name, const int persist) {
int deleteprop2(const char *name, int persist) {
if (check_legal_property_name(name))
return 1;
if (init_resetprop()) return -1;
@@ -302,8 +247,8 @@ int deleteprop2(const char *name, const int persist) {
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);
persist = persist_deleteprop(name);
return __system_property_del(name) && !(persist && strncmp(name, "persist.", 8) == 0);
}
int read_prop_file(const char* filename, const int trigger) {
@@ -336,7 +281,7 @@ int read_prop_file(const char* filename, const int trigger) {
}
if (comment) continue;
pch = strchr(line, '=');
// Ignore ivalid formats
// Ignore invalid formats
if ( ((pch == NULL) || (i >= (pch - line))) || (pch >= line + read - 1) ) continue;
// Separate the string
*pch = '\0';
@@ -367,7 +312,7 @@ int resetprop_main(int argc, char *argv[]) {
goto usage;
}
case 'v':
verbose = 1;
prop_verbose = 1;
continue;
case 'p':
persist = 1;
@@ -390,7 +335,7 @@ int resetprop_main(int argc, char *argv[]) {
switch (argc) {
case 0:
print_all_props(persist);
print_props(persist);
return 0;
case 1:
prop = getprop2(argv[0], persist);

View File

@@ -153,7 +153,7 @@ class prop_area {
}
const prop_info* find(const char* name);
bool del(const char *name); // resetprop add
bool del(const char *name); /* resetprop add */
bool add(const char* name, unsigned int namelen, const char* value, unsigned int valuelen);
bool foreach (void (*propfn)(const prop_info* pi, void* cookie), void* cookie);
@@ -184,7 +184,7 @@ class prop_area {
const prop_info* find_property(prop_bt* const trie, const char* name, uint32_t namelen,
const char* value, uint32_t valuelen, bool alloc_if_needed);
bool find_property_and_del(prop_bt *const trie, const char *name); // resetprop add
bool find_property_and_del(prop_bt *const trie, const char *name); /* resetprop add */
bool foreach_property(prop_bt* const trie, void (*propfn)(const prop_info* pi, void* cookie),
void* cookie);
@@ -283,7 +283,8 @@ static prop_area* map_prop_area_rw(const char* filename, const char* context,
return pa;
}
static prop_area* map_fd_ro(const int fd) {
// resetprop: map the memory as rw
static prop_area* map_fd_rw(const int fd) {
struct stat fd_stat;
if (fstat(fd, &fd_stat) < 0) {
return nullptr;
@@ -298,7 +299,7 @@ static prop_area* map_fd_ro(const int fd) {
pa_size = fd_stat.st_size;
pa_data_size = pa_size - sizeof(prop_area);
void* const map_result = mmap(nullptr, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // resetprop: add PROT_WRITE
void* const map_result = mmap(nullptr, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); /* resetprop: add PROT_WRITE */
if (map_result == MAP_FAILED) {
return nullptr;
}
@@ -313,10 +314,10 @@ static prop_area* map_fd_ro(const int fd) {
}
static prop_area* map_prop_area(const char* filename) {
int fd = open(filename, O_CLOEXEC | O_NOFOLLOW | O_RDWR); // resetprop: O_RDONLY -> O_RDWR
int fd = open(filename, O_CLOEXEC | O_NOFOLLOW | O_RDWR); /* resetprop: O_RDONLY -> O_RDWR */
if (fd == -1) return nullptr;
prop_area* map_result = map_fd_ro(fd);
prop_area* map_result = map_fd_rw(fd);
close(fd);
return map_result;
@@ -530,7 +531,7 @@ bool prop_area::find_property_and_del(prop_bt* const trie, const char* name) {
uint_least32_t prop_offset = atomic_load_explicit(&current->prop, memory_order_relaxed);
if (prop_offset != 0) {
atomic_store_explicit(&current->prop, 0, memory_order_release); // resetprop: nullify the offset to delete the prop
atomic_store_explicit(&current->prop, 0, memory_order_release);
return true;
} else {
return false;
@@ -1116,16 +1117,16 @@ static bool initialize_properties() {
if (!initialize_properties_from_file("/system/etc/selinux/plat_property_contexts")) {
return false;
}
if (!initialize_properties_from_file("/vendor/etc/selinux/nonplat_property_contexts")) {
return false;
}
// Don't check for failure here, so we always have a sane list of properties.
// E.g. In case of recovery, the vendor partition will not have mounted and we
// still need the system / platform properties to function.
initialize_properties_from_file("/vendor/etc/selinux/nonplat_property_contexts") ||
initialize_properties_from_file("/vendor/etc/selinux/vendor_property_contexts");
} else {
if (!initialize_properties_from_file("/plat_property_contexts")) {
return false;
}
if (!initialize_properties_from_file("/nonplat_property_contexts")) {
return false;
}
initialize_properties_from_file("/nonplat_property_contexts");
}
return true;

View File

@@ -344,7 +344,7 @@ void fclone_attr(const int sourcefd, const int targetfd) {
#define UNLABEL_CON "u:object_r:unlabeled:s0"
#define SYSTEM_CON "u:object_r:system_file:s0"
void restorecon(int dirfd, int force) {
void restorecon(int dirfd) {
struct dirent *entry;
DIR *dir;
int fd;
@@ -352,7 +352,7 @@ void restorecon(int dirfd, int force) {
fd_getpath(dirfd, path, sizeof(path));
lgetfilecon(path, &con);
if (force || strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0)
if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0)
lsetfilecon(path, SYSTEM_CON);
freecon(con);
@@ -362,12 +362,12 @@ void restorecon(int dirfd, int force) {
continue;
if (entry->d_type == DT_DIR) {
fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
restorecon(fd, force);
restorecon(fd);
} 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)
if (strlen(con) == 0 || strcmp(con, UNLABEL_CON) == 0)
lsetfilecon(path, SYSTEM_CON);
freecon(con);
}
@@ -379,7 +379,7 @@ void restorecon(int dirfd, int force) {
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);
int fd = xopen(filename, (rw ? O_RDWR : O_RDONLY) | O_CLOEXEC);
fstat(fd, &st);
if (S_ISBLK(st.st_mode))
ioctl(fd, BLKGETSIZE64, size);
@@ -407,7 +407,7 @@ void fd_full_read(int fd, void **buf, size_t *size) {
}
void full_read(const char *filename, void **buf, size_t *size) {
int fd = xopen(filename, O_RDONLY);
int fd = xopen(filename, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
*buf = NULL;
*size = 0;
@@ -418,7 +418,7 @@ 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) {
int fd = xopenat(dirfd, filename, O_RDONLY);
int fd = xopenat(dirfd, filename, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
*buf = NULL;
*size = 0;

View File

@@ -17,7 +17,7 @@ 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);
pid = exec_command(1, &fd, NULL, "/system/bin/e2fsck", "-yf", img, NULL);
if (pid < 0)
return 1;
while (fdgets(buffer, sizeof(buffer), fd))
@@ -58,11 +58,13 @@ int create_img(const char *img, int size) {
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;
char size_str[16];
snprintf(size_str, sizeof(size_str), "%dM", size);
ret = exec_command_sync("/system/bin/make_ext4fs", "-b", "4096", "-l", size_str, img, NULL);
if (ret < 0) {
// On Android P there is no make_ext4fs, use mke2fs
ret = exec_command_sync("/system/bin/mke2fs", "-b", "4096", "-t", "ext4", img, size_str, NULL);
}
return ret;
}
@@ -71,7 +73,7 @@ int get_img_size(const char *img, int *used, int *total) {
return 1;
char buffer[PATH_MAX];
int pid, fd = -1, status = 1;
pid = exec_command(1, &fd, NULL, "e2fsck", "-n", img, NULL);
pid = exec_command(1, &fd, NULL, "/system/bin/e2fsck", "-n", img, NULL);
if (pid < 0)
return 1;
while (fdgets(buffer, sizeof(buffer), fd)) {
@@ -103,7 +105,7 @@ int resize_img(const char *img, int size) {
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);
pid = exec_command(1, &fd, NULL, "/system/bin/resize2fs", img, buffer, NULL);
if (pid < 0)
return 1;
while (fdgets(buffer, sizeof(buffer), fd))

View File

@@ -280,7 +280,7 @@ static int v_exec_command(int err, int *fd, void (*setupenv)(struct vector*), co
}
execvpe(argv0, (char **) vec_entry(&args), envp);
PLOGE("execvpe");
PLOGE("execvpe %s", argv0);
return -1;
}

View File

@@ -84,16 +84,14 @@ chmod -R 755 .
CHROMEOS=false
ui_print "- Unpacking boot image"
./magiskboot --unpack "$BOOTIMAGE"
eval $LIB32PFX ./magiskboot --unpack "$BOOTIMAGE"
case $? in
1 )
abort "! Unable to unpack boot image"
;;
2 )
ui_print "! Insufficient boot partition size detected"
HIGHCOMP=true
ui_print "- Enable high compression mode"
;;
3 )
ui_print "- ChromeOS boot image detected"
@@ -114,38 +112,53 @@ esac
# Test patch status and do restore, after this section, ramdisk.cpio.orig is guaranteed to exist
ui_print "- Checking ramdisk status"
./magiskboot --cpio ramdisk.cpio test
MAGISK_PATCHED=false
eval $LIB32PFX ./magiskboot --cpio ramdisk.cpio test
case $? in
0 ) # Stock boot
ui_print "- Stock boot image detected"
ui_print "- Backing up stock boot image"
SHA1=`./magiskboot --sha1 "$BOOTIMAGE" 2>/dev/null`
SHA1=`eval $LIB32PFX ./magiskboot --sha1 "$BOOTIMAGE" 2>/dev/null`
STOCKDUMP=stock_boot_${SHA1}.img.gz
./magiskboot --compress "$BOOTIMAGE" $STOCKDUMP
eval $LIB32PFX ./magiskboot --compress "$BOOTIMAGE" $STOCKDUMP
cp -af ramdisk.cpio ramdisk.cpio.orig
;;
1 ) # Magisk patched
ui_print "- Magisk patched image detected"
# Find SHA1 of stock boot image
[ -z $SHA1 ] && SHA1=`./magiskboot --cpio ramdisk.cpio sha1 2>/dev/null`
./magiskboot --cpio ramdisk.cpio restore
cp -af ramdisk.cpio ramdisk.cpio.orig
MAGISK_PATCHED=true
HIGHCOMP=false
;;
2 ) # Other patched
2 ) # High compression mode
MAGISK_PATCHED=true
HIGHCOMP=true
;;
3 ) # Other patched
ui_print "! Boot image patched by other programs"
abort "! Please restore stock boot image"
;;
esac
if $MAGISK_PATCHED; then
ui_print "- Magisk patched image detected"
# Find SHA1 of stock boot image
[ -z $SHA1 ] && SHA1=`eval $LIB32PFX ./magiskboot --cpio ramdisk.cpio sha1 2>/dev/null`
eval $LIB32PFX ./magiskboot --cpio ramdisk.cpio restore
cp -af ramdisk.cpio ramdisk.cpio.orig
fi
if $HIGHCOMP; then
ui_print "! Insufficient boot partition size detected"
ui_print "- Enable high compression mode"
fi
##########################################################################################
# Ramdisk patches
##########################################################################################
ui_print "- Patching ramdisk"
./magiskboot --cpio ramdisk.cpio \
'add 750 init magiskinit' \
"magisk ramdisk.cpio.orig $HIGHCOMP $KEEPVERITY $KEEPFORCEENCRYPT $SHA1"
eval $LIB32PFX ./magiskboot --cpio ramdisk.cpio \
\"add 750 init magiskinit\" \
\"magisk ramdisk.cpio.orig $HIGHCOMP $KEEPVERITY $KEEPFORCEENCRYPT $SHA1\"
rm -f ramdisk.cpio.orig
@@ -154,17 +167,17 @@ rm -f ramdisk.cpio.orig
##########################################################################################
if ! $KEEPVERITY && [ -f dtb ]; then
./magiskboot --dtb-patch dtb && ui_print "- Patching fstab in dtb to remove dm-verity"
eval $LIB32PFX ./magiskboot --dtb-patch dtb && ui_print "- Patching fstab in dtb to remove dm-verity"
fi
if [ -f kernel ]; then
# Remove Samsung RKP in stock kernel
./magiskboot --hexpatch kernel \
eval $LIB32PFX ./magiskboot --hexpatch kernel \
49010054011440B93FA00F71E9000054010840B93FA00F7189000054001840B91FA00F7188010054 \
A1020054011440B93FA00F7140020054010840B93FA00F71E0010054001840B91FA00F7181010054
# skip_initramfs -> want_initramfs
./magiskboot --hexpatch kernel \
eval $LIB32PFX ./magiskboot --hexpatch kernel \
736B69705F696E697472616D6673 \
77616E745F696E697472616D6673
fi
@@ -174,9 +187,9 @@ fi
##########################################################################################
ui_print "- Repacking boot image"
./magiskboot --repack "$BOOTIMAGE" || abort "! Unable to repack boot image!"
eval $LIB32PFX ./magiskboot --repack "$BOOTIMAGE" || abort "! Unable to repack boot image!"
# Sign chromeos boot
$CHROMEOS && sign_chromeos
./magiskboot --cleanup
eval $LIB32PFX ./magiskboot --cleanup

View File

@@ -69,7 +69,7 @@ api_level_arch_detect
ui_print "- Device platform: $ARCH"
BINDIR=$INSTALLER/$ARCH
BINDIR=$INSTALLER/$ARCH32
chmod -R 755 $CHROMEDIR $BINDIR
# Check if system root is installed and remove
@@ -105,7 +105,7 @@ chmod -R 755 $MAGISKBIN
if [ -d /system/addon.d ]; then
ui_print "- Adding addon.d survival script"
mount -o rw,remount /system
cp -af $INSTALLER/addon.d/99-magisk.sh /system/addon.d/99-magisk.sh
cp -af $INSTALLER/common/99-magisk.sh /system/addon.d/99-magisk.sh
chmod 755 /system/addon.d/99-magisk.sh
fi

View File

@@ -45,7 +45,7 @@ cd $MAGISKBIN
ui_print "- Found Boot Image: $BOOTIMAGE"
ui_print "- Unpacking boot image"
./magiskboot --unpack "$BOOTIMAGE"
eval $LIB32PFX ./magiskboot --unpack "$BOOTIMAGE"
CHROMEOS=false
case $? in
@@ -67,29 +67,29 @@ esac
# Detect boot image state
ui_print "- Checking ramdisk status"
./magiskboot --cpio ramdisk.cpio test
eval $LIB32PFX ./magiskboot --cpio ramdisk.cpio test
case $? in
0 ) # Stock boot
ui_print "- Stock boot image detected"
abort "! Magisk is not installed!"
;;
1 ) # Magisk patched
1|2 ) # Magisk patched
ui_print "- Magisk patched image detected"
# Find SHA1 of stock boot image
[ -z $SHA1 ] && SHA1=`./magiskboot --cpio ramdisk.cpio sha1 2>/dev/null`
[ -z $SHA1 ] && SHA1=`eval $LIB32PFX ./magiskboot --cpio ramdisk.cpio sha1 2>/dev/null`
OK=false
[ ! -z $SHA1 ] && restore_imgs $SHA1 && OK=true
if ! $OK; then
ui_print "! Boot image backup unavailable"
ui_print "- Restoring ramdisk with internal backup"
./magiskboot --cpio ramdisk.cpio restore
./magiskboot --repack $BOOTIMAGE
eval $LIB32PFX ./magiskboot --cpio ramdisk.cpio restore
eval $LIB32PFX ./magiskboot --repack $BOOTIMAGE
# Sign chromeos boot
$CHROMEOS && sign_chromeos
flash_boot_image new-boot.img "$BOOTIMAGE"
fi
;;
2 ) # Other patched
3 ) # Other patched
ui_print "! Boot image patched by other programs"
abort "! Cannot uninstall"
;;
@@ -103,4 +103,4 @@ rm -rf /cache/*magisk* /cache/unblock /data/*magisk* /data/cache/*magisk* /data
/data/user*/*/magisk.db /data/user*/*/com.topjohnwu.magisk /data/user*/*/.tmp.magisk.config \
/data/adb/*magisk* 2>/dev/null
$BOOTMODE && reboot
$BOOTMODE && /system/bin/reboot

View File

@@ -20,7 +20,7 @@ MAGISKBIN=/data/adb/magisk
[ -z $MOUNTPATH ] && MOUNTPATH=/sbin/.core/img
[ -z $IMG ] && IMG=/data/adb/magisk.img
BOOTSIGNER="/system/bin/dalvikvm -Xnodex2oat -Xnoimage-dex2oat -cp \$APK com.topjohnwu.magisk.utils.BootSigner"
BOOTSIGNER="eval \$LIBPFX /system/bin/dalvikvm -Xnodex2oat -Xnoimage-dex2oat -cp \$APK com.topjohnwu.magisk.utils.BootSigner"
BOOTSIGNED=false
get_outfd() {
@@ -128,15 +128,15 @@ find_boot_image() {
run_migrations() {
# Update the broken boot backup
if [ -f /data/stock_boot_.img.gz ]; then
$MAGISKBIN/magiskboot --decompress /data/stock_boot_.img.gz /data/stock_boot.img
eval $LIB32PFX $MAGISKBIN/magiskboot --decompress /data/stock_boot_.img.gz /data/stock_boot.img
fi
# Update our previous backup to new format if exists
if [ -f /data/stock_boot.img ]; then
ui_print "- Migrating boot image backup"
SHA1=`$MAGISKBIN/magiskboot --sha1 /data/stock_boot.img 2>/dev/null`
SHA1=`eval $LIB32PFX $MAGISKBIN/magiskboot --sha1 /data/stock_boot.img 2>/dev/null`
STOCKDUMP=/data/stock_boot_${SHA1}.img
mv /data/stock_boot.img $STOCKDUMP
$MAGISKBIN/magiskboot --compress $STOCKDUMP
eval $LIB32PFX $MAGISKBIN/magiskboot --compress $STOCKDUMP
fi
# Move the stock backups
if [ -f /data/magisk/stock_boot* ]; then
@@ -154,7 +154,7 @@ run_migrations() {
flash_boot_image() {
# Make sure all blocks are writable
$MAGISKBIN/magisk --unlock-blocks 2>/dev/null
eval $LIB32PFX $MAGISKBIN/magisk --unlock-blocks 2>/dev/null
case "$1" in
*.gz) COMMAND="gzip -d < '$1'";;
*) COMMAND="cat '$1'";;
@@ -184,11 +184,11 @@ find_dtbo_image() {
patch_dtbo_image() {
if [ ! -z $DTBOIMAGE ]; then
if $MAGISKBIN/magiskboot --dtb-test $DTBOIMAGE; then
if eval $LIB32PFX $MAGISKBIN/magiskboot --dtb-test $DTBOIMAGE; then
ui_print "- Backing up stock dtbo image"
$MAGISKBIN/magiskboot --compress $DTBOIMAGE $MAGISKBIN/stock_dtbo.img.gz
eval $LIB32PFX $MAGISKBIN/magiskboot --compress $DTBOIMAGE $MAGISKBIN/stock_dtbo.img.gz
ui_print "- Patching fstab in dtbo to remove avb-verity"
$MAGISKBIN/magiskboot --dtb-patch $DTBOIMAGE
eval $LIB32PFX $MAGISKBIN/magiskboot --dtb-patch $DTBOIMAGE
return 0
fi
fi
@@ -200,7 +200,7 @@ restore_imgs() {
STOCKDTBO=/data/stock_dtbo.img.gz
# Make sure all blocks are writable
$MAGISKBIN/magisk --unlock-blocks 2>/dev/null
eval $LIB32PFX $MAGISKBIN/magisk --unlock-blocks 2>/dev/null
find_dtbo_image
if [ ! -z "$DTBOIMAGE" -a -f "$STOCKDTBO" ]; then
ui_print "- Restoring stock dtbo image"
@@ -220,7 +220,7 @@ sign_chromeos() {
ui_print "- Signing ChromeOS boot image"
echo > empty
./chromeos/futility vbutil_kernel --pack new-boot.img.signed \
eval $LIBPFX ./chromeos/futility vbutil_kernel --pack new-boot.img.signed \
--keyblock ./chromeos/kernel.keyblock --signprivate ./chromeos/kernel_data_key.vbprivk \
--version 1 --vmlinuz new-boot.img --config empty --arch arm --bootloader empty --flags 0x1
@@ -266,11 +266,12 @@ api_level_arch_detect() {
ABILONG=`grep_prop ro.product.cpu.abi`
ARCH=arm
ARCH32=arm
IS64BIT=false
if [ "$ABI" = "x86" ]; then ARCH=x86; fi;
if [ "$ABI2" = "x86" ]; then ARCH=x86; fi;
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=true; fi;
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=true; fi;
if [ "$ABI" = "x86" ]; then ARCH=x86; ARCH32=x86; fi;
if [ "$ABI2" = "x86" ]; then ARCH=x86; ARCH32=x86; fi;
if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; ARCH32=arm; IS64BIT=true; fi;
if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; ARCH32=x86; IS64BIT=true; fi;
}
boot_actions() {
@@ -286,7 +287,6 @@ recovery_actions() {
mount -o bind /dev/urandom /dev/random
# Preserve environment varibles
OLD_PATH=$PATH
OLD_LD_PATH=$LD_LIBRARY_PATH
if [ ! -d $TMPDIR/bin ]; then
# Add busybox to PATH
mkdir -p $TMPDIR/bin
@@ -296,13 +296,13 @@ recovery_actions() {
fi
# Temporarily block out all custom recovery binaries/libs
mv /sbin /sbin_tmp
# Add all possible library paths
$IS64BIT && export LD_LIBRARY_PATH=/system/lib64:/system/vendor/lib64 || export LD_LIBRARY_PATH=/system/lib:/system/vendor/lib
# Set library paths
$IS64BIT && LIBPFX="LD_LIBRARY_PATH=/system/lib64:/system/vendor/lib64" || LIBPFX="LD_LIBRARY_PATH=/system/lib:/system/vendor/lib"
LIB32PFX="LD_LIBRARY_PATH=/system/lib:/system/vendor/lib"
}
recovery_cleanup() {
mv /sbin_tmp /sbin 2>/dev/null
export LD_LIBRARY_PATH=$OLD_LD_PATH
[ -z $OLD_PATH ] || export PATH=$OLD_PATH
ui_print "- Unmounting partitions"
umount -l /system_root 2>/dev/null
@@ -348,7 +348,7 @@ request_zip_size_check() {
}
image_size_check() {
SIZE="`$MAGISKBIN/magisk --imgsize $IMG`"
SIZE="`eval $LIB32PFX $MAGISKBIN/magisk --imgsize $IMG`"
curUsedM=`echo "$SIZE" | cut -d" " -f1`
curSizeM=`echo "$SIZE" | cut -d" " -f2`
curFreeM=$((curSizeM - curUsedM))
@@ -362,28 +362,28 @@ mount_magisk_img() {
if [ "$reqSizeM" -gt "$curFreeM" ]; then
newSizeM=$(((reqSizeM + curUsedM) / 32 * 32 + 64))
ui_print "- Resizing $IMG to ${newSizeM}M"
$MAGISKBIN/magisk --resizeimg $IMG $newSizeM >&2
eval $LIB32PFX $MAGISKBIN/magisk --resizeimg $IMG $newSizeM >&2
fi
else
newSizeM=$((reqSizeM / 32 * 32 + 64));
ui_print "- Creating $IMG with size ${newSizeM}M"
$MAGISKBIN/magisk --createimg $IMG $newSizeM >&2
eval $LIB32PFX $MAGISKBIN/magisk --createimg $IMG $newSizeM >&2
fi
ui_print "- Mounting $IMG to $MOUNTPATH"
MAGISKLOOP=`$MAGISKBIN/magisk --mountimg $IMG $MOUNTPATH`
MAGISKLOOP=`eval $LIB32PFX $MAGISKBIN/magisk --mountimg $IMG $MOUNTPATH`
is_mounted $MOUNTPATH || abort "! $IMG mount failed..."
}
unmount_magisk_img() {
$MAGISKBIN/magisk --umountimg $MOUNTPATH $MAGISKLOOP
eval $LIB32PFX $MAGISKBIN/magisk --umountimg $MOUNTPATH $MAGISKLOOP
# Shrink the image if possible
image_size_check $IMG
newSizeM=$((curUsedM / 32 * 32 + 64))
if [ $curSizeM -gt $newSizeM ]; then
ui_print "- Shrinking $IMG to ${newSizeM}M"
$MAGISKBIN/magisk --resizeimg $IMG $newSizeM
eval $LIB32PFX $MAGISKBIN/magisk --resizeimg $IMG $newSizeM
fi
}

View File

@@ -1,13 +1,13 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
buildToolsVersion "27.0.3"
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "com.topjohnwu.snet"
minSdkVersion 21
targetSdkVersion 27
targetSdkVersion rootProject.ext.compileSdkVersion
versionCode 1
versionName "1.0"
}
@@ -20,10 +20,6 @@ android {
}
}
repositories {
google()
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.google.android.gms:play-services-safetynet:7.0.0' /* The oldest version */

View File

@@ -494,6 +494,7 @@ public class SignAPK {
outputStream.write(total_size & 0xff);
outputStream.write((total_size >> 8) & 0xff);
temp.writeTo(outputStream);
outputStream.close();
}
private static void signFile(Manifest manifest, JarMap inputJar,
X509Certificate publicKey, PrivateKey privateKey,