Unify Magisk configuration
Introduce monogisk tool
This commit is contained in:
parent
8d6f3c2450
commit
e710848345
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
out/
|
||||
obj/
|
||||
libs/
|
||||
*.zip
|
||||
|
355
build.py
355
build.py
@ -38,23 +38,36 @@ import shutil
|
||||
import lzma
|
||||
import base64
|
||||
|
||||
def silentremove(file):
|
||||
def mv(source, target):
|
||||
print('mv: {} -> {}'.format(source, target))
|
||||
shutil.move(source, target)
|
||||
|
||||
def cp(source, target):
|
||||
print('cp: {} -> {}'.format(source, target))
|
||||
shutil.copyfile(source, target)
|
||||
|
||||
def rm(file):
|
||||
try:
|
||||
os.remove(file)
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
def mkdir(path, mode=0o777):
|
||||
try:
|
||||
os.mkdir(path, mode)
|
||||
except:
|
||||
pass
|
||||
|
||||
def mkdir_p(path, mode=0o777):
|
||||
os.makedirs(path, mode, exist_ok=True)
|
||||
|
||||
def zip_with_msg(zipfile, source, target):
|
||||
if not os.path.exists(source):
|
||||
error('{} does not exist! Try build \'binary\' and \'apk\' before zipping!'.format(source))
|
||||
print('zip: {} -> {}'.format(source, target))
|
||||
zipfile.write(source, target)
|
||||
|
||||
def cp(source, target):
|
||||
print('cp: {} -> {}'.format(source, target))
|
||||
shutil.copyfile(source, target)
|
||||
|
||||
def build_all(args):
|
||||
build_binary(args)
|
||||
build_apk(args)
|
||||
@ -67,13 +80,40 @@ def build_binary(args):
|
||||
# Force update Android.mk timestamp to trigger recompilation
|
||||
os.utime(os.path.join('jni', 'Android.mk'))
|
||||
|
||||
ndk_build = os.path.join(os.environ['ANDROID_HOME'], 'ndk-bundle', 'ndk-build')
|
||||
debug_flag = '' if args.release else '-DMAGISK_DEBUG'
|
||||
proc = subprocess.run('{} APP_CFLAGS=\"-DMAGISK_VERSION=\\\"{}\\\" -DMAGISK_VER_CODE={} {}\" -j{}'.format(
|
||||
ndk_build, args.versionString, args.versionCode, debug_flag, multiprocessing.cpu_count()), shell=True)
|
||||
cflag = 'APP_CFLAGS=\"-DMAGISK_VERSION=\\\"{}\\\" -DMAGISK_VER_CODE={} {}\"'.format(args.versionString, args.versionCode, debug_flag)
|
||||
|
||||
ndk_build = os.path.join(os.environ['ANDROID_HOME'], 'ndk-bundle', 'ndk-build')
|
||||
# Prebuild
|
||||
proc = subprocess.run('PRECOMPILE=true {} {} -j{}'.format(ndk_build, cflag, multiprocessing.cpu_count()), shell=True)
|
||||
if proc.returncode != 0:
|
||||
error('Build Magisk binary failed!')
|
||||
|
||||
print('')
|
||||
for arch in ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']:
|
||||
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')
|
||||
for binary in ['magisk', 'magiskinit']:
|
||||
mv(os.path.join('libs', arch, binary), os.path.join('out', arch, binary))
|
||||
with open(os.path.join('out', arch, binary), 'rb') as bin:
|
||||
dump.write('const uint8_t {}_dump[] = "'.format(binary))
|
||||
dump.write(''.join("\\x{:02X}".format(c) for c in lzma.compress(bin.read(), preset=9)))
|
||||
dump.write('";\n')
|
||||
print('')
|
||||
|
||||
proc = subprocess.run('{} {} -j{}'.format(ndk_build, cflag, multiprocessing.cpu_count()), shell=True)
|
||||
if proc.returncode != 0:
|
||||
error('Build Magisk binary failed!')
|
||||
|
||||
print('')
|
||||
for arch in ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']:
|
||||
for binary in ['monogisk', 'magiskboot', 'b64xz', 'busybox']:
|
||||
try:
|
||||
mv(os.path.join('libs', arch, binary), os.path.join('out', arch, binary))
|
||||
except:
|
||||
pass
|
||||
|
||||
def build_apk(args):
|
||||
header('* Building Magisk Manager')
|
||||
|
||||
@ -104,8 +144,8 @@ def build_apk(args):
|
||||
# Find the latest build tools
|
||||
build_tool = sorted(os.listdir(os.path.join(os.environ['ANDROID_HOME'], 'build-tools')))[-1]
|
||||
|
||||
silentremove(aligned)
|
||||
silentremove(release)
|
||||
rm(aligned)
|
||||
rm(release)
|
||||
|
||||
proc = subprocess.run([
|
||||
os.path.join(os.environ['ANDROID_HOME'], 'build-tools', build_tool, 'zipalign'),
|
||||
@ -129,13 +169,24 @@ def build_apk(args):
|
||||
if proc.returncode != 0:
|
||||
error('Release sign Magisk Manager failed!')
|
||||
|
||||
silentremove(unsigned)
|
||||
silentremove(aligned)
|
||||
rm(unsigned)
|
||||
rm(aligned)
|
||||
|
||||
mkdir(os.path.join('..', 'out'))
|
||||
target = os.path.join('..', 'out', 'app-release.apk')
|
||||
print('')
|
||||
mv(release, target)
|
||||
else:
|
||||
proc = subprocess.run('{} app:assembleDebug'.format(os.path.join('.', 'gradlew')), shell=True)
|
||||
if proc.returncode != 0:
|
||||
error('Build Magisk Manager failed!')
|
||||
|
||||
source = os.path.join('app', 'build', 'outputs', 'apk', 'debug', 'app-debug.apk')
|
||||
mkdir(os.path.join('..', 'out'))
|
||||
target = os.path.join('..', 'out', 'app-debug.apk')
|
||||
print('')
|
||||
mv(source, target)
|
||||
|
||||
# Return to upper directory
|
||||
os.chdir('..')
|
||||
|
||||
@ -145,11 +196,137 @@ def build_snet(args):
|
||||
if proc.returncode != 0:
|
||||
error('Build snet extention failed!')
|
||||
source = os.path.join('snet', 'build', 'outputs', 'apk', 'release', 'snet-release-unsigned.apk')
|
||||
target = os.path.join('..', 'snet.apk')
|
||||
mkdir(os.path.join('..', 'out'))
|
||||
target = os.path.join('..', 'out', 'snet.apk')
|
||||
print('')
|
||||
cp(source, target)
|
||||
mv(source, target)
|
||||
os.chdir('..')
|
||||
|
||||
def gen_update_binary():
|
||||
update_bin = []
|
||||
binary = os.path.join('out', 'armeabi-v7a', 'b64xz')
|
||||
if not os.path.exists(binary):
|
||||
error('Please build \'binary\' before zipping!')
|
||||
with open(binary, 'rb') as b64xz:
|
||||
update_bin.append('#! /sbin/sh\nEX_ARM=\'')
|
||||
update_bin.append(''.join("\\x{:02X}".format(c) for c in b64xz.read()))
|
||||
binary = os.path.join('out', 'x86', 'b64xz')
|
||||
with open(binary, 'rb') as b64xz:
|
||||
update_bin.append('\'\nEX_X86=\'')
|
||||
update_bin.append(''.join("\\x{:02X}".format(c) for c in b64xz.read()))
|
||||
binary = os.path.join('out', 'armeabi-v7a', 'busybox')
|
||||
with open(binary, 'rb') as busybox:
|
||||
update_bin.append('\'\nBB_ARM=')
|
||||
update_bin.append(base64.b64encode(lzma.compress(busybox.read(), preset=9)).decode('ascii'))
|
||||
binary = os.path.join('out', 'x86', 'busybox')
|
||||
with open(binary, 'rb') as busybox:
|
||||
update_bin.append('\nBB_X86=')
|
||||
update_bin.append(base64.b64encode(lzma.compress(busybox.read(), preset=9)).decode('ascii'))
|
||||
update_bin.append('\n')
|
||||
with open(os.path.join('scripts', 'update_binary.sh'), 'r') as script:
|
||||
update_bin.append(script.read())
|
||||
return ''.join(update_bin)
|
||||
|
||||
def zip_main(args):
|
||||
header('* Packing Flashable Zip')
|
||||
|
||||
with zipfile.ZipFile('tmp_unsigned.zip', 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf:
|
||||
# META-INF
|
||||
# update-binary
|
||||
target = os.path.join('META-INF', 'com', 'google', 'android', 'update-binary')
|
||||
print('zip: ' + target)
|
||||
zipf.writestr(target, gen_update_binary())
|
||||
# updater-script
|
||||
source = os.path.join('scripts', 'flash_script.sh')
|
||||
target = os.path.join('META-INF', 'com', 'google', 'android', 'updater-script')
|
||||
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 binary in ['monogisk', 'magiskboot']:
|
||||
source = os.path.join('out', lib_dir, binary)
|
||||
target = os.path.join(zip_dir, binary)
|
||||
zip_with_msg(zipf, source, target)
|
||||
|
||||
# APK
|
||||
source = os.path.join('out', 'app-release.apk' if args.release else 'app-debug.apk')
|
||||
target = os.path.join('common', 'magisk.apk')
|
||||
zip_with_msg(zipf, source, target)
|
||||
|
||||
# Scripts
|
||||
# boot_patch.sh
|
||||
source = os.path.join('scripts', 'boot_patch.sh')
|
||||
target = os.path.join('common', 'boot_patch.sh')
|
||||
zip_with_msg(zipf, source, target)
|
||||
# util_functions.sh
|
||||
source = os.path.join('scripts', 'util_functions.sh')
|
||||
with open(source, 'r') as script:
|
||||
# Add version info util_functions.sh
|
||||
util_func = script.read().replace(
|
||||
'MAGISK_VERSION_STUB', 'MAGISK_VER="{}"\nMAGISK_VER_CODE={}'.format(args.versionString, args.versionCode))
|
||||
target = os.path.join('common', 'util_functions.sh')
|
||||
print('zip: ' + source + ' -> ' + target)
|
||||
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')
|
||||
zip_with_msg(zipf, source, target)
|
||||
|
||||
# Prebuilts
|
||||
for chromeos in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']:
|
||||
source = os.path.join('chromeos', chromeos)
|
||||
zip_with_msg(zipf, source, source)
|
||||
|
||||
# End of zipping
|
||||
|
||||
output = os.path.join('out', 'Magisk-v{}.zip'.format(args.versionString))
|
||||
sign_adjust_zip('tmp_unsigned.zip', output)
|
||||
|
||||
def zip_uninstaller(args):
|
||||
header('* Packing Uninstaller Zip')
|
||||
|
||||
with zipfile.ZipFile('tmp_unsigned.zip', 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf:
|
||||
# META-INF
|
||||
# update-binary
|
||||
target = os.path.join('META-INF', 'com', 'google', 'android', 'update-binary')
|
||||
print('zip: ' + target)
|
||||
zipf.writestr(target, gen_update_binary())
|
||||
# updater-script
|
||||
source = os.path.join('scripts', 'uninstaller_loader.sh')
|
||||
target = os.path.join('META-INF', 'com', 'google', 'android', 'updater-script')
|
||||
zip_with_msg(zipf, source, target)
|
||||
|
||||
# Binaries
|
||||
for lib_dir, zip_dir in [('arm64-v8a', 'arm64'), ('armeabi-v7a', 'arm'), ('x86', 'x86'), ('x86_64', 'x64')]:
|
||||
source = os.path.join('out', lib_dir, 'magiskboot')
|
||||
target = os.path.join(zip_dir, 'magiskboot')
|
||||
zip_with_msg(zipf, source, target)
|
||||
|
||||
source = os.path.join('scripts', 'magisk_uninstaller.sh')
|
||||
target = 'magisk_uninstaller.sh'
|
||||
zip_with_msg(zipf, source, target)
|
||||
|
||||
# Scripts
|
||||
# util_functions.sh
|
||||
source = os.path.join('scripts', 'util_functions.sh')
|
||||
with open(source, 'r') as script:
|
||||
# Remove the stub
|
||||
util_func = script.read().replace(
|
||||
'MAGISK_VERSION_STUB', '')
|
||||
target = os.path.join('util_functions.sh')
|
||||
print('zip: ' + source + ' -> ' + target)
|
||||
zipf.writestr(target, util_func)
|
||||
|
||||
# Prebuilts
|
||||
for chromeos in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']:
|
||||
source = os.path.join('chromeos', chromeos)
|
||||
zip_with_msg(zipf, source, source)
|
||||
|
||||
# End of zipping
|
||||
|
||||
output = os.path.join('out', 'Magisk-uninstaller-{}.zip'.format(datetime.datetime.now().strftime('%Y%m%d')))
|
||||
sign_adjust_zip('tmp_unsigned.zip', output)
|
||||
|
||||
def sign_adjust_zip(unsigned, output):
|
||||
signer_name = 'zipsigner-1.0.jar'
|
||||
jarsigner = os.path.join('java', 'crypto', 'build', 'libs', signer_name)
|
||||
@ -191,142 +368,9 @@ def sign_adjust_zip(unsigned, output):
|
||||
error('Second sign flashable zip failed!')
|
||||
|
||||
# Cleanup
|
||||
silentremove(unsigned)
|
||||
silentremove('tmp_signed.zip')
|
||||
silentremove('tmp_adjusted.zip')
|
||||
|
||||
def gen_update_binary():
|
||||
update_bin = []
|
||||
binary = os.path.join('libs', 'armeabi-v7a', 'b64xz')
|
||||
if not os.path.exists(binary):
|
||||
error('Please build \'binary\' before zipping!')
|
||||
with open(binary, 'rb') as b64xz:
|
||||
update_bin.append('#! /sbin/sh\nEX_ARM=\'')
|
||||
update_bin.append(''.join("\\x{:02X}".format(c) for c in b64xz.read()))
|
||||
binary = os.path.join('libs', 'x86', 'b64xz')
|
||||
with open(binary, 'rb') as b64xz:
|
||||
update_bin.append('\'\nEX_X86=\'')
|
||||
update_bin.append(''.join("\\x{:02X}".format(c) for c in b64xz.read()))
|
||||
binary = os.path.join('libs', 'armeabi-v7a', 'busybox')
|
||||
with open(binary, 'rb') as busybox:
|
||||
update_bin.append('\'\nBB_ARM=')
|
||||
update_bin.append(base64.b64encode(lzma.compress(busybox.read())).decode('ascii'))
|
||||
binary = os.path.join('libs', 'x86', 'busybox')
|
||||
with open(binary, 'rb') as busybox:
|
||||
update_bin.append('\nBB_X86=')
|
||||
update_bin.append(base64.b64encode(lzma.compress(busybox.read())).decode('ascii'))
|
||||
update_bin.append('\n')
|
||||
with open(os.path.join('scripts', 'update_binary.sh'), 'r') as script:
|
||||
update_bin.append(script.read())
|
||||
return ''.join(update_bin)
|
||||
|
||||
def zip_main(args):
|
||||
header('* Packing Flashable Zip')
|
||||
|
||||
with zipfile.ZipFile('tmp_unsigned.zip', 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf:
|
||||
# META-INF
|
||||
# update-binary
|
||||
target = os.path.join('META-INF', 'com', 'google', 'android', 'update-binary')
|
||||
print('zip: ' + target)
|
||||
zipf.writestr(target, gen_update_binary())
|
||||
# updater-script
|
||||
source = os.path.join('scripts', 'flash_script.sh')
|
||||
target = os.path.join('META-INF', 'com', 'google', 'android', 'updater-script')
|
||||
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 binary in ['magisk', 'magiskboot']:
|
||||
source = os.path.join('libs', lib_dir, binary)
|
||||
target = os.path.join(zip_dir, binary)
|
||||
zip_with_msg(zipf, source, target)
|
||||
source = os.path.join('libs', 'arm64-v8a', 'magiskinit')
|
||||
target = os.path.join('arm64', 'magiskinit')
|
||||
zip_with_msg(zipf, source, target)
|
||||
|
||||
# APK
|
||||
source = os.path.join('java', 'app', 'build', 'outputs', 'apk',
|
||||
'release' if args.release else 'debug', 'app-release.apk' if args.release else 'app-debug.apk')
|
||||
target = os.path.join('common', 'magisk.apk')
|
||||
zip_with_msg(zipf, source, target)
|
||||
|
||||
# Scripts
|
||||
# boot_patch.sh
|
||||
source = os.path.join('scripts', 'boot_patch.sh')
|
||||
target = os.path.join('common', 'boot_patch.sh')
|
||||
zip_with_msg(zipf, source, target)
|
||||
# util_functions.sh
|
||||
source = os.path.join('scripts', 'util_functions.sh')
|
||||
with open(source, 'r') as script:
|
||||
# Add version info util_functions.sh
|
||||
util_func = script.read().replace(
|
||||
'MAGISK_VERSION_STUB', 'MAGISK_VER="{}"\nMAGISK_VER_CODE={}'.format(args.versionString, args.versionCode))
|
||||
target = os.path.join('common', 'util_functions.sh')
|
||||
print('zip: ' + source + ' -> ' + target)
|
||||
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')
|
||||
zip_with_msg(zipf, source, target)
|
||||
# init.magisk.rc
|
||||
source = os.path.join('scripts', 'init.magisk.rc')
|
||||
target = os.path.join('common', 'init.magisk.rc')
|
||||
zip_with_msg(zipf, source, target)
|
||||
|
||||
# Prebuilts
|
||||
for chromeos in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']:
|
||||
source = os.path.join('chromeos', chromeos)
|
||||
zip_with_msg(zipf, source, source)
|
||||
|
||||
# End of zipping
|
||||
|
||||
output = 'Magisk-v{}.zip'.format(args.versionString)
|
||||
sign_adjust_zip('tmp_unsigned.zip', output)
|
||||
|
||||
def zip_uninstaller(args):
|
||||
header('* Packing Uninstaller Zip')
|
||||
|
||||
with zipfile.ZipFile('tmp_unsigned.zip', 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf:
|
||||
# META-INF
|
||||
# update-binary
|
||||
target = os.path.join('META-INF', 'com', 'google', 'android', 'update-binary')
|
||||
print('zip: ' + target)
|
||||
zipf.writestr(target, gen_update_binary())
|
||||
# updater-script
|
||||
source = os.path.join('scripts', 'uninstaller_loader.sh')
|
||||
target = os.path.join('META-INF', 'com', 'google', 'android', 'updater-script')
|
||||
zip_with_msg(zipf, source, target)
|
||||
|
||||
# Binaries
|
||||
for lib_dir, zip_dir in [('arm64-v8a', 'arm64'), ('armeabi-v7a', 'arm'), ('x86', 'x86'), ('x86_64', 'x64')]:
|
||||
source = os.path.join('libs', lib_dir, 'magiskboot')
|
||||
target = os.path.join(zip_dir, 'magiskboot')
|
||||
zip_with_msg(zipf, source, target)
|
||||
|
||||
source = os.path.join('scripts', 'magisk_uninstaller.sh')
|
||||
target = 'magisk_uninstaller.sh'
|
||||
zip_with_msg(zipf, source, target)
|
||||
|
||||
# Scripts
|
||||
# util_functions.sh
|
||||
source = os.path.join('scripts', 'util_functions.sh')
|
||||
with open(source, 'r') as script:
|
||||
# Remove the stub
|
||||
util_func = script.read().replace(
|
||||
'MAGISK_VERSION_STUB', '')
|
||||
target = os.path.join('util_functions.sh')
|
||||
print('zip: ' + source + ' -> ' + target)
|
||||
zipf.writestr(target, util_func)
|
||||
|
||||
# Prebuilts
|
||||
for chromeos in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']:
|
||||
source = os.path.join('chromeos', chromeos)
|
||||
zip_with_msg(zipf, source, source)
|
||||
|
||||
# End of zipping
|
||||
|
||||
output = 'Magisk-uninstaller-{}.zip'.format(datetime.datetime.now().strftime('%Y%m%d'))
|
||||
sign_adjust_zip('tmp_unsigned.zip', output)
|
||||
rm(unsigned)
|
||||
rm('tmp_signed.zip')
|
||||
rm('tmp_adjusted.zip')
|
||||
|
||||
def cleanup(args):
|
||||
if len(args.target) == 0:
|
||||
@ -335,20 +379,23 @@ def cleanup(args):
|
||||
if 'binary' in args.target:
|
||||
header('* Cleaning binaries')
|
||||
subprocess.run(os.path.join(os.environ['ANDROID_HOME'], 'ndk-bundle', 'ndk-build') + ' clean', shell=True)
|
||||
for arch in ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']:
|
||||
shutil.rmtree(os.path.join('out', arch), ignore_errors=True)
|
||||
|
||||
if 'java' in args.target:
|
||||
header('* Cleaning java')
|
||||
os.chdir('java')
|
||||
subprocess.run('{} clean'.format(os.path.join('.', 'gradlew')), shell=True)
|
||||
os.chdir('..')
|
||||
silentremove('snet.apk')
|
||||
for f in os.listdir('out'):
|
||||
if '.apk' in f:
|
||||
rm(os.path.join('out', f))
|
||||
|
||||
if 'zip' in args.target:
|
||||
header('* Cleaning zip files')
|
||||
for f in os.listdir('.'):
|
||||
for f in os.listdir('out'):
|
||||
if '.zip' in f:
|
||||
print('rm {}'.format(f))
|
||||
silentremove(f)
|
||||
rm(os.path.join('out', f))
|
||||
|
||||
parser = argparse.ArgumentParser(description='Magisk build script')
|
||||
parser.add_argument('--release', action='store_true', help='compile Magisk for release')
|
||||
|
2
java
2
java
@ -1 +1 @@
|
||||
Subproject commit fdd700f3e5c2f9d7688d2434d4dbee8c12524411
|
||||
Subproject commit 99c74b31be15a239fdffe4a727d2d83feb52b8bb
|
@ -14,17 +14,17 @@ LIBFDT := $(EXT_PATH)/dtc/libfdt
|
||||
# Binaries
|
||||
########################
|
||||
|
||||
ifdef PRECOMPILE
|
||||
|
||||
# magisk main binary
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magisk
|
||||
LOCAL_STATIC_LIBRARIES := libsepol
|
||||
LOCAL_SHARED_LIBRARIES := libsqlite libselinux
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
jni/include \
|
||||
jni/external \
|
||||
$(LIBSELINUX) \
|
||||
$(LIBSEPOL)
|
||||
$(LIBSELINUX)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
daemon/magisk.c \
|
||||
@ -41,10 +41,6 @@ LOCAL_SRC_FILES := \
|
||||
magiskhide/magiskhide.c \
|
||||
magiskhide/proc_monitor.c \
|
||||
magiskhide/hide_utils.c \
|
||||
magiskpolicy/magiskpolicy.c \
|
||||
magiskpolicy/rules.c \
|
||||
magiskpolicy/sepolicy.c \
|
||||
magiskpolicy/api.c \
|
||||
resetprop/resetprop.cpp \
|
||||
resetprop/system_properties.cpp \
|
||||
su/su.c \
|
||||
@ -59,6 +55,37 @@ LOCAL_CPPFLAGS := -std=c++11
|
||||
LOCAL_LDLIBS := -llog
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# magiskinit
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magiskinit
|
||||
LOCAL_STATIC_LIBRARIES := libsepol
|
||||
LOCAL_C_INCLUDES := jni/include $(LIBSEPOL)
|
||||
LOCAL_SRC_FILES := \
|
||||
init/magiskinit.c \
|
||||
utils/vector.c \
|
||||
utils/file.c \
|
||||
utils/xwrap.c \
|
||||
magiskpolicy/api.c \
|
||||
magiskpolicy/magiskpolicy.c \
|
||||
magiskpolicy/rules.c \
|
||||
magiskpolicy/sepolicy.c
|
||||
|
||||
LOCAL_CFLAGS := -DNO_SELINUX
|
||||
LOCAL_LDFLAGS := -static
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# precompile
|
||||
else
|
||||
|
||||
# monogisk
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := monogisk
|
||||
LOCAL_STATIC_LIBRARIES := liblzma
|
||||
LOCAL_C_INCLUDES := jni/include out/$(TARGET_ARCH_ABI) $(LIBLZMA)
|
||||
LOCAL_SRC_FILES := init/monogisk.c
|
||||
LOCAL_LDFLAGS := -static
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# magiskboot
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magiskboot
|
||||
@ -81,29 +108,13 @@ LOCAL_SRC_FILES := \
|
||||
magiskboot/types.c \
|
||||
magiskboot/dtb.c \
|
||||
utils/xwrap.c \
|
||||
utils/file.c \
|
||||
utils/vector.c
|
||||
|
||||
LOCAL_CFLAGS := -DNO_SELINUX
|
||||
LOCAL_LDLIBS := -lz
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# magiskinit
|
||||
ifeq ($(TARGET_ARCH_ABI), arm64-v8a)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := magiskinit
|
||||
LOCAL_STATIC_LIBRARIES := libsepol
|
||||
LOCAL_C_INCLUDES := jni/include $(LIBSEPOL)
|
||||
LOCAL_SRC_FILES := \
|
||||
magiskinit.c \
|
||||
magiskboot/boot_utils.c \
|
||||
utils/file.c \
|
||||
utils/xwrap.c \
|
||||
magiskpolicy/rules.c \
|
||||
magiskpolicy/sepolicy.c \
|
||||
magiskpolicy/api.c
|
||||
LOCAL_CFLAGS := -DNO_SELINUX
|
||||
LOCAL_LDFLAGS := -static
|
||||
include $(BUILD_EXECUTABLE)
|
||||
endif
|
||||
|
||||
# 32-bit static binaries
|
||||
ifneq ($(TARGET_ARCH_ABI), x86_64)
|
||||
ifneq ($(TARGET_ARCH_ABI), arm64-v8a)
|
||||
@ -120,6 +131,9 @@ include jni/external/busybox/Android.mk
|
||||
endif
|
||||
endif
|
||||
|
||||
# Precompile
|
||||
endif
|
||||
|
||||
########################
|
||||
# Externals
|
||||
########################
|
||||
|
@ -568,7 +568,7 @@ void fix_filecon() {
|
||||
****************/
|
||||
|
||||
static void unblock_boot_process() {
|
||||
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT));
|
||||
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0));
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
@ -743,7 +743,8 @@ void late_start(int client) {
|
||||
if (buf2 == NULL) buf2 = xmalloc(PATH_MAX);
|
||||
|
||||
// Wait till the full patch is done
|
||||
pthread_join(sepol_patch, NULL);
|
||||
while (access(PATCHDONE, F_OK) == -1)
|
||||
usleep(500); /* Wait 0.5ms */
|
||||
|
||||
// Run scripts after full patch, most reliable way to run scripts
|
||||
LOGI("* Running service.d scripts\n");
|
||||
|
@ -103,16 +103,6 @@ static int setup_socket(struct sockaddr_un *sun) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void *large_sepol_patch(void *args) {
|
||||
LOGD("sepol: Starting large patch thread\n");
|
||||
// Patch su to everything
|
||||
sepol_allow("su", ALL, ALL, ALL);
|
||||
dump_policydb(SELINUX_LOAD);
|
||||
LOGD("sepol: Large patch done\n");
|
||||
destroy_policydb();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *start_magisk_hide(void *args) {
|
||||
launch_magiskhide(-1);
|
||||
return NULL;
|
||||
@ -137,11 +127,6 @@ void start_daemon() {
|
||||
xdup2(fd, STDERR_FILENO);
|
||||
close(fd);
|
||||
|
||||
// Patch selinux with medium patch before we do anything
|
||||
load_policydb(SELINUX_POLICY);
|
||||
sepol_med_rules();
|
||||
dump_policydb(SELINUX_LOAD);
|
||||
|
||||
struct sockaddr_un sun;
|
||||
fd = setup_socket(&sun);
|
||||
|
||||
@ -159,9 +144,6 @@ void start_daemon() {
|
||||
// Start the log monitor
|
||||
monitor_logs();
|
||||
|
||||
// Continue the larger patch in another thread, we will join later
|
||||
xpthread_create(&sepol_patch, NULL, large_sepol_patch, NULL);
|
||||
|
||||
LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") daemon started\n");
|
||||
|
||||
// Change process name
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "magisk.h"
|
||||
@ -12,10 +13,10 @@
|
||||
char *argv0;
|
||||
|
||||
char *applet[] =
|
||||
{ "su", "resetprop", "magiskpolicy", "supolicy", "magiskhide", NULL };
|
||||
{ "su", "resetprop", "magiskhide", NULL };
|
||||
|
||||
int (*applet_main[]) (int, char *[]) =
|
||||
{ su_client_main, resetprop_main, magiskpolicy_main, magiskpolicy_main, magiskhide_main, NULL };
|
||||
{ su_client_main, resetprop_main, magiskhide_main, NULL };
|
||||
|
||||
int create_links(const char *bin, const char *path) {
|
||||
char self[PATH_MAX], linkpath[PATH_MAX];
|
||||
@ -56,7 +57,7 @@ static void usage() {
|
||||
" --clone-attr SRC DEST clone permission, owner, and selinux context\n"
|
||||
"\n"
|
||||
"Supported init services:\n"
|
||||
" daemon post-fs, post-fs-data, service\n"
|
||||
" daemon, post-fs, post-fs-data, service\n"
|
||||
"\n"
|
||||
"Supported applets:\n"
|
||||
, argv0, argv0);
|
||||
@ -69,10 +70,7 @@ static void usage() {
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
argv0 = argv[0];
|
||||
char * arg = strrchr(argv[0], '/');
|
||||
if (arg) ++arg;
|
||||
else arg = argv[0];
|
||||
if (strcmp(arg, "magisk") == 0) {
|
||||
if (strcmp(basename(argv[0]), "magisk") == 0) {
|
||||
if (argc < 2) usage();
|
||||
if (strcmp(argv[1], "-c") == 0) {
|
||||
printf("%s\n", MAGISK_VER_STR);
|
||||
@ -168,16 +166,15 @@ int main(int argc, char *argv[]) {
|
||||
// It's calling applets
|
||||
--argc;
|
||||
++argv;
|
||||
arg = argv[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Applets
|
||||
for (int i = 0; applet[i]; ++i) {
|
||||
if (strcmp(arg, applet[i]) == 0)
|
||||
if (strcmp(basename(argv[0]), applet[i]) == 0)
|
||||
return (*applet_main[i])(argc, argv);
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: applet not found\n", arg);
|
||||
fprintf(stderr, "%s: applet not found\n", basename(argv[0]));
|
||||
return 1;
|
||||
}
|
||||
|
@ -8,6 +8,9 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define str(a) #a
|
||||
#define xstr(a) str(a)
|
||||
|
||||
#ifdef IS_DAEMON
|
||||
|
||||
#include <pthread.h>
|
||||
|
@ -6,9 +6,6 @@
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
#define str(a) #a
|
||||
#define xstr(a) str(a)
|
||||
|
||||
#define MAGISK_VER_STR xstr(MAGISK_VERSION) ":MAGISK"
|
||||
#define REQUESTOR_DAEMON_PATH "\0MAGISK"
|
||||
|
||||
@ -20,6 +17,7 @@
|
||||
#define LASTLOG "/cache/last_magisk.log"
|
||||
#define DEBUG_LOG "/data/magisk_debug.log"
|
||||
#define UNBLOCKFILE "/dev/.magisk.unblock"
|
||||
#define PATCHDONE "/dev/.magisk.patch.done"
|
||||
#define DISABLEFILE "/cache/.disable_magisk"
|
||||
#define UNINSTALLER "/cache/magisk_uninstaller.sh"
|
||||
#define CACHEMOUNT "/cache/magisk_mount"
|
||||
|
45
jni/include/magiskrc.h
Normal file
45
jni/include/magiskrc.h
Normal file
@ -0,0 +1,45 @@
|
||||
const char magiskrc[] =
|
||||
|
||||
// Triggers
|
||||
|
||||
"on post-fs\n"
|
||||
" start logd\n"
|
||||
" start magisk_daemon\n"
|
||||
" wait /dev/.magisk.unblock 5\n"
|
||||
" rm /dev/.magisk.unblock\n"
|
||||
" start magisk_pfs\n"
|
||||
" wait /dev/.magisk.unblock 10\n"
|
||||
"\n"
|
||||
|
||||
"on post-fs-data\n"
|
||||
" load_persist_props\n"
|
||||
" rm /dev/.magisk.unblock\n"
|
||||
" start magisk_pfsd\n"
|
||||
" wait /dev/.magisk.unblock 10\n"
|
||||
"\n"
|
||||
|
||||
// Services
|
||||
|
||||
"service magisk_daemon /sbin/magisk --daemon\n"
|
||||
" user root\n"
|
||||
" seclabel u:r:su:s0\n"
|
||||
"\n"
|
||||
|
||||
"service magisk_pfs /sbin/magisk --post-fs\n"
|
||||
" user root\n"
|
||||
" seclabel u:r:su:s0\n"
|
||||
" oneshot\n"
|
||||
"\n"
|
||||
|
||||
"service magisk_pfsd /sbin/magisk --post-fs-data\n"
|
||||
" user root\n"
|
||||
" seclabel u:r:su:s0\n"
|
||||
" oneshot\n"
|
||||
"\n"
|
||||
|
||||
"service magisk_service /sbin/magisk --service\n"
|
||||
" class late_start\n"
|
||||
" user root\n"
|
||||
" seclabel u:r:su:s0\n"
|
||||
" oneshot\n"
|
||||
;
|
@ -116,6 +116,8 @@ int fsetattr(int fd, struct file_attr *a);
|
||||
void fclone_attr(const int sourcefd, const int targetfd);
|
||||
void clone_attr(const char *source, const char *target);
|
||||
void restorecon(int dirfd, int force);
|
||||
void mmap_ro(const char *filename, void **buf, size_t *size);
|
||||
void mmap_rw(const char *filename, void **buf, size_t *size);
|
||||
|
||||
// img.c
|
||||
|
||||
|
364
jni/init/magiskinit.c
Normal file
364
jni/init/magiskinit.c
Normal file
@ -0,0 +1,364 @@
|
||||
/* magiskinit.c - Pre-init Magisk support
|
||||
*
|
||||
* This code has to be compiled statically to work properly.
|
||||
*
|
||||
* This binary will be extracted from monogisk, and dos all pre-init operations to setup
|
||||
* a Magisk environment. The tool modifies rootfs on the fly, providing fundamental support
|
||||
* such as init, init.rc, and sepolicy patching. Magiskinit is also responsible to construct
|
||||
* a proper rootfs on skip_initramfs devices.
|
||||
* On skip_initramfs devices, it will parse kernel cmdline, mount sysfs, parse through
|
||||
* uevent files to make the system (or vendor if available) block device node, then copy
|
||||
* rootfs files from system. The "overlay" folder is constructed by monogisk,
|
||||
* which contains additional files extracted from the tool. These files will be moved to /.
|
||||
* This tool will be replaced with the real init to continue the boot process, but hardlinks are
|
||||
* preserved as it also provides CLI for sepolicy patching (magiskpolicy)
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#include <cil/cil.h>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
#include "magiskpolicy.h"
|
||||
|
||||
struct cmdline {
|
||||
int skip_initramfs;
|
||||
char slot[3];
|
||||
};
|
||||
|
||||
struct device {
|
||||
dev_t major;
|
||||
dev_t minor;
|
||||
char devname[32];
|
||||
char partname[32];
|
||||
char path[64];
|
||||
};
|
||||
|
||||
extern policydb_t *policydb;
|
||||
|
||||
static void parse_cmdline(struct cmdline *cmd) {
|
||||
char *tok;
|
||||
char buffer[4096];
|
||||
mkdir("/proc", 0555);
|
||||
mount("proc", "/proc", "proc", 0, NULL);
|
||||
int fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC);
|
||||
ssize_t size = read(fd, buffer, sizeof(buffer));
|
||||
buffer[size] = '\0';
|
||||
close(fd);
|
||||
umount("/proc");
|
||||
tok = strtok(buffer, " ");
|
||||
cmd->skip_initramfs = 0;
|
||||
cmd->slot[0] = '\0';
|
||||
while (tok != NULL) {
|
||||
if (strncmp(tok, "androidboot.slot_suffix", 23) == 0) {
|
||||
sscanf(tok, "androidboot.slot_suffix=%s", cmd->slot);
|
||||
} else if (strcmp(tok, "skip_initramfs") == 0) {
|
||||
cmd->skip_initramfs = 1;
|
||||
}
|
||||
tok = strtok(NULL, " ");
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_device(struct device *dev, char *uevent) {
|
||||
char *tok;
|
||||
tok = strtok(uevent, "\n");
|
||||
while (tok != NULL) {
|
||||
if (strncmp(tok, "MAJOR", 5) == 0) {
|
||||
sscanf(tok, "MAJOR=%ld", (long*) &dev->major);
|
||||
} else if (strncmp(tok, "MINOR", 5) == 0) {
|
||||
sscanf(tok, "MINOR=%ld", (long*) &dev->minor);
|
||||
} else if (strncmp(tok, "DEVNAME", 7) == 0) {
|
||||
sscanf(tok, "DEVNAME=%s", dev->devname);
|
||||
} else if (strncmp(tok, "PARTNAME", 8) == 0) {
|
||||
sscanf(tok, "PARTNAME=%s", dev->partname);
|
||||
}
|
||||
tok = strtok(NULL, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int setup_block(struct device *dev, const char *partname) {
|
||||
char buffer[1024], path[128];
|
||||
struct dirent *entry;
|
||||
DIR *dir = opendir("/sys/dev/block");
|
||||
if (dir == NULL)
|
||||
return 1;
|
||||
int found = 0;
|
||||
while ((entry = readdir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
snprintf(path, sizeof(path), "/sys/dev/block/%s/uevent", entry->d_name);
|
||||
int fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
ssize_t size = read(fd, buffer, sizeof(buffer));
|
||||
buffer[size] = '\0';
|
||||
close(fd);
|
||||
parse_device(dev, buffer);
|
||||
if (strcmp(dev->partname, partname) == 0) {
|
||||
snprintf(dev->path, sizeof(dev->path), "/dev/block/%s", dev->devname);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
if (!found)
|
||||
return 1;
|
||||
|
||||
mkdir("/dev", 0755);
|
||||
mkdir("/dev/block", 0755);
|
||||
mknod(dev->path, S_IFBLK | 0600, makedev(dev->major, dev->minor));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *patch_init_rc(char *data, uint32_t *size) {
|
||||
int injected = 0;
|
||||
char *new_data = malloc(*size + 23);
|
||||
char *old_data = data;
|
||||
uint32_t pos = 0;
|
||||
|
||||
for (char *tok = strsep(&old_data, "\n"); tok; tok = strsep(&old_data, "\n")) {
|
||||
if (!injected && strncmp(tok, "import", 6) == 0) {
|
||||
if (strstr(tok, "init.magisk.rc")) {
|
||||
injected = 1;
|
||||
} else {
|
||||
strcpy(new_data + pos, "import /init.magisk.rc\n");
|
||||
pos += 23;
|
||||
injected = 1;
|
||||
}
|
||||
} else if (strstr(tok, "selinux.reload_policy")) {
|
||||
continue;
|
||||
}
|
||||
// Copy the line
|
||||
strcpy(new_data + pos, tok);
|
||||
pos += strlen(tok);
|
||||
new_data[pos++] = '\n';
|
||||
}
|
||||
|
||||
*size = pos;
|
||||
return new_data;
|
||||
}
|
||||
|
||||
static void patch_ramdisk() {
|
||||
void *addr;
|
||||
size_t size;
|
||||
mmap_rw("/init", &addr, &size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (memcmp(addr + i, "/system/etc/selinux/plat_sepolicy.cil", 37) == 0) {
|
||||
memcpy(addr + i, "/system/etc/selinux/plat_sepolicy.xxx", 37);
|
||||
break;
|
||||
}
|
||||
}
|
||||
munmap(addr, size);
|
||||
|
||||
mmap_rw("/init.rc", &addr, &size);
|
||||
uint32_t new_size = size;
|
||||
void *init_rc = patch_init_rc(addr, &new_size);
|
||||
munmap(addr, size);
|
||||
|
||||
int fd = open("/init.rc", O_WRONLY | O_TRUNC | O_CLOEXEC);
|
||||
write(fd, init_rc, new_size);
|
||||
close(fd);
|
||||
free(init_rc);
|
||||
}
|
||||
|
||||
static int strend(const char *s1, const char *s2) {
|
||||
int l1 = strlen(s1);
|
||||
int l2 = strlen(s2);
|
||||
return strcmp(s1 + l1 - l2, s2);
|
||||
}
|
||||
|
||||
static int compile_cil() {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
char path[128];
|
||||
|
||||
struct cil_db *db = NULL;
|
||||
sepol_policydb_t *pdb = NULL;
|
||||
void *addr;
|
||||
size_t size;
|
||||
|
||||
cil_db_init(&db);
|
||||
cil_set_mls(db, 1);
|
||||
cil_set_target_platform(db, SEPOL_TARGET_SELINUX);
|
||||
cil_set_policy_version(db, POLICYDB_VERSION_XPERMS_IOCTL);
|
||||
cil_set_attrs_expand_generated(db, 0);
|
||||
|
||||
// plat
|
||||
mmap_ro("/system/etc/selinux/plat_sepolicy.cil", &addr, &size);
|
||||
cil_add_file(db, "/system/etc/selinux/plat_sepolicy.cil", addr, size);
|
||||
munmap(addr, size);
|
||||
|
||||
// mapping
|
||||
char plat[10];
|
||||
int fd = open("/vendor/etc/selinux/plat_sepolicy_vers.txt", O_RDONLY | O_CLOEXEC);
|
||||
if (fd > 0) {
|
||||
plat[read(fd, plat, sizeof(plat)) - 1] = '\0';
|
||||
snprintf(path, sizeof(path), "/system/etc/selinux/mapping/%s.cil", plat);
|
||||
mmap_ro(path, &addr, &size);
|
||||
cil_add_file(db, path, addr, size);
|
||||
munmap(addr, size);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
dir = opendir("/vendor/etc/selinux");
|
||||
while ((entry = readdir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
if (strend(entry->d_name, ".cil") == 0) {
|
||||
snprintf(path, sizeof(path), "/vendor/etc/selinux/%s", entry->d_name);
|
||||
mmap_ro(path, &addr, &size);
|
||||
cil_add_file(db, path, addr, size);
|
||||
munmap(addr, size);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
cil_compile(db);
|
||||
cil_build_policydb(db, &pdb);
|
||||
cil_db_destroy(&db);
|
||||
|
||||
policydb = &pdb->p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verify_precompiled() {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
int fd;
|
||||
char sys_sha[70], ven_sha[70];
|
||||
|
||||
dir = opendir("/vendor/etc/selinux");
|
||||
while ((entry = readdir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
if (strend(entry->d_name, ".sha256") == 0) {
|
||||
fd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
ven_sha[read(fd, ven_sha, sizeof(ven_sha))] = '\0';
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
dir = opendir("/system/etc/selinux");
|
||||
while ((entry = readdir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
if (strend(entry->d_name, ".sha256") == 0) {
|
||||
fd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_CLOEXEC);
|
||||
sys_sha[read(fd, sys_sha, sizeof(sys_sha))] = '\0';
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
return strcmp(sys_sha, ven_sha);
|
||||
}
|
||||
|
||||
static void patch_sepolicy() {
|
||||
if (access("/sepolicy", R_OK) == 0) {
|
||||
load_policydb("/sepolicy");
|
||||
} else if (access("/vendor/etc/selinux/precompiled_sepolicy", R_OK) == 0
|
||||
&& verify_precompiled() == 0) {
|
||||
load_policydb("/vendor/etc/selinux/precompiled_sepolicy");
|
||||
} else if (access("/system/etc/selinux/plat_sepolicy.cil", R_OK) == 0) {
|
||||
compile_cil();
|
||||
}
|
||||
|
||||
sepol_med_rules();
|
||||
dump_policydb("/sepolicy");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (strcmp(basename(argv[0]), "magiskpolicy") == 0 || strcmp(basename(argv[0]), "supolicy") == 0)
|
||||
return magiskpolicy_main(argc, argv);
|
||||
if (argc > 1 && (strcmp(argv[1], "magiskpolicy") == 0 || strcmp(argv[1], "supolicy") == 0))
|
||||
return magiskpolicy_main(argc - 1, argv + 1);
|
||||
|
||||
umask(0);
|
||||
|
||||
struct cmdline cmd;
|
||||
parse_cmdline(&cmd);
|
||||
|
||||
int root = open("/", O_RDONLY | O_CLOEXEC);
|
||||
|
||||
if (cmd.skip_initramfs) {
|
||||
// Exclude overlay folder
|
||||
excl_list = (char *[]) { "overlay", ".backup", NULL };
|
||||
// Clear rootfs
|
||||
frm_rf(root);
|
||||
|
||||
mkdir("/sys", 0755);
|
||||
mount("sysfs", "/sys", "sysfs", 0, NULL);
|
||||
|
||||
char partname[32];
|
||||
snprintf(partname, sizeof(partname), "system%s", cmd.slot);
|
||||
|
||||
struct device dev;
|
||||
setup_block(&dev, partname);
|
||||
|
||||
mkdir("/system_root", 0755);
|
||||
mount(dev.path, "/system_root", "ext4", MS_RDONLY, NULL);
|
||||
int system_root = open("/system_root", O_RDONLY | O_CLOEXEC);
|
||||
|
||||
// Exclude system folder
|
||||
excl_list = (char *[]) { "system", NULL };
|
||||
clone_dir(system_root, root);
|
||||
mkdir("/system", 0755);
|
||||
mount("/system_root/system", "/system", NULL, MS_BIND, NULL);
|
||||
|
||||
snprintf(partname, sizeof(partname), "vendor%s", cmd.slot);
|
||||
|
||||
// We need to mount independent vendor partition
|
||||
if (setup_block(&dev, partname) == 0)
|
||||
mount(dev.path, "/vendor", "ext4", MS_RDONLY, NULL);
|
||||
|
||||
close(system_root);
|
||||
} else {
|
||||
// Revert original init binary
|
||||
unlink("/init");
|
||||
link("/.backup/init", "/init");
|
||||
}
|
||||
|
||||
int overlay = open("/overlay", O_RDONLY | O_CLOEXEC);
|
||||
mv_dir(overlay, root);
|
||||
|
||||
patch_ramdisk();
|
||||
patch_sepolicy();
|
||||
|
||||
// Clean up
|
||||
rmdir("/overlay");
|
||||
umount("/vendor");
|
||||
close(overlay);
|
||||
close(root);
|
||||
|
||||
if (fork() == 0) {
|
||||
// Fork a new process for full patch
|
||||
setsid();
|
||||
sepol_allow("su", ALL, ALL, ALL);
|
||||
while (access(SELINUX_LOAD, W_OK) == -1) {
|
||||
usleep(500); /* Wait 0.5ms */
|
||||
}
|
||||
dump_policydb(SELINUX_LOAD);
|
||||
close(open(PATCHDONE, O_RDONLY | O_CREAT, 0));
|
||||
destroy_policydb();
|
||||
} else {
|
||||
// Finally, give control back!
|
||||
execv("/init", argv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
121
jni/init/monogisk.c
Normal file
121
jni/init/monogisk.c
Normal file
@ -0,0 +1,121 @@
|
||||
/* monogisk.c - Monolithic binary hosting Magisk binaries
|
||||
*
|
||||
* This code has to be compiled statically to work properly.
|
||||
*
|
||||
* To unify Magisk support for both legacy "normal" devices and new skip_initramfs devices,
|
||||
* this tool is born. Magisk binary compilation is split into two parts - first part contains
|
||||
* "magisk" and "magiskinit". The python build script will load these 2 binaries and compress
|
||||
* them with lzma2, dumping the results into "dump.h". Monogisk is simply just a static lzma
|
||||
* extractor embedded with binary blobs, with a few additional operations to construct an
|
||||
* environment for "magiskinit" to handle the rest of the work.
|
||||
*/
|
||||
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <lzma.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "dump.h"
|
||||
#include "magiskrc.h"
|
||||
|
||||
#define str(a) #a
|
||||
#define xstr(a) str(a)
|
||||
#define BUFSIZE 0x100000
|
||||
|
||||
lzma_stream strm = LZMA_STREAM_INIT;
|
||||
|
||||
static void usage() {
|
||||
const char usage[] =
|
||||
"Monogisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") (by topjohnwu)\n"
|
||||
"A monolithic binary used as /init to add Magisk support\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
" monogisk -x <binary> <out>\n"
|
||||
" extract \"magisk\", \"magiskinit\", or \"magiskrc\"\n"
|
||||
" /init\n"
|
||||
" Startup the system with Magisk support\n"
|
||||
"\n";
|
||||
write(STDERR_FILENO, usage, sizeof(usage));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int unxz(lzma_stream *strm, const void *buf, size_t size, int fd) {
|
||||
lzma_ret ret = 0;
|
||||
uint8_t out[BUFSIZE];
|
||||
strm->next_in = buf;
|
||||
strm->avail_in = size;
|
||||
do {
|
||||
strm->next_out = out;
|
||||
strm->avail_out = sizeof(out);
|
||||
ret = lzma_code(strm, LZMA_RUN);
|
||||
write(fd, out, sizeof(out) - strm->avail_out);
|
||||
} while (strm->avail_out == 0 && ret == LZMA_OK);
|
||||
|
||||
if (ret != LZMA_OK && ret != LZMA_STREAM_END)
|
||||
write(STDERR_FILENO, "LZMA error!\n", 13);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dump_magisk(const char *path, mode_t mode) {
|
||||
if (lzma_auto_decoder(&strm, UINT64_MAX, 0) != LZMA_OK)
|
||||
return 1;
|
||||
unlink(path);
|
||||
int fd = creat(path, mode);
|
||||
int ret = unxz(&strm, magisk_dump, sizeof(magisk_dump), fd);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dump_magiskinit(const char *path, mode_t mode) {
|
||||
if (lzma_auto_decoder(&strm, UINT64_MAX, 0) != LZMA_OK)
|
||||
return 1;
|
||||
unlink(path);
|
||||
int fd = creat(path, mode);
|
||||
int ret = unxz(&strm, magiskinit_dump, sizeof(magiskinit_dump), fd);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dump_magiskrc(const char *path, mode_t mode) {
|
||||
unlink(path);
|
||||
int fd = creat(path, mode);
|
||||
write(fd, magiskrc, sizeof(magiskrc));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_main(int argc, char *argv[]) {
|
||||
dump_magiskinit("/init", 0750);
|
||||
mkdir("/overlay", 0);
|
||||
dump_magiskrc("/overlay/init.magisk.rc", 0750);
|
||||
mkdir("/overlay/sbin", 0755);
|
||||
dump_magisk("/overlay/sbin/magisk", 0755);
|
||||
mkdir("/overlay/root", 0755);
|
||||
link("/init", "/overlay/root/magiskpolicy");
|
||||
link("/init", "/overlay/root/supolicy");
|
||||
execv("/init", argv);
|
||||
return 1; /* Should not happen */
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
umask(0);
|
||||
|
||||
if (argc == 1)
|
||||
return init_main(argc, argv);
|
||||
|
||||
if (argc < 4)
|
||||
usage();
|
||||
|
||||
if (strcmp(argv[2], "magisk") == 0)
|
||||
dump_magisk(argv[3], 0755);
|
||||
else if (strcmp(argv[2], "magiskinit") == 0)
|
||||
dump_magiskinit(argv[3], 0755);
|
||||
else
|
||||
usage();
|
||||
|
||||
lzma_end(&strm);
|
||||
return 0;
|
||||
}
|
@ -1,25 +1,8 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
void mmap_ro(const char *filename, void **buf, size_t *size) {
|
||||
int fd = xopen(filename, O_RDONLY);
|
||||
*size = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
*buf = *size > 0 ? xmmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0) : NULL;
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void mmap_rw(const char *filename, void **buf, size_t *size) {
|
||||
int fd = xopen(filename, O_RDWR);
|
||||
*size = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
*buf = *size > 0 ? xmmap(NULL, *size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0) : NULL;
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void write_zero(int fd, size_t size) {
|
||||
size_t pos = lseek(fd, 0, SEEK_CUR);
|
||||
ftruncate(fd, pos + size);
|
||||
@ -51,35 +34,6 @@ int open_new(const char *filename) {
|
||||
return xopen(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
}
|
||||
|
||||
void *patch_init_rc(char *data, uint32_t *size) {
|
||||
int injected = 0;
|
||||
char *new_data = xmalloc(*size + 23);
|
||||
char *old_data = data;
|
||||
uint32_t pos = 0;
|
||||
|
||||
for (char *tok = strsep(&old_data, "\n"); tok; tok = strsep(&old_data, "\n")) {
|
||||
if (!injected && strncmp(tok, "import", 6) == 0) {
|
||||
if (strstr(tok, "init.magisk.rc")) {
|
||||
injected = 1;
|
||||
} else {
|
||||
fprintf(stderr, "Inject [import /init.magisk.rc] to [init.rc]\n");
|
||||
strcpy(new_data + pos, "import /init.magisk.rc\n");
|
||||
pos += 23;
|
||||
injected = 1;
|
||||
}
|
||||
} else if (strstr(tok, "selinux.reload_policy")) {
|
||||
continue;
|
||||
}
|
||||
// Copy the line
|
||||
strcpy(new_data + pos, tok);
|
||||
pos += strlen(tok);
|
||||
new_data[pos++] = '\n';
|
||||
}
|
||||
|
||||
*size = pos;
|
||||
return new_data;
|
||||
}
|
||||
|
||||
int check_verity_pattern(const char *s) {
|
||||
int pos = 0;
|
||||
if (s[0] == ',') ++pos;
|
||||
|
@ -186,7 +186,7 @@ static void cpio_test(struct vector *v) {
|
||||
int ret = STOCK_BOOT;
|
||||
cpio_entry *f;
|
||||
const char *OTHER_LIST[] = { "sbin/launch_daemonsu.sh", "sbin/su", "init.xposed.rc", "boot/sbin/launch_daemonsu.sh", NULL };
|
||||
const char *MAGISK_LIST[] = { "init.magisk.rc", "overlay/init.magisk.rc", NULL };
|
||||
const char *MAGISK_LIST[] = { ".backup/.magisk", "init.magisk.rc", "overlay/init.magisk.rc", NULL };
|
||||
vec_for_each(v, f) {
|
||||
for (int i = 0; OTHER_LIST[i]; ++i) {
|
||||
if (strcmp(f->filename, OTHER_LIST[i]) == 0) {
|
||||
@ -208,42 +208,36 @@ static void cpio_patch(struct vector *v, int keepverity, int keepforceencrypt) {
|
||||
cpio_entry *f;
|
||||
int skip, write;
|
||||
vec_for_each(v, f) {
|
||||
if (strcmp(f->filename, "init.rc") == 0) {
|
||||
void *new_data = patch_init_rc(f->data, &f->filesize);
|
||||
free(f->data);
|
||||
f->data = new_data;
|
||||
} else {
|
||||
if (!keepverity) {
|
||||
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
|
||||
write = 0;
|
||||
for (int read = 0; read < f->filesize; ++write, ++read) {
|
||||
if ((skip = check_verity_pattern(f->data + read)) > 0) {
|
||||
fprintf(stderr, "Remove pattern [%.*s] in [%s]\n", skip, f->data + read, f->filename);
|
||||
read += skip;
|
||||
}
|
||||
f->data[write] = f->data[read];
|
||||
if (!keepverity) {
|
||||
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
|
||||
write = 0;
|
||||
for (int read = 0; read < f->filesize; ++write, ++read) {
|
||||
if ((skip = check_verity_pattern(f->data + read)) > 0) {
|
||||
fprintf(stderr, "Remove pattern [%.*s] in [%s]\n", skip, f->data + read, f->filename);
|
||||
read += skip;
|
||||
}
|
||||
f->filesize = write;
|
||||
} else if (strcmp(f->filename, "verity_key") == 0) {
|
||||
fprintf(stderr, "Remove [verity_key]\n");
|
||||
f->remove = 1;
|
||||
f->data[write] = f->data[read];
|
||||
}
|
||||
f->filesize = write;
|
||||
} else if (strcmp(f->filename, "verity_key") == 0) {
|
||||
fprintf(stderr, "Remove [verity_key]\n");
|
||||
f->remove = 1;
|
||||
}
|
||||
if (!keepforceencrypt) {
|
||||
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
|
||||
write = 0;
|
||||
for (int read = 0; read < f->filesize; ++write, ++read) {
|
||||
if ((skip = check_encryption_pattern(f->data + read)) > 0) {
|
||||
// assert(skip > 11)!
|
||||
fprintf(stderr, "Replace pattern [%.*s] with [encryptable] in [%s]\n", skip, f->data + read, f->filename);
|
||||
memcpy(f->data + write, "encryptable", 11);
|
||||
write += 11;
|
||||
read += skip;
|
||||
}
|
||||
f->data[write] = f->data[read];
|
||||
}
|
||||
if (!keepforceencrypt) {
|
||||
if (strstr(f->filename, "fstab") != NULL && S_ISREG(f->mode)) {
|
||||
write = 0;
|
||||
for (int read = 0; read < f->filesize; ++write, ++read) {
|
||||
if ((skip = check_encryption_pattern(f->data + read)) > 0) {
|
||||
// assert(skip > 11)!
|
||||
fprintf(stderr, "Replace pattern [%.*s] with [encryptable] in [%s]\n", skip, f->data + read, f->filename);
|
||||
memcpy(f->data + write, "encryptable", 11);
|
||||
write += 11;
|
||||
read += skip;
|
||||
}
|
||||
f->filesize = write;
|
||||
f->data[write] = f->data[read];
|
||||
}
|
||||
f->filesize = write;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -265,19 +259,35 @@ static void cpio_extract(const char *entry, const char *filename, struct vector
|
||||
LOGE("Cannot find the file entry [%s]\n", entry);
|
||||
}
|
||||
|
||||
static void cpio_backup(const char *orig, struct vector *v) {
|
||||
static void cpio_backup(const char *orig, const char *sha1, struct vector *v) {
|
||||
struct vector o_body, *o = &o_body, bak;
|
||||
cpio_entry *m, *n, *dir, *rem;
|
||||
cpio_entry *m, *n, *rem, *cksm;
|
||||
char buf[PATH_MAX];
|
||||
int res, doBak;
|
||||
|
||||
dir = xcalloc(sizeof(*dir), 1);
|
||||
rem = xcalloc(sizeof(*rem), 1);
|
||||
if (sha1) cksm = xcalloc(sizeof(*cksm), 1);
|
||||
vec_init(o);
|
||||
vec_init(&bak);
|
||||
// First push back the directory and the rmlist
|
||||
vec_push_back(&bak, dir);
|
||||
|
||||
m = xcalloc(sizeof(*m), 1);
|
||||
m->filename = strdup(".backup");
|
||||
m->namesize = strlen(m->filename) + 1;
|
||||
m->mode = S_IFDIR;
|
||||
vec_push_back(&bak, m);
|
||||
|
||||
m = xcalloc(sizeof(*m), 1);
|
||||
m->filename = strdup(".backup/.magisk");
|
||||
m->namesize = strlen(m->filename) + 1;
|
||||
m->mode = S_IFREG;
|
||||
vec_push_back(&bak, m);
|
||||
|
||||
rem = xcalloc(sizeof(*rem), 1);
|
||||
rem->filename = strdup(".backup/.rmlist");
|
||||
rem->namesize = strlen(rem->filename) + 1;
|
||||
rem->mode = S_IFREG;
|
||||
vec_push_back(&bak, rem);
|
||||
|
||||
if (sha1) vec_push_back(&bak, cksm);
|
||||
parse_cpio(orig, o);
|
||||
// Remove possible backups in original ramdisk
|
||||
cpio_rm(1, ".backup", o);
|
||||
@ -287,13 +297,14 @@ static void cpio_backup(const char *orig, struct vector *v) {
|
||||
vec_sort(v, cpio_cmp);
|
||||
vec_sort(o, cpio_cmp);
|
||||
|
||||
// Init the directory and rmlist
|
||||
dir->filename = strdup(".backup");
|
||||
dir->namesize = strlen(dir->filename) + 1;
|
||||
dir->mode = S_IFDIR;
|
||||
rem->filename = strdup(".backup/.rmlist");
|
||||
rem->namesize = strlen(rem->filename) + 1;
|
||||
rem->mode = S_IFREG;
|
||||
if (sha1) {
|
||||
fprintf(stderr, "Save SHA1: [%s] -> [.backup/.sha1]\n", sha1);
|
||||
cksm->filename = strdup(".backup/.sha1");
|
||||
cksm->namesize = strlen(cksm->filename) + 1;
|
||||
cksm->mode = S_IFREG;
|
||||
cksm->data = strdup(sha1);
|
||||
cksm->filesize = strlen(sha1) + 1;
|
||||
}
|
||||
|
||||
// Start comparing
|
||||
size_t i = 0, j = 0;
|
||||
@ -349,12 +360,8 @@ static void cpio_backup(const char *orig, struct vector *v) {
|
||||
vec_push_back(v, m);
|
||||
}
|
||||
|
||||
// Don't include if empty
|
||||
if (rem->filesize == 0) {
|
||||
if (rem->filesize == 0)
|
||||
rem->remove = 1;
|
||||
if (bak.size == 2)
|
||||
dir->remove = 1;
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
cpio_vec_destroy(o);
|
||||
@ -367,21 +374,24 @@ static int cpio_restore(struct vector *v) {
|
||||
if (strstr(f->filename, ".backup") != NULL) {
|
||||
ret = 0;
|
||||
f->remove = 1;
|
||||
if (strcmp(f->filename, ".backup") == 0) continue;
|
||||
if (strcmp(f->filename, ".backup/.rmlist") == 0) {
|
||||
for (int pos = 0; pos < f->filesize; pos += strlen(f->data + pos) + 1)
|
||||
cpio_rm(0, f->data + pos, v);
|
||||
if (f->filename[7] == '\0') continue;
|
||||
if (f->filename[8] == '.') {
|
||||
if (strcmp(f->filename, ".backup/.rmlist") == 0) {
|
||||
for (int pos = 0; pos < f->filesize; pos += strlen(f->data + pos) + 1)
|
||||
cpio_rm(0, f->data + pos, v);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
n = xcalloc(sizeof(*n), 1);
|
||||
memcpy(n, f, sizeof(*f));
|
||||
n->namesize -= 8;
|
||||
n->filename = strdup(f->filename + 8);
|
||||
n->data = f->data;
|
||||
f->data = NULL;
|
||||
n->remove = 0;
|
||||
fprintf(stderr, "Restore [%s] -> [%s]\n", f->filename, n->filename);
|
||||
cpio_vec_insert(v, n);
|
||||
}
|
||||
n = xcalloc(sizeof(*n), 1);
|
||||
memcpy(n, f, sizeof(*f));
|
||||
n->namesize -= 8;
|
||||
n->filename = strdup(f->filename + 8);
|
||||
n->data = f->data;
|
||||
f->data = NULL;
|
||||
n->remove = 0;
|
||||
fprintf(stderr, "Restoring [%s] -> [%s]\n", f->filename, n->filename);
|
||||
cpio_vec_insert(v, n);
|
||||
}
|
||||
}
|
||||
// Some known stuff we can remove
|
||||
@ -406,6 +416,8 @@ static void cpio_stocksha1(struct vector *v) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(f->filename, ".backup/.sha1") == 0) {
|
||||
printf("%s\n", f->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -443,7 +455,7 @@ int cpio_commands(const char *command, int argc, char *argv[]) {
|
||||
cmd = RESTORE;
|
||||
} else if (strcmp(command, "stocksha1") == 0) {
|
||||
cmd = STOCKSHA1;
|
||||
} else if (argc == 1 && strcmp(command, "backup") == 0) {
|
||||
} else if (argc >= 1 && strcmp(command, "backup") == 0) {
|
||||
cmd = BACKUP;
|
||||
} else if (argc > 0 && strcmp(command, "rm") == 0) {
|
||||
cmd = RM;
|
||||
@ -479,7 +491,7 @@ int cpio_commands(const char *command, int argc, char *argv[]) {
|
||||
cpio_stocksha1(&v);
|
||||
return 0;
|
||||
case BACKUP:
|
||||
cpio_backup(argv[0], &v);
|
||||
cpio_backup(argv[0], argc > 1 ? argv[1] : NULL, &v);
|
||||
case RM:
|
||||
cpio_rm(recursive, argv[0], &v);
|
||||
break;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "logging.h"
|
||||
#include "bootimg.h"
|
||||
|
||||
#define KERNEL_FILE "kernel"
|
||||
@ -12,9 +13,6 @@
|
||||
#define DTB_FILE "dtb"
|
||||
#define NEW_BOOT "new-boot.img"
|
||||
|
||||
#define str(a) #a
|
||||
#define xstr(a) str(a)
|
||||
|
||||
// Main entries
|
||||
void unpack(const char *image);
|
||||
void repack(const char* orig_image, const char* out_image);
|
||||
@ -36,13 +34,10 @@ long long comp(file_t type, int to, const void *from, size_t size);
|
||||
long long decomp(file_t type, int to, const void *from, size_t size);
|
||||
|
||||
// Utils
|
||||
extern void mmap_ro(const char *filename, void **buf, size_t *size);
|
||||
extern void mmap_rw(const char *filename, void **buf, size_t *size);
|
||||
extern void write_zero(int fd, size_t size);
|
||||
extern void mem_align(size_t *pos, size_t align);
|
||||
extern void file_align(int fd, size_t align, int out);
|
||||
extern int open_new(const char *filename);
|
||||
extern void *patch_init_rc(char *data, uint32_t *size);
|
||||
extern int check_verity_pattern(const char *s);
|
||||
extern int check_encryption_pattern(const char *s);
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "magiskboot.h"
|
||||
#include "utils.h"
|
||||
#include "sha1.h"
|
||||
|
||||
/********************
|
||||
@ -47,8 +48,9 @@ static void usage(char *arg0) {
|
||||
" Return value: 0/stock 1/Magisk 2/other (e.g. phh, SuperSU)\n"
|
||||
" -patch <KEEPVERITY> <KEEPFORCEENCRYPT>\n"
|
||||
" Patch cpio for Magisk. KEEP**** are true/false values\n"
|
||||
" -backup <origcpio>\n"
|
||||
" -backup <origcpio> [SHA1]\n"
|
||||
" Create ramdisk backups into <incpio> from <origcpio>\n"
|
||||
" SHA1 of stock boot image is optional\n"
|
||||
" -restore\n"
|
||||
" Restore ramdisk from ramdisk backup within <incpio>\n"
|
||||
" -stocksha1\n"
|
||||
|
311
jni/magiskinit.c
311
jni/magiskinit.c
@ -1,311 +0,0 @@
|
||||
/* magiskinit.c - Workaround for skip_initramfs devices
|
||||
*
|
||||
* This code has to be compiled statically to work properly.
|
||||
*
|
||||
* Magiskinit will mount sysfs, parse through uevent files to make the system block device,
|
||||
* then it'll mount the system partition and clone rootfs except files under /system.
|
||||
* Folders placed in "overlay" will then be overlayed to the root.
|
||||
* Lastly, before giving control back to the real init, it'll patch the root files,
|
||||
* extract (or compile if needed) sepolicy and patch it to load Magisk.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#include <cil/cil.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "magiskpolicy.h"
|
||||
|
||||
struct cmdline {
|
||||
int skip_initramfs;
|
||||
char slot[3];
|
||||
};
|
||||
|
||||
struct device {
|
||||
dev_t major;
|
||||
dev_t minor;
|
||||
char devname[32];
|
||||
char partname[32];
|
||||
char path[64];
|
||||
};
|
||||
|
||||
extern policydb_t *policydb;
|
||||
|
||||
extern void mmap_ro(const char *filename, void **buf, size_t *size);
|
||||
extern void mmap_rw(const char *filename, void **buf, size_t *size);
|
||||
extern void *patch_init_rc(char *data, uint32_t *size);
|
||||
|
||||
static void parse_cmdline(struct cmdline *cmd) {
|
||||
char *tok;
|
||||
char buffer[4096];
|
||||
mkdir("/proc", 0555);
|
||||
mount("proc", "/proc", "proc", 0, NULL);
|
||||
int fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC);
|
||||
ssize_t size = read(fd, buffer, sizeof(buffer));
|
||||
buffer[size] = '\0';
|
||||
close(fd);
|
||||
umount("/proc");
|
||||
tok = strtok(buffer, " ");
|
||||
cmd->skip_initramfs = 0;
|
||||
cmd->slot[0] = '\0';
|
||||
while (tok != NULL) {
|
||||
if (strncmp(tok, "androidboot.slot_suffix", 23) == 0) {
|
||||
sscanf(tok, "androidboot.slot_suffix=%s", cmd->slot);
|
||||
} else if (strcmp(tok, "skip_initramfs") == 0) {
|
||||
cmd->skip_initramfs = 1;
|
||||
}
|
||||
tok = strtok(NULL, " ");
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_device(struct device *dev, char *uevent) {
|
||||
char *tok;
|
||||
tok = strtok(uevent, "\n");
|
||||
while (tok != NULL) {
|
||||
if (strncmp(tok, "MAJOR", 5) == 0) {
|
||||
sscanf(tok, "MAJOR=%ld", (long*) &dev->major);
|
||||
} else if (strncmp(tok, "MINOR", 5) == 0) {
|
||||
sscanf(tok, "MINOR=%ld", (long*) &dev->minor);
|
||||
} else if (strncmp(tok, "DEVNAME", 7) == 0) {
|
||||
sscanf(tok, "DEVNAME=%s", dev->devname);
|
||||
} else if (strncmp(tok, "PARTNAME", 8) == 0) {
|
||||
sscanf(tok, "PARTNAME=%s", dev->partname);
|
||||
}
|
||||
tok = strtok(NULL, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int setup_block(struct device *dev, const char *partname) {
|
||||
char buffer[1024], path[128];
|
||||
struct dirent *entry;
|
||||
DIR *dir = opendir("/sys/dev/block");
|
||||
if (dir == NULL)
|
||||
return 1;
|
||||
int found = 0;
|
||||
while ((entry = readdir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
snprintf(path, sizeof(path), "/sys/dev/block/%s/uevent", entry->d_name);
|
||||
int fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
ssize_t size = read(fd, buffer, sizeof(buffer));
|
||||
buffer[size] = '\0';
|
||||
close(fd);
|
||||
parse_device(dev, buffer);
|
||||
if (strcmp(dev->partname, partname) == 0) {
|
||||
snprintf(dev->path, sizeof(dev->path), "/dev/block/%s", dev->devname);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
if (!found)
|
||||
return 1;
|
||||
|
||||
mkdir("/dev", 0755);
|
||||
mkdir("/dev/block", 0755);
|
||||
mknod(dev->path, S_IFBLK | 0600, makedev(dev->major, dev->minor));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void patch_ramdisk() {
|
||||
void *addr;
|
||||
size_t size;
|
||||
mmap_rw("/init", &addr, &size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (memcmp(addr + i, "/system/etc/selinux/plat_sepolicy.cil", 37) == 0) {
|
||||
memcpy(addr + i, "/system/etc/selinux/plat_sepolicy.xxx", 37);
|
||||
break;
|
||||
}
|
||||
}
|
||||
munmap(addr, size);
|
||||
mmap_rw("/init.rc", &addr, &size);
|
||||
uint32_t new_size = size;
|
||||
void *init_rc = patch_init_rc(addr, &new_size);
|
||||
munmap(addr, size);
|
||||
int fd = open("/init.rc", O_WRONLY | O_TRUNC | O_CLOEXEC);
|
||||
write(fd, init_rc, new_size);
|
||||
close(fd);
|
||||
free(init_rc);
|
||||
}
|
||||
|
||||
static int strend(const char *s1, const char *s2) {
|
||||
int l1 = strlen(s1);
|
||||
int l2 = strlen(s2);
|
||||
return strcmp(s1 + l1 - l2, s2);
|
||||
}
|
||||
|
||||
static void patch_sepolicy() {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
char *sepolicy = NULL, path[128];
|
||||
if (access("/system_root/sepolicy", R_OK) == 0)
|
||||
sepolicy = "/system_root/sepolicy";
|
||||
if (sepolicy == NULL && access("/vendor/etc/selinux/precompiled_sepolicy", R_OK) == 0) {
|
||||
void *sys_sha = NULL, *ven_sha = NULL;
|
||||
size_t sys_size = 0, ven_size = 0;
|
||||
if ((dir = opendir("/vendor/etc/selinux")) == NULL)
|
||||
goto check_done;
|
||||
while ((entry = readdir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
if (strend(entry->d_name, ".sha256") == 0) {
|
||||
snprintf(path, sizeof(path), "/vendor/etc/selinux/%s", entry->d_name);
|
||||
mmap_ro(path, &ven_sha, &ven_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
if ((dir = opendir("/system/etc/selinux")) == NULL)
|
||||
goto check_done;
|
||||
while ((entry = readdir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
if (strend(entry->d_name, ".sha256") == 0) {
|
||||
snprintf(path, sizeof(path), "/system/etc/selinux/%s", entry->d_name);
|
||||
mmap_ro(path, &sys_sha, &sys_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
if (sys_size == ven_size && memcmp(sys_sha, ven_sha, sys_size) == 0)
|
||||
sepolicy = "/vendor/etc/selinux/precompiled_sepolicy";
|
||||
munmap(sys_sha, sys_size);
|
||||
munmap(ven_sha, ven_size);
|
||||
}
|
||||
|
||||
check_done:
|
||||
|
||||
if (sepolicy) {
|
||||
load_policydb(sepolicy);
|
||||
} else {
|
||||
// Compile cil
|
||||
struct cil_db *db = NULL;
|
||||
sepol_policydb_t *pdb = NULL;
|
||||
void *addr;
|
||||
size_t size;
|
||||
|
||||
cil_db_init(&db);
|
||||
cil_set_mls(db, 1);
|
||||
cil_set_target_platform(db, SEPOL_TARGET_SELINUX);
|
||||
cil_set_policy_version(db, POLICYDB_VERSION_XPERMS_IOCTL);
|
||||
cil_set_attrs_expand_generated(db, 0);
|
||||
|
||||
mmap_ro("/system/etc/selinux/plat_sepolicy.cil", &addr, &size);
|
||||
cil_add_file(db, "/system/etc/selinux/plat_sepolicy.cil", addr, size);
|
||||
munmap(addr, size);
|
||||
|
||||
dir = opendir("/system/etc/selinux/mapping");
|
||||
while ((entry = readdir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
if (strend(entry->d_name, ".cil") == 0) {
|
||||
snprintf(path, sizeof(path), "/system/etc/selinux/mapping/%s", entry->d_name);
|
||||
mmap_ro(path, &addr, &size);
|
||||
cil_add_file(db, path, addr, size);
|
||||
munmap(addr, size);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
dir = opendir("/vendor/etc/selinux");
|
||||
while ((entry = readdir(dir))) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
if (strend(entry->d_name, ".cil") == 0) {
|
||||
snprintf(path, sizeof(path), "/vendor/etc/selinux/%s", entry->d_name);
|
||||
mmap_ro(path, &addr, &size);
|
||||
cil_add_file(db, path, addr, size);
|
||||
munmap(addr, size);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
cil_compile(db);
|
||||
cil_build_policydb(db, &pdb);
|
||||
cil_db_destroy(&db);
|
||||
|
||||
policydb = &pdb->p;
|
||||
}
|
||||
|
||||
// Magisk patches
|
||||
sepol_min_rules();
|
||||
dump_policydb("/sepolicy");
|
||||
destroy_policydb();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
umask(0);
|
||||
|
||||
struct cmdline cmd;
|
||||
parse_cmdline(&cmd);
|
||||
|
||||
if (cmd.skip_initramfs) {
|
||||
// Normal boot mode
|
||||
// Clear rootfs
|
||||
int root = open("/", O_RDONLY | O_CLOEXEC);
|
||||
|
||||
// Exclude overlay folder
|
||||
excl_list = (char *[]) { "overlay", NULL };
|
||||
frm_rf(root);
|
||||
|
||||
mkdir("/sys", 0755);
|
||||
mount("sysfs", "/sys", "sysfs", 0, NULL);
|
||||
|
||||
char partname[32];
|
||||
snprintf(partname, sizeof(partname), "system%s", cmd.slot);
|
||||
|
||||
struct device dev;
|
||||
setup_block(&dev, partname);
|
||||
|
||||
mkdir("/system_root", 0755);
|
||||
mount(dev.path, "/system_root", "ext4", MS_RDONLY, NULL);
|
||||
int system_root = open("/system_root", O_RDONLY | O_CLOEXEC);
|
||||
|
||||
// Exclude system folder
|
||||
excl_list = (char *[]) { "system", NULL };
|
||||
clone_dir(system_root, root);
|
||||
mkdir("/system", 0755);
|
||||
mount("/system_root/system", "/system", NULL, MS_BIND, NULL);
|
||||
|
||||
int overlay = open("/overlay", O_RDONLY | O_CLOEXEC);
|
||||
if (overlay > 0)
|
||||
mv_dir(overlay, root);
|
||||
|
||||
snprintf(partname, sizeof(partname), "vendor%s", cmd.slot);
|
||||
|
||||
// We need to mount independent vendor partition
|
||||
if (setup_block(&dev, partname) == 0)
|
||||
mount(dev.path, "/vendor", "ext4", MS_RDONLY, NULL);
|
||||
|
||||
patch_ramdisk();
|
||||
patch_sepolicy();
|
||||
|
||||
close(root);
|
||||
close(system_root);
|
||||
close(overlay);
|
||||
rmdir("/overlay");
|
||||
umount("/vendor");
|
||||
} else {
|
||||
// Recovery mode
|
||||
// Revert original init binary
|
||||
unlink("/init");
|
||||
rename("/.backup/init", "/init");
|
||||
}
|
||||
|
||||
execv("/init", argv);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1 +1 @@
|
||||
Subproject commit 3c6a170138cacb1f817c65181bd6e3ef15cfca9e
|
||||
Subproject commit 9e96824161ddf1d6af516f44cad4d0e904a7abed
|
@ -5,6 +5,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifndef NO_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
@ -52,6 +53,8 @@ int mkdir_p(const char *pathname, mode_t mode) {
|
||||
|
||||
void rm_rf(const char *path) {
|
||||
int fd = xopen(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return;
|
||||
frm_rf(fd);
|
||||
close(fd);
|
||||
rmdir(path);
|
||||
@ -294,6 +297,22 @@ void fclone_attr(const int sourcefd, const int targetfd) {
|
||||
fsetattr(targetfd, &a);
|
||||
}
|
||||
|
||||
void mmap_ro(const char *filename, void **buf, size_t *size) {
|
||||
int fd = xopen(filename, O_RDONLY);
|
||||
*size = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
*buf = *size > 0 ? xmmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0) : NULL;
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void mmap_rw(const char *filename, void **buf, size_t *size) {
|
||||
int fd = xopen(filename, O_RDWR);
|
||||
*size = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
*buf = *size > 0 ? xmmap(NULL, *size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0) : NULL;
|
||||
close(fd);
|
||||
}
|
||||
|
||||
#ifndef NO_SELINUX
|
||||
|
||||
#define UNLABEL_CON "u:object_r:unlabeled:s0"
|
||||
|
@ -11,18 +11,15 @@
|
||||
# boot_patch.sh script A script to patch boot. Expect path to boot image as parameter.
|
||||
# (this file) The script will use binaries and files in its same directory
|
||||
# to complete the patching process
|
||||
# magisk binary The main binary for all Magisk operations.
|
||||
# It is also used to patch the sepolicy in the ramdisk.
|
||||
# monogisk binary The monolithic binary to replace /init
|
||||
# magiskboot binary A tool to unpack boot image, decompress ramdisk, extract ramdisk
|
||||
# , and patch the ramdisk for Magisk support
|
||||
# init.magisk.rc script A new line will be added to init.rc to import this script.
|
||||
# All magisk entrypoints are defined here
|
||||
# chromeos folder This folder should store all the utilities and keys to sign
|
||||
# (optional) a chromeos device, used in the tablet Pixel C
|
||||
#
|
||||
# If the script is not running as root, then the input boot image should be a stock image
|
||||
# or have a backup included in ramdisk internally, since we cannot access the stock boot
|
||||
# image placed under /data we've created when previously installing
|
||||
# image placed under /data we've created when previously installed
|
||||
#
|
||||
##########################################################################################
|
||||
##########################################################################################
|
||||
@ -47,21 +44,6 @@ basename_wrap() {
|
||||
echo ${1##*/}
|
||||
}
|
||||
|
||||
# --cpio-add <incpio> <mode> <entry> <infile>
|
||||
cpio_add() {
|
||||
./magiskboot --cpio-add ramdisk.cpio $1 $2 $3
|
||||
}
|
||||
|
||||
# --cpio-extract <incpio> <entry> <outfile>
|
||||
cpio_extract() {
|
||||
./magiskboot --cpio-extract ramdisk.cpio $1 $2
|
||||
}
|
||||
|
||||
# --cpio-mkdir <incpio> <mode> <entry>
|
||||
cpio_mkdir() {
|
||||
./magiskboot --cpio-mkdir ramdisk.cpio $1 $2
|
||||
}
|
||||
|
||||
##########################################################################################
|
||||
# Initialization
|
||||
##########################################################################################
|
||||
@ -85,6 +67,9 @@ BOOTIMAGE="$1"
|
||||
|
||||
chmod -R 755 .
|
||||
|
||||
# Extract magisk if doesn't exist
|
||||
[ -e magisk ] || ./monogisk -x magisk magisk
|
||||
|
||||
##########################################################################################
|
||||
# Unpack
|
||||
##########################################################################################
|
||||
@ -172,33 +157,11 @@ esac
|
||||
|
||||
ui_print "- Patching ramdisk"
|
||||
|
||||
if [ ! -z $SHA1 ]; then
|
||||
cp init.magisk.rc init.magisk.rc.bak
|
||||
echo "# STOCKSHA1=$SHA1" >> init.magisk.rc
|
||||
fi
|
||||
|
||||
if $SKIP_INITRAMFS; then
|
||||
cpio_add 750 init magiskinit
|
||||
cpio_mkdir 000 overlay
|
||||
cpio_add 750 overlay/init.magisk.rc init.magisk.rc
|
||||
cpio_mkdir 750 overlay/sbin
|
||||
cpio_add 755 overlay/sbin/magisk magisk
|
||||
else
|
||||
./magiskboot --cpio-patch ramdisk.cpio $KEEPVERITY $KEEPFORCEENCRYPT
|
||||
|
||||
cpio_extract sepolicy sepolicy
|
||||
./magisk magiskpolicy --load sepolicy --save sepolicy --minimal
|
||||
cpio_add 644 sepolicy sepolicy
|
||||
rm -f sepolicy
|
||||
|
||||
cpio_add 750 init.magisk.rc init.magisk.rc
|
||||
cpio_add 755 sbin/magisk magisk
|
||||
fi
|
||||
|
||||
mv init.magisk.rc.bak init.magisk.rc 2>/dev/null
|
||||
./magiskboot --cpio-add ramdisk.cpio 750 init monogisk
|
||||
./magiskboot --cpio-patch ramdisk.cpio $KEEPVERITY $KEEPFORCEENCRYPT
|
||||
|
||||
# Create ramdisk backups
|
||||
./magiskboot --cpio-backup ramdisk.cpio ramdisk.cpio.orig
|
||||
./magiskboot --cpio-backup ramdisk.cpio ramdisk.cpio.orig $SHA1
|
||||
|
||||
if ! $KEEPVERITY && [ -f dtb ]; then
|
||||
./magiskboot --dtb-patch dtb && ui_print "- Patching fstab in dtb to remove dm-verity"
|
||||
@ -218,7 +181,7 @@ rm -f ramdisk.cpio.orig
|
||||
A1020054011440B93FA00F7140020054010840B93FA00F71E0010054001840B91FA00F7181010054
|
||||
|
||||
# skip_initramfs -> want_initramfs
|
||||
$SKIP_INITRAMFS && ./magiskboot --hexpatch kernel \
|
||||
./magiskboot --hexpatch kernel \
|
||||
736B69705F696E697472616D6673 \
|
||||
77616E745F696E697472616D6673
|
||||
|
||||
|
@ -79,18 +79,12 @@ ui_print "- Constructing environment"
|
||||
|
||||
is_mounted /data && MAGISKBIN=/data/magisk || MAGISKBIN=/cache/data_bin
|
||||
|
||||
if $BOOTMODE; then
|
||||
# Cleanup binary mirrors
|
||||
umount -l /dev/magisk/mirror/bin 2>/dev/null
|
||||
rm -rf /dev/magisk/mirror/bin 2>/dev/null
|
||||
fi
|
||||
|
||||
# Save our stock boot image dump before removing it
|
||||
mv /data/magisk/stock_boot* /data 2>/dev/null
|
||||
|
||||
# Copy required files
|
||||
rm -rf $MAGISKBIN 2>/dev/null
|
||||
mkdir -p $MAGISKBIN
|
||||
rm -rf $MAGISKBIN/* 2>/dev/null
|
||||
mkdir -p $MAGISKBIN 2>/dev/null
|
||||
cp -af $BINDIR/. $COMMONDIR/. $CHROMEDIR $TMPDIR/bin/busybox $MAGISKBIN
|
||||
chmod -R 755 $MAGISKBIN
|
||||
|
||||
|
@ -1,41 +0,0 @@
|
||||
# Triggers
|
||||
|
||||
on post-fs
|
||||
start logd
|
||||
start magisk_daemon
|
||||
wait /dev/.magisk.unblock 5
|
||||
rm /dev/.magisk.unblock
|
||||
start magisk_pfs
|
||||
wait /dev/.magisk.unblock 10
|
||||
|
||||
on post-fs-data
|
||||
load_persist_props
|
||||
rm /dev/.magisk.unblock
|
||||
start magisk_pfsd
|
||||
wait /dev/.magisk.unblock 10
|
||||
|
||||
# Services
|
||||
|
||||
# Self recoverable service
|
||||
service magisk_daemon /sbin/magisk --daemon
|
||||
user root
|
||||
seclabel u:r:su:s0
|
||||
|
||||
# launch post-fs script
|
||||
service magisk_pfs /sbin/magisk --post-fs
|
||||
user root
|
||||
seclabel u:r:su:s0
|
||||
oneshot
|
||||
|
||||
# launch post-fs-data script
|
||||
service magisk_pfsd /sbin/magisk --post-fs-data
|
||||
user root
|
||||
seclabel u:r:su:s0
|
||||
oneshot
|
||||
|
||||
# launch late_start script
|
||||
service magisk_service /sbin/magisk --service
|
||||
class late_start
|
||||
user root
|
||||
seclabel u:r:su:s0
|
||||
oneshot
|
Loading…
Reference in New Issue
Block a user