diff options
-rw-r--r-- | src/basic/util.c | 45 | ||||
-rw-r--r-- | src/basic/util.h | 4 | ||||
-rw-r--r-- | src/core/machine-id-setup.c | 4 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-container.c | 12 | ||||
-rw-r--r-- | src/machine/machine-dbus.c | 8 | ||||
-rw-r--r-- | src/shared/logs-show.c | 4 |
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); |