#!/usr/bin/env bats load helpers function setup() { setup_busybox # Create fake rootfs. mkdir rootfs/testdir rootfs/testdir2 rootfs/testdir3 echo "Forbidden information!" >rootfs/testfile # add extra masked paths update_config '(.. | select(.maskedPaths? != null)) .maskedPaths += ["/testdir", "/testfile"]' } function teardown() { teardown_bundle } @test "mask paths [file]" { runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox [ "$status" -eq 0 ] runc exec test_busybox cat /testfile [ "$status" -eq 0 ] [ -z "$output" ] runc exec test_busybox rm -f /testfile [ "$status" -eq 1 ] [[ "${output}" == *"Read-only file system"* ]] runc exec test_busybox umount /testfile [ "$status" -eq 1 ] [[ "${output}" == *"Operation not permitted"* ]] } @test "mask paths [directory]" { runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox [ "$status" -eq 0 ] runc exec test_busybox ls /testdir [ "$status" -eq 0 ] [ -z "$output" ] runc exec test_busybox touch /testdir/foo [ "$status" -eq 1 ] [[ "${output}" == *"Read-only file system"* ]] runc exec test_busybox rm -rf /testdir [ "$status" -eq 1 ] [[ "${output}" == *"Read-only file system"* ]] runc exec test_busybox umount /testdir [ "$status" -eq 1 ] [[ "${output}" == *"Operation not permitted"* ]] } @test "mask paths [duplicate paths]" { update_config '(.. | select(.maskedPaths? != null)) .maskedPaths += ["/testdir", "/testfile"]' runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox [ "$status" -eq 0 ] runc exec test_busybox sh -c "mount | grep /testdir -c" [ "$status" -eq 0 ] [[ "${output}" == "1" ]] runc exec test_busybox sh -c "mount | grep /testfile -c" [ "$status" -eq 0 ] [[ "${output}" == "1" ]] } @test "mask paths [prohibit symlink /proc]" { ln -s /symlink rootfs/proc runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox [ "$status" -eq 1 ] [[ "${output}" == *"must be mounted on ordinary directory"* ]] } @test "mask paths [prohibit symlink /sys]" { # In rootless containers, /sys is a bind mount not a real sysfs. requires root ln -s /symlink rootfs/sys runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox [ "$status" -eq 1 ] # On cgroup v1, this may fail before checking if /sys is a symlink, # so we merely check that it fails, and do not check the exact error # message like for /proc above. } @test "mask paths [directories share tmpfs]" { update_config '(.. | select(.maskedPaths? != null)) .maskedPaths += ["/testdir2", "/testdir3"]' runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox [ "$status" -eq 0 ] # shellcheck disable=SC2016 runc exec test_busybox sh -euc ' set -- $(stat -c %d /testdir /testdir2 /testdir3) [ "$1" = "$2" ] [ "$2" = "$3" ] ' [ "$status" -eq 0 ] runc exec test_busybox touch /testdir2/foo [ "$status" -eq 1 ] [[ "${output}" == *"Read-only file system"* ]] } @test "mask paths [directory with read-only rootfs]" { update_config '(.. | select(.maskedPaths? != null)) .maskedPaths += ["/testdir2", "/testdir3"]' update_config '.root.readonly = true' runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox [ "$status" -eq 0 ] runc exec test_busybox ls /testdir [ "$status" -eq 0 ] [ -z "$output" ] }