Skip to content

Commit

Permalink
tests: Add mount propagation test
Browse files Browse the repository at this point in the history
This tests the current behavior of making /sysroot a private mount so
that submounts on /var do not propagate back to /sysroot. It also shows
how submounts of /sysroot do not propagate into separate mount
namespaces for the same reason.
  • Loading branch information
dbnicholson committed Aug 30, 2024
1 parent 2b01c93 commit 877e870
Showing 1 changed file with 128 additions and 0 deletions.
128 changes: 128 additions & 0 deletions tests/kolainst/destructive/mount-propagation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/bin/bash
# https://bugzilla.redhat.com/show_bug.cgi?id=1498281
set -xeuo pipefail

. ${KOLA_EXT_DATA}/libinsttest.sh

require_writable_sysroot

has_mount() {
local target=${1:?No target specified}
local pid=${2:?No PID specified}
local mounts="/proc/${pid}/mounts"

# Unlike grep, awk doesn't exit based on whether it matched anything or not,
# so that needs to be emulated.
awk 'BEGIN {ret = 1}; $2 == "'"${target}"'" {print; ret = 0}; END {exit ret}' "${mounts}"
}

assert_has_mount() {
local target=${1:?No target specified}
local pid=${2:-$$}
if ! has_mount "${target}" "${pid}"; then
cat "/proc/${pid}/mounts" >&2
fatal "Mount '$target' not found in process $pid"
fi
}

assert_not_has_mount() {
local target=${1:?No target specified}
local pid=${2:-$$}
if has_mount "${target}" "${pid}"; then
cat "/proc/${pid}/mounts" >&2
fatal "Mount '$target' found in process $pid"
fi
}

test_mounts() {
local stateroot=$(rpmostree_query_json '.deployments[0].osname')

echo "Root namespace mountinfo:"
cat "/proc/$$/mountinfo"

echo "Sub namespace mountinfo:"
cat "/proc/${ns_pid}/mountinfo"

# Make sure the 2 PIDs are really in different mount namespaces.
root_ns=$(readlink "/proc/$$/ns/mnt")
sub_ns=$(readlink "/proc/${ns_pid}/ns/mnt")
assert_not_streq "${root_ns}" "${sub_ns}"

# Check the mounts exist in the root namespace and the /var/foo mount has not
# propagated back to /sysroot.
assert_has_mount /var/foo
assert_has_mount /sysroot/bar
assert_not_has_mount "/sysroot/ostree/deploy/${stateroot}/var/foo"

# Repeat with the sub mount namespace. Since /sysroot is marked private,
# /sysroot/bar will not be propagated into it.
assert_has_mount /var/foo "${ns_pid}"
assert_not_has_mount /sysroot/bar "${ns_pid}"
assert_not_has_mount "/sysroot/ostree/deploy/${stateroot}/var/foo" "${ns_pid}"
}

case "${AUTOPKGTEST_REBOOT_MARK:-}" in
"")
mkdir -p /var/foo /sysroot/bar

# Create a process in a separate mount namespace to see if the mounts
# propagate into it correctly.
unshare -m --propagation unchanged -- sleep infinity &
ns_pid=$!

mount -t tmpfs foo /var/foo
mount -t tmpfs bar /sysroot/bar

test_mounts

# Now setup for the same test but with the mounts made early via fstab.
cat >> /etc/fstab <<"EOF"
foo /var/foo tmpfs defaults 0 0
bar /sysroot/bar tmpfs defaults 0 0
EOF

# We want to start a process in a separate namespace after ostree-remount
# has completed but before systemd starts the fstab generated mount units.
cat > /etc/systemd/system/test-mounts.service <<"EOF"
[Unit]
DefaultDependencies=no
After=ostree-remount.service
Before=var-foo.mount sysroot-bar.mount
RequiresMountsFor=/var /sysroot
Conflicts=shutdown.target
Before=shutdown.target
[Service]
Type=exec
ExecStart=/usr/bin/sleep infinity
ProtectSystem=strict
[Install]
WantedBy=local-fs.target
EOF
systemctl enable test-mounts.service

/tmp/autopkgtest-reboot 2
;;
2)
# Check that the test service is running and get its PID.
ns_state=$(systemctl show -P ActiveState test-mounts.service)
assert_streq "${ns_state}" active
ns_pid=$(systemctl show -P MainPID test-mounts.service)

# Make sure that test-mounts.service started after ostree-remount.service
# but before /var/foo and /sysroot/bar were mounted so that we can see if
# the mounts were propagated into its mount namespace.
remount_finished=$(journalctl -o json -g Finished -u ostree-remount.service | tail -n1 | jq -r .__MONOTONIC_TIMESTAMP)
test_starting=$(journalctl -o json -g Starting -u test-mounts.service | tail -n1 | jq -r .__MONOTONIC_TIMESTAMP)
test_started=$(journalctl -o json -g Started -u test-mounts.service | tail -n1 | jq -r .__MONOTONIC_TIMESTAMP)
foo_mounting=$(journalctl -o json -g Mounting -u var-foo.mount | tail -n1 | jq -r .__MONOTONIC_TIMESTAMP)
bar_mounting=$(journalctl -o json -g Mounting -u sysroot-bar.mount | tail -n1 | jq -r .__MONOTONIC_TIMESTAMP)
test "${remount_finished}" -lt "${test_starting}"
test "${test_started}" -lt "${foo_mounting}"
test "${test_started}" -lt "${bar_mounting}"

test_mounts
;;
*) fatal "Unexpected AUTOPKGTEST_REBOOT_MARK=${AUTOPKGTEST_REBOOT_MARK}" ;;
esac

0 comments on commit 877e870

Please sign in to comment.