summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--recipes-core/initrdscripts/COPYING.MIT17
-rw-r--r--recipes-core/initrdscripts/README.md162
-rw-r--r--recipes-core/initrdscripts/files/.init-readonly-rootfs-overlay-boot.sh.kate-swpbin0 -> 139 bytes
-rwxr-xr-xrecipes-core/initrdscripts/files/init-readonly-rootfs-overlay-boot.sh326
-rw-r--r--recipes-core/initrdscripts/initramfs-readonly-rootfs-overlay_1.0.bb8
-rw-r--r--recipes-core/initrdscripts/initscripts-readonly-rootfs-overlay_1.0.bb1
-rw-r--r--recipes-core/initrdscripts/readonly-rootfs-overlay-init-script.inc36
7 files changed, 550 insertions, 0 deletions
diff --git a/recipes-core/initrdscripts/COPYING.MIT b/recipes-core/initrdscripts/COPYING.MIT
new file mode 100644
index 0000000..89de354
--- /dev/null
+++ b/recipes-core/initrdscripts/COPYING.MIT
@@ -0,0 +1,17 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/recipes-core/initrdscripts/README.md b/recipes-core/initrdscripts/README.md
new file mode 100644
index 0000000..a038dfa
--- /dev/null
+++ b/recipes-core/initrdscripts/README.md
@@ -0,0 +1,162 @@
+# meta-readonly-rootfs-overlay
+
+This OpenEmbedded layer provides the necessary scripts and configurations to
+setup a writable root file system overlay on top of a read-only root file system.
+
+## Why does this exists?
+
+Having a read-only root file system is useful for many scenarios:
+
+- Separate user specific changes from system configuration, and being able to
+find differences
+- Allow factory reset, by deleting the user specific changes
+- Have a fallback image in case the user specific changes made the root file
+system no longer bootable.
+
+Because some data on the root file system changes on first boot or while the
+system is running, just mounting the complete root file system as read-only
+breaks many applications. There are different solutions to this problem:
+
+- Symlinking/Bind mounting files and directories that could potentially change
+while the system is running to a writable partition
+- Instead of having a read-only root files system, mounting a writable overlay
+root file system, that uses a read-only file system as its base and writes
+changed data to another writable partition.
+
+To implement the first solution, the developer needs to analyse which file
+needs to change and then create symlinks for them. When doing factory reset,
+the developer needs to overwrite every file that is linked with the factory
+configuration, to avoid dangling symlinks/binds. While this is more work on the
+developer side, it might increase the security, because only files that are
+symlinked/bind-mounted can be changed. However, IMO that is better left to file
+permissions.
+
+This meta-layer provides the second solution. Here no investigation of writable
+files are needed and factory reset can be done by just deleting all files or
+formatting the writable volume.
+
+# Dependencies
+
+This layer depends on:
+
+```
+ URI: git://git.openembedded.org/bitbake
+ branch: krogoth
+```
+
+```
+ URI: git://git.openembedded.org/openembedded-core
+ layers: meta
+ branch: krogoth
+```
+
+# Patches
+
+Please submit any patches against the readonly-rootfs-overlay layer via pull
+request.
+
+
+# Table of Contents
+
+1. [Adding the readonly-rootfs-overlay layer to your build](#adding-the-readonly-rootfs-overlay-layer-to-your-build)
+1. [Read-only root filesystem](#read-only-root-filesystem)
+1. [Kernel command line parameters](#kernel-command-line-parameters)
+
+
+## Adding the readonly-rootfs-overlay layer to your build
+
+In order to use this layer, you need to make the build system aware of
+it.
+
+Assuming the readonly-rootfs-overlay layer exists at the top-level of your
+OpenEmbedded source tree, you can add it to the build system by adding the
+location of the readonly-rootfs-overlay layer to bblayers.conf, along with any
+other layers needed. e.g.:
+
+```
+ BBLAYERS ?= " \
+ /path/to/layers/meta \
+ /path/to/layers/meta-poky \
+ /path/to/layers/meta-yocto-bsp \
+ /path/to/layers/meta-readonly-rootfs-overlay \
+ "
+```
+
+To add the script to your image, just add:
+
+```
+ IMAGE_INSTALL_append = " initscripts-readonly-rootfs-overlay"
+```
+
+to your `local.conf` or image recipe. Or use
+`core-image-rorootfs-overlay-initramfs` as initrd.
+
+## Read-only root filesystem
+
+If you use this layer you do *not* need to set `read-only-rootfs` in the
+`IMAGE_FEATURES` or `EXTRA_IMAGE_FEATURES` variable.
+
+## Kernel command line parameters
+
+These examples are not meant to be complete. They just contain parameters that
+are used by the initscript of this repository. Some additional paramters might
+be necessary.
+
+### Example using initrd:
+
+```
+root=/dev/sda1 rootrw=/dev/sda2
+```
+
+This cmd line start `/sbin/init` with the `/dev/sda1` partition as the read-only
+rootfs and the `/dev/sda2` partition as the read-write persistent state.
+
+```
+root=/dev/sda1 rootrw=/dev/sda2 init=/bin/sh
+```
+
+The same as before but it now starts `/bin/sh` instead of `/sbin/init`.
+
+### Example without initrd:
+
+```
+root=/dev/sda1 rootrw=/dev/sda2 init=/init
+```
+
+This cmd line starts `/sbin/init` with `/dev/sda1` partition as the read-only
+rootfs and the `/dev/sda2` partition as the read-write persistent state. When
+using this init script without an initrd, `init=/init` has to be set.
+
+```
+root=/dev/sda1 rootrw=/dev/sda2 init=/init rootinit=/bin/sh
+```
+
+The same as before but it now starts `/bin/sh` instead of `/sbin/init`
+
+### Details
+
+`root=` specifies the read-only root file system device. If this is not
+specified, the current rootfs is used.
+
+`rootfstype=` if support for the read-only file system is not build into the
+kernel, you can specify the required module name here. It will also be used in
+the mount command.
+
+`rootoptions=` specifies the mount options of the read-only file system.
+Defaults to `noatime,nodiratime`.
+
+`rootinit=` if the `init` parameter was used to specify this init script,
+`rootinit` can be used to overwrite the default (`/sbin/init`).
+
+`rootrw=` specifies the read-write file system device. If this is not
+specified, `tmpfs` is used.
+
+`rootrwfstype=` if support for the read-write file system is not build into the
+kernel, you can specify the required module name here. It will also be used in
+the mount command.
+
+`rootrwoptions=` specifies the mount options of the read-write file system.
+Defaults to `rw,noatime,mode=755`.
+
+`rootrwreset=` set to `yes` if you want to delete all the files in the
+read-write file system prior to building the overlay root files system.
diff --git a/recipes-core/initrdscripts/files/.init-readonly-rootfs-overlay-boot.sh.kate-swp b/recipes-core/initrdscripts/files/.init-readonly-rootfs-overlay-boot.sh.kate-swp
new file mode 100644
index 0000000..4a52bfd
--- /dev/null
+++ b/recipes-core/initrdscripts/files/.init-readonly-rootfs-overlay-boot.sh.kate-swp
Binary files differ
diff --git a/recipes-core/initrdscripts/files/init-readonly-rootfs-overlay-boot.sh b/recipes-core/initrdscripts/files/init-readonly-rootfs-overlay-boot.sh
new file mode 100755
index 0000000..6ec69ab
--- /dev/null
+++ b/recipes-core/initrdscripts/files/init-readonly-rootfs-overlay-boot.sh
@@ -0,0 +1,326 @@
+#!/bin/bash
+# fsck output of the upper file system (rw) is
+# written to /dev/kmsg
+
+# Kernel arguments for this script:
+# This script allows one to specify the root read-only device with
+# kernel argument:
+# root=
+# What follows can be a PARTUUID, PARTLABEL, or some other mechanism
+# understood by findfs, including the plain device name.
+#
+# The rw file system overlayed on top of root defaults to:
+# rootrw='PARTLABEL=user_data'
+# This is the first GPT partition found with the name user_data.
+#
+# Another file system can be specified by PARTUUID, or the
+# plain device name, or anything understood by findfs.
+# For instance:
+# rootrw=/dev/mmcblk0p10
+# to use the SD card.
+#
+# fsck is not done to the root file system. It is assumed it cannot be
+# corrupted.
+# By default, fsck -p [rootrw device] is done.
+#
+# There are two kernel options governing fsck:
+#
+# fsck.repair=true|false|force
+# false skips fsck, force adds the -f option.
+# true is the default (fsck with no -f option)
+# fsck.mode=preen|yes|no
+# These represent -p, -y, and -n options.
+# Preen (-p) is the default
+#
+# Additional options exist to specify the init program
+# mount options, file system type. root_rwreset="yes"
+# will cause the read/write file system to be erased.
+#
+
+
+# Enable strict shell mode
+set -euo pipefail
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+
+MOUNT="/bin/mount"
+UMOUNT="/bin/umount"
+
+INIT="/sbin/init"
+ROOT_ROINIT="/sbin/init"
+
+ROOT_MOUNT="/mnt"
+ROOT_RODEVICE=""
+ROOT_RWDEVICE=""
+ROOT_ROMOUNT="/run/media/rfs/ro"
+ROOT_RWMOUNT="/run/media/rfs/rw"
+ROOT_RWRESET="no"
+
+ROOT_ROFSTYPE=""
+ROOT_ROMOUNTOPTIONS="bind"
+ROOT_ROMOUNTOPTIONS_DEVICE="noatime,nodiratime,ro"
+
+ROOT_RWFSTYPE=""
+ROOT_RWMOUNTOPTIONS="rw,noatime,mode=755 tmpfs"
+ROOT_RWMOUNTOPTIONS_DEVICE="rw,noatime"
+
+# Arithmetic assignments of 0 are false, and then
+# script uses set -e, so use let instead.
+DO_FSCK=1
+DO_STOP=0
+FSCKOPT="-p"
+
+
+finddevice() {
+ DEVICE="$1"
+ if dev=$(findfs "${DEVICE}") && ((${#dev})) ; then
+ # Replace the rootfs string with the findfs device result
+ log "Searched for ${DEVICE} and found $dev"
+ echo "$dev"
+ return 0
+ fi
+ log "Could not find $DEVICE"
+ return 1
+}
+
+early_setup() {
+ mkdir -p /proc
+ mkdir -p /sys
+ $MOUNT -t proc proc /proc
+ $MOUNT -t sysfs sysfs /sys
+ grep -w "/dev" /proc/mounts >/dev/null || $MOUNT -t devtmpfs none /dev
+}
+
+read_args() {
+ # Default is to do fsck with -p option on user_data partition.
+ [ -z "${CMDLINE+x}" ] && CMDLINE=`cat /proc/cmdline`
+ for arg in $CMDLINE; do
+ # Set optarg to option parameter, and '' if no parameter was
+ # given
+ optarg=`expr "x$arg" : 'x[^=]*=\(.*\)' || echo ''`
+ case $arg in
+ shinitramfs)
+ ((DO_STOP=1)) ;;
+ root=*)
+ ROOT_RODEVICE=$optarg
+ if rootdev=$(finddevice "${ROOT_RODEVICE}") ; then
+ # Replace the rootfs string with the findfs device result
+ ROOT_RODEVICE="${rootdev}"
+ fi
+ ;;
+ rootfstype=*)
+ ROOT_ROFSTYPE="$optarg" ;;
+ rootinit=*)
+ ROOT_ROINIT=$optarg ;;
+ rootoptions=*)
+ ROOT_ROMOUNTOPTIONS_DEVICE="$optarg" ;;
+ rootrw=*)
+ ROOT_RWDEVICE=$optarg
+ if rootrwdev="$(finddevice ${ROOT_RWDEVICE})" ; then
+ # Replace the rootfs string with the findfs device result
+ ROOT_RODEVICE="${rootrwdev}"
+ fi
+ ;;
+ rootrwfstype=*)
+ ROOT_RWFSTYPE="$optarg" ;;
+ rootrwreset=*)
+ ROOT_RWRESET=$optarg ;;
+ rootrwoptions=*)
+ ROOT_RWMOUNTOPTIONS_DEVICE="$optarg" ;;
+ init=*)
+ INIT=$optarg ;;
+ fsck.mode=*)
+ fsck_mode=$optarg
+ case $fsck_mode in
+ preen)
+ FSCKOPT="-p" ;;
+ yes)
+ FSCKOPT="-y" ;;
+ no)
+ FSCKOPT="-n" ;;
+ esac
+ ;;
+ fsck.repair=*)
+ fsck_repair=$optarg
+ case $fsck_repair in
+ force)
+ if ((${#FSCKOPT)) ; then
+ FSCKOPT+="f"
+ else
+ FSCKOPT="-f"
+ fi
+ DO_FSCK=1
+ ;;
+ yes)
+ DO_FSCK=1
+ ;;
+ no)
+ DO_FSCK=0
+ ;;
+ esac
+
+ ;;
+ esac
+ done
+}
+
+fatal() {
+ echo "rorootfs-overlay: $1" >$CONSOLE
+ echo >$CONSOLE
+ exec bash
+}
+
+log() {
+ echo "rorootfs-overlay: $1" >$CONSOLE
+}
+
+early_setup
+
+[ -z "${CONSOLE+x}" ] && CONSOLE="/dev/console"
+
+read_args
+
+mount_and_boot() {
+ mkdir -p $ROOT_MOUNT $ROOT_ROMOUNT $ROOT_RWMOUNT
+
+ # Build mount options for read only root file system.
+ # If no read-only device was specified via kernel command line, use
+ # current root file system via bind mount.
+ ROOT_ROMOUNTPARAMS_BIND="-o ${ROOT_ROMOUNTOPTIONS} /"
+ if [ -n "${ROOT_RODEVICE}" ]; then
+ ROOT_ROMOUNTPARAMS="-o ${ROOT_ROMOUNTOPTIONS_DEVICE} $ROOT_RODEVICE"
+ if [ -n "${ROOT_ROFSTYPE}" ]; then
+ ROOT_ROMOUNTPARAMS="-t $ROOT_ROFSTYPE $ROOT_ROMOUNTPARAMS"
+ fi
+ else
+ ROOT_ROMOUNTPARAMS="$ROOT_ROMOUNTPARAMS_BIND"
+ fi
+
+ mountlog=$($MOUNT $ROOT_ROMOUNTPARAMS "$ROOT_ROMOUNT" 2>&1)
+ mountresult=$?
+ if ((mountresult != 0)) ; then
+ log "Failed root mount (result $mountresult): $mountlog"
+ log "mounts: $(cat /proc/mounts)"
+ else
+ log "Mounted ro root: $(grep "$ROOT_ROMOUNT" /proc/mounts)"
+ fi
+
+ log "Mounted root: $(grep root /proc/mounts)"
+
+ # If future init is the same as current file, use $ROOT_ROINIT
+ # Tries to avoid loop to infinity if init is set to current file via
+ # kernel command line
+ if cmp -s "$0" "$INIT"; then
+ INIT="$ROOT_ROINIT"
+ fi
+
+ # find user_data
+ if [[ -z ${ROOT_RWDEVICE} ]] ; then
+ userdata=$(findfs PARTLABEL=user_data)
+ blkid_out=$(blkid $userdata)
+ if [[ -n $userdata ]] ; then
+ if [[ $blkid_out =~ TYPE=\"([^\"]+)\" ]]; then
+ log "Detected user_data partition with ${BASH_REMATCH[1]} file system"
+ else
+ log "Create new user_data partition ext4 file system"
+ mkfs.ext4 -O 64bit $userdata
+ fi
+ ROOT_RWDEVICE="$userdata"
+ fi # Found user_data GPT partition
+ fi # Empty ROOT_RWDEVICE
+ # Build mount options for read write root file system.
+ # If a read-write device was specified via kernel command line
+ # or partition table, use it, otherwise default to tmpfs.
+ if [ -n "${ROOT_RWDEVICE}" ]; then
+ ROOT_RWMOUNTPARAMS="-o $ROOT_RWMOUNTOPTIONS_DEVICE $ROOT_RWDEVICE"
+ if [ -n "${ROOT_RWFSTYPE}" ]; then
+ ROOT_RWMOUNTPARAMS="-t $ROOT_RWFSTYPE $ROOT_RWMOUNTPARAMS"
+ fi
+ else
+ ROOT_RWMOUNTPARAMS="-t tmpfs -o $ROOT_RWMOUNTOPTIONS"
+ fi
+
+ if ((DO_FSCK == 1)) ; then
+ if log_result=$(fsck $FSCKOPT $ROOT_RWDEVICE 2>&1) ; then
+ log "OK fsck user_data: fsck $FSCKOPT $ROOT_RWDEVICE: $(fsck $FSCKOPT $ROOT_RWDEVICE 2>&1)"
+ echo "fsck user_data: $log_result" >/dev/kmsg
+ else
+ log "ERR fsck user_data: fsck $FSCKOPT $ROOT_RWDEVICE: $(fsck $FSCKOPT $ROOT_RWDEVICE 2>&1)"
+ log "$log_result"
+ # Write fsck to kernel log
+ echo "ERR fsck user_data: fsck $FSCKOPT $ROOT_RWDEVICE: $(fsck $FSCKOPT $ROOT_RWDEVICE 2>&1)" >/dev/kmsg
+ echo "$log_result" >/dev/kmsg
+ fi
+ fi
+
+ # Mount read-write file system into initram root file system
+ if ! $MOUNT $ROOT_RWMOUNTPARAMS $ROOT_RWMOUNT ; then
+ fatal "Could not mount read-write rootfs"
+ fi
+
+ # Reset read-write file system if specified
+ if [ "yes" == "$ROOT_RWRESET" -a -n "${ROOT_RWMOUNT}" ]; then
+ rm -rf $ROOT_RWMOUNT/*
+ fi
+
+ # Determine which unification file system to use
+ union_fs_type=""
+ if grep -w "overlay" /proc/filesystems >/dev/null; then
+ union_fs_type="overlay"
+ elif grep -w "aufs" /proc/filesystems >/dev/null; then
+ union_fs_type="aufs"
+ else
+ union_fs_type=""
+ fi
+
+ # Create/Mount overlay root file system
+ case $union_fs_type in
+ "overlay")
+ log "$(cat /proc/mounts)"
+ mkdir -p $ROOT_RWMOUNT/upperdir $ROOT_RWMOUNT/work
+ if ! $MOUNT -t overlay overlay \
+ -o "$(printf "%s%s%s" \
+ "lowerdir=$ROOT_ROMOUNT," \
+ "upperdir=$ROOT_RWMOUNT/upperdir," \
+ "workdir=$ROOT_RWMOUNT/work")" \
+ $ROOT_MOUNT ; then
+ log "$MOUNT -t overlay overlay \
+ -o \"$(printf \"%s%s%s\" \
+ \"lowerdir=$ROOT_ROMOUNT,\" \
+ \"upperdir=$ROOT_RWMOUNT/upperdir,\" \
+ \"workdir=$ROOT_RWMOUNT/work\")\" \
+ $ROOT_MOUNT"
+ fatal "Cound not mount overlay"
+ fi
+ ;;
+ "aufs")
+ $MOUNT -t aufs i\
+ -o "dirs=$ROOT_RWMOUNT=rw:$ROOT_ROMOUNT=ro" \
+ aufs $ROOT_MOUNT
+ ;;
+ "")
+ fatal "No overlay filesystem type available"
+ ;;
+ esac
+
+ # Move read-only and read-write root file system into the overlay
+ # file system
+ mkdir -p $ROOT_MOUNT/$ROOT_ROMOUNT $ROOT_MOUNT/$ROOT_RWMOUNT
+ $MOUNT -n --move $ROOT_ROMOUNT ${ROOT_MOUNT}/$ROOT_ROMOUNT
+ $MOUNT -n --move $ROOT_RWMOUNT ${ROOT_MOUNT}/$ROOT_RWMOUNT
+
+ $MOUNT -n --move /proc ${ROOT_MOUNT}/proc
+ $MOUNT -n --move /sys ${ROOT_MOUNT}/sys
+ $MOUNT -n --move /dev ${ROOT_MOUNT}/dev
+ log "overlay: $(grep 'overlay' ${ROOT_MOUNT}/proc/mounts)"
+ cd $ROOT_MOUNT
+ if ((DO_STOP)) ; then
+ fatal "Initramfs Shell mode selected -- bash shell"
+ fi
+
+ # switch to actual init in the overlay root file system
+ exec switch_root $ROOT_MOUNT $INIT ||
+ fatal "Couldn't chroot, dropping to shell"
+}
+
+mount_and_boot
diff --git a/recipes-core/initrdscripts/initramfs-readonly-rootfs-overlay_1.0.bb b/recipes-core/initrdscripts/initramfs-readonly-rootfs-overlay_1.0.bb
new file mode 100644
index 0000000..164d394
--- /dev/null
+++ b/recipes-core/initrdscripts/initramfs-readonly-rootfs-overlay_1.0.bb
@@ -0,0 +1,8 @@
+require readonly-rootfs-overlay-init-script.inc
+
+do_install_append() {
+ install -d ${D}/dev
+ mknod -m 622 ${D}/dev/console c 5 1
+}
+
+FILES_${PN} += "/dev"
diff --git a/recipes-core/initrdscripts/initscripts-readonly-rootfs-overlay_1.0.bb b/recipes-core/initrdscripts/initscripts-readonly-rootfs-overlay_1.0.bb
new file mode 100644
index 0000000..9428356
--- /dev/null
+++ b/recipes-core/initrdscripts/initscripts-readonly-rootfs-overlay_1.0.bb
@@ -0,0 +1 @@
+require readonly-rootfs-overlay-init-script.inc
diff --git a/recipes-core/initrdscripts/readonly-rootfs-overlay-init-script.inc b/recipes-core/initrdscripts/readonly-rootfs-overlay-init-script.inc
new file mode 100644
index 0000000..d1b8104
--- /dev/null
+++ b/recipes-core/initrdscripts/readonly-rootfs-overlay-init-script.inc
@@ -0,0 +1,36 @@
+SUMMARY = "Read only rootfs with overlay init script"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420"
+DEPENDS = "virtual/kernel"
+
+# This was derived from https://github.com/cmhe/meta-readonly-rootfs-overlay
+
+# script uses bash, findfs, busybox is problematic, so use real fsck,
+# and add ext4 utilities in case some one needs to try to recover the
+# user_data file system
+RDEPENDS_${PN} = " \
+ bash \
+ util-linux-findfs \
+ util-linux-fsck \
+ e2fsprogs \
+ e2fsprogs-mke2fs \
+ e2fsprogs-badblocks \
+ e2fsprogs-e2fsck \
+ e2fsprogs-tune2fs \
+ e2fsprogs-resize2fs \
+ "
+
+SRC_URI = "file://init-readonly-rootfs-overlay-boot.sh"
+
+S = "${WORKDIR}"
+
+do_install() {
+ install -m 0755 ${WORKDIR}/init-readonly-rootfs-overlay-boot.sh ${D}/init
+ install -d "${D}/run/media/rfs/ro"
+ install -d "${D}/run/media/rfs/rw"
+}
+
+FILES_${PN} += " /init /run"
+
+# Due to kernel dependency
+PACKAGE_ARCH = "${MACHINE_ARCH}"