diff --git a/postmarketos-mkinitfs-hook-usb-shell/20-usb-shell.sh b/postmarketos-mkinitfs-hook-usb-shell/20-usb-shell.sh index ff7172b21..2d945b6cd 100644 --- a/postmarketos-mkinitfs-hook-usb-shell/20-usb-shell.sh +++ b/postmarketos-mkinitfs-hook-usb-shell/20-usb-shell.sh @@ -1,7 +1,9 @@ #!/bin/sh -IP=172.16.42.1 +. ./init_functions.sh TELNET_PORT=24 +setup_usb_network +start_udhcpd telnetd -b "${IP}:${TELNET_PORT}" -l /bin/sh echo "---" @@ -9,4 +11,3 @@ echo "WARNING: usb shell is active on ${IP}:${TELNET_PORT}." echo "This is a security hole! Only use it for debugging, and" echo "uninstall the usb-shell hook afterwards!" echo "---" - diff --git a/postmarketos-mkinitfs-hook-usb-shell/APKBUILD b/postmarketos-mkinitfs-hook-usb-shell/APKBUILD index c8ee54645..9184e05df 100644 --- a/postmarketos-mkinitfs-hook-usb-shell/APKBUILD +++ b/postmarketos-mkinitfs-hook-usb-shell/APKBUILD @@ -1,6 +1,6 @@ pkgname=postmarketos-mkinitfs-hook-usb-shell -pkgver=0.0.1 -pkgrel=1 +pkgver=0.1.0 +pkgrel=0 pkgdesc="Root shell in the initramfs (security hole, for debugging only)" url="https://github.com/postmarketOS" # multipath-tools: kpartx @@ -18,4 +18,4 @@ package() { install -Dm644 "$srcdir"/20-usb-shell.sh \ "$pkgdir"/etc/postmarketos-mkinitfs/hooks/ } -sha512sums="7154ded57cba1ff76fb8be9bd773ccdb4cd70c588ef763469d7e2fc9796fba13e5624480669b528138c1c5ebfc1a7927dcb80b850e72308b89736d9baee9c231 20-usb-shell.sh" +sha512sums="40c6c445fdd03f8c76ba39075e9112ca963dd832f392e469057b622826f274604ec950bbbb89620c5c88e5d76caa0fa4665e445e33ebe31d4c566d4359d24935 20-usb-shell.sh" diff --git a/postmarketos-mkinitfs/10-usb-unlock.sh b/postmarketos-mkinitfs/10-usb-unlock.sh index 70b473d8d..131538932 100644 --- a/postmarketos-mkinitfs/10-usb-unlock.sh +++ b/postmarketos-mkinitfs/10-usb-unlock.sh @@ -1,62 +1,28 @@ #!/bin/sh -IP=172.16.42.1 +. ./init_functions.sh + TELNET_PORT=23 -. /init_functions.sh +start_usb_unlock() { + # Only run if we have an encrypted partition + cryptsetup isLuks "$(find_root_partition)" || return -log "info" "show_splash $partition" + # Set up networking + setup_usb_network + start_udhcpd -usb_setup_android() { - SYS=/sys/class/android_usb/android0 - [ -e "$SYS" ] || return - printf "%s" "0" > "$SYS/enable" - printf "%s" "18D1" > "$SYS/idVendor" - printf "%s" "D001" > "$SYS/idProduct" - printf "%s" "rndis" > "$SYS/functions" - printf "%s" "1" > "$SYS/enable" -} + # Telnet splash + show_splash /splash1.ppm.gz -dhcpcd_start() -{ - # get usb interface - INTERFACE="" - ifconfig rndis0 "$IP" && INTERFACE=rndis0 - if [ -z $INTERFACE ]; then - ifconfig usb0 "$IP" && INTERFACE=usb0 - fi - - # create /etc/udhcpd.conf - { - echo "start 172.16.42.2" - echo "end 172.16.42.254" - echo "lease_file /var/udhcpd.leases" - echo "interface $INTERFACE" - echo "option subnet 255.255.255.0" - } > /etc/udhcpd.conf - udhcpd -} - -telnetd_start() -{ - mkdir -p /dev/pts - mount -t devpts devpts /dev/pts + # Start the telnet daemon { echo '#!/bin/sh' echo '. /init_functions.sh' echo 'unlock_root_partition' echo 'killall cryptsetup telnetd' - } > /telnet_connect.sh + } >/telnet_connect.sh chmod +x /telnet_connect.sh telnetd -b "${IP}:${TELNET_PORT}" -l /telnet_connect.sh } -partition=$(find_root_partition) - -usb_setup_android -dhcpcd_start - -if $(cryptsetup isLuks "$partition"); then - log "info" "password needed to decrypt $partition, launching telnetd" - telnetd_start -fi - +start_usb_unlock diff --git a/postmarketos-mkinitfs/APKBUILD b/postmarketos-mkinitfs/APKBUILD index e41c05200..5b3b4ca57 100644 --- a/postmarketos-mkinitfs/APKBUILD +++ b/postmarketos-mkinitfs/APKBUILD @@ -1,6 +1,6 @@ pkgname=postmarketos-mkinitfs -pkgver=0.0.5 -pkgrel=5 +pkgver=0.1.0 +pkgrel=1 pkgdesc="Tool to generate initramfs images for postmarketOS" url="https://github.com/postmarketOS" # multipath-tools: kpartx @@ -27,9 +27,9 @@ package() { install -Dm644 "$srcdir/10-usb-unlock.sh" \ "$pkgdir/etc/postmarketos-mkinitfs/hooks/" } -sha512sums="6f4d96b5b5e19811d7b03a5f20e6ee766d22047c182e9b21c56e99634b2300978d8c98f42f9a889e356a295bb968053d1d289a8ebddf52a696b4630df6839b45 init.sh.in -6795e225e0576b003ea492a05d83d28092753af7cc4dd6a8b75ae2d2ca3555f951d632c7ee5ee7db3a7b606bb77cc9a035804a81a1f5b4fdad6a7aac5a0ee6b4 init_functions.sh +sha512sums="99d7e3a12ee655b869f6acece453c348cb8f8ed59358331ebed25d4c74186d2afd29c73f62fdc7ff9df352a632dbcb363eae1ef0c988c29acc8f288293ec91d2 init.sh.in +66f442648fb38529ec594e62ee2307269ca875c7f9340726adcb211e9be42a6ba60fd296af0503a65c7f230c25cf3494783e4282f2468c63116b9500f5d184c6 init_functions.sh dd3c86c6ba4f91e20b72f4180049960a58dc01002f69ad9e5d98c752da3b34711c2bbe6e0c7d003eb6a4a8d9e185796aa2fe84c0231a3057b204912c439140f7 mkinitfs.sh -bea0eae6852f4a401347bbbd6c376ea8cc5bfa4817d2c87170a4f2a916e25f155769eb8e97e16d39bf2eac84e3fdaf6f8c7a0564ec561a96e32407daa1d71e1c 10-usb-unlock.sh +81d001ab185a8db1b9335d7c8c278d49ab0446bc15bb00dd22e4de16633433a183888f3f1096399bfe361ed719dcc4203afdf4b4f10e74a9c1e50bbbfc46951c 10-usb-unlock.sh 35a8eabad947347afec7e3f5860d31ab9e3534972c0960ccf553c7e1cc9262316bfdddb8d61d3588db1ee2261077597617806080b9956798b3e5088d6f9b596b splash1.ppm.gz bf11d8b3a50db984cfbb2cafe6687de327242c1f6f56c6fdd02ca579b05213f9c886aa1c0527530fdec21b16e65e68962e40a600c4ce155819df2f610b435087 splash2.ppm.gz" diff --git a/postmarketos-mkinitfs/init.sh.in b/postmarketos-mkinitfs/init.sh.in index 3bef0a826..4941a0d9b 100644 --- a/postmarketos-mkinitfs/init.sh.in +++ b/postmarketos-mkinitfs/init.sh.in @@ -4,35 +4,44 @@ export PATH=/usr/bin:/bin:/usr/sbin:/sbin /bin/busybox --install -s /bin/busybox-extras --install -s +setup_log -# kernel modules -modprobe -a @MODULES@ +# Kernel modules +[ -d /lib/modules ] && modprobe -a @MODULES@ -# mdev -mount -t proc -o nodev,noexec,nosuid proc /proc -mount -t sysfs -o nodev,noexec,nosuid sysfs /sys -echo /sbin/mdev > /proc/sys/kernel/hotplug -mdev -s - -# subpartitions +# Mount everything, set up mdev +mount_proc_sys_dev +setup_mdev mount_subpartitions -# hooks +# Always run dhcp daemon/usb networking for now (later this should only +# be enabled, when having the usb-shell hook installed for debugging, +# or get activated after the initramfs is done with an OpenRC service). +setup_usb_network +start_udhcpd + +# Hooks for hook in /etc/postmarketos-mkinitfs/hooks/*.sh; do [ -e "$hook" ] || continue sh "$hook" done -show_splash /splash1.ppm.gz -# unlock root partition +# Unlock root partition unlock_root_partition -# switch root +# Switch root show_splash /splash2.ppm.gz -killall telnetd mdev 2&> /dev/null -mount -w -t ext4 $(find_root_partition) /sysroot +killall telnetd mdev 2>/dev/null umount /proc umount /sys umount /dev/pts umount /dev + +# shellcheck disable=SC2093 exec switch_root /sysroot /sbin/init + +echo "ERROR: switch_root failed!" +echo "Looping forever. Install and use the usb-shell hook to debug this." +while true; do + sleep 1 +done diff --git a/postmarketos-mkinitfs/init_functions.sh b/postmarketos-mkinitfs/init_functions.sh index ae00bd525..462d877ae 100644 --- a/postmarketos-mkinitfs/init_functions.sh +++ b/postmarketos-mkinitfs/init_functions.sh @@ -1,15 +1,43 @@ #!/bin/sh # This file will be in /init_functions.sh inside the initramfs. +IP=172.16.42.1 -log() -{ - echo "[$1] $2" >> /tmp/boot.log +# Redirect stdout and stderr to logfile +setup_log() { + # Bail out if PMOS_NO_OUTPUT_REDIRECT is set + echo "### postmarketOS initramfs ###" + grep -q PMOS_NO_OUTPUT_REDIRECT /proc/cmdline && return + + # Print a message about what is going on to the normal output + echo "NOTE: All output from the initramfs gets redirected to:" + echo "/pmOS_init.log" + echo "If you want to disable this behavior (e.g. because you're" + echo "debugging over serial), please add this to your kernel" + echo "command line: PMOS_NO_OUTPUT_REDIRECT" + + # Start redirect, print the first line again + exec >/pmOS_init.log 2>&1 + echo "### postmarketOS initramfs ###" } -mount_subpartitions() -{ +mount_proc_sys_dev() { + # mdev + mount -t proc -o nodev,noexec,nosuid proc /proc + mount -t sysfs -o nodev,noexec,nosuid sysfs /sys + + # /dev/pts (needed for telnet) + mkdir -p /dev/pts + mount -t devpts devpts /dev/pts +} + +setup_mdev() { + echo /sbin/mdev >/proc/sys/kernel/hotplug + mdev -s +} + +mount_subpartitions() { for i in /dev/mmcblk*; do - case "$(kpartx -l "$i" 2> /dev/null | wc -l)" in + case "$(kpartx -l "$i" 2>/dev/null | wc -l)" in 2) echo "mount subpartitions of $i" kpartx -afs "$i" @@ -22,45 +50,117 @@ mount_subpartitions() done } -find_root_partition() -{ - DEVICE=$(blkid | grep "crypto_LUKS" | tail -1 | cut -d ":" -f 1) +find_root_partition() { + # The partition layout is one of the following: + # a) boot, root partitions on sdcard + # b) boot, root partition on the "system" partition (which has its + # own partition header! so we have partitions on partitions!) + # + # mount_subpartitions() must get executed before calling + # find_root_partition(), so partitions from b) also get found. + # + # However, after executing mount_subpartitions(), the partitions + # from a) get mounted to /dev/mapper - and then you can only use + # the ones from /dev/mapper, not the original partition paths (they + # will appear as busy when trying to mount them). This is an + # unwanted side-effect, that we must deal with. + # The subpartitions from b) get mounted to /dev/mapper, and this is + # what we want. + # + # To deal with the side-effect, we use the partitions from + # /dev/mapper first, and then fall back to partitions with all paths + # (in case the user inserted an SD card after mount_subpartitions() + # ran!). + # Try the partitions in /dev/mapper first. + for id in pmOS_root crypto_LUKS; do + DEVICE="$(blkid | grep /dev/mapper | grep "$id" \ + | cut -d ":" -f 1)" + [ -z "$DEVICE" ] || break + done + + # Then try all devices if [ -z "$DEVICE" ]; then - DEVICE=$(blkid | grep "pmOS_root" | tail -1 | cut -d ":" -f 1) + for id in pmOS_root crypto_LUKS; do + DEVICE="$(blkid | grep "$id" | cut -d ":" -f 1)" + [ -z "$DEVICE" ] || break + done fi - - log "info" "root partition is $DEVICE" - - echo $DEVICE + echo "$DEVICE" } -unlock_root_partition() -{ - log "info" "unlock_root_partition()" - while ! [ -e /dev/mapper/root ]; do +setup_usb_network_android() { + # Only run, when we have the android usb driver + SYS=/sys/class/android_usb/android0 + [ -e "$SYS" ] || return + + # Do the setup + printf "%s" "0" >"$SYS/enable" + printf "%s" "18D1" >"$SYS/idVendor" + printf "%s" "D001" >"$SYS/idProduct" + printf "%s" "rndis" >"$SYS/functions" + printf "%s" "1" >"$SYS/enable" +} + +setup_usb_network() { + # Only run once + _marker="/tmp/_setup_usb_network" + [ -e "$_marker" ] && return + touch "$_marker" + + # Run all usb network setup functions (add more below!) + setup_usb_network_android +} + +start_udhcpd() { + # Only run once + [ -e /etc/udhcpd.conf ] && return + + # Get usb interface + INTERFACE="" + ifconfig rndis0 "$IP" && INTERFACE=rndis0 + if [ -z $INTERFACE ]; then + ifconfig usb0 "$IP" && INTERFACE=usb0 + fi + + # Create /etc/udhcpd.conf + { + echo "start 172.16.42.2" + echo "end 172.16.42.254" + echo "lease_file /var/udhcpd.leases" + echo "interface $INTERFACE" + echo "option subnet 255.255.255.0" + } >/etc/udhcpd.conf + + # Start the dhcpcd daemon (forks into background) + udhcpd +} + +unlock_root_partition() { + # Wait for the root partition (and unlock it if it is encrypted) + while ! [ -e /sysroot/usr ]; do partition="$(find_root_partition)" if [ -z "$partition" ]; then echo "Could not find the root partition." echo "Maybe you need to insert the sdcard, if your device has" echo "any? Trying again in one second..." sleep 1 + elif cryptsetup isLuks "$partition"; then + cryptsetup luksOpen "$partition" root || continue + partition="/dev/mapper/root" + break else - if $(cryptsetup isLuks "$partition"); then - cryptsetup luksOpen "$partition" root - log "info" "decrypted $partition" - else - log "info" "unencrypted $partition" - break - fi + # Unencrypted + break fi done + + # Mount the root partition + [ -e /sysroot/usr ] || mount -w -t ext4 "$partition" /sysroot } # $1: path to ppm.gz file -show_splash() -{ - log "info" "show_splash $1" - gzip -c -d "$1" > /tmp/splash.ppm +show_splash() { + gzip -c -d "$1" >/tmp/splash.ppm fbsplash -s /tmp/splash.ppm }