]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn: create /dev/net/tun only when it is accessible
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 17 Feb 2025 14:59:46 +0000 (23:59 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 18 Feb 2025 14:24:20 +0000 (23:24 +0900)
Follow-up for 985ea98e7f90c92fcc0b8441fafb190353d2feb8.

When DevicePolicy= is enabled, but DeviceAllow= for /dev/net/tun is not
specified, bind-mounting the device node from the host system is
meaningless, as it cannot be used in the container anyway.

Let's check the device node is accessible before creating or
bind-mounting.

src/nspawn/nspawn.c
test/units/TEST-13-NSPAWN.nspawn.sh

index 31757f4ee102af44c38b3cd122fb3457bac4de13..8ded13506d3dd54813c5d782b5591b9158d4ff3a 100644 (file)
@@ -2308,12 +2308,13 @@ static int copy_devnodes(const char *dest) {
                         return r;
         }
 
-        /* We unconditionally try to create /dev/net/tun, but let's ignore failure if --private-network is
-         * unspecified. The failure can be triggered when e.g. DevicePolicy= is set, but DeviceAllow= does
-         * not contains the device node, and --private-users=pick is specified. */
-        r = copy_devnode_one(dest, "net/tun", /* ignore_mknod_failure = */ !arg_private_network);
-        if (r < 0)
-                return r;
+        /* Similarly, create /dev/net/tun only when it is accessible. */
+        _cleanup_close_ int tun_fd = open("/dev/net/tun", O_CLOEXEC|O_RDWR);
+        if (tun_fd >= 0) {
+                r = copy_devnode_one(dest, "net/tun", /* ignore_mknod_failure = */ false);
+                if (r < 0)
+                        return r;
+        }
 
         return 0;
 }
index 076e94c7b1157bf38664f4346a61dc62aa882c22..e814cede57e25ff389f2ba5ba7abbd823a9f8b4e 100755 (executable)
@@ -1231,31 +1231,16 @@ testcase_unpriv_fuse() {
 }
 
 test_tun() {
-    local expect=${1?}
-    local exists=${2?}
-    local command command_exists command_not_exists
-    shift 2
-
-    command_exists='[[ -c /dev/net/tun ]]; [[ "$(stat /dev/net/tun --format=%u)" == 0 ]]; [[ "$(stat /dev/net/tun --format=%g)" == 0 ]]'
-    command_not_exists='[[ ! -e /dev/net/tun ]]'
-
-    if [[ "$exists" == 0 ]]; then
-        command="$command_not_exists"
-    else
-        command="$command_exists"
-    fi
-
-    systemd-nspawn "$@" bash -xec "$command_exists"
+    systemd-nspawn "$@" bash -xec '[[ -c /dev/net/tun ]]; [[ "$(stat /dev/net/tun --format=%u)" == 0 ]]; [[ "$(stat /dev/net/tun --format=%g)" == 0 ]]'
 
     # check if the owner of the host device is unchanged, see issue #34243.
     [[ "$(stat /dev/net/tun --format=%u)" == 0 ]]
     [[ "$(stat /dev/net/tun --format=%g)" == 0 ]]
 
     # Without DeviceAllow= for /dev/net/tun, see issue #35116.
-    assert_rc \
-        "$expect" \
-        systemd-run --wait -p Environment=SYSTEMD_LOG_LEVEL=debug -p DevicePolicy=closed -p DeviceAllow="char-pts rw" \
-        systemd-nspawn "$@" bash -xec "$command"
+    systemd-run \
+        --wait -p Environment=SYSTEMD_LOG_LEVEL=debug -p DevicePolicy=closed -p DeviceAllow="char-pts rw" \
+        systemd-nspawn "$@" bash -xec '[[ ! -e /dev/net/tun ]]'
 
     [[ "$(stat /dev/net/tun --format=%u)" == 0 ]]
     [[ "$(stat /dev/net/tun --format=%g)" == 0 ]]
@@ -1272,12 +1257,12 @@ testcase_dev_net_tun() {
     root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.tun.XXX)"
     create_dummy_container "$root"
 
-    test_tun 0 1 --ephemeral --directory="$root" --private-users=no
-    test_tun 0 1 --ephemeral --directory="$root" --private-users=yes
-    test_tun 0 0 --ephemeral --directory="$root" --private-users=pick
-    test_tun 0 1 --ephemeral --directory="$root" --private-users=no   --private-network
-    test_tun 0 1 --ephemeral --directory="$root" --private-users=yes  --private-network
-    test_tun 1 0 --ephemeral --directory="$root" --private-users=pick --private-network
+    test_tun --ephemeral --directory="$root" --private-users=no
+    test_tun --ephemeral --directory="$root" --private-users=yes
+    test_tun --ephemeral --directory="$root" --private-users=pick
+    test_tun --ephemeral --directory="$root" --private-users=no   --private-network
+    test_tun --ephemeral --directory="$root" --private-users=yes  --private-network
+    test_tun --ephemeral --directory="$root" --private-users=pick --private-network
 
     rm -fr "$root"
 }