if (notify_fd < 0)
return notify_fd;
+ /* Join the external network namespace first, while we are still in the parent's
+ * user namespace and have CAP_SYS_ADMIN there. Once we clone with CLONE_NEWUSER,
+ * the child will be in a new user namespace, lacking the capabilities in the
+ * parent user namespace required to join its network namespace. */
+ if (arg_network_namespace_path && setns(netns_fd, CLONE_NEWNET) < 0)
+ return log_error_errno(errno, "Failed to join network namespace: %m");
+
pid_t pid = raw_clone(SIGCHLD|CLONE_NEWNS|
arg_clone_ns_flags |
(IN_SET(arg_userns_mode, USER_NAMESPACE_FIXED, USER_NAMESPACE_PICK) ? CLONE_NEWUSER : 0) |
/* The inner child has all namespaces that are requested, so that we all are owned by the
* user if user namespaces are turned on. */
- if (arg_network_namespace_path && setns(netns_fd, CLONE_NEWNET) < 0)
- return log_error_errno(errno, "Failed to join network namespace: %m");
-
if (arg_userns_mode == USER_NAMESPACE_MANAGED) {
/* In managed usernamespace operation, sysfs + procfs are special, we'll have to
* mount them inside the inner namespaces, but before we switch root. Hence do so
ip a | grep -v -E '^1: lo.*UP'
ip netns del nspawn_test
+ # test --network-namespace-path works when combined with --private-users=pick
+ ip netns add nspawn_test
+ ip netns exec nspawn_test ip link add foo type dummy
+
+ if [[ "$IS_USERNS_SUPPORTED" == "yes" && "$api_vfs_writable" == "no" ]]; then
+ SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
+ systemd-nspawn --register=no \
+ --directory="$root" \
+ --private-users=pick \
+ --network-namespace-path=/run/netns/nspawn_test \
+ ip link show dev foo
+ fi
+
+ ip netns del nspawn_test
+
rm -fr "$root"
return 0