Skip to content

Commit

Permalink
alpine: avoid wiping out writable host mounts under /home, etc.
Browse files Browse the repository at this point in the history
A host directory could be wiped out when all the following conditions are met:
- The directory is mounted to Lima via virtiofs or 9p (reverse-sshfs is not affected)
- The mount is writable
- The mount point in the guest is under one of: /etc /home /root /usr/local /var/lib
- The guest OS is Alpine Linux

Fix issue 2221
Fix rancher-sandbox/rancher-desktop issue 6582

Co-authored-by: Jan Dubois <jan.dubois@suse.com>
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
  • Loading branch information
AkihiroSuda and jandubois committed Mar 9, 2024
1 parent b1dbefb commit 994df39
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 9 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ jobs:
- opensuse.yaml
- experimental/net-user-v2.yaml
- docker.yaml
- ../hack/test-templates/alpine-9p-writable.yaml
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -258,6 +259,8 @@ jobs:
retry_on: error
max_attempts: 3
command: ./hack/test-templates.sh templates/${{ matrix.template }}
- name: "Check that the host home is not wiped"
run: test -e ~/.cache/lima
- name: "Show cache"
run: ./hack/debug-cache.sh

Expand Down
2 changes: 1 addition & 1 deletion hack/test-port-forwarding.pl
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
foreach my $id (0..@test-1) {
my $test = $test[$id];
my $nc = "nc -l $test->{guest_ip} $test->{guest_port}";
if ($instance eq "alpine") {
if ($instance =~ /^alpine/) {
$nc = "nc -l -s $test->{guest_ip} -p $test->{guest_port}";
}

Expand Down
2 changes: 1 addition & 1 deletion hack/test-templates.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ declare -A CHECKS=(
)

case "$NAME" in
"alpine")
"alpine"*)
WARNING "Alpine does not support systemd"
CHECKS["systemd"]=
CHECKS["container-engine"]=
Expand Down
18 changes: 18 additions & 0 deletions hack/test-templates/alpine-9p-writable.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Background: https://github.com/lima-vm/lima/pull/2234
# Should be tested on a Linux host
images:
- location: "https://github.com/lima-vm/alpine-lima/releases/download/v0.2.37/alpine-lima-std-3.19.0-x86_64.iso"
arch: "x86_64"
digest: "sha512:568852df405e6b9858e678171a9894c058f483df0b0570c22cf33fc75f349ba6cc5bb3d50188180d8c31faaf53400fe884ca3e5f949961b03b2bf53e65de88d7"
- location: "https://github.com/lima-vm/alpine-lima/releases/download/v0.2.37/alpine-lima-std-3.19.0-aarch64.iso"
arch: "aarch64"
digest: "sha512:3a4bd5ad0201f503e9bb9f3b812aa0df292e2e099148c0323d23244046ad199a2946ef9e0619fec28726bfdcc528233f43c3b4b036c9e06e92ac730d579f0ca3"

mountType: "9p"
mounts:
- location: "~"
writable: true

containerd:
system: false
user: false
37 changes: 30 additions & 7 deletions pkg/cidata/cidata.TEMPLATE.d/boot/04-persistent-data-volume.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,34 @@ test -f /etc/alpine-release || exit 0
# Data directories that should be persisted across reboots
DATADIRS="/etc /home /root /tmp /usr/local /var/lib"

# Prepare mnt.sh (used for restoring mounts later)
echo "#!/bin/sh" >/mnt.sh
echo "set -eux" >>/mnt.sh
for DIR in ${DATADIRS}; do
while IFS= read -r LINE; do
[ -z "$LINE" ] && continue
MNTDEV="$(echo "${LINE}" | awk '{print $1}')"
# unmangle " \t\n\\#"
# https://github.com/torvalds/linux/blob/v6.6/fs/proc_namespace.c#L89
MNTPNT="$(echo "${LINE}" | awk '{print $2}' | sed -e 's/\\040/ /g; s/\\011/\t/g; s/\\012/\n/g; s/\\134/\\/g; s/\\043/#/g')"
# Ignore if MNTPNT is neither DIR nor a parent directory of DIR.
# It is not a parent if MNTPNT doesn't start with DIR, or the first
# character after DIR isn't a slash.
WITHOUT_DIR="${MNTPNT#"$DIR"}"
# shellcheck disable=SC2166
[ "$MNTPNT" != "$DIR" ] && [ "$MNTPNT" == "$WITHOUT_DIR" -o "${WITHOUT_DIR::1}" != "/" ] && continue
MNTTYPE="$(echo "${LINE}" | awk '{print $3}')"
[ "${MNTTYPE}" = "ext4" ] && continue
[ "${MNTTYPE}" = "tmpfs" ] && continue
MNTOPTS="$(echo "${LINE}" | awk '{print $4}')"
echo "mount -t ${MNTTYPE} -o ${MNTOPTS} ${MNTDEV} ${MNTPNT}" >>/mnt.sh
# Before mv, unmount filesystems (virtiofs, 9p, etc.) below "${DIR}", otherwise host mounts will be wiped out
# https://github.com/rancher-sandbox/rancher-desktop/issues/6582
umount "${MNTPNT}" || exit 1
done </proc/mounts
done
chmod +x /mnt.sh

# When running from RAM try to move persistent data to data-volume
# FIXME: the test for tmpfs mounts is probably Alpine-specific
if [ "$(awk '$2 == "/" {print $3}' /proc/mounts)" == "tmpfs" ]; then
Expand Down Expand Up @@ -61,11 +89,6 @@ if [ "$(awk '$2 == "/" {print $3}' /proc/mounts)" == "tmpfs" ]; then
PART=$(lsblk --list /dev/"${DISK}" --noheadings --output name,type | awk '$2 == "part" {print $1}')
mkfs.ext4 -L data-volume /dev/"${PART}"
mount -t ext4 /dev/disk/by-label/data-volume /mnt/data
# Unmount all mount points under /tmp so we can move it to the data volume:
# "mount1 on /tmp/lima type 9p (rw,dirsync,relatime,mmap,access=client,trans=virtio)"
for MP in $(mount | awk '$3 ~ /^\/tmp\// {print $3}'); do
umount "${MP}"
done
# setup apk package cache
mkdir -p /mnt/data/apk/cache
mkdir -p /etc/apk
Expand All @@ -88,8 +111,8 @@ if [ "$(awk '$2 == "/" {print $3}' /proc/mounts)" == "tmpfs" ]; then
mount --bind /mnt/data"${DIR}" "${DIR}"
fi
done
# Make sure to re-mount any mount points under /tmp
mount -a
# Remount submounts on top of the new ${DIR}
/mnt.sh
# Reinstall packages from /mnt/data/apk/cache into the RAM disk
apk fix --no-network
fi

0 comments on commit 994df39

Please sign in to comment.