summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nspawn/nspawn.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index afef5f727e..8aa7b9d805 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -4820,6 +4820,58 @@ static int initialize_rlimits(void) {
return 0;
}
+static int cant_be_in_netns(void) {
+ union sockaddr_union sa = {
+ .un = {
+ .sun_family = AF_UNIX,
+ .sun_path = "/run/udev/control",
+ },
+ };
+ char udev_path[STRLEN("/proc//ns/net") + DECIMAL_STR_MAX(pid_t)];
+ _cleanup_free_ char *udev_ns = NULL, *our_ns = NULL;
+ _cleanup_close_ int fd = -1;
+ struct ucred ucred;
+ int r;
+
+ /* Check if we are in the same netns as udev. If we aren't, then device monitoring (and thus waiting
+ * for loopback block devices) won't work, and we will hang. Detect this case and exit early with a
+ * nice message. */
+
+ if (!arg_image) /* only matters if --image= us used, i.e. we actually need to use loopback devices */
+ return 0;
+
+ fd = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to allocate udev control socket: %m");
+
+ if (connect(fd, &sa.un, SOCKADDR_UN_LEN(sa.un)) < 0) {
+
+ if (errno == ENOENT || ERRNO_IS_DISCONNECT(errno))
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "Sorry, but --image= requires access to the host's /run/ hierarchy, since we need access to udev.");
+
+ return log_error_errno(errno, "Failed to connect socket to udev control socket: %m");
+ }
+
+ r = getpeercred(fd, &ucred);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine peer of udev control socket: %m");
+
+ xsprintf(udev_path, "/proc/" PID_FMT "/ns/net", ucred.pid);
+ r = readlink_malloc(udev_path, &udev_ns);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read network namespace of udev: %m");
+
+ r = readlink_malloc("/proc/self/ns/net", &our_ns);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read our own network namespace: %m");
+
+ if (!streq(our_ns, udev_ns))
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "Sorry, but --image= is only supported in the main network namespace, since we need access to udev/AF_NETLINK.");
+ return 0;
+}
+
static int run(int argc, char *argv[]) {
bool secondary = false, remove_directory = false, remove_image = false,
veth_created = false, remove_tmprootdir = false;
@@ -4846,6 +4898,10 @@ static int run(int argc, char *argv[]) {
if (r < 0)
goto finish;
+ r = cant_be_in_netns();
+ if (r < 0)
+ goto finish;
+
r = initialize_rlimits();
if (r < 0)
goto finish;