]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/namespace-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "missing_fs.h"
9 #include "missing_magic.h"
10 #include "namespace-util.h"
11 #include "process-util.h"
12 #include "stat-util.h"
13 #include "user-util.h"
15 int namespace_open(pid_t pid
, int *pidns_fd
, int *mntns_fd
, int *netns_fd
, int *userns_fd
, int *root_fd
) {
16 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, netnsfd
= -1, usernsfd
= -1;
24 mntns
= procfs_file_alloca(pid
, "ns/mnt");
25 mntnsfd
= open(mntns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
33 pidns
= procfs_file_alloca(pid
, "ns/pid");
34 pidnsfd
= open(pidns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
42 netns
= procfs_file_alloca(pid
, "ns/net");
43 netnsfd
= open(netns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
51 userns
= procfs_file_alloca(pid
, "ns/user");
52 usernsfd
= open(userns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
53 if (usernsfd
< 0 && errno
!= ENOENT
)
60 root
= procfs_file_alloca(pid
, "root");
61 rfd
= open(root
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
67 *pidns_fd
= TAKE_FD(pidnsfd
);
70 *mntns_fd
= TAKE_FD(mntnsfd
);
73 *netns_fd
= TAKE_FD(netnsfd
);
76 *userns_fd
= TAKE_FD(usernsfd
);
79 *root_fd
= TAKE_FD(rfd
);
84 int namespace_enter(int pidns_fd
, int mntns_fd
, int netns_fd
, int userns_fd
, int root_fd
) {
86 /* Can't setns to your own userns, since then you could
87 * escalate from non-root to root in your own namespace, so
88 * check if namespaces equal before attempting to enter. */
89 _cleanup_free_
char *userns_fd_path
= NULL
;
91 if (asprintf(&userns_fd_path
, "/proc/self/fd/%d", userns_fd
) < 0)
94 r
= files_same(userns_fd_path
, "/proc/self/ns/user", 0);
102 if (setns(pidns_fd
, CLONE_NEWPID
) < 0)
106 if (setns(mntns_fd
, CLONE_NEWNS
) < 0)
110 if (setns(netns_fd
, CLONE_NEWNET
) < 0)
114 if (setns(userns_fd
, CLONE_NEWUSER
) < 0)
118 if (fchdir(root_fd
) < 0)
125 return reset_uid_gid();
128 int fd_is_network_ns(int fd
) {
132 /* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
133 * way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
134 * this somewhat nicely.
136 * This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
137 * refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
139 if (fstatfs(fd
, &s
) < 0)
142 if (!is_fs_type(&s
, NSFS_MAGIC
)) {
143 /* On really old kernels, there was no "nsfs", and network namespace sockets belonged to procfs
144 * instead. Handle that in a somewhat smart way. */
146 if (is_fs_type(&s
, PROC_SUPER_MAGIC
)) {
149 /* OK, so it is procfs. Let's see if our own network namespace is procfs, too. If so, then the
150 * passed fd might refer to a network namespace, but we can't know for sure. In that case,
151 * return a recognizable error. */
153 if (statfs("/proc/self/ns/net", &t
) < 0)
156 if (s
.f_type
== t
.f_type
)
157 return -EUCLEAN
; /* It's possible, we simply don't know */
163 r
= ioctl(fd
, NS_GET_NSTYPE
);
165 if (errno
== ENOTTY
) /* Old kernels didn't know this ioctl, let's also return a recognizable error in that case */
171 return r
== CLONE_NEWNET
;
174 int detach_mount_namespace(void) {
176 /* Detaches the mount namespace, disabling propagation from our namespace to the host */
178 if (unshare(CLONE_NEWNS
) < 0)
181 if (mount(NULL
, "/", NULL
, MS_SLAVE
| MS_REC
, NULL
) < 0)