summaryrefslogtreecommitdiff
path: root/src/nspawn
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-04-22 17:12:35 +0200
committerLennart Poettering <lennart@poettering.net>2020-04-23 09:18:43 +0200
commit287b7376933a1f1e0ea9a573d2de036fd675d327 (patch)
treea4fe673740720e5a31c87675eb4acf9bf6009ddc /src/nspawn
parent1433e0f2127baafc5bc301dbe3e1584a63fb56e7 (diff)
downloadsystemd-287b7376933a1f1e0ea9a573d2de036fd675d327.tar.gz
nspawn: refuse politely when we are run in the non-host netns in combination with --image=
Strictly speaking this doesn't really fix #15079, but it at least means we won't hang anymore. Fixes: #15079
Diffstat (limited to 'src/nspawn')
-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;