From: Yu Watanabe Date: Mon, 17 Feb 2025 14:59:46 +0000 (+0900) Subject: nspawn: create /dev/net/tun only when it is accessible X-Git-Tag: v258-rc1~1312^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9fff6bf59e6cfbbc8bddee1e802a94a38d29063a;p=thirdparty%2Fsystemd.git nspawn: create /dev/net/tun only when it is accessible 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. --- diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 31757f4ee10..8ded13506d3 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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; } diff --git a/test/units/TEST-13-NSPAWN.nspawn.sh b/test/units/TEST-13-NSPAWN.nspawn.sh index 076e94c7b11..e814cede57e 100755 --- a/test/units/TEST-13-NSPAWN.nspawn.sh +++ b/test/units/TEST-13-NSPAWN.nspawn.sh @@ -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" }