summaryrefslogtreecommitdiffstats
path: root/src/basic/stat-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2018-10-31 13:04:20 +0100
committerEvgeny Vereshchagin <evvers@ya.ru>2018-10-31 19:42:45 +0100
commit6619ad889da260cf83079cc74a85d571acd1df5a (patch)
treea533525e98e38b5806259d1d4dd68a477c8b73e8 /src/basic/stat-util.c
parentask-password: check keyring in ask_password_tty and ask_password_agent (diff)
downloadsystemd-6619ad889da260cf83079cc74a85d571acd1df5a.tar.xz
systemd-6619ad889da260cf83079cc74a85d571acd1df5a.zip
nspawn: beef up netns checking a bit, for compat with old kernels
Fixes: #10544
Diffstat (limited to 'src/basic/stat-util.c')
-rw-r--r--src/basic/stat-util.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c
index 4e8651f428..3bef0dfe44 100644
--- a/src/basic/stat-util.c
+++ b/src/basic/stat-util.c
@@ -213,15 +213,47 @@ int fd_is_network_fs(int fd) {
}
int fd_is_network_ns(int fd) {
+ struct statfs s;
int r;
- r = fd_is_fs_type(fd, NSFS_MAGIC);
- if (r <= 0)
- return r;
+ /* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
+ * way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
+ * this somewhat nicely.
+ *
+ * This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
+ * refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
+
+ if (fstatfs(fd, &s) < 0)
+ return -errno;
+
+ if (!is_fs_type(&s, NSFS_MAGIC)) {
+ /* On really old kernels, there was no "nsfs", and network namespace sockets belonged to procfs
+ * instead. Handle that in a somewhat smart way. */
+
+ if (is_fs_type(&s, PROC_SUPER_MAGIC)) {
+ struct statfs t;
+
+ /* OK, so it is procfs. Let's see if our own network namespace is procfs, too. If so, then the
+ * passed fd might refer to a network namespace, but we can't know for sure. In that case,
+ * return a recognizable error. */
+
+ if (statfs("/proc/self/ns/net", &t) < 0)
+ return -errno;
+
+ if (s.f_type == t.f_type)
+ return -EUCLEAN; /* It's possible, we simply don't know */
+ }
+
+ return 0; /* No! */
+ }
r = ioctl(fd, NS_GET_NSTYPE);
- if (r < 0)
+ if (r < 0) {
+ if (errno == ENOTTY) /* Old kernels didn't know this ioctl, let's also return a recognizable error in that case */
+ return -EUCLEAN;
+
return -errno;
+ }
return r == CLONE_NEWNET;
}