diff options
-rw-r--r-- | src/nspawn/nspawn.c | 56 |
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; |