summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/basic/util.c45
-rw-r--r--src/basic/util.h4
-rw-r--r--src/core/machine-id-setup.c4
-rw-r--r--src/libsystemd/sd-bus/bus-container.c12
-rw-r--r--src/machine/machine-dbus.c8
-rw-r--r--src/shared/logs-show.c4
6 files changed, 54 insertions, 23 deletions
diff --git a/src/basic/util.c b/src/basic/util.c
index ebfc6c6a72..9571f0ab12 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -4950,8 +4950,8 @@ int container_get_leader(const char *machine, pid_t *pid) {
return 0;
}
-int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *root_fd) {
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1;
+int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
int rfd = -1;
assert(pid >= 0);
@@ -4983,6 +4983,15 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *
return -errno;
}
+ if (userns_fd) {
+ const char *userns;
+
+ userns = procfs_file_alloca(pid, "ns/user");
+ usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (usernsfd < 0 && errno != ENOENT)
+ return -errno;
+ }
+
if (root_fd) {
const char *root;
@@ -5001,15 +5010,33 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *
if (netns_fd)
*netns_fd = netnsfd;
+ if (userns_fd)
+ *userns_fd = usernsfd;
+
if (root_fd)
*root_fd = rfd;
- pidnsfd = mntnsfd = netnsfd = -1;
+ pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
return 0;
}
-int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) {
+int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
+ if (userns_fd >= 0) {
+ /* Can't setns to your own userns, since then you could
+ * escalate from non-root to root in your own namespace, so
+ * check if namespaces equal before attempting to enter. */
+ _cleanup_free_ char *userns_fd_path = NULL;
+ int r;
+ if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
+ return -ENOMEM;
+
+ r = files_same(userns_fd_path, "/proc/self/ns/user");
+ if (r < 0)
+ return r;
+ if (r)
+ userns_fd = -1;
+ }
if (pidns_fd >= 0)
if (setns(pidns_fd, CLONE_NEWPID) < 0)
@@ -5023,6 +5050,10 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) {
if (setns(netns_fd, CLONE_NEWNET) < 0)
return -errno;
+ if (userns_fd >= 0)
+ if (setns(userns_fd, CLONE_NEWUSER) < 0)
+ return -errno;
+
if (root_fd >= 0) {
if (fchdir(root_fd) < 0)
return -errno;
@@ -6038,7 +6069,7 @@ int ptsname_malloc(int fd, char **ret) {
}
int openpt_in_namespace(pid_t pid, int flags) {
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
_cleanup_close_pair_ int pair[2] = { -1, -1 };
union {
struct cmsghdr cmsghdr;
@@ -6055,7 +6086,7 @@ int openpt_in_namespace(pid_t pid, int flags) {
assert(pid > 0);
- r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
+ r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
if (r < 0)
return r;
@@ -6071,7 +6102,7 @@ int openpt_in_namespace(pid_t pid, int flags) {
pair[0] = safe_close(pair[0]);
- r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
+ r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
if (r < 0)
_exit(EXIT_FAILURE);
diff --git a/src/basic/util.h b/src/basic/util.h
index 098f9edcc1..8f21d56ed8 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -803,8 +803,8 @@ int get_proc_cmdline_key(const char *parameter, char **value);
int container_get_leader(const char *machine, pid_t *pid);
-int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *root_fd);
-int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd);
+int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
+int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
int getpeercred(int fd, struct ucred *ucred);
int getpeersec(int fd, char **ret);
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
index 8e26362546..2d5ae3b3b9 100644
--- a/src/core/machine-id-setup.c
+++ b/src/core/machine-id-setup.c
@@ -325,7 +325,7 @@ int machine_id_commit(const char *root) {
fd = safe_close(fd);
/* Store current mount namespace */
- r = namespace_open(0, NULL, &initial_mntns_fd, NULL, NULL);
+ r = namespace_open(0, NULL, &initial_mntns_fd, NULL, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Can't fetch current mount namespace: %m");
@@ -351,7 +351,7 @@ int machine_id_commit(const char *root) {
fd = safe_close(fd);
/* Return to initial namespace and proceed a lazy tmpfs unmount */
- r = namespace_enter(-1, initial_mntns_fd, -1, -1);
+ r = namespace_enter(-1, initial_mntns_fd, -1, -1, -1);
if (r < 0)
return log_warning_errno(r, "Failed to switch back to initial mount namespace: %m.\nWe'll keep transient %s file until next reboot.", etc_machine_id);
diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c
index fa7a207448..101e4af18d 100644
--- a/src/libsystemd/sd-bus/bus-container.c
+++ b/src/libsystemd/sd-bus/bus-container.c
@@ -29,7 +29,7 @@
#include "bus-container.h"
int bus_container_connect_socket(sd_bus *b) {
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
pid_t child;
siginfo_t si;
int r;
@@ -45,7 +45,7 @@ int bus_container_connect_socket(sd_bus *b) {
return r;
}
- r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &rootfd);
+ r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
if (r < 0)
return r;
@@ -64,7 +64,7 @@ int bus_container_connect_socket(sd_bus *b) {
if (child == 0) {
pid_t grandchild;
- r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
+ r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
if (r < 0)
_exit(255);
@@ -120,7 +120,7 @@ int bus_container_connect_socket(sd_bus *b) {
int bus_container_connect_kernel(sd_bus *b) {
_cleanup_close_pair_ int pair[2] = { -1, -1 };
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(int))];
@@ -146,7 +146,7 @@ int bus_container_connect_kernel(sd_bus *b) {
return r;
}
- r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &rootfd);
+ r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
if (r < 0)
return r;
@@ -162,7 +162,7 @@ int bus_container_connect_kernel(sd_bus *b) {
pair[0] = safe_close(pair[0]);
- r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
+ r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
if (r < 0)
_exit(EXIT_FAILURE);
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index 7658d7146d..b62a9bd813 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -212,7 +212,7 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd
if (streq(us, them))
return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
- r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
+ r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL, NULL);
if (r < 0)
return r;
@@ -230,7 +230,7 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd
pair[0] = safe_close(pair[0]);
- r = namespace_enter(-1, -1, netns_fd, -1);
+ r = namespace_enter(-1, -1, netns_fd, -1, -1);
if (r < 0)
_exit(EXIT_FAILURE);
@@ -346,7 +346,7 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
if (m->class != MACHINE_CONTAINER)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
- r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
+ r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd);
if (r < 0)
return r;
@@ -362,7 +362,7 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
pair[0] = safe_close(pair[0]);
- r = namespace_enter(-1, mntns_fd, -1, root_fd);
+ r = namespace_enter(-1, mntns_fd, -1, -1, root_fd);
if (r < 0)
_exit(EXIT_FAILURE);
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index 068da465d9..b78cb7678c 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -1141,7 +1141,7 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
if (r < 0)
return r;
- r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
+ r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, NULL, &rootfd);
if (r < 0)
return r;
@@ -1157,7 +1157,7 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
pair[0] = safe_close(pair[0]);
- r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
+ r = namespace_enter(pidnsfd, mntnsfd, -1, -1, rootfd);
if (r < 0)
_exit(EXIT_FAILURE);