Andrew Geissler | 9aee500 | 2022-03-30 16:27:02 +0000 | [diff] [blame^] | 1 | #!/bin/sh |
| 2 | |
| 3 | # SPDX-License-Identifier: MIT |
| 4 | # |
| 5 | # Copyright 2022 (C), Microsoft Corporation |
| 6 | |
| 7 | # Simple initramfs module intended to mount a read-write (RW) |
| 8 | # overlayfs on top of /, keeping the original root filesystem |
| 9 | # as read-only (RO), free from modifications by the user. |
| 10 | # |
| 11 | # NOTE: The read-only IMAGE_FEATURE is not required for this to work |
| 12 | # |
| 13 | # This script is based on the overlay-etc.bbclass, which sets up |
| 14 | # an overlay on top of the /etc directory, but in this case allows |
| 15 | # accessing the original, unmodified rootfs at /rofs after boot. |
| 16 | # |
| 17 | # It relies on the initramfs-module-rootfs to mount the original |
| 18 | # root filesystem, and requires 'rootrw=<foo>' to be passed as a |
| 19 | # kernel parameter, specifying the device/partition intended to |
| 20 | # use as RW. |
| 21 | # |
| 22 | # This module needs to be executed after the initramfs-module-rootfs |
| 23 | # since it relies on it to mount the filesystem at initramfs startup |
| 24 | # but before the finish module which normally switches root. |
| 25 | # After overlayroot is executed the usual boot flow continues from |
| 26 | # the real init process. |
| 27 | # |
| 28 | # If something goes wrong while running this module, the rootfs |
| 29 | # is still mounted RO (with no overlay) and the finish module is |
| 30 | # executed to continue booting normally. |
| 31 | # |
| 32 | # It also has a dependency on overlayfs being enabled in the |
| 33 | # running kernel via KERNEL_FEATURES (kmeta) or any other means. |
| 34 | |
| 35 | |
| 36 | PATH=/sbin:/bin:/usr/sbin:/usr/bin |
| 37 | |
| 38 | # We get OLDROOT from the rootfs module |
| 39 | OLDROOT="/rootfs" |
| 40 | |
| 41 | NEWROOT="${RWMOUNT}/root" |
| 42 | RWMOUNT="/overlay" |
| 43 | ROMOUNT="${RWMOUNT}/rofs" |
| 44 | UPPER_DIR="${RWMOUNT}/upper" |
| 45 | WORK_DIR="${RWMOUNT}/work" |
| 46 | |
| 47 | MODULES_DIR=/init.d |
| 48 | |
| 49 | # Something went wrong, make sure / is mounted as read only anyway. |
| 50 | exit_gracefully() { |
| 51 | echo $1 >/dev/console |
| 52 | echo >/dev/console |
| 53 | echo "OverlayRoot mounting failed, starting system as read-only" >/dev/console |
| 54 | echo >/dev/console |
| 55 | |
| 56 | # The following is borrowed from rootfs-postcommands.bbclass |
| 57 | # This basically looks at the real rootfs mounting options and |
| 58 | # replaces them with "ro" |
| 59 | |
| 60 | # Tweak the mount option and fs_passno for rootfs in fstab |
| 61 | if [ -f ${OLDROOT}/etc/fstab ]; then |
| 62 | sed -i -e '/^[#[:space:]]*\/dev\/root/{s/defaults/ro/;s/\([[:space:]]*[[:digit:]]\)\([[:space:]]*\)[[:digit:]]$/\1\20/}' ${OLDROOT}/etc/fstab |
| 63 | fi |
| 64 | |
| 65 | # Tweak the "mount -o remount,rw /" command in busybox-inittab inittab |
| 66 | if [ -f ${OLDROOT}/etc/inittab ]; then |
| 67 | sed -i 's|/bin/mount -o remount,rw /|/bin/mount -o remount,ro /|' ${OLDROOT}/etc/inittab |
| 68 | fi |
| 69 | |
| 70 | # Continue as if the overlayroot module didn't exist to continue booting |
| 71 | . $MODULES_DIR/99-finish |
| 72 | eval "finish_run" |
| 73 | } |
| 74 | |
| 75 | |
| 76 | if [ -z "$bootparam_rootrw" ]; then |
| 77 | exit_gracefully "rootrw= kernel parameter doesn't exist and its required to mount the overlayfs" |
| 78 | fi |
| 79 | |
| 80 | mkdir -p ${RWMOUNT} |
| 81 | |
| 82 | # Mount RW device |
| 83 | if mount -n -t ${bootparam_rootfstype:-ext4} -o ${bootparam_rootflags:-defaults} ${bootparam_rootrw} ${RWMOUNT} |
| 84 | then |
| 85 | # Set up overlay directories |
| 86 | mkdir -p ${UPPER_DIR} |
| 87 | mkdir -p ${WORK_DIR} |
| 88 | mkdir -p ${NEWROOT} |
| 89 | mkdir -p ${ROMOUNT} |
| 90 | |
| 91 | # Remount OLDROOT as read-only |
| 92 | mount -o bind ${OLDROOT} ${ROMOUNT} |
| 93 | mount -o remount,ro ${ROMOUNT} |
| 94 | |
| 95 | # Mount RW overlay |
| 96 | mount -t overlay overlay -o lowerdir=${ROMOUNT},upperdir=${UPPER_DIR},workdir=${WORK_DIR} ${NEWROOT} || exit_gracefully "initramfs-overlayroot: Mounting overlay failed" |
| 97 | else |
| 98 | exit_gracefully "initramfs-overlayroot: Mounting RW device failed" |
| 99 | fi |
| 100 | |
| 101 | # Set up filesystems on overlay |
| 102 | mkdir -p ${NEWROOT}/proc |
| 103 | mkdir -p ${NEWROOT}/dev |
| 104 | mkdir -p ${NEWROOT}/sys |
| 105 | mkdir -p ${NEWROOT}/rofs |
| 106 | |
| 107 | mount -n --move ${ROMOUNT} ${NEWROOT}/rofs |
| 108 | mount -n --move /proc ${NEWROOT}/proc |
| 109 | mount -n --move /sys ${NEWROOT}/sys |
| 110 | mount -n --move /dev ${NEWROOT}/dev |
| 111 | |
| 112 | exec chroot ${NEWROOT}/ ${bootparam_init:-/sbin/init} || exit_gracefully "Couldn't chroot into overlay" |