2 # SPDX-License-Identifier: LGPL-2.1-or-later
3 # shellcheck disable=SC2016
5 # Notes on coverage: when collecting coverage we need the $BUILD_DIR present
6 # and writable in the container as well. To do this in the least intrusive way,
7 # two things are going on in the background (only when built with -Db_coverage=true):
8 # 1) the systemd-nspawn@.service is copied to /etc/systemd/system/ with
9 # --bind=$BUILD_DIR appended to the ExecStart= line
10 # 2) each create_dummy_container() call also creates an .nspawn file in /run/systemd/nspawn/
11 # with the last fragment from the path used as a name
13 # The first change is quite self-contained and applies only to containers run
14 # with machinectl. The second one might cause some unexpected side-effects, namely:
15 # - nspawn config (setting) files don't support dropins, so tests that test
16 # the config files might need some tweaking (as seen below with
17 # the $COVERAGE_BUILD_DIR shenanigans) since they overwrite the .nspawn file
18 # - also a note - if /etc/systemd/nspawn/cont-name.nspawn exists, it takes
19 # precedence and /run/systemd/nspawn/cont-name.nspawn won't be read even
21 # - also a note 2 - --bind= overrides any Bind= from a config file
22 # - in some cases we don't create a test container using create_dummy_container(),
23 # so in that case an explicit call to coverage_create_nspawn_dropin() is needed
25 # However, even after jumping through all these hooks, there still might (and is)
26 # some "incorrectly" missing coverage, especially in the window between spawning
27 # the inner child process and bind-mounting the coverage $BUILD_DIR
31 # shellcheck source=test/units/test-control.sh
32 .
"$(dirname "$0")"/test-control.sh
33 # shellcheck source=test/units/util.sh
34 .
"$(dirname "$0")"/util.sh
37 export SYSTEMD_LOG_LEVEL
=debug
38 export SYSTEMD_LOG_TARGET
=journal
43 mountpoint
-q /var
/lib
/machines
&& umount
--recursive /var
/lib
/machines
44 rm -f /run
/systemd
/nspawn
/*.nspawn
50 IS_CGROUPSV2_SUPPORTED
=no
52 if mount
-t cgroup2 cgroup2
/tmp
/cgroup2
; then
53 IS_CGROUPSV2_SUPPORTED
=yes
58 # check cgroup namespaces
60 if [[ -f /proc
/1/ns
/cgroup
]]; then
64 IS_USERNS_SUPPORTED
=no
65 # On some systems (e.g. CentOS 7) the default limit for user namespaces
66 # is set to 0, which causes the following unshare syscall to fail, even
67 # with enabled user namespaces support. By setting this value explicitly
68 # we can ensure the user namespaces support to be detected correctly.
69 sysctl
-w user.max_user_namespaces
=10000
70 if unshare
-U bash
-c :; then
71 IS_USERNS_SUPPORTED
=yes
74 # Mount tmpfs over /var/lib/machines to not pollute the image
75 mkdir
-p /var
/lib
/machines
76 mount
-t tmpfs tmpfs
/var
/lib
/machines
79 local template root image uuid tmpdir
82 template
="$(mktemp -d /tmp/nspawn-template.XXX)"
83 create_dummy_container
"$template"
84 # Create a simple image from the just created container template
85 image
="$(mktemp /var/lib/machines/testsuite-13.image-XXX.img)"
86 dd if=/dev
/zero of
="$image" bs
=1M count
=64
89 mount
-o loop
"$image" /mnt
90 cp -r "$template"/* /mnt
/
93 systemd-nspawn
--help --no-pager
94 systemd-nspawn
--version
97 root
="$(mktemp -u -d /var/lib/machines/testsuite-13.sanity.XXX)"
98 coverage_create_nspawn_dropin
"$root"
99 (! systemd-nspawn
--directory="$root" bash
-xec 'echo hello')
100 # Initialize $root from $template (the $root directory must not exist, hence
101 # the `mktemp -u` above)
102 systemd-nspawn
--directory="$root" --template="$template" bash
-xec 'echo hello'
103 systemd-nspawn
--directory="$root" bash
-xec 'echo hello; touch /initialized'
104 test -e "$root/initialized"
105 # Check if the $root doesn't get re-initialized once it's not empty
106 systemd-nspawn
--directory="$root" --template="$template" bash
-xec 'echo hello'
107 test -e "$root/initialized"
109 systemd-nspawn
--directory="$root" --ephemeral bash
-xec 'touch /ephemeral'
110 test ! -e "$root/ephemeral"
111 (! systemd-nspawn
--directory="$root" \
113 bash
-xec 'touch /nope')
114 test ! -e "$root/nope"
115 systemd-nspawn
--image="$image" bash
-xec 'echo hello'
118 touch "$root/usr/has-usr"
119 # volatile(=yes): rootfs is tmpfs, /usr/ from the OS tree is mounted read only
120 systemd-nspawn
--directory="$root"\
122 bash
-xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope'
123 test ! -e "$root/nope"
124 test ! -e "$root/usr/read-only"
125 systemd-nspawn
--directory="$root"\
127 bash
-xec 'test -e /usr/has-usr; touch /usr/read-only && exit 1; touch /nope'
128 test ! -e "$root/nope"
129 test ! -e "$root/usr/read-only"
130 # volatile=state: rootfs is read-only, /var/ is tmpfs
131 systemd-nspawn
--directory="$root" \
133 bash
-xec 'test -e /usr/has-usr; mountpoint /var; touch /read-only && exit 1; touch /var/nope'
134 test ! -e "$root/read-only"
135 test ! -e "$root/var/nope"
136 # volatile=state: tmpfs overlay is mounted over rootfs
137 systemd-nspawn
--directory="$root" \
139 bash
-xec 'test -e /usr/has-usr; touch /nope; touch /var/also-nope; touch /usr/nope-too'
140 test ! -e "$root/nope"
141 test ! -e "$root/var/also-nope"
142 test ! -e "$root/usr/nope-too"
144 # --machine=, --hostname=
145 systemd-nspawn
--directory="$root" \
146 --machine="foo-bar.baz" \
147 bash
-xec '[[ $(hostname) == foo-bar.baz ]]'
148 systemd-nspawn
--directory="$root" \
149 --hostname="hello.world.tld" \
150 bash
-xec '[[ $(hostname) == hello.world.tld ]]'
151 systemd-nspawn
--directory="$root" \
152 --machine="foo-bar.baz" \
153 --hostname="hello.world.tld" \
154 bash
-xec '[[ $(hostname) == hello.world.tld ]]'
157 rm -f "$root/etc/machine-id"
158 uuid
="deadbeef-dead-dead-beef-000000000000"
159 systemd-nspawn
--directory="$root" \
161 bash
-xec "[[ \$container_uuid == $uuid ]]"
164 systemd-nspawn
--directory="$root" bash
-xec '[[ $$ -eq 1 ]]'
165 systemd-nspawn
--directory="$root" --as-pid2 bash
-xec '[[ $$ -eq 2 ]]'
168 # "Fake" getent passwd's bare minimum, so we don't have to pull it in
169 # with all the DSO shenanigans
170 cat >"$root/bin/getent" <<\EOF
173 if [[ $# -eq 0 ]]; then
175 elif [[ $1 == passwd
]]; then
176 echo "testuser:x:1000:1000:testuser:/:/bin/sh"
177 elif [[ $1 == initgroups
]]; then
181 chmod +x
"$root/bin/getent"
182 systemd-nspawn
--directory="$root" bash
-xec '[[ $USER == root ]]'
183 systemd-nspawn
--directory="$root" --user=testuser bash
-xec '[[ $USER == testuser ]]'
185 # --settings= + .nspawn files
186 mkdir
-p /run
/systemd
/nspawn
/
187 uuid
="deadbeef-dead-dead-beef-000000000000"
188 echo -ne "[Exec]\nMachineID=deadbeef-dead-dead-beef-111111111111" >/run
/systemd
/nspawn
/foo-bar.nspawn
189 systemd-nspawn
--directory="$root" \
192 bash
-xec '[[ $container_uuid == deadbeef-dead-dead-beef-111111111111 ]]'
193 systemd-nspawn
--directory="$root" \
197 bash
-xec "[[ \$container_uuid == $uuid ]]"
198 systemd-nspawn
--directory="$root" \
201 --settings=override \
202 bash
-xec '[[ $container_uuid == deadbeef-dead-dead-beef-111111111111 ]]'
203 systemd-nspawn
--directory="$root" \
207 bash
-xec "[[ \$container_uuid == $uuid ]]"
210 mkdir
"$tmpdir"/{1,2,3}
211 touch "$tmpdir/1/one" "$tmpdir/2/two" "$tmpdir/3/three"
214 systemd-nspawn
--directory="$root" \
215 ${COVERAGE_BUILD_DIR:+--bind="$COVERAGE_BUILD_DIR"} \
216 --bind="$tmpdir:/foo" \
217 --bind="$tmpdir:/also-foo:noidmap,norbind" \
218 bash
-xec 'test -e /foo/foo; touch /foo/bar; test -e /also-foo/bar'
219 test -e "$tmpdir/bar"
221 systemd-nspawn
--directory="$root" \
222 --bind-ro="$tmpdir:/foo" \
223 --bind-ro="$tmpdir:/bar:noidmap,norbind" \
224 bash
-xec 'test -e /foo/foo; touch /foo/baz && exit 1; touch /bar && exit 1; true'
226 systemd-nspawn
--directory="$root" \
227 --inaccessible=/var \
228 bash
-xec 'touch /var/foo && exit 1; true'
230 systemd-nspawn
--directory="$root" \
231 --tmpfs=/var
:rw
,nosuid
,noexec \
232 bash
-xec 'touch /var/nope'
233 test ! -e "$root/var/nope"
235 systemd-nspawn
--directory="$root" \
236 --overlay="$tmpdir/1:$tmpdir/2:$tmpdir/3:/var" \
237 bash
-xec 'test -e /var/one; test -e /var/two; test -e /var/three; touch /var/foo'
238 test -e "$tmpdir/3/foo"
240 systemd-nspawn
--directory="$root" \
241 --overlay-ro="$tmpdir/1:$tmpdir/2:$tmpdir/3:/var" \
242 bash
-xec 'test -e /var/one; test -e /var/two; test -e /var/three; touch /var/nope && exit 1; true'
243 test ! -e "$tmpdir/3/nope"
246 # --port (sanity only)
247 systemd-nspawn
--network-veth --directory="$root" --port=80 --port=90 true
248 systemd-nspawn
--network-veth --directory="$root" --port=80:8080 true
249 systemd-nspawn
--network-veth --directory="$root" --port=tcp
:80 true
250 systemd-nspawn
--network-veth --directory="$root" --port=tcp
:80:8080 true
251 systemd-nspawn
--network-veth --directory="$root" --port=udp
:80 true
252 systemd-nspawn
--network-veth --directory="$root" --port=udp
:80:8080 --port=tcp
:80:8080 true
253 (! systemd-nspawn
--network-veth --directory="$root" --port= true
)
254 (! systemd-nspawn
--network-veth --directory="$root" --port=-1 true
)
255 (! systemd-nspawn
--network-veth --directory="$root" --port=: true
)
256 (! systemd-nspawn
--network-veth --directory="$root" --port=icmp
:80:8080 true
)
257 (! systemd-nspawn
--network-veth --directory="$root" --port=tcp
::8080 true
)
258 (! systemd-nspawn
--network-veth --directory="$root" --port=8080: true
)
259 # Exercise adding/removing ports from an interface
260 systemd-nspawn
--directory="$root" \
266 bash
-xec 'ip addr add dev host0 10.0.0.10/24; ip a; ip addr del dev host0 10.0.0.10/24'
268 # --load-credential=, --set-credential=
269 echo "foo bar" >/tmp
/cred.path
270 systemd-nspawn
--directory="$root" \
271 --load-credential=cred.path
:/tmp
/cred.path \
272 --set-credential="cred.set:hello world" \
273 bash
-xec '[[ "$(</run/host/credentials/cred.path)" == "foo bar" ]]; [[ "$(</run/host/credentials/cred.set)" == "hello world" ]]'
277 systemd-nspawn
--directory="$root" --suppress-sync=yes bash
-xec 'echo hello'
278 systemd-nspawn
--capability=help
279 systemd-nspawn
--resolv-conf=help
280 systemd-nspawn
--timezone=help
282 # Handling of invalid arguments
293 network-
{interface
,macvlan
,ipvlan
,veth-extra
,bridge
,zone
}
302 private-users-ownership
315 for opt
in "${opts[@]}"; do
316 (! systemd-nspawn
"--$opt")
317 [[ "$opt" == network-zone
]] && continue
318 (! systemd-nspawn
"--$opt=''")
319 (! systemd-nspawn
"--$opt=%\$Å¡")
321 (! systemd-nspawn
--volatile="")
322 (! systemd-nspawn
--volatile=-1)
323 (! systemd-nspawn
--rlimit==)
326 nspawn_settings_cleanup
() {
327 for dev
in sd-host-only sd-shared
{1,2,3} sd-macvlan
{1,2} sd-ipvlan
{1,2}; do
328 ip link del
"$dev" ||
:
334 testcase_nspawn_settings
() {
335 local root container dev private_users wlan_names
337 mkdir
-p /run
/systemd
/nspawn
338 root
="$(mktemp -d /var/lib/machines/testsuite-13.nspawn-settings.XXX)"
339 container
="$(basename "$root")"
340 create_dummy_container
"$root"
341 rm -f "/etc/systemd/nspawn/$container.nspawn"
342 mkdir
-p "$root/tmp" "$root"/opt
/{tmp
,inaccessible
,also-inaccessible
}
344 # add virtual wlan interfaces
345 if modprobe mac80211_hwsim radios
=2; then
346 wlan_names
="wlan0 wlan1:wl-renamed1"
349 for dev
in sd-host-only sd-shared
{1,2,3} sd-macvlan
{1,2} sd-macvlanloong sd-ipvlan
{1,2} sd-ipvlanlooong
; do
350 ip link add
"$dev" type dummy
353 ip link property add dev sd-shared3 altname sd-altname3 altname sd-altname-tooooooooooooo-long
355 trap nspawn_settings_cleanup RETURN
357 # Let's start with one huge config to test as much as we can at once
358 cat >"/run/systemd/nspawn/$container.nspawn" <<EOF
363 Parameters=bash /entrypoint.sh "foo bar" 'bar baz'
365 Environment=BAZ="hello world"
367 WorkingDirectory=/tmp
368 Capability=CAP_BLOCK_SUSPEND CAP_BPF CAP_CHOWN
369 DropCapability=CAP_AUDIT_CONTROL CAP_AUDIT_WRITE
370 AmbientCapability=CAP_BPF CAP_CHOWN
372 MachineID=f28f129b51874b1280a89421ec4b4ad4
375 SystemCallFilter=@basic-io @chown
376 SystemCallFilter=~ @clock
377 LimitNOFILE=1024:2048
380 CPUAffinity=0,0-5,1-5
381 Hostname=nspawn-settings
390 TemporaryFileSystem=/tmp
391 TemporaryFileSystem=/opt/tmp
392 Inaccessible=/opt/inaccessible
393 Inaccessible=/opt/also-inaccessible
394 PrivateUsersOwnership=auto
396 ${COVERAGE_BUILD_DIR:+"Bind=$COVERAGE_BUILD_DIR"}
401 VirtualEthernetExtra=my-fancy-veth1
402 VirtualEthernetExtra=fancy-veth2:my-fancy-veth2
403 Interface=sd-shared1 sd-shared2:sd-renamed2 sd-shared3:sd-altname3 ${wlan_names:-}
404 MACVLAN=sd-macvlan1 sd-macvlan2:my-macvlan2 sd-macvlanloong
405 IPVLAN=sd-ipvlan1 sd-ipvlan2:my-ipvlan2 sd-ipvlanlooong
412 cat >"$root/entrypoint.sh" <<\EOF
418 [[ "$1" == "foo bar" ]]
419 [[ "$2" == "bar baz" ]]
421 [[ "$USER" == root
]]
423 [[ "$BAZ" == "hello world" ]]
425 [[ "$container_uuid" == f28f129b-5187-4b12-80a8-9421ec4b4ad4
]]
426 [[ "$(ulimit -S -n)" -eq 1024 ]]
427 [[ "$(ulimit -H -n)" -eq 2048 ]]
428 [[ "$(ulimit -S -r)" -eq 8 ]]
429 [[ "$(ulimit -H -r)" -eq 16 ]]
430 [[ "$(</proc/self/oom_score_adj)" -eq 32 ]]
431 [[ "$(hostname)" == nspawn-settings
]]
432 [[ -e /etc
/resolv.conf
]]
433 [[ ! -e /etc
/localtime
]]
439 touch /opt
/inaccessible
/foo
&& exit 1
440 touch /opt
/also-inaccessible
/foo
&& exit 1
444 ip link |
grep host-only
&& exit 1
445 ip link |
grep host0@
446 ip link |
grep my-fancy-veth1@
447 ip link |
grep my-fancy-veth2@
448 ip link |
grep sd-shared1
449 ip link |
grep sd-renamed2
450 ip link |
grep sd-shared3
451 ip link |
grep sd-altname3
452 ip link |
grep sd-altname-tooooooooooooo-long
453 ip link |
grep mv-sd-macvlan1@
454 ip link |
grep my-macvlan2@
455 ip link |
grep iv-sd-ipvlan1@
456 ip link |
grep my-ipvlan2@
458 if [[ -n "${wlan_names:-}" ]]; then
459 cat >>"$root/entrypoint.sh" <<\EOF
461 ip link |
grep wl-renamed1
465 timeout
30 systemd-nspawn
--directory="$root"
467 # And now for stuff that needs to run separately
469 # Note on the condition below: since our container tree is owned by root,
470 # both "yes" and "identity" private users settings will behave the same
471 # as PrivateUsers=0:65535, which makes BindUser= fail as the UID already
472 # exists there, so skip setting it in such case
473 for private_users
in "131072:65536" yes identity pick
; do
474 cat >"/run/systemd/nspawn/$container.nspawn" <<EOF
476 Hostname=private-users
477 PrivateUsers=$private_users
480 PrivateUsersOwnership=auto
482 $([[ "$private_users" =~ (yes|identity) ]] || echo "BindUser=testuser")
483 ${COVERAGE_BUILD_DIR:+"Bind=$COVERAGE_BUILD_DIR"}
485 cat "/run/systemd/nspawn/$container.nspawn"
486 chown
-R root
:root
"$root"
487 systemd-nspawn
--directory="$root" bash
-xec '[[ "$(hostname)" == private-users ]]'
490 rm -fr "$root" "/run/systemd/nspawn/$container.nspawn"
493 bind_user_cleanup
() {
494 userdel
--force --remove nspawn-bind-user-1
495 userdel
--force --remove nspawn-bind-user-2
498 testcase_bind_user
() {
501 root
="$(mktemp -d /var/lib/machines/testsuite-13.bind-user.XXX)"
502 create_dummy_container
"$root"
503 useradd
--create-home --user-group nspawn-bind-user-1
504 useradd
--create-home --user-group nspawn-bind-user-2
505 trap bind_user_cleanup RETURN
506 touch /home
/nspawn-bind-user-
1/foo
507 touch /home
/nspawn-bind-user-
2/bar
508 # Add a couple of POSIX ACLs to test the patch-uid stuff
510 setfacl
-R -m 'd:u:nspawn-bind-user-1:rwX' -m 'u:nspawn-bind-user-1:rwX' "$root/opt"
511 setfacl
-R -m 'd:g:nspawn-bind-user-1:rwX' -m 'g:nspawn-bind-user-1:rwX' "$root/opt"
513 systemd-nspawn
--directory="$root" \
514 --private-users=pick \
515 --bind-user=nspawn-bind-user-1 \
516 bash
-xec 'test -e /run/host/home/nspawn-bind-user-1/foo'
518 systemd-nspawn
--directory="$root" \
519 --private-users=pick \
520 --private-users-ownership=chown \
521 --bind-user=nspawn-bind-user-1 \
522 --bind-user=nspawn-bind-user-2 \
523 bash
-xec 'test -e /run/host/home/nspawn-bind-user-1/foo; test -e /run/host/home/nspawn-bind-user-2/bar'
524 chown
-R root
:root
"$root"
526 # User/group name collision
527 echo "nspawn-bind-user-2:x:1000:1000:nspawn-bind-user-2:/home/nspawn-bind-user-2:/bin/bash" >"$root/etc/passwd"
528 (! systemd-nspawn
--directory="$root" \
529 --private-users=pick \
530 --bind-user=nspawn-bind-user-1 \
531 --bind-user=nspawn-bind-user-2 \
533 rm -f "$root/etc/passwd"
535 echo "nspawn-bind-user-2:x:1000:" >"$root/etc/group"
536 (! systemd-nspawn
--directory="$root" \
537 --private-users=pick \
538 --bind-user=nspawn-bind-user-1 \
539 --bind-user=nspawn-bind-user-2 \
541 rm -f "$root/etc/group"
546 testcase_bind_tmp_path
() {
547 # https://github.com/systemd/systemd/issues/4789
550 root
="$(mktemp -d /var/lib/machines/testsuite-13.bind-tmp-path.XXX)"
551 create_dummy_container
"$root"
553 systemd-nspawn
--register=no \
554 --directory="$root" \
556 bash
-c 'test -e /tmp/bind'
558 rm -fr "$root" /tmp
/bind
562 # https://github.com/systemd/systemd/issues/13170
565 root
="$(mktemp -d /var/lib/machines/testsuite-13.norbind-path.XXX)"
566 mkdir
-p /tmp
/binddir
/subdir
567 echo -n "outer" >/tmp
/binddir
/subdir
/file
568 mount
-t tmpfs tmpfs
/tmp
/binddir
/subdir
569 echo -n "inner" >/tmp
/binddir
/subdir
/file
570 create_dummy_container
"$root"
572 systemd-nspawn
--register=no \
573 --directory="$root" \
574 --bind=/tmp
/binddir
:/mnt
:norbind \
575 bash
-c 'CONTENT=$(cat /mnt/subdir/file); if [[ $CONTENT != "outer" ]]; then echo "*** unexpected content: $CONTENT"; exit 1; fi'
577 umount
/tmp
/binddir
/subdir
578 rm -fr "$root" /tmp
/binddir
/
581 rootidmap_cleanup
() {
584 mountpoint
-q "$dir/bind" && umount
"$dir/bind"
588 testcase_rootidmap
() {
589 local root cmd permissions
592 root
="$(mktemp -d /var/lib/machines/testsuite-13.rootidmap-path.XXX)"
593 # Create ext4 image, as ext4 supports idmapped-mounts.
594 mkdir
-p /tmp
/rootidmap
/bind
595 dd if=/dev
/zero of
=/tmp
/rootidmap
/ext4.img bs
=4k count
=2048
596 mkfs.ext4
/tmp
/rootidmap
/ext4.img
597 mount
/tmp
/rootidmap
/ext4.img
/tmp
/rootidmap
/bind
598 trap "rootidmap_cleanup /tmp/rootidmap/" RETURN
600 touch /tmp
/rootidmap
/bind
/file
601 chown
-R "$owner:$owner" /tmp
/rootidmap
/bind
603 create_dummy_container
"$root"
604 cmd
='PERMISSIONS=$(stat -c "%u:%g" /mnt/file); if [[ $PERMISSIONS != "0:0" ]]; then echo "*** wrong permissions: $PERMISSIONS"; return 1; fi; touch /mnt/other_file'
605 if ! SYSTEMD_LOG_TARGET
=console \
606 systemd-nspawn
--register=no \
607 --directory="$root" \
608 --bind=/tmp
/rootidmap
/bind:/mnt
:rootidmap \
609 bash
-c "$cmd" |
& tee nspawn.out
; then
610 if grep -q "Failed to map ids for bind mount.*: Function not implemented" nspawn.out
; then
611 echo "idmapped mounts are not supported, skipping the test..."
618 permissions
=$
(stat
-c "%u:%g" /tmp
/rootidmap
/bind
/other_file
)
619 if [[ $permissions != "$owner:$owner" ]]; then
620 echo "*** wrong permissions: $permissions"
621 [[ "$IS_USERNS_SUPPORTED" == "yes" ]] && return 1
625 owneridmap_cleanup
() {
628 mountpoint
-q "$dir/bind" && umount
"$dir/bind"
632 testcase_owneridmap
() {
633 local root cmd permissions
636 root
="$(mktemp -d /var/lib/machines/testsuite-13.owneridmap-path.XXX)"
637 # Create ext4 image, as ext4 supports idmapped-mounts.
638 mkdir
-p /tmp
/owneridmap
/bind
639 dd if=/dev
/zero of
=/tmp
/owneridmap
/ext4.img bs
=4k count
=2048
640 mkfs.ext4
/tmp
/owneridmap
/ext4.img
641 mount
/tmp
/owneridmap
/ext4.img
/tmp
/owneridmap
/bind
642 trap "owneridmap_cleanup /tmp/owneridmap/" RETURN
644 touch /tmp
/owneridmap
/bind
/file
645 chown
-R "$owner:$owner" /tmp
/owneridmap
/bind
647 # Allow users to read and execute / in order to execute binaries
650 create_dummy_container
"$root"
653 # "Fake" getent passwd's bare minimum, so we don't have to pull it in
654 # with all the DSO shenanigans
655 cat >"$root/bin/getent" <<\EOF
658 if [[ $# -eq 0 ]]; then
660 elif [[ $1 == passwd
]]; then
661 echo "testuser:x:1010:1010:testuser:/:/bin/sh"
662 elif [[ $1 == initgroups
]]; then
666 chmod +x
"$root/bin/getent"
668 mkdir
-p "$root/home/testuser"
669 chown
1010:1010 "$root/home/testuser"
671 cmd
='PERMISSIONS=$(stat -c "%u:%g" /home/testuser/file); if [[ $PERMISSIONS != "1010:1010" ]]; then echo "*** wrong permissions: $PERMISSIONS"; return 1; fi; touch /home/testuser/other_file'
672 if ! SYSTEMD_LOG_TARGET
=console \
673 systemd-nspawn
--register=no \
674 --directory="$root" \
677 --bind=/tmp
/owneridmap
/bind:/home
/testuser
:owneridmap \
678 /usr
/bin
/bash
-c "$cmd" |
& tee nspawn.out
; then
679 if grep -q "Failed to map ids for bind mount.*: Function not implemented" nspawn.out
; then
680 echo "idmapped mounts are not supported, skipping the test..."
687 permissions
=$
(stat
-c "%u:%g" /tmp
/owneridmap
/bind
/other_file
)
688 if [[ $permissions != "$owner:$owner" ]]; then
689 echo "*** wrong permissions: $permissions"
690 [[ "$IS_USERNS_SUPPORTED" == "yes" ]] && return 1
694 testcase_notification_socket
() {
695 # https://github.com/systemd/systemd/issues/4944
697 local cmd
='echo a | nc -U -u -w 1 /run/host/notify'
699 root
="$(mktemp -d /var/lib/machines/testsuite-13.check_notification_socket.XXX)"
700 create_dummy_container
"$root"
702 systemd-nspawn
--register=no
--directory="$root" bash
-x -c "$cmd"
703 systemd-nspawn
--register=no
--directory="$root" -U bash
-x -c "$cmd"
708 testcase_os_release
() {
709 local root entrypoint os_release_source
711 root
="$(mktemp -d /var/lib/machines/testsuite-13.os-release.XXX)"
712 create_dummy_container
"$root"
713 entrypoint
="$root/entrypoint.sh"
714 cat >"$entrypoint" <<\EOF
718 [[ -n "${ID:-}" && "$ID" != "$container_host_id" ]] && exit 1
719 [[ -n "${VERSION_ID:-}" && "$VERSION_ID" != "$container_host_version_id" ]] && exit 1
720 [[ -n "${BUILD_ID:-}" && "$BUILD_ID" != "$container_host_build_id" ]] && exit 1
721 [[ -n "${VARIANT_ID:-}" && "$VARIANT_ID" != "$container_host_variant_id" ]] && exit 1
724 (cd /run
/host && md5sum os-release
) |
md5sum -c
726 chmod +x
"$entrypoint"
728 os_release_source
="/etc/os-release"
729 if [[ ! -r "$os_release_source" ]]; then
730 os_release_source
="/usr/lib/os-release"
731 elif [[ -L "$os_release_source" ]]; then
732 # Ensure that /etc always wins if available
733 cp --remove-destination -fv /usr
/lib
/os-release
/etc
/os-release
734 echo MARKER
=1 >>/etc
/os-release
737 systemd-nspawn
--register=no \
738 --directory="$root" \
739 --bind="$os_release_source:/tmp/os-release" \
740 "${entrypoint##"$root"}"
742 if grep -q MARKER
/etc
/os-release
; then
743 ln -svrf /usr
/lib
/os-release
/etc
/os-release
749 testcase_machinectl_bind
() {
750 local service_path service_name root container_name ec
751 local cmd
='for i in $(seq 1 20); do if test -f /tmp/marker; then exit 0; fi; sleep .5; done; exit 1;'
753 root
="$(mktemp -d /var/lib/machines/testsuite-13.machinectl-bind.XXX)"
754 create_dummy_container
"$root"
755 container_name
="$(basename "$root")"
757 service_path
="$(mktemp /run/systemd/system/nspawn-machinectl-bind-XXX.service)"
758 service_name
="${service_path##*/}"
759 cat >"$service_path" <<EOF
762 ExecStart=systemd-nspawn --directory="$root" --notify-ready=no /usr/bin/bash -xec "$cmd"
765 systemctl daemon-reload
766 systemctl start
"$service_name"
768 machinectl
bind --mkdir "$container_name" /tmp
/marker
770 timeout
10 bash
-c "while [[ '\$(systemctl show -P SubState $service_name)' == running ]]; do sleep .2; done"
771 ec
="$(systemctl show -P ExecMainStatus "$service_name")"
772 systemctl stop
"$service_name"
774 rm -fr "$root" "$service_path"
780 # Basic test coverage to avoid issues like https://github.com/systemd/systemd/issues/19976
781 if ! command -v selinuxenabled
>/dev
/null ||
! selinuxenabled
; then
782 echo >&2 "SELinux is not enabled, skipping SELinux-related tests"
788 root
="$(mktemp -d /var/lib/machines/testsuite-13.selinux.XXX)"
789 create_dummy_container
"$root"
790 chcon
-R -t container_t
"$root"
792 systemd-nspawn
--register=no \
794 --directory="$root" \
795 --selinux-apifs-context=system_u
:object_r
:container_file_t
:s0
:c0
,c1 \
796 --selinux-context=system_u
:system_r
:container_t
:s0
:c0
,c1
801 testcase_ephemeral_config
() {
802 # https://github.com/systemd/systemd/issues/13297
803 local root container_name
805 root
="$(mktemp -d /var/lib/machines/testsuite-13.ephemeral-config.XXX)"
806 create_dummy_container
"$root"
807 container_name
="$(basename "$root")"
809 mkdir
-p /run
/systemd
/nspawn
/
810 rm -f "/etc/systemd/nspawn/$container_name.nspawn"
811 cat >"/run/systemd/nspawn/$container_name.nspawn" <<EOF
813 ${COVERAGE_BUILD_DIR:+"Bind=$COVERAGE_BUILD_DIR"}
814 BindReadOnly=/tmp/ephemeral-config
816 touch /tmp
/ephemeral-config
818 systemd-nspawn
--register=no \
819 --directory="$root" \
821 bash
-x -c "test -f /tmp/ephemeral-config"
823 systemd-nspawn
--register=no \
824 --directory="$root" \
827 bash
-x -c "! test -f /tmp/ephemeral-config"
829 rm -fr "$root" "/run/systemd/nspawn/$container_name.nspawn"
833 local cgroupsv2
="${1:?}"
834 local use_cgns
="${2:?}"
835 local api_vfs_writable
="${3:?}"
838 if [[ "$cgroupsv2" == "yes" && "$IS_CGROUPSV2_SUPPORTED" == "no" ]]; then
839 echo >&2 "Unified cgroup hierarchy is not supported, skipping..."
843 if [[ "$use_cgns" == "yes" && "$IS_CGNS_SUPPORTED" == "no" ]]; then
844 echo >&2 "CGroup namespaces are not supported, skipping..."
848 root
="$(mktemp -d "/var
/lib
/machines
/testsuite-13.unified-
$1-cgns-$2-api-vfs-writable-$3.XXX
")"
849 create_dummy_container
"$root"
851 SYSTEMD_NSPAWN_UNIFIED_HIERARCHY
="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS
="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE
="$api_vfs_writable" \
852 systemd-nspawn
--register=no \
853 --directory="$root" \
856 SYSTEMD_NSPAWN_UNIFIED_HIERARCHY
="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS
="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE
="$api_vfs_writable" \
857 systemd-nspawn
--register=no \
858 --directory="$root" \
862 if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY
="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS
="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE
="$api_vfs_writable" \
863 systemd-nspawn
--register=no \
864 --directory="$root" \
865 --private-users=pick \
867 [[ "$IS_USERNS_SUPPORTED" == "yes" && "$api_vfs_writable" == "network" ]] && return 1
869 [[ "$IS_USERNS_SUPPORTED" == "no" && "$api_vfs_writable" = "network" ]] && return 1
872 if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY
="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS
="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE
="$api_vfs_writable" \
873 systemd-nspawn
--register=no \
874 --directory="$root" \
876 --private-users=pick \
878 [[ "$IS_USERNS_SUPPORTED" == "yes" && "$api_vfs_writable" == "yes" ]] && return 1
880 [[ "$IS_USERNS_SUPPORTED" == "no" && "$api_vfs_writable" = "yes" ]] && return 1
883 local netns_opt
="--network-namespace-path=/proc/self/ns/net"
886 "--network-bridge=lo"
887 "--network-interface=lo"
888 "--network-ipvlan=lo"
889 "--network-macvlan=lo"
891 "--network-veth-extra=lo"
892 "--network-zone=zone"
895 # --network-namespace-path and network-related options cannot be used together
896 for net_opt
in "${net_opts[@]}"; do
897 echo "$netns_opt in combination with $net_opt should fail"
898 if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY
="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS
="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE
="$api_vfs_writable" \
899 systemd-nspawn
--register=no \
900 --directory="$root" \
904 echo >&2 "unexpected pass"
909 # allow combination of --network-namespace-path and --private-network
910 SYSTEMD_NSPAWN_UNIFIED_HIERARCHY
="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS
="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE
="$api_vfs_writable" \
911 systemd-nspawn
--register=no \
912 --directory="$root" \
917 # test --network-namespace-path works with a network namespace created by "ip netns"
918 ip netns add nspawn_test
919 netns_opt
="--network-namespace-path=/run/netns/nspawn_test"
920 SYSTEMD_NSPAWN_UNIFIED_HIERARCHY
="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS
="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE
="$api_vfs_writable" \
921 systemd-nspawn
--register=no \
922 --directory="$root" \
923 --network-namespace-path=/run
/netns
/nspawn_test \
924 ip a |
grep -v -E '^1: lo.*UP'
925 ip netns del nspawn_test
932 testcase_check_os_release
() {
933 # https://github.com/systemd/systemd/issues/29185
934 local base common_opts root
936 base
="$(mktemp -d /var/lib/machines/testsuite-13.check_os_release_base.XXX)"
937 root
="$(mktemp -d /var/lib/machines/testsuite-13.check_os_release.XXX)"
938 create_dummy_container
"$base"
939 cp -d "$base"/{bin
,sbin
,lib
,lib64
} "$root/"
944 --bind-ro="$base/usr:/usr"
947 # Empty /etc/ & /usr/
948 (! systemd-nspawn
"${common_opts[@]}")
949 (! SYSTEMD_NSPAWN_CHECK_OS_RELEASE
=1 systemd-nspawn
"${common_opts[@]}")
950 (! SYSTEMD_NSPAWN_CHECK_OS_RELEASE
=foo systemd-nspawn
"${common_opts[@]}")
951 SYSTEMD_NSPAWN_CHECK_OS_RELEASE
=0 systemd-nspawn
"${common_opts[@]}"
953 # Empty /usr/ + a broken /etc/os-release -> /usr/os-release symlink
954 ln -svrf "$root/etc/os-release" "$root/usr/os-release"
955 (! systemd-nspawn
"${common_opts[@]}")
956 (! SYSTEMD_NSPAWN_CHECK_OS_RELEASE
=1 systemd-nspawn
"${common_opts[@]}")
957 SYSTEMD_NSPAWN_CHECK_OS_RELEASE
=0 systemd-nspawn
"${common_opts[@]}"
959 rm -fr "$root" "$base"
964 for api_vfs_writable
in yes no network
; do
965 matrix_run_one no no
$api_vfs_writable
966 matrix_run_one
yes no
$api_vfs_writable
967 matrix_run_one no
yes $api_vfs_writable
968 matrix_run_one
yes yes $api_vfs_writable