From 8bd6208ff72cd2eeb486ba34c62001a39de25ace Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Tue, 15 Oct 2024 09:50:30 -0600 Subject: [PATCH] overlayfs-setup: Fallback to read only mount when overlay not supported Overlayfs doesn't support using case insensitive filesystems such as vfat and exfat as a lower directory. Change the mount to read only so changes can't be made there. In theory this would simply be `mount -o remount,ro`. Unfortunately, if systemd has setup an automount, autofs is not our friend. In that case, the mount options need to be persisted into the mount unit so that a subsequent remounting retains the ro option. https://phabricator.endlessm.com/T35641 --- eos-live-boot-overlayfs-setup | 67 ++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/eos-live-boot-overlayfs-setup b/eos-live-boot-overlayfs-setup index 7003446..b90804f 100755 --- a/eos-live-boot-overlayfs-setup +++ b/eos-live-boot-overlayfs-setup @@ -88,6 +88,64 @@ setup_and_mount_storage() { mount "${device}" /run/eos-live } +setup_ro_mount() { + local path=$1 + + # If the directory isn't a mount point, make a read only bind mount + # on top of the directory and be done. + if ! findmnt "$path" >/dev/null; then + mount -o bind,ro "$path" "$path" + return 0 + fi + + # In case of an automount, trigger the real mount so its options can + # be inspected. + ls "$path" >/dev/null + + # If it's already mounted read only, assume we're done. + local mounted_options + mounted_options=$(findmnt -n -f -d backward -o OPTIONS "$path") + [[ $mounted_options =~ (,|^)ro(,|$) ]] && return 0 + + # If there's an automount, adjust the mount options in the mount + # unit so the read only option persists across mountings. + local escaped_path automount_unit + escaped_path=$(systemd-escape -p "$path") + automount_unit="${escaped_path}.automount" + if systemctl -q is-active "$automount_unit"; then + # If the mount unit's Options don't contain ro, add a drop-in to + # set it. + local mount_unit mount_options new_mount_options + mount_unit="${escaped_path}.mount" + mount_options=$(systemctl show -P Options "$mount_unit") + if [[ $mount_options =~ (,|^)(ro|rw)(,|$) ]]; then + new_mount_options=$(sed -E 's/(,|^)rw(,|$)/\1ro\2/' <<< "$mount_options") + else + new_mount_options="${mount_options}${mount_options:+,}ro" + fi + + if [ "$new_mount_options" != "$mount_options" ]; then + local dropin_dir="/run/systemd/system/${mount_unit}.d" + local dropin_conf="${dropin_dir}/readonly.conf" + mkdir -p "$dropin_dir" + echo "Changing ${mount_unit} Options from \"${mount_options}\"" \ + "to \"${new_mount_options}\"" >&2 + cat > "$dropin_conf" </dev/null && return 0 mkdir -p "/run/eos-live/$dir" "/run/eos-live/$dir-workdir" - mount -t overlay -o \ + if ! mount -t overlay -o \ "rw,upperdir=/run/eos-live/$dir,lowerdir=/$dir,workdir=/run/eos-live/$dir-workdir" \ "eos-live-$dir" "/$dir" + then + # Overlayfs doesn't support using case insensitive filesystems + # such as vfat and exfat as a lower directory. Change the mount + # to read only so changes can't be made there. + echo "Could not mount overlayfs on /$dir, trying to mount read only" >&2 + setup_ro_mount "/$dir" + fi } # Use persistent storage to back overlayfses, if available