-
-
Save Maxdamantus/54d0bdb77523aa7d03120ebb1f10df4e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/init-root/bin/busybox sh | |
bb=/init-root/bin/busybox | |
run_chroot() { | |
( | |
$bb mkdir -p /mnt | |
exec 40<&0 | |
# stage 0 | |
exec 42<<'SETUP_SH' | |
set -x | |
bb=/init-root/bin/busybox | |
$bb mount -t tmpfs tmp /mnt | |
$bb cp -a /init-root/. /lib /mnt/ | |
# /init not reused, but could be useful for debugging | |
$bb cp -a /init /mnt/ | |
cd /mnt/ | |
$bb mount --move . / | |
exec $bb chroot . /bin/busybox sh <&43 43<&- | |
SETUP_SH | |
# stage 1 | |
exec 43<<'SETUP_SH' | |
set -x | |
for x in `busybox --list`; do | |
busybox ln -s busybox /bin/"$x" | |
done | |
mkdir -p /sys /proc /dev /dev/pts /etc /run | |
mount -t sysfs sys /sys | |
mount -t proc proc /proc | |
mount -t devpts devpts /dev/pts -o gid=5,noexec,nosuid | |
mdev -s | |
mkdir -p /etc | |
echo "root:x:0:0:root:/:/bin/sh" >/etc/passwd | |
echo "root:x:0:" >/etc/group | |
echo "/bin/sh" >/etc/shells | |
(umask 077; set +x; echo "root:$(cat /.secrets/passwd):::::::" >/etc/shadow) | |
chmod go-rw /.secrets/* | |
cat >/m-mount-root.sh <&44 44<&- | |
chmod +x /m-mount-root.sh | |
exec sh <&40 40<&- | |
SETUP_SH | |
# /m-mount-root.sh | |
# UNUSED | |
exec 44<<-'MOUNT_ROOT_SH' | |
#!/bin/sh | |
set -x -e | |
key_file=/proc/1/root/data/.cryptmmckey | |
retry=0 | |
while :; do | |
test -e "$key_file" && break | |
if [ $((retry++)) -ge 200 ]; then | |
echo 'giving up waiting for key' | |
break | |
fi | |
sleep 0.1 | |
done | |
cryptsetup open /dev/mmcblk0p2 cryptmmc "$key_file" | |
mkdir -p /mnt/root | |
mount -o ro,noatime /dev/mapper/cryptmmc /mnt/root | |
MOUNT_ROOT_SH | |
# /m-mount-root.sh | |
exec 44<<-'MOUNT_ROOT_SH' | |
#!/bin/sh | |
set -x -e | |
retry=0 | |
while :; do | |
mount="$(grep '^[^ ]\+ /data .*\<rw\>' </proc/1/mounts)" && break | |
if [ $((retry++)) -ge 200 ]; then | |
echo 'giving up finding data mount' | |
exit 1 | |
fi | |
sleep 0.1 | |
done | |
mkdir -p /mnt/data /mnt/root | |
dev="$(echo "$mount" | cut -f1 -d' ' | sed 's:/dev/block/:/dev/:')" | |
mdev -s | |
test -e "$dev" | |
mount -o noatime "$dev" /mnt/data | |
mount -o bind /mnt/data/.debian/root /mnt/root | |
MOUNT_ROOT_SH | |
exec $bb unshare -m $bb sh <&42 42<&- | |
) | |
} | |
recovery() { | |
run_chroot <<'RECOVERY_SH' | |
set -x | |
# show that we're alive | |
echo 0 >/sys/class/backlight/backlight/bl_power | |
for x in `seq 0 20 250` `seq 250 -20 0` `seq 0 20 250`; do sleep 0.1 && echo $x >/sys/class/backlight/backlight/brightness; done | |
echo 'write to /dev/ipa' | |
echo 1 >/dev/ipa | |
sleep 3 | |
mkdir /config | |
mount -t configfs configfs /config | |
cd /config | |
gadget=/config/usb_gadget/g1 | |
mkdir $gadget | |
mkdir $gadget/functions/gsi.rndis | |
mkdir $gadget/configs/b.1 | |
mkdir $gadget/configs/b.1/strings/0x409 | |
echo rndis >$gadget/configs/b.1/strings/0x409/configuration | |
echo 0x2A70 >$gadget/idVendor | |
echo 0xF00E >$gadget/idProduct | |
# adb/fastboot uses f1, using something exclusive | |
(cd $gadget/configs/b.1 && ln -s ../../functions/gsi.rndis f5) | |
echo >$gadget/UDC | |
echo a600000.dwc3 >$gadget/UDC && break | |
dmesg | |
ipaddr=192.168.30.1 | |
ifconfig rndis0 "$ipaddr" netmask 255.255.255.0 | |
# reconfigure interface in case fastbootd activation removes it temporarily | |
(while sleep 5; do ifconfig rndis0 "$ipaddr" netmask 255.255.255.0; done) & | |
dropbear -r /.secrets/dropbear_key | |
ln -s /proc/1/root/fifo-continue / | |
echo ' | |
echo ro.adb.secure=0 >>/proc/1/root/prop.default | |
echo >/fifo-continue | |
' >/stock-recovery | |
echo ' | |
cat /proc/cmdline | sed '\''s/\(\<androidboot\.verifiedbootstate=\)[^ ]*\>/\1orange/'\'' >/proc/1/root/dev/.proc_cmdline | |
nsenter -t 1 -m -r/ -- mount --bind /proc/1/root/dev/.proc_cmdline /proc/1/root/proc/cmdline | |
' >/stock-unlock | |
(sleep 60 && [ -e /fifo-continue ] && exec >/fifo-continue) & | |
RECOVERY_SH | |
# wait for `stock-recovery` to be invoked, or above sleep to complete | |
$bb mkfifo /fifo-continue | |
# NOTE: fifo open needs to be in a child process (cat), since we are pid 1, so might get a SIGCHILD interrupt | |
$bb cat /fifo-continue >/dev/null | |
$bb rm /fifo-continue | |
} | |
boot() { | |
run_chroot <<'BOOT_SH' | |
set -x | |
precompiled_sepolicy=/odm/etc/selinux/precompiled_sepolicy | |
strace_1_bg() { | |
strace -p 1 -o strace-out -A "$@" & | |
strace_pid=$! | |
local retry=0 | |
while ! grep $'^TracerPid:\t'"$strace_pid"'$' /proc/1/status; do | |
if [ $((retry++)) -ge 200 ]; then | |
echo 'giving up waiting for strace to attach' | |
break | |
fi | |
sleep 0.1 | |
done | |
} | |
strace_1_kill() { | |
kill $strace_pid | |
while grep $'^TracerPid:\t'"$strace_pid"'$' /proc/1/status; do | |
if [ $((retry++)) -ge 200 ]; then | |
echo 'giving up waiting for strace to exit' | |
break | |
fi | |
sleep 0.1 | |
done | |
} | |
strace_1_bg -P "$precompiled_sepolicy" --inject=faccessat:delay_exit=30s | |
( | |
while ! [ -e /proc/1/root/"$precompiled_sepolicy" ]; | |
do sleep 0.1 | |
done | |
cleanup_mounts= | |
for x in /proc/1/root/"$precompiled_sepolicy".*.sha256; do | |
nsenter -t 1 -m -r/ -- mount --bind /proc/1/root/dev/null "$x" | |
cleanup_mounts="$cleanup_mounts $x" | |
done | |
tmp=/proc/1/root/dev/.secilc-tmp | |
mkdir "$tmp" | |
mkfifo "$tmp"/log | |
cat <"$tmp"/log & | |
mkfifo "$tmp"/fence-trace-attached | |
echo catpid=$! | |
ls -lh /proc/1/root/ | |
cp "$(realpath "$(which busybox)")" "$tmp"/busybox | |
cp /proc/1/root/system/bin/secilc "$tmp"/secilc-real | |
cat >"$tmp"/unconfined.cil <<'CIL' | |
(block debroot | |
(type m_unconfined) | |
(typepermissive m_unconfined) | |
(typeattributeset domain (m_unconfined)) | |
; required at least for use of loop devices, not permissive | |
(allow kernel m_unconfined (fd (all))) | |
; required for ecryptfs | |
(allow unlabeled unlabeled (filesystem (associate))) | |
) | |
CIL | |
cat >"$tmp"/secilc-tmp <<'SECILC_SH' | |
#!/dev/.secilc-tmp/busybox sh | |
set -x | |
tmp=/dev/.secilc-tmp | |
exec >"$tmp"/log 2>&1 | |
echo intercepted-secilc "$@" | |
echo "$tmp"/secilc-real "$@" >"$tmp"/cmd | |
for x in "$@"; do echo "$x"; done >"$tmp"/secilc-args | |
# wait until outer strace is attached, so setenforce will be delayed | |
read <"$tmp"/fence-trace-attached | |
exec "$tmp"/secilc-real "$@" "$tmp"/unconfined.cil | |
SECILC_SH | |
chmod +x "$tmp"/secilc-tmp | |
nsenter -t 1 -m -r/ -- mount --bind "$tmp"/secilc-tmp /proc/1/root/system/bin/secilc | |
cleanup_mounts="$cleanup_mounts /proc/1/root/system/bin/secilc" | |
# finished setting up secilc interceptor, resume init so it can execute it | |
strace_1_kill | |
# if init gets to the point where it's about to write `1` to enforce, we really want it to wait (eg, 30 seconds) until our `attr/current` loop has finished. generally it will probably finish by the time it's done a delayed read (1 second). prefer to do it during the `read` since the `write` will never actually happen if permissive mode is enabled. | |
strace_1_bg -P /sys/fs/selinux/enforce --inject=write:delay_enter=30s --inject=read:delay_exit=1s | |
(exec >"$tmp"/fence-trace-attached) | |
echo pid=$$ | |
ls -lh /proc/self | |
cat /proc/self/attr/current | |
retry=0 | |
while :; do | |
ctx='u:r:debroot.m_unconfined:s0' | |
echo -n "$ctx" >/proc/self/attr/current | |
grep -F "$ctx" </proc/self/attr/current && break | |
# give up eventually, so we don't end up running the entire OS under strace | |
if [ $((retry++)) -ge 200 ]; then | |
echo 'giving up setting context' | |
break | |
fi | |
sleep 0.1 | |
done | |
# capture secilc args so that a second stage init can add extra policy if desired | |
cp "$tmp"/secilc-args /secilc-args | |
# clean up secilc injection stuff added into android's namespace/filesystem | |
rm -rf "$tmp" | |
for x in $cleanup_mounts; do | |
nsenter -t 1 -m -r/ -- umount "$x" | |
done | |
echo pid=$$ | |
ls -lh /proc/self | |
cat /proc/self/attr/current | |
strace_1_kill | |
( | |
set -e | |
/m-mount-root.sh | |
# file will already be unlinked; capture the contents for debugging before the last references are lost | |
cp /proc/self/fd/1 /init-log | |
cd /mnt/root | |
exec >/dev/null 2>&1 | |
echo /init-entered | sh ./enter | |
) && exit 0 | |
# capture again, for debugging | |
cp /proc/self/fd/1 /init-log | |
dropbear -p 127.0.0.1:23 -r /.secrets/dropbear_key -P /dropbear.pid | |
) & | |
BOOT_SH | |
} | |
$bb mkdir -p /dev | |
# busybox opens /dev/null as stdin when backgrounding with `&` | |
$bb mknod /dev/null c 1 3 | |
if false; then | |
$bb mkdir /sd | |
$bb mknod /dev_mmc b 179 1 | |
$bb mknod /dev_kmsg c 1 11 | |
$bb mount -t vfat -o rw,sync /dev_mmc /sd | |
$bb dmesg >/sd/bootout-test.txt | |
set -x | |
exec >/sd/bootout.txt 2>&1 | |
echo mk | |
($bb cat <&5 2>&1 &) 5</dev_kmsg >/sd/kmsg.txt | |
$bb umount -l /sd | |
$bb dmesg | |
else | |
# NOTE: will avoid corruption of ssh connections | |
exec >/init-log 2>&1 | |
fi | |
$bb [ -e /init-type-boot ] && boot | |
$bb [ -e /init-type-recovery ] && recovery | |
$bb test -e /init-sh-inject && . /init-sh/inject | |
$bb mv /init-orig /init || exit 1 | |
$bb rm -rf /init-root | |
exec /init "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment