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 36PATH=/sbin:/bin:/usr/sbin:/usr/bin 37 38# We get OLDROOT from the rootfs module 39OLDROOT="/rootfs" 40 41NEWROOT="${RWMOUNT}/root" 42RWMOUNT="/overlay" 43ROMOUNT="${RWMOUNT}/rofs" 44UPPER_DIR="${RWMOUNT}/upper" 45WORK_DIR="${RWMOUNT}/work" 46 47MODULES_DIR=/init.d 48 49# Something went wrong, make sure / is mounted as read only anyway. 50exit_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 76if [ -z "$bootparam_rootrw" ]; then 77 exit_gracefully "rootrw= kernel parameter doesn't exist and its required to mount the overlayfs" 78fi 79 80mkdir -p ${RWMOUNT} 81 82# Mount RW device 83if mount -n -t ${bootparam_rootfstype:-ext4} -o ${bootparam_rootflags:-defaults} ${bootparam_rootrw} ${RWMOUNT} 84then 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" 97else 98 exit_gracefully "initramfs-overlayroot: Mounting RW device failed" 99fi 100 101# Set up filesystems on overlay 102mkdir -p ${NEWROOT}/proc 103mkdir -p ${NEWROOT}/dev 104mkdir -p ${NEWROOT}/sys 105mkdir -p ${NEWROOT}/rofs 106 107mount -n --move ${ROMOUNT} ${NEWROOT}/rofs 108mount -n --move /proc ${NEWROOT}/proc 109mount -n --move /sys ${NEWROOT}/sys 110mount -n --move /dev ${NEWROOT}/dev 111 112exec chroot ${NEWROOT}/ ${bootparam_init:-/sbin/init} || exit_gracefully "Couldn't chroot into overlay" 113