]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/namespace-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
7 #include "missing_fs.h"
8 #include "missing_magic.h"
9 #include "namespace-util.h"
10 #include "process-util.h"
11 #include "stat-util.h"
12 #include "user-util.h"
14 int namespace_open(pid_t pid
, int *pidns_fd
, int *mntns_fd
, int *netns_fd
, int *userns_fd
, int *root_fd
) {
15 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, netnsfd
= -1, usernsfd
= -1;
23 mntns
= procfs_file_alloca(pid
, "ns/mnt");
24 mntnsfd
= open(mntns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
32 pidns
= procfs_file_alloca(pid
, "ns/pid");
33 pidnsfd
= open(pidns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
41 netns
= procfs_file_alloca(pid
, "ns/net");
42 netnsfd
= open(netns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
50 userns
= procfs_file_alloca(pid
, "ns/user");
51 usernsfd
= open(userns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
52 if (usernsfd
< 0 && errno
!= ENOENT
)
59 root
= procfs_file_alloca(pid
, "root");
60 rfd
= open(root
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
66 *pidns_fd
= TAKE_FD(pidnsfd
);
69 *mntns_fd
= TAKE_FD(mntnsfd
);
72 *netns_fd
= TAKE_FD(netnsfd
);
75 *userns_fd
= TAKE_FD(usernsfd
);
78 *root_fd
= TAKE_FD(rfd
);
83 int namespace_enter(int pidns_fd
, int mntns_fd
, int netns_fd
, int userns_fd
, int root_fd
) {
85 /* Can't setns to your own userns, since then you could
86 * escalate from non-root to root in your own namespace, so
87 * check if namespaces equal before attempting to enter. */
88 _cleanup_free_
char *userns_fd_path
= NULL
;
90 if (asprintf(&userns_fd_path
, "/proc/self/fd/%d", userns_fd
) < 0)
93 r
= files_same(userns_fd_path
, "/proc/self/ns/user", 0);
101 if (setns(pidns_fd
, CLONE_NEWPID
) < 0)
105 if (setns(mntns_fd
, CLONE_NEWNS
) < 0)
109 if (setns(netns_fd
, CLONE_NEWNET
) < 0)
113 if (setns(userns_fd
, CLONE_NEWUSER
) < 0)
117 if (fchdir(root_fd
) < 0)
124 return reset_uid_gid();
127 int fd_is_network_ns(int fd
) {
131 /* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
132 * way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
133 * this somewhat nicely.
135 * This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
136 * refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
138 if (fstatfs(fd
, &s
) < 0)
141 if (!is_fs_type(&s
, NSFS_MAGIC
)) {
142 /* On really old kernels, there was no "nsfs", and network namespace sockets belonged to procfs
143 * instead. Handle that in a somewhat smart way. */
145 if (is_fs_type(&s
, PROC_SUPER_MAGIC
)) {
148 /* OK, so it is procfs. Let's see if our own network namespace is procfs, too. If so, then the
149 * passed fd might refer to a network namespace, but we can't know for sure. In that case,
150 * return a recognizable error. */
152 if (statfs("/proc/self/ns/net", &t
) < 0)
155 if (s
.f_type
== t
.f_type
)
156 return -EUCLEAN
; /* It's possible, we simply don't know */
162 r
= ioctl(fd
, NS_GET_NSTYPE
);
164 if (errno
== ENOTTY
) /* Old kernels didn't know this ioctl, let's also return a recognizable error in that case */
170 return r
== CLONE_NEWNET
;