...

Text file src/github.com/opencontainers/runc/tests/integration/userns.bats

Documentation: github.com/opencontainers/runc/tests/integration

     1#!/usr/bin/env bats
     2
     3load helpers
     4
     5function setup() {
     6	setup_busybox
     7
     8	# Prepare source folders for bind mount
     9	mkdir -p source-{accessible,inaccessible-1,inaccessible-2}/dir
    10	touch source-{accessible,inaccessible-1,inaccessible-2}/dir/foo.txt
    11
    12	# Permissions only to the owner, it is inaccessible to group/others
    13	chmod 700 source-inaccessible-{1,2}
    14
    15	mkdir -p rootfs/{proc,sys,tmp}
    16	mkdir -p rootfs/tmp/mount-{1,2}
    17
    18	to_umount_list="$(mktemp "$BATS_RUN_TMPDIR/userns-mounts.XXXXXX")"
    19	if [ "$ROOTLESS" -eq 0 ]; then
    20		update_config ' .linux.namespaces += [{"type": "user"}]
    21			| .linux.uidMappings += [{"hostID": 100000, "containerID": 0, "size": 65534}]
    22			| .linux.gidMappings += [{"hostID": 200000, "containerID": 0, "size": 65534}] '
    23	fi
    24}
    25
    26function teardown() {
    27	teardown_bundle
    28
    29	if [ -v to_umount_list ]; then
    30		while read -r mount_path; do
    31			umount -l "$mount_path" || :
    32			rm -f "$mount_path"
    33		done <"$to_umount_list"
    34		rm -f "$to_umount_list"
    35		unset to_umount_list
    36	fi
    37}
    38
    39@test "userns with simple mount" {
    40	update_config ' .process.args += ["-c", "stat /tmp/mount-1/foo.txt"]
    41		| .mounts += [{"source": "source-accessible/dir", "destination": "/tmp/mount-1", "options": ["bind"]}] '
    42
    43	runc run test_busybox
    44	[ "$status" -eq 0 ]
    45}
    46
    47# We had bugs where 1 mount worked but not 2+, test with 2 as it is a more
    48# general case.
    49@test "userns with 2 inaccessible mounts" {
    50	update_config '   .process.args += ["-c", "stat /tmp/mount-1/foo.txt /tmp/mount-2/foo.txt"]
    51			| .mounts += [	{ "source": "source-inaccessible-1/dir", "destination": "/tmp/mount-1", "options": ["bind"] },
    52			                { "source": "source-inaccessible-2/dir", "destination": "/tmp/mount-2", "options": ["bind"] }
    53			           ]'
    54
    55	# When not running rootless, this should work: while
    56	# "source-inaccessible-1" can't be read by the uid in the userns, the fd
    57	# is opened before changing to the userns and sent over via SCM_RIGHTs
    58	# (with env var _LIBCONTAINER_MOUNT_FDS). Idem for
    59	# source-inaccessible-2.
    60	# On rootless, the owner is the same so it is accessible.
    61	runc run test_busybox
    62	[ "$status" -eq 0 ]
    63}
    64
    65# exec + bindmounts + user ns is a special case in the code. Test that it works.
    66@test "userns with inaccessible mount + exec" {
    67	update_config ' .mounts += [ 	{ "source": "source-inaccessible-1/dir", "destination": "/tmp/mount-1", "options": ["bind"] },
    68					{ "source": "source-inaccessible-2/dir", "destination": "/tmp/mount-2", "options": ["bind"] }
    69			         ]'
    70
    71	runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
    72	[ "$status" -eq 0 ]
    73
    74	runc exec test_busybox stat /tmp/mount-1/foo.txt /tmp/mount-2/foo.txt
    75	[ "$status" -eq 0 ]
    76}
    77
    78# Issue fixed by https://github.com/opencontainers/runc/pull/3510.
    79@test "userns with bind mount before a cgroupfs mount" {
    80	# This can only be reproduced on cgroup v1 (and no cgroupns) due to the
    81	# way it is mounted in such case (a bunch of of bind mounts).
    82	requires cgroups_v1
    83
    84	# Add a bind mount right before the /sys/fs/cgroup mount,
    85	# and make sure cgroupns is not enabled.
    86	update_config '	  .mounts |= map(if .destination == "/sys/fs/cgroup" then ({"source": "source-accessible/dir", "destination": "/tmp/mount-1", "options": ["bind"]}, .) else . end)
    87			| .linux.namespaces -= [{"type": "cgroup"}]'
    88
    89	runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
    90	[ "$status" -eq 0 ]
    91
    92	# Make sure this is real cgroupfs.
    93	runc exec test_busybox cat /sys/fs/cgroup/{pids,memory}/tasks
    94	[ "$status" -eq 0 ]
    95}
    96
    97@test "userns join other container userns" {
    98	# Create a detached container with the id-mapping we want.
    99	update_config '.process.args = ["sleep", "infinity"]'
   100	runc run -d --console-socket "$CONSOLE_SOCKET" target_userns
   101	[ "$status" -eq 0 ]
   102
   103	# Configure our container to attach to the first container's userns.
   104	target_pid="$(__runc state target_userns | jq .pid)"
   105	update_config '.linux.namespaces |= map(if .type == "user" then (.path = "/proc/'"$target_pid"'/ns/" + .type) else . end)
   106		| del(.linux.uidMappings)
   107		| del(.linux.gidMappings)'
   108	runc run -d --console-socket "$CONSOLE_SOCKET" in_userns
   109	[ "$status" -eq 0 ]
   110
   111	runc exec in_userns cat /proc/self/uid_map
   112	[ "$status" -eq 0 ]
   113	if [ $EUID -eq 0 ]; then
   114		grep -E '^\s+0\s+100000\s+65534$' <<<"$output"
   115	else
   116		grep -E '^\s+0\s+'$EUID'\s+1$' <<<"$output"
   117	fi
   118
   119	runc exec in_userns cat /proc/self/gid_map
   120	[ "$status" -eq 0 ]
   121	if [ $EUID -eq 0 ]; then
   122		grep -E '^\s+0\s+200000\s+65534$' <<<"$output"
   123	else
   124		grep -E '^\s+0\s+'$EUID'\s+1$' <<<"$output"
   125	fi
   126}
   127
   128@test "userns join other container userns [bind-mounted nsfd]" {
   129	requires root
   130
   131	# Create a detached container with the id-mapping we want.
   132	update_config '.process.args = ["sleep", "infinity"]'
   133	runc run -d --console-socket "$CONSOLE_SOCKET" target_userns
   134	[ "$status" -eq 0 ]
   135
   136	# Bind-mount the first containers userns nsfd to a different path, to
   137	# exercise the non-fast-path (where runc has to join the userns to get the
   138	# mappings).
   139	target_pid="$(__runc state target_userns | jq .pid)"
   140	userns_path=$(mktemp "$BATS_RUN_TMPDIR/userns.XXXXXX")
   141	mount --bind "/proc/$target_pid/ns/user" "$userns_path"
   142	echo "$userns_path" >>"$to_umount_list"
   143
   144	# Configure our container to attach to the first container's userns.
   145	update_config '.linux.namespaces |= map(if .type == "user" then (.path = "'"$userns_path"'") else . end)
   146		| del(.linux.uidMappings)
   147		| del(.linux.gidMappings)'
   148	runc run -d --console-socket "$CONSOLE_SOCKET" in_userns
   149	[ "$status" -eq 0 ]
   150
   151	runc exec in_userns cat /proc/self/uid_map
   152	[ "$status" -eq 0 ]
   153	if [ $EUID -eq 0 ]; then
   154		grep -E '^\s+0\s+100000\s+65534$' <<<"$output"
   155	else
   156		grep -E '^\s+0\s+'$EUID'\s+1$' <<<"$output"
   157	fi
   158
   159	runc exec in_userns cat /proc/self/gid_map
   160	[ "$status" -eq 0 ]
   161	if [ $EUID -eq 0 ]; then
   162		grep -E '^\s+0\s+200000\s+65534$' <<<"$output"
   163	else
   164		grep -E '^\s+0\s+'$EUID'\s+1$' <<<"$output"
   165	fi
   166}

View as plain text