]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/namespace-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
4 #include <linux/magic.h>
8 #include "namespace-util.h"
9 #include "process-util.h"
10 #include "stat-util.h"
11 #include "user-util.h"
13 int namespace_open(pid_t pid
, int *pidns_fd
, int *mntns_fd
, int *netns_fd
, int *userns_fd
, int *root_fd
) {
14 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, netnsfd
= -1, usernsfd
= -1;
22 mntns
= procfs_file_alloca(pid
, "ns/mnt");
23 mntnsfd
= open(mntns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
31 pidns
= procfs_file_alloca(pid
, "ns/pid");
32 pidnsfd
= open(pidns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
40 netns
= procfs_file_alloca(pid
, "ns/net");
41 netnsfd
= open(netns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
49 userns
= procfs_file_alloca(pid
, "ns/user");
50 usernsfd
= open(userns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
51 if (usernsfd
< 0 && errno
!= ENOENT
)
58 root
= procfs_file_alloca(pid
, "root");
59 rfd
= open(root
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
65 *pidns_fd
= TAKE_FD(pidnsfd
);
68 *mntns_fd
= TAKE_FD(mntnsfd
);
71 *netns_fd
= TAKE_FD(netnsfd
);
74 *userns_fd
= TAKE_FD(usernsfd
);
77 *root_fd
= TAKE_FD(rfd
);
82 int namespace_enter(int pidns_fd
, int mntns_fd
, int netns_fd
, int userns_fd
, int root_fd
) {
84 /* Can't setns to your own userns, since then you could
85 * escalate from non-root to root in your own namespace, so
86 * check if namespaces equal before attempting to enter. */
87 _cleanup_free_
char *userns_fd_path
= NULL
;
89 if (asprintf(&userns_fd_path
, "/proc/self/fd/%d", userns_fd
) < 0)
92 r
= files_same(userns_fd_path
, "/proc/self/ns/user", 0);
100 if (setns(pidns_fd
, CLONE_NEWPID
) < 0)
104 if (setns(mntns_fd
, CLONE_NEWNS
) < 0)
108 if (setns(netns_fd
, CLONE_NEWNET
) < 0)
112 if (setns(userns_fd
, CLONE_NEWUSER
) < 0)
116 if (fchdir(root_fd
) < 0)
123 return reset_uid_gid();
126 int fd_is_network_ns(int fd
) {
130 /* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
131 * way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
132 * this somewhat nicely.
134 * This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
135 * refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
137 if (fstatfs(fd
, &s
) < 0)
140 if (!is_fs_type(&s
, NSFS_MAGIC
)) {
141 /* On really old kernels, there was no "nsfs", and network namespace sockets belonged to procfs
142 * instead. Handle that in a somewhat smart way. */
144 if (is_fs_type(&s
, PROC_SUPER_MAGIC
)) {
147 /* OK, so it is procfs. Let's see if our own network namespace is procfs, too. If so, then the
148 * passed fd might refer to a network namespace, but we can't know for sure. In that case,
149 * return a recognizable error. */
151 if (statfs("/proc/self/ns/net", &t
) < 0)
154 if (s
.f_type
== t
.f_type
)
155 return -EUCLEAN
; /* It's possible, we simply don't know */
161 r
= ioctl(fd
, NS_GET_NSTYPE
);
163 if (errno
== ENOTTY
) /* Old kernels didn't know this ioctl, let's also return a recognizable error in that case */
169 return r
== CLONE_NEWNET
;