mirror of
https://github.com/systemd/systemd
synced 2024-10-15 04:24:19 +00:00
nspawn: beef up netns checking a bit, for compat with old kernels
Fixes: #10544
This commit is contained in:
parent
c7b7d74e81
commit
6619ad889d
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -3761,10 +3761,12 @@ static int run(int master,
|
|||
return log_error_errno(errno, "Cannot open file %s: %m", arg_network_namespace_path);
|
||||
|
||||
r = fd_is_network_ns(netns_fd);
|
||||
if (r < 0 && r != -ENOTTY)
|
||||
if (r == -EUCLEAN)
|
||||
log_debug_errno(r, "Cannot determine if passed network namespace path '%s' really refers to a network namespace, assuming it does.", arg_network_namespace_path);
|
||||
else if (r < 0)
|
||||
return log_error_errno(r, "Failed to check %s fs type: %m", arg_network_namespace_path);
|
||||
if (r == 0) {
|
||||
log_error("Path %s doesn't refer to a network namespace", arg_network_namespace_path);
|
||||
else if (r == 0) {
|
||||
log_error("Path %s doesn't refer to a network namespace, refusing.", arg_network_namespace_path);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,11 +67,26 @@ static void test_path_is_temporary_fs(void) {
|
|||
assert_se(path_is_temporary_fs("/i-dont-exist") == -ENOENT);
|
||||
}
|
||||
|
||||
static void test_fd_is_network_ns(void) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
assert_se(fd_is_network_ns(STDIN_FILENO) == 0);
|
||||
assert_se(fd_is_network_ns(STDERR_FILENO) == 0);
|
||||
assert_se(fd_is_network_ns(STDOUT_FILENO) == 0);
|
||||
|
||||
assert_se((fd = open("/proc/self/ns/mnt", O_CLOEXEC|O_RDONLY)) >= 0);
|
||||
assert_se(IN_SET(fd_is_network_ns(fd), 0, -EUCLEAN));
|
||||
fd = safe_close(fd);
|
||||
|
||||
assert_se((fd = open("/proc/self/ns/net", O_CLOEXEC|O_RDONLY)) >= 0);
|
||||
assert_se(IN_SET(fd_is_network_ns(fd), 1, -EUCLEAN));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_files_same();
|
||||
test_is_symlink();
|
||||
test_path_is_fs_type();
|
||||
test_path_is_temporary_fs();
|
||||
test_fd_is_network_ns();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue