summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Yuan <me@yhndnzj.com>2025-01-08 12:43:05 +0100
committerMike Yuan <me@yhndnzj.com>2025-01-11 15:53:14 +0100
commit8c2c8235a64be93e9e8d18927ad997efda156a95 (patch)
tree9b4f88aa9dead4b847d6de02d902dd4172a05450
parentnamespace-util: group userns functions together (diff)
downloadsystemd-8c2c8235a64be93e9e8d18927ad997efda156a95.tar.xz
systemd-8c2c8235a64be93e9e8d18927ad997efda156a95.zip
namespace-util: introduce userns_enter_and_pin() helper
which generalizes forking a process into userns and freeze() Addresses https://github.com/systemd/systemd/pull/35833/files#r1905508153
-rw-r--r--src/basic/namespace-util.c23
-rw-r--r--src/basic/namespace-util.h1
-rw-r--r--src/basic/uid-range.c43
3 files changed, 22 insertions, 45 deletions
diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c
index 2ae5003459..6ece5108df 100644
--- a/src/basic/namespace-util.c
+++ b/src/basic/namespace-util.c
@@ -558,7 +558,7 @@ int userns_acquire(const char *uid_map, const char *gid_map) {
return TAKE_FD(userns_fd);
}
-int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid) {
+int userns_enter_and_pin(int userns_fd, pid_t *ret_pid) {
_cleanup_(close_pairp) int pfd[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t pid = 0;
ssize_t n;
@@ -566,12 +566,13 @@ int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid) {
int r;
assert(userns_fd >= 0);
+ assert(ret_pid);
if (pipe2(pfd, O_CLOEXEC) < 0)
return -errno;
r = safe_fork_full(
- "(sd-baseuns)",
+ "(sd-pinuserns)",
/* stdio_fds= */ NULL,
(int[]) { pfd[1], userns_fd }, 2,
FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL,
@@ -608,6 +609,20 @@ int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid) {
assert(n == 1);
assert(x == 'x');
+ *ret_pid = TAKE_PID(pid);
+ return 0;
+}
+
+int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid) {
+ _cleanup_(sigkill_waitp) pid_t pid = 0;
+ int r;
+
+ assert(userns_fd >= 0);
+
+ r = userns_enter_and_pin(userns_fd, &pid);
+ if (r < 0)
+ return r;
+
uid_t uid;
r = uid_map_search_root(pid, "uid_map", &uid);
if (r < 0)
@@ -630,13 +645,13 @@ int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid) {
}
int process_is_owned_by_uid(const PidRef *pidref, uid_t uid) {
- assert(uid_is_valid(uid));
-
int r;
/* Checks if the specified process either is owned directly by the specified user, or if it is inside
* a user namespace owned by it. */
+ assert(uid_is_valid(uid));
+
uid_t process_uid;
r = pidref_get_uid(pidref, &process_uid);
if (r < 0)
diff --git a/src/basic/namespace-util.h b/src/basic/namespace-util.h
index 58347cbf88..49e2de3bb3 100644
--- a/src/basic/namespace-util.h
+++ b/src/basic/namespace-util.h
@@ -87,6 +87,7 @@ int parse_userns_uid_range(const char *s, uid_t *ret_uid_shift, uid_t *ret_uid_r
int userns_acquire_empty(void);
int userns_acquire(const char *uid_map, const char *gid_map);
+int userns_enter_and_pin(int userns_fd, pid_t *ret_pid);
int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid);
diff --git a/src/basic/uid-range.c b/src/basic/uid-range.c
index 687ddacc57..cbae1bbf78 100644
--- a/src/basic/uid-range.c
+++ b/src/basic/uid-range.c
@@ -9,6 +9,7 @@
#include "fd-util.h"
#include "format-util.h"
#include "macro.h"
+#include "namespace-util.h"
#include "path-util.h"
#include "process-util.h"
#include "sort-util.h"
@@ -264,10 +265,7 @@ int uid_range_load_userns(const char *path, UIDRangeUsernsMode mode, UIDRange **
}
int uid_range_load_userns_by_fd(int userns_fd, UIDRangeUsernsMode mode, UIDRange **ret) {
- _cleanup_(close_pairp) int pfd[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t pid = 0;
- ssize_t n;
- char x;
int r;
assert(userns_fd >= 0);
@@ -275,46 +273,9 @@ int uid_range_load_userns_by_fd(int userns_fd, UIDRangeUsernsMode mode, UIDRange
assert(mode < _UID_RANGE_USERNS_MODE_MAX);
assert(ret);
- if (pipe2(pfd, O_CLOEXEC) < 0)
- return -errno;
-
- r = safe_fork_full(
- "(sd-mkuserns)",
- /* stdio_fds= */ NULL,
- (int[]) { pfd[1], userns_fd }, 2,
- FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL,
- &pid);
+ r = userns_enter_and_pin(userns_fd, &pid);
if (r < 0)
return r;
- if (r == 0) {
- /* Child. */
-
- if (setns(userns_fd, CLONE_NEWUSER) < 0) {
- log_debug_errno(errno, "Failed to join userns: %m");
- _exit(EXIT_FAILURE);
- }
-
- userns_fd = safe_close(userns_fd);
-
- n = write(pfd[1], &(const char) { 'x' }, 1);
- if (n < 0) {
- log_debug_errno(errno, "Failed to write to fifo: %m");
- _exit(EXIT_FAILURE);
- }
- assert(n == 1);
-
- freeze();
- }
-
- pfd[1] = safe_close(pfd[1]);
-
- n = read(pfd[0], &x, 1);
- if (n < 0)
- return -errno;
- if (n == 0)
- return -EPROTO;
- assert(n == 1);
- assert(x == 'x');
const char *p = procfs_file_alloca(
pid,