diff --git a/README.MD b/README.MD new file mode 100644 index 000000000..8b351456d --- /dev/null +++ b/README.MD @@ -0,0 +1,4 @@ +# Magisk +Static binaries included: +* Busybox: http://forum.xda-developers.com/android/software-hacking/tool-busybox-flashable-archs-t3348543 +* Open source su binary: https://github.com/seSuperuser/Superuser diff --git a/jni/sepolicy-inject b/jni/sepolicy-inject index dd2d55696..c69db035e 160000 --- a/jni/sepolicy-inject +++ b/jni/sepolicy-inject @@ -1 +1 @@ -Subproject commit dd2d556962df6d38c98e6003113c0cb899facc30 +Subproject commit c69db035ee32e34256c3cd8562e28bc4f5fba2db diff --git a/zip_static/META-INF/com/google/android/update-binary b/zip_static/META-INF/com/google/android/update-binary new file mode 100644 index 000000000..b49fb4731 --- /dev/null +++ b/zip_static/META-INF/com/google/android/update-binary @@ -0,0 +1,462 @@ +#!/sbin/sh +########################################################################################## +# +# Magisk Boot Image Patcher +# by topjohnwu +# +# This zip will patch your boot image with Magisk support +# +########################################################################################## + +TMPDIR=/tmp + +if [ -z "$BOOTMODE" ]; then + BOOTMODE=false +fi + +mount -o rw,remount rootfs / +mkdir /magisk 2>/dev/null + +if ($BOOTMODE); then + TMPDIR=/data/tmp + mount -o ro,remount rootfs / +fi + +INSTALLER=$TMPDIR/magisk + +COREDIR=/magisk/.core + +########################################################################################## +# Flashable update-binary preparation +########################################################################################## + +OUTFD=$2 +ZIP=$3 + +readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null +if [ "$?" -eq "0" ]; then + OUTFD=0 + + for FD in `ls /proc/$$/fd`; do + readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null + if [ "$?" -eq "0" ]; then + ps | grep " 3 $FD " | grep -v grep >/dev/null + if [ "$?" -eq "0" ]; then + OUTFD=$FD + break + fi + fi + done +fi + +mkdir -p $INSTALLER +cd $INSTALLER +unzip -o "$ZIP" + +########################################################################################## +# Functions +########################################################################################## + +ui_print() { + if ($BOOTMODE); then + echo "$1" + else + echo -n -e "ui_print $1\n" >> /proc/self/fd/$OUTFD + echo -n -e "ui_print\n" >> /proc/self/fd/$OUTFD + fi +} + +getvar() { + local VARNAME=$1 + local VALUE=$(eval echo \$"$VARNAME"); + for FILE in /data/.magisk /cache/.magisk /system/.magisk; do + if [ -z "$VALUE" ]; then + LINE=$(cat $FILE 2>/dev/null | grep "$VARNAME=") + if [ ! -z "$LINE" ]; then + VALUE=${LINE#*=} + fi + fi + done + eval $VARNAME=\$VALUE +} + +find_boot_image() { + if [ -z "$BOOTIMAGE" ]; then + for PARTITION in kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do + BOOTIMAGE=$(readlink /dev/block/by-name/$PARTITION || readlink /dev/block/platform/*/by-name/$PARTITION || readlink /dev/block/platform/*/*/by-name/$PARTITION) + if [ ! -z "$BOOTIMAGE" ]; then break; fi + done + fi +} + +is_mounted() { + if [ ! -z "$2" ]; then + cat /proc/mounts | grep $1 | grep $2, >/dev/null + else + cat /proc/mounts | grep $1 >/dev/null + fi + return $? +} + +grep_prop() { + REGEX="s/^$1=//p" + shift + FILES=$@ + if [ -z "$FILES" ]; then + FILES='/system/build.prop' + fi + cat $FILES 2>/dev/null | sed -n $REGEX | head -n 1 +} + +repack_boot() { + cd $RAMDISK + find . | cpio -o -H newc 2>/dev/null | gzip -9 > $UNPACKDIR/ramdisk.gz + cd $UNPACKDIR + $BINDIR/bootimgtools --repack $ORIGBOOT + if [ -f chromeos ]; then + echo " " > config + echo " " > bootloader + $CHROMEDIR/futility vbutil_kernel --pack new-boot.img.signed --keyblock $CHROMEDIR/kernel.keyblock --signprivate $CHROMEDIR/kernel_data_key.vbprivk --version 1 --vmlinuz new-boot.img --config config --arch arm --bootloader bootloader --flags 0x1 + rm -f new-boot.img + mv new-boot.img.signed new-boot.img + fi + if ($SAMSUNG); then + SAMSUNG_CHECK=$(cat new-boot.img | grep SEANDROIDENFORCE) + if [ $? -ne 0 ]; then + echo -n "SEANDROIDENFORCE" >> new-boot.img + fi + fi + mv new-boot.img $NEWBOOT + $BINDIR/bootimgtools --hexpatch $NEWBOOT \ + 49010054011440B93FA00F71E9000054010840B93FA00F7189000054001840B91FA00F7188010054 \ + A1020054011440B93FA00F7140020054010840B93FA00F71E0010054001840B91FA00F7181010054 +} + +########################################################################################## +# Detection +########################################################################################## + +ui_print "****************************" +ui_print "Magisk v7 Boot Image Patcher" +ui_print "****************************" + +if [ ! -d "$INSTALLER/common" ]; then + ui_print "! Failed: Unable to extract zip file!" + exit 1 +fi + +ui_print "- Mounting /system(ro), /cache, /data" +mount -o ro /system 2>/dev/null +mount /cache 2>/dev/null +mount /data 2>/dev/null + +if [ ! -f '/system/build.prop' ]; then + ui_print "! Failed: /system could not be mounted!" + exit 1 +fi + +API=$(grep_prop ro.build.version.sdk) +ABI=$(grep_prop ro.product.cpu.abi | cut -c-3) +ABI2=$(grep_prop ro.product.cpu.abi2 | cut -c-3) +ABILONG=$(grep_prop ro.product.cpu.abi) + +ARCH=arm +IS64BIT= +if [ "$ABI" = "x86" ]; then ARCH=x86; fi; +if [ "$ABI2" = "x86" ]; then ARCH=x86; fi; +if [ "$ABILONG" = "arm64-v8a" ]; then ARCH=arm64; IS64BIT=1; fi; +if [ "$ABILONG" = "x86_64" ]; then ARCH=x64; IS64BIT=1; fi; + + +if [ "$API" -lt "21" ]; then + ui_print "! Magisk is only for Lollipop 5.0+ (SDK 21+)" + exit 1 +fi + +ui_print "- Device platform: $ARCH" + +BINDIR=$INSTALLER/arm +if [ "$ARCH" = "x86" -o "$ARCH" = "x64" ]; then + BINDIR=$INSTALLER/x86 +fi + +find_boot_image +if [ -z "$BOOTIMAGE" ]; then + ui_print "! Unable to detect boot image" + exit 1 +fi + +if [ -z "$NOOVERRIDE" ]; then + # read override variables + getvar KEEPVERITY + getvar KEEPFORCEENCRYPT + getvar KEEPSUPERSU +fi + +if [ -z "$KEEPVERITY" ]; then + # we don't keep dm-verity by default + KEEPVERITY=false +fi +if [ -z "$KEEPFORCEENCRYPT" ]; then + # we don't keep forceencrypt by default + KEEPFORCEENCRYPT=false +fi +if [ -z "$KEEPSUPERSU" ]; then + # we don't keep SuperSU by default + KEEPSUPERSU=false +fi + +SAMSUNG=false +SAMSUNG_CHECK=$(cat /system/build.prop | grep "ro.build.fingerprint=" | grep -i "samsung") +if [ $? -eq 0 ]; then + SAMSUNG=true +fi + +########################################################################################## +# Image +########################################################################################## + +if (is_mounted /data); then + IMG=/data/magisk.img +else + IMG=/cache/magisk.img + ui_print "- Data unavalible, use cache workaround" +fi + +if [ -f "$IMG" ]; then + ui_print "- $IMG detected!" +else + ui_print "- Creating $IMG" + make_ext4fs -l 64M -a /magisk -S $INSTALLER/common/file_contexts_image $IMG +fi + +if (! is_mounted /magisk); then + ui_print "- Mounting $IMG to /magisk" + LOOPDEVICE= + for LOOP in 0 1 2 3 4 5 6 7; do + if (! is_mounted /magisk); then + LOOPDEVICE=/dev/block/loop$LOOP + if [ ! -f "$LOOPDEVICE" ]; then + mknod $LOOPDEVICE b 7 $LOOP + fi + losetup $LOOPDEVICE $IMG + if [ "$?" -eq "0" ]; then + mount -t ext4 -o loop $LOOPDEVICE /magisk + if (! is_mounted /magisk); then + /system/bin/toolbox mount -t ext4 -o loop $LOOPDEVICE /magisk + fi + if (! is_mounted /magisk); then + /system/bin/toybox mount -t ext4 -o loop $LOOPDEVICE /magisk + fi + fi + if (is_mounted /magisk); then + break; + fi + fi + done +fi + +rm -rf $COREDIR/bin 2>/dev/null + +########################################################################################## +# Environment +########################################################################################## + +ui_print "- Constructing environment" + +if (is_mounted /data); then + rm -rf /data/busybox /data/magisk + mkdir -p /data/busybox + mkdir -p /data/magisk + cp -af $BINDIR/busybox $BINDIR/su $BINDIR/sepolicy-inject /data/magisk + chmod 755 /data/busybox /data/magisk /data/magisk/* + chcon 'u:object_r:system_file:s0' /data/busybox /data/magisk /data/magisk/* + /data/magisk/busybox --install -s /data/busybox + # Prevent issues + rm -f /data/busybox/su /data/busybox/sh +else + rm -rf /cache/data_bin + mkdir -p /cache/data_bin + cp -af $BINDIR/busybox $BINDIR/su $BINDIR/sepolicy-inject /cache/data_bin +fi + +########################################################################################## +# Boot image patch +########################################################################################## + +ui_print "- Found Boot Image: $BOOTIMAGE" + +rm -rf $TMPDIR/boottmp 2>/dev/null +mkdir -p $TMPDIR/boottmp + +CHROMEDIR=$INSTALLER/chromeos +ORIGBOOT=$TMPDIR/boottmp/boot.img +NEWBOOT=$TMPDIR/boottmp/new-boot.img +UNPACKDIR=$TMPDIR/boottmp/bootunpack +RAMDISK=$TMPDIR/boottmp/ramdisk +mkdir -p $UNPACKDIR +mkdir -p $RAMDISK + +chmod 777 $CHROMEDIR/futility $BINDIR/* + +ui_print "- Dumping boot image" +dd if=$BOOTIMAGE of=$ORIGBOOT + +ui_print "- Unpacking boot image" +cd $UNPACKDIR +$BINDIR/bootimgtools --extract $ORIGBOOT + +chmod 755 $(find $TMPDIR/boottmp -type d) +chmod 644 $(find $TMPDIR/boottmp -type f) + +cd $RAMDISK +gunzip -c < $UNPACKDIR/ramdisk.gz | cpio -i + +if [ -f "supersu" ]; then + KEEPSUPERSU=true +fi + +if (! $KEEPSUPERSU); then + # Backups + if [ -d ".backup" ]; then + ui_print "- Reverting ramdisk backup" + cp -af .backup/* . + rm -rf magisk init.magisk.rc sbin/magic_mask.sh sbin/magisk_wrapper.sh 2>/dev/null + else + if [ -d "magisk" -o -d "su" ]; then + cp -af /data/stock_boot*.gz /data/stock_boot.img.gz 2>/dev/null + gzip -d /data/stock_boot.img.gz 2>/dev/null + if [ -f "/data/stock_boot.img" ]; then + ui_print "- Using boot image backup" + cp -af /data/stock_boot.img $ORIGBOOT + rm -rf $RAMDISK $TMPDIR + mkdir -p $UNPACKDIR + mkdir -p $RAMDISK + cd $UNPACKDIR + $BINDIR/bootimgtools --extract $ORIGBOOT + cd $RAMDISK + gunzip -c < $UNPACKDIR/ramdisk.gz | cpio -i + else + ui_print "! No backups found" + ui_print "! Installer will still proceed, but might cause issues" + ui_print "! If possible, please restore to stock boot then flash Magisk again" + # Force removing SuperSU parts + rm -rf su init.supersu.rc sbin/launch_daemonsu.sh 2>/dev/null + fi + fi + ui_print "- Creating backups" + mkdir .backup + cp -af init.rc *fstab* verity_key sepolicy .backup 2>/dev/null + if (is_mounted /data); then + cp -af $ORIGBOOT /data/stock_boot.img + else + cp -af $ORIGBOOT /cache/stock_boot.img + fi + fi +fi + +# Patch ramdisk +ui_print "- Patching ramdisk" + +if [ $(grep -c "import /init.magisk.rc" init.rc) -eq "0" ]; then + sed -i "/import \/init\.environ\.rc/iimport /init.magisk.rc" init.rc +fi + +if (! $KEEPSUPERSU); then + sed -i "/selinux.reload_policy/d" init.rc + find . -type f -name "*fstab*" 2>/dev/null | while read FSTAB ; do + if (! $KEEPVERITY); then + sed -i "s/,support_scfs//g" $FSTAB + sed -i 's;,\{0,1\}verify\(=[^,]*\)\{0,1\};;g' $FSTAB + fi + if (! $KEEPFORCEENCRYPT); then + sed -i "s/forceencrypt/encryptable/g" $FSTAB + sed -i "s/forcefdeorfbe/encryptable/g" $FSTAB + fi + done + rm verity_key 2>/dev/null + + # sepolicy patches + # LD_LIBRARY_PATH=$BINDIR $BINDIR/supolicy --file sepolicy sepolicy.patched + # mv -f sepolicy.patched sepolicy + . $INSTALLER/common/supatch.sh + allow su_daemon "rootfs proc init system_file" "file dir lnk_file" "*" + allow init su_daemon unix_stream_socket connectto + allow su_daemon shell_exec file getattr + allow su_daemon tmpfs dir "*" + allow su_daemon selinuxfs file "read open write" + allow su_daemon kernel security "read_policy load_policy" + allow su_daemon toolbox_exec file "*" + allow kernel su fd use + allow init "rootfs system_file" file "*" + if $BINDIR/sepolicy-inject -e -s toolbox -P sepolicy; then + allow toolbox property_socket sock_file write + allow toolbox init unix_stream_socket connectto + allow toolbox init fifo_file "*" + allow toolbox default_prop property_service "*" + allow toolbox device dir "*" + fi + # Just in case + $BINDIR/sepolicy-inject -Z init -P sepolicy + $BINDIR/sepolicy-inject -Z toolbox -P sepolicy + $BINDIR/sepolicy-inject -Z su_daemon -P sepolicy + # Fix Xposed + allow zygote app_data_file "dir file" "*" + allow zygote input_device "dir chr_file" "*" + allow untrusted_app untrusted_app capability setgid + allow "system_server system_app" "app_data_file" "file dir" "*" +fi + +# Add new items +mkdir -p magisk 2>/dev/null +cp -af $INSTALLER/common/init.magisk.rc init.magisk.rc +cp -af $INSTALLER/common/magic_mask.sh sbin/magic_mask.sh +cp -af $INSTALLER/common/magisk_wrapper.sh sbin/magisk_wrapper.sh + +if (! $KEEPSUPERSU); then + cp -af $BINDIR/su $BINDIR/sepolicy-inject magisk +else + touch supersu +fi + +chmod 0755 magisk magisk/* +chmod 0750 init.magisk.rc sbin/magic_mask.sh sbin/magisk_wrapper.sh + +ui_print "- Repacking boot image" +repack_boot + +ORIGSIZE=$(ls -l $ORIGBOOT | awk '{print $5}') +NEWSIZE=$(ls -l $NEWBOOT | awk '{print $5}') +if [ "$NEWSIZE" -gt "$ORIGSIZE" ]; then + ui_print "! Boot partition space insufficient" + ui_print "! Remove ramdisk backups and binaries" + rm -rf $RAMDISK/.backup $NEWBOOT $RAMDISK/magisk/* 2>/dev/null + if (! $KEEPSUPERSU); then + mkdir -p /cache/magisk + cp $BINDIR/su $BINDIR/sepolicy-inject /cache/magisk + chmod 755 /cache/magisk /cache/magisk/* + chcon 'u:object_r:system_file:s0' /cache/magisk /cache/magisk/* + fi + repack_boot + NEWSIZE=$(ls -l $NEWBOOT | awk '{print $5}') + if [ "$NEWSIZE" -gt "$ORIGSIZE" ]; then + ui_print "! Boot partition size still too small..." + ui_print "! Unable to install Magisk" + exit 1 + fi +fi + +chmod 644 $NEWBOOT + +ui_print "- Flashing new boot image" +dd if=/dev/zero of=$BOOTIMAGE bs=4096 2>/dev/null +dd if=$NEWBOOT of=$BOOTIMAGE bs=4096 + +if (! $BOOTMODE); then + umount /magisk + losetup -d $LOOPDEVICE + umount /system +fi + +ui_print "- Done" +exit 0 diff --git a/zip_static/META-INF/com/google/android/updater-script b/zip_static/META-INF/com/google/android/updater-script new file mode 100644 index 000000000..67d290281 --- /dev/null +++ b/zip_static/META-INF/com/google/android/updater-script @@ -0,0 +1 @@ +# this is a dummy file, the magic is in update-binary \ No newline at end of file diff --git a/zip_static/arm/busybox b/zip_static/arm/busybox new file mode 100644 index 000000000..985254672 Binary files /dev/null and b/zip_static/arm/busybox differ diff --git a/zip_static/arm/su b/zip_static/arm/su new file mode 100644 index 000000000..7314e51e4 Binary files /dev/null and b/zip_static/arm/su differ diff --git a/zip_static/chromeos/futility b/zip_static/chromeos/futility new file mode 100644 index 000000000..28304a1bc Binary files /dev/null and b/zip_static/chromeos/futility differ diff --git a/zip_static/chromeos/kernel.keyblock b/zip_static/chromeos/kernel.keyblock new file mode 100644 index 000000000..9740be4e6 Binary files /dev/null and b/zip_static/chromeos/kernel.keyblock differ diff --git a/zip_static/chromeos/kernel_data_key.vbprivk b/zip_static/chromeos/kernel_data_key.vbprivk new file mode 100644 index 000000000..8d392fb29 Binary files /dev/null and b/zip_static/chromeos/kernel_data_key.vbprivk differ diff --git a/zip_static/common/file_contexts_image b/zip_static/common/file_contexts_image new file mode 100644 index 000000000..ee54edc68 --- /dev/null +++ b/zip_static/common/file_contexts_image @@ -0,0 +1 @@ +/magisk(/.*)? u:object_r:system_file:s0 diff --git a/zip_static/common/init.magisk.rc b/zip_static/common/init.magisk.rc new file mode 100644 index 000000000..6ca9532cc --- /dev/null +++ b/zip_static/common/init.magisk.rc @@ -0,0 +1,58 @@ +# Triggers + +on post-fs + # Paths + export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin:/su/bin:/magisk/.core/bin:/magisk/busybox/bin:/data/magisk + + # Start root + start phhsu + wait /dev/su 1 + + start magisk_pfs + wait /dev/unblock 20 + rmdir /dev/unblock + +on post-fs-data + + # Try to start root again in case post-fs failed + start phhsu + wait /dev/su 1 + + start magisk_pfsd + wait /dev/unblock 20 + rmdir /dev/unblock + +on property:magisk.root=* + start magisk_root + +# Services + +service phhsu /sbin/magisk_wrapper.sh phhsu + user root + seclabel u:r:su_daemon:s0 + oneshot + +# launch post-fs script +service magisk_pfs /sbin/magisk_wrapper.sh post-fs + user root + seclabel u:r:init:s0 + oneshot + +# launch post-fs-data script +service magisk_pfsd /sbin/magisk_wrapper.sh post-fs-data + user root + seclabel u:r:init:s0 + oneshot + +# launch late_start script +service magisk_service /sbin/magisk_wrapper.sh service + class late_start + user root + seclabel u:r:init:s0 + oneshot + +# root handling +service magisk_root /sbin/magisk_wrapper.sh root + user root + seclabel u:r:init:s0 + oneshot \ No newline at end of file diff --git a/zip_static/common/magic_mask.sh b/zip_static/common/magic_mask.sh new file mode 100644 index 000000000..c00f0ac65 --- /dev/null +++ b/zip_static/common/magic_mask.sh @@ -0,0 +1,402 @@ +#!/system/bin/sh + +LOGFILE=/cache/magisk.log +IMG=/data/magisk.img + +COREDIR=/magisk/.core + +DUMMDIR=$COREDIR/dummy +MIRRDIR=$COREDIR/mirror + +TMPDIR=/cache/tmp + +# Use the included busybox to do everything in all scripts for maximum compatibility +# We also do so because we rely on the option "-c" for cp (reserve contexts) +export PATH="/data/busybox:$PATH" +# Version info +setprop magisk.version 7 + +log_print() { + echo $1 + echo $1 >> $LOGFILE + log -p i -t Magisk "$1" +} + +mktouch() { + mkdir -p ${1%/*} 2>/dev/null + if [ -z "$2" ]; then + touch $1 2>/dev/null + else + echo $2 > $1 2>/dev/null + fi +} + +unblock() { + mkdir -p /dev/unblock + exit +} + +run_scripts() { + BASE=/magisk + if [ "$1" = "post-fs" ]; then + BASE=/cache/magisk + fi + + for MOD in $BASE/* ; do + if [ ! -f "$MOD/disable" ]; then + if [ -f "$MOD/$1.sh" ]; then + chmod 755 $MOD/$1.sh + chcon 'u:object_r:system_file:s0' $MOD/$1.sh + log_print "$1: $MOD/$1.sh" + $MOD/$1.sh + fi + fi + done +} + +loopsetup() { + LOOPDEVICE= + for DEV in $(ls /dev/block/loop*); do + if [ `losetup $DEV $1 >/dev/null 2>&1; echo $?` -eq 0 ]; then + LOOPDEVICE=$DEV + break + fi + done +} + +target_size_check() { + e2fsck -p -f $1 + curBlocks=`e2fsck -n $1 2>/dev/null | cut -d, -f3 | cut -d\ -f2`; + curUsedM=$((`echo "$curBlocks" | cut -d/ -f1` * 4 / 1024)); + curSizeM=$((`echo "$curBlocks" | cut -d/ -f2` * 4 / 1024)); + curFreeM=$((curSizeM - curUsedM)); +} + +travel() { + cd $1/$2 + if [ -f ".replace" ]; then + rm -rf $TMPDIR/$2 + mktouch $TMPDIR/$2 $1 + else + for ITEM in * ; do + if [ ! -e "/$2/$ITEM" ]; then + # New item found + if [ $2 = "system" ]; then + # We cannot add new items to /system root, delete it + rm -rf $ITEM + else + if [ -d "$TMPDIR/dummy/$2" ]; then + # We are in a higher level, delete the lower levels + rm -rf $TMPDIR/dummy/$2 + fi + # Mount the dummy parent + mktouch $TMPDIR/dummy/$2 + + mkdir -p $DUMMDIR/$2 2>/dev/null + if [ -d "$ITEM" ]; then + # Create new dummy directory + mkdir -p $DUMMDIR/$2/$ITEM + elif [ -L "$ITEM" ]; then + # Symlinks are small, copy them + cp -afc $ITEM $DUMMDIR/$2/$ITEM + else + # Create new dummy file + mktouch $DUMMDIR/$2/$ITEM + fi + + # Clone the original /system structure (depth 1) + if [ -e "/$2" ]; then + for DUMMY in /$2/* ; do + if [ -d "$DUMMY" ]; then + # Create dummy directory + mkdir -p $DUMMDIR$DUMMY + elif [ -L "$DUMMY" ]; then + # Symlinks are small, copy them + cp -afc $DUMMY $DUMMDIR$DUMMY + else + # Create dummy file + mktouch $DUMMDIR$DUMMY + fi + done + fi + fi + fi + + if [ -d "$ITEM" ]; then + # It's an directory, travel deeper + (travel $1 $2/$ITEM) + elif [ ! -L "$ITEM" ]; then + # Mount this file + mktouch $TMPDIR/$2/$ITEM $1 + fi + done + fi +} + +bind_mount() { + if [ -e "$1" -a -e "$2" ]; then + mount -o bind $1 $2 + if [ "$?" -eq "0" ]; then log_print "Mount: $1"; + else log_print "Mount Fail: $1"; fi + fi +} + +merge_image() { + if [ -f "$1" ]; then + log_print "$1 found" + if [ -f "$IMG" ]; then + log_print "$IMG found, attempt to merge" + + # Handle large images + target_size_check $1 + MERGEUSED=$curUsedM + target_size_check $IMG + if [ "$MERGEUSED" -gt "$curFreeM" ]; then + NEWDATASIZE=$((((MERGEUSED + curUsedM) / 32 + 2) * 32)) + log_print "Expanding $IMG to ${NEWDATASIZE}M..." + resize2fs $IMG ${NEWDATASIZE}M + fi + + # Start merging + mkdir /cache/data_img + mkdir /cache/merge_img + + # setup loop devices + loopsetup $IMG + LOOPDATA=$LOOPDEVICE + log_print "$LOOPDATA $IMG" + + loopsetup $1 + LOOPMERGE=$LOOPDEVICE + log_print "$LOOPMERGE $1" + + if [ ! -z "$LOOPDATA" ]; then + if [ ! -z "$LOOPMERGE" ]; then + # if loop devices have been setup, mount images + OK=true + + if [ `mount -t ext4 -o rw,noatime $LOOPDATA /cache/data_img >/dev/null 2>&1; echo $?` -ne 0 ]; then + OK=false + fi + + if [ `mount -t ext4 -o rw,noatime $LOOPMERGE /cache/merge_img >/dev/null 2>&1; echo $?` -ne 0 ]; then + OK=false + fi + + if ($OK); then + # Merge (will reserve selinux contexts) + if [ `cp -afc /cache/merge_img/. /cache/data_img >/dev/null 2>&1; echo $?` -eq 0 ]; then + log_print "Merge complete" + fi + fi + + umount /cache/data_img + umount /cache/merge_img + fi + fi + + losetup -d $LOOPDATA + losetup -d $LOOPMERGE + + rmdir /cache/data_img + rmdir /cache/merge_img + else + log_print "Moving $1 to $IMG " + mv $1 $IMG + fi + rm -f $1 + fi +} + +case $1 in + post-fs ) + mv $LOGFILE /cache/last_magisk.log + touch $LOGFILE + chmod 644 $LOGFILE + log_print "Magisk post-fs mode running..." + + for MOD in /cache/magisk/* ; do + if [ -f "$MOD/remove" ]; then + log_print "Remove module: $MOD" + rm -rf $MOD + elif [ -f "$MOD/auto_mount" -a ! -f "$MOD/disable" ]; then + find $MOD/system -type f 2>/dev/null | while read ITEM ; do + TARGET=${ITEM#$MOD} + bind_mount $ITEM $TARGET + done + fi + done + + run_scripts post-fs + unblock + ;; + + post-fs-data ) + if [ `mount | grep " /data " >/dev/null 2>&1; echo $?` -ne 0 ]; then + # /data not mounted yet, we will be called again later + unblock + fi + + if [ `mount | grep " /data " | grep "tmpfs" >/dev/null 2>&1; echo $?` -eq 0 ]; then + # /data not mounted yet, we will be called again later + unblock + fi + + log_print "Magisk post-fs-data mode running..." + + if [ -d "/cache/data_bin" ]; then + rm -rf /data/busybox /data/magisk + mkdir -p /data/busybox + mv /cache/data_bin /data/magisk + chmod 755 /data/busybox /data/magisk /data/magisk/* + chcon 'u:object_r:system_file:s0' /data/busybox /data/magisk /data/magisk/* + /data/magisk/busybox --install -s /data/busybox + # Prevent issues + rm -f /data/busybox/su /data/busybox/sh + fi + + mv /cache/stock_boot.img /data 2>/dev/null + + # Handle image merging + merge_image /cache/magisk.img + merge_image /data/magisk_merge.img + + # Mount /data image + if [ `cat /proc/mounts | grep /magisk >/dev/null 2>&1; echo $?` -ne 0 ]; then + loopsetup $IMG + if [ ! -z "$LOOPDEVICE" ]; then + mount -t ext4 -o rw,noatime $LOOPDEVICE /magisk + fi + fi + + if [ `cat /proc/mounts | grep /magisk >/dev/null 2>&1; echo $?` -ne 0 ]; then + log_print "magisk.img mount failed, nothing to do :(" + unblock + fi + + mkdir -p $DUMMDIR + mkdir -p $MIRRDIR/system + + log_print "Preparing modules" + # First do cleanups + rm -rf $DUMMDIR/* + rmdir $(find /magisk -type d -depth ! -path "*core*" ) 2>/dev/null + + # Travel through all mods + for MOD in /magisk/* ; do + if [ -f "$MOD/remove" ]; then + log_print "Remove module: $MOD" + rm -rf $MOD + elif [ -f "$MOD/auto_mount" -a -d "$MOD/system" -a ! -f "$MOD/disable" ]; then + (travel $MOD system) + fi + done + + # Proper permissions + find $DUMMDIR -type d -exec chmod 755 {} \; + find $DUMMDIR -type f -exec chmod 644 {} \; + + # linker(64), t*box, and app_process* are required if we need to dummy mount bin folder + if [ -f "$TMPDIR/dummy/system/bin" ]; then + rm -f $DUMMDIR/system/bin/linker* $DUMMDIR/system/bin/t*box $DUMMDIR/system/bin/app_process* + cd /system/bin + cp -afc linker* t*box app_process* $DUMMDIR/system/bin/ + fi + + # Shrink the image if possible + if [ `umount /magisk >/dev/null 2>&1; echo $?` -eq 0 ]; then + losetup -d $LOOPDEVICE + target_size_check $IMG + NEWDATASIZE=$(((curUsedM / 32 + 2) * 32)) + if [ "$curSizeM" -gt "$NEWDATASIZE" ]; then + log_print "Shrinking $IMG to ${NEWDATASIZE}M..." + resize2fs $IMG ${NEWDATASIZE}M + fi + loopsetup $IMG + if [ ! -z "$LOOPDEVICE" ]; then + mount -t ext4 -o rw,noatime $LOOPDEVICE /magisk + fi + fi + + if [ `cat /proc/mounts | grep /magisk >/dev/null 2>&1; echo $?` -ne 0 ]; then + log_print "magisk.img mount failed, nothing to do :(" + unblock + fi + + # Remove legacy phh root and crap folder + rm -rf /magisk/phh + rm -rf /magisk/lost+found + + # Start doing tasks + + # Stage 1 + log_print "Bind mount dummy system" + find $TMPDIR/dummy -type f 2>/dev/null | while read ITEM ; do + TARGET=${ITEM#$TMPDIR/dummy} + ORIG=$DUMMDIR$TARGET + bind_mount $ORIG $TARGET + done + + # Stage 2 + log_print "Bind mount module items" + find $TMPDIR/system -type f 2>/dev/null | while read ITEM ; do + TARGET=${ITEM#$TMPDIR} + ORIG=`cat $ITEM`$TARGET + bind_mount $ORIG $TARGET + rm -f $DUMMDIR${TARGET%/*}/.dummy 2>/dev/null + done + + # Run scripts + run_scripts post-fs-data + + # Bind hosts for Adblock apps + if [ ! -f "$COREDIR/hosts" ]; then + cp -afc /system/etc/hosts $COREDIR/hosts + fi + log_print "Enabling systemless hosts file support" + bind_mount $COREDIR/hosts /system/etc/hosts + + # Stage 3 + log_print "Bind mount system mirror" + bind_mount /system $MIRRDIR/system + + # Stage 4 + log_print "Bind mount mirror items" + # Find all empty directores and dummy files, they should be mounted by original files in /system + find $DUMMDIR -type d -exec sh -c 'if [ -z "$(ls -A $1)" ]; then echo $1; fi' -- {} \; -o \( -type f -size 0 -print \) | while read ITEM ; do + ORIG=${ITEM/dummy/mirror} + TARGET=${ITEM#$DUMMDIR} + bind_mount $ORIG $TARGET + done + + # All done + rm -rf $TMPDIR + + if [ ! -f "/supersu" ]; then + # Expose root path + setprop magisk.supath /magisk/.core/bin + setprop magisk.root 1 + fi + + unblock + ;; + + service ) + rm -rf /cache/unblock + log_print "Magisk late_start service mode running..." + run_scripts service + ;; + + root ) + SUPATH=$(getprop magisk.supath) + ROOT=$(getprop magisk.root) + if [ "$ROOT" -eq "1" ]; then + log_print "Enabling root" + rm -f SUPATH + ln -s /data/magisk $SUPATH + else + log_print "Disabling root" + rm -f SUPATH + fi + ;; +esac diff --git a/zip_static/common/magisk_wrapper.sh b/zip_static/common/magisk_wrapper.sh new file mode 100644 index 000000000..be726f014 --- /dev/null +++ b/zip_static/common/magisk_wrapper.sh @@ -0,0 +1,42 @@ +#!/system/bin/sh + +BINDIR=/magisk/.core/bin + +# Find where's su binary +for DIR in /magisk /data/magisk /cache/magisk /su/bin; do + [ -f "$DIR/su" ] && break +done + +case $1 in + phhsu ) + if [ ! -d "/dev/su" ]; then + $DIR/sepolicy-inject --live --auto -s su + exec $DIR/su --daemon + fi + ;; + post-fs ) + # If su call fails, temporary switch to permissive (workaround) + # This workaround will not always work (e.g. Samsung stock boot images) + if [ `$DIR/su -c "/sbin/magic_mask.sh post-fs" >/dev/null 2>&1; echo $?` -ne 0 ]; then + echo 0 > /sys/fs/selinux/enforce + /sbin/magic_mask.sh post-fs + echo 1 > /sys/fs/selinux/enforce + fi + ;; + post-fs-data ) + # su call shall always work + if [ `$DIR/su -c "/sbin/magic_mask.sh post-fs-data" >/dev/null 2>&1; echo $?` -ne 0 ]; then + /sbin/magic_mask.sh post-fs-data + fi + ;; + service ) + # su call shall always work + if [ `$DIR/su -c "/sbin/magic_mask.sh service" >/dev/null 2>&1; echo $?` -ne 0 ]; then + /sbin/magic_mask.sh service + fi + ;; + root ) + # This will only be used in phh root + $DIR/su -c "/sbin/magic_mask.sh root" + ;; +esac \ No newline at end of file diff --git a/zip_static/common/supatch.sh b/zip_static/common/supatch.sh new file mode 100644 index 000000000..f3dba9144 --- /dev/null +++ b/zip_static/common/supatch.sh @@ -0,0 +1,226 @@ +#Extracted from global_macros +rw_socket_perms="ioctl read getattr write setattr lock append bind connect getopt setopt shutdown" +create_socket_perms="create $rw_socket_perms" +rw_stream_socket_perms="$rw_socket_perms listen accept" +create_stream_socket_perms="create $rw_stream_socket_perms" + +# bootimg.sh + +#allow +allow() { + [ -z "$1" -o -z "$2" -o -z "$3" ] && false + for s in $1;do + for t in $2;do + for c in $3;do + echo "allow ($s) ($t) ($c) ($4)" + if [ "$4" = "*" ]; then + $BINDIR/sepolicy-inject -s $s -t $t -c $c -P sepolicy >/dev/null 2>&1 + else + $BINDIR/sepolicy-inject -s $s -t $t -c $3 -p $(echo $4|tr ' ' ',') -P sepolicy 2>/dev/null 2>&1 + fi + done + done + done +} + +noaudit() { + for s in $1;do + for t in $2;do + for p in $4;do + $BINDIR/sepolicy-inject -s $s -t $t -c $3 -p $p -P sepolicy 2>/dev/null 2>&1 + done + done + done +} + +# su-communication + +#allowSuClient +allowSuClient() { + #All domain-s already have read access to rootfs + allow $1 rootfs file "execute_no_trans execute" #TODO: Why do I need execute?!? (on MTK 5.1, kernel 3.10) + allow $1 su_daemon unix_stream_socket "connectto getopt" + + allow $1 su_device dir "search read" + allow $1 su_device sock_file "read write" + allow su_daemon $1 "fd" "use" + + allow su_daemon $1 fifo_file "read write getattr ioctl" + + #Read /proc/callerpid/cmdline in from_init, drop? + #Requiring sys_ptrace sucks + allow su_daemon "$1" "dir" "search" + allow su_daemon "$1" "file" "read open" + allow su_daemon "$1" "lnk_file" "read" + allow su_daemon su_daemon "capability" "sys_ptrace" +} + +suDaemonTo() { + allow su_daemon $1 "process" "transition" + noaudit su_daemon $1 "process" "siginh rlimitinh noatsecure" +} + +suDaemonRights() { + allow su_daemon rootfs file "entrypoint" + + allow su_daemon su_daemon "dir" "search read" + allow su_daemon su_daemon "file" "read write open" + allow su_daemon su_daemon "lnk_file" "read" + allow su_daemon su_daemon "unix_dgram_socket" "create connect write" + allow su_daemon su_daemon "unix_stream_socket" "$create_stream_socket_perms" + + allow su_daemon devpts chr_file "read write open getattr" + #untrusted_app_devpts not in Android 4.4 + allow su_daemon untrusted_app_devpts chr_file "read write open getattr" || true + + allow su_daemon su_daemon "capability" "setuid setgid" + + #Access to /data/data/me.phh.superuser/xxx + allow su_daemon app_data_file "dir" "getattr search write add_name" + allow su_daemon app_data_file "file" "getattr read open lock" + + #FIXME: This shouldn't exist + #dac_override can be fixed by having pts_slave's fd forwarded over socket + #Instead of forwarding the name + allow su_daemon su_daemon "capability" "dac_override" + + allow su_daemon su_daemon "process" "fork sigchld" + + #toolbox needed for log + allow su_daemon toolbox_exec "file" "execute read open execute_no_trans" || true + + #Create /dev/me.phh.superuser. Could be done by init + allow su_daemon device "dir" "write add_name" + allow su_daemon su_device "dir" "create setattr remove_name add_name" + allow su_daemon su_device "sock_file" "create unlink" + + #Allow su daemon to start su apk + allow su_daemon zygote_exec "file" "execute read open execute_no_trans" + allow su_daemon zygote_exec "lnk_file" "read getattr" + + #Send request to APK + allow su_daemon su_device dir "search write add_name" + + #Allow su_daemon to switch to su or su_sensitive + allow su_daemon su_daemon "process" "setexec" + + #Allow su_daemon to execute a shell (every commands are supposed to go through a shell) + allow su_daemon shell_exec file "execute read open" + + allow su_daemon su_daemon "capability" "chown" + + suDaemonTo su +} + +# rights + +#In this file lies the real permissions of a process running in su + +suBind() { + #Allow to override /system/xbin/su + allow su_daemon su_exec "file" "mounton read" + + #We will create files in /dev/su/, they will be marked as su_device + allow su_daemon su_device "dir file lnk_file" "*" + allow su_daemon su_device "file" "relabelfrom" + allow su_daemon system_file "file" "relabelto" +} + +#This is the vital minimum for su to open a uid 0 shell +suRights() { + + #Admit su_daemon is meant to be god. + allow su_daemon su_daemon "capability" "sys_admin" + + allow servicemanager su "dir" "search read" + allow servicemanager su "file" "open read" + allow servicemanager su "process" "getattr" + allow servicemanager su "binder" "transfer" + [ "$API" -ge 20 ] && allow system_server su binder "call" +} + +suL9() { + allow su_daemon su_daemon "dir file lnk_file" "*" + allow su_daemon system_data_file "dir file lnk_file" "*" + allow su_daemon "labeledfs" filesystem "associate" + allow su_daemon su_daemon process setfscreate + allow su_daemon tmpfs filesystem associate + allow su_daemon su_daemon file relabelfrom + allow su_daemon system_file file mounton +} + +otherToSU() { + # allowLog + if allow su logd unix_dgram_socket "sendto";then + allow logd su dir "search" + allow logd su file "read open getattr" + fi + + # suBackL0 + [ "$API" -ge 20 ] && allow system_server su binder "call transfer" + #ES Explorer opens a sokcet + allow untrusted_app su unix_stream_socket "$rw_socket_perms connectto" + #Any domain is allowed to send su "sigchld" + #TODO: Have sepolicy-inject handle that + #allow "=domain" su process "sigchld" + allow surfaceflinger su "process" "sigchld" + + # suNetworkL0 + $BINDIR/sepolicy-inject -a netdomain -s su -P sepolicy + $BINDIR/sepolicy-inject -a bluetoothdomain -s su -P sepolicy + + # suBackL6 + #Used by CF.lumen (restarts surfaceflinger, and communicates with it) + #TODO: Add a rule to enforce surfaceflinger doesn't have dac_override + allow surfaceflinger app_data_file "dir file lnk_file" "*" + $BINDIR/sepolicy-inject -a mlstrustedsubject -s surfaceflinger -P sepolicy +} + +#Samsung specific +#Prevent system from loading policy +if $BINDIR/sepolicy-inject -e -s knox_system_app -P sepolicy;then + $BINDIR/sepolicy-inject --not -s init -t kernel -c security -p load_policy -P sepolicy + for i in policyloader_app system_server system_app installd init ueventd runas drsd debuggerd vold zygote auditd servicemanager itsonbs commonplatformappdomain;do + $BINDIR/sepolicy-inject --not -s "$i" -t security_spota_file -c dir -p read,write -P sepolicy + $BINDIR/sepolicy-inject --not -s "$i" -t security_spota_file -c file -p read,write -P sepolicy + done +fi + +#Create domains if they don't exist +$BINDIR/sepolicy-inject -z su -P sepolicy +$BINDIR/sepolicy-inject -z su_device -P sepolicy +$BINDIR/sepolicy-inject -z su_daemon -P sepolicy + +#Autotransition su's socket to su_device +$BINDIR/sepolicy-inject -s su_daemon -f device -c file -t su_device -P sepolicy +$BINDIR/sepolicy-inject -s su_daemon -f device -c dir -t su_device -P sepolicy +allow su_device tmpfs filesystem "associate" + +#Transition from untrusted_app to su_client +#TODO: other contexts want access to su? +allowSuClient shell +allowSuClient untrusted_app +allowSuClient platform_app +allowSuClient su + +#HTC Debug context requires SU +$BINDIR/sepolicy-inject -e -s ssd_tool -P sepolicy && allowSuClient ssd_tool + +#Allow init to execute su daemon/transition +allow init su_daemon process "transition" +noaudit init su_daemon process "rlimitinh siginh noatsecure" +suDaemonRights +suBind + +suRights +otherToSU + +#Need to set su_device/su as trusted to be accessible from other categories +$BINDIR/sepolicy-inject -a mlstrustedobject -s su_device -P sepolicy +$BINDIR/sepolicy-inject -a mlstrustedsubject -s su_daemon -P sepolicy +$BINDIR/sepolicy-inject -a mlstrustedsubject -s su -P sepolicy + +suL9 + +# Just in case :) +$BINDIR/sepolicy-inject -Z su -P sepolicy diff --git a/zip_static/x86/busybox b/zip_static/x86/busybox new file mode 100644 index 000000000..a83050ad9 Binary files /dev/null and b/zip_static/x86/busybox differ diff --git a/zip_static/x86/su b/zip_static/x86/su new file mode 100644 index 000000000..52196cb32 Binary files /dev/null and b/zip_static/x86/su differ