uid-range: add new uid_range_load_userns_by_fd() helper

This is similar to uid_range_load_userns() but instead of reading the
uid_map off a process it reads it off a userns fd.

(Of course the kernel has no API for this right now, hence we fork off a
throw-away process which joins the user namespace, and then read off the
data from there.)
This commit is contained in:
Lennart Poettering
2024-04-06 16:08:23 +02:00
parent 6ebb53d945
commit 20ba086e77
2 changed files with 62 additions and 0 deletions
+61
View File
@@ -10,6 +10,7 @@
#include "format-util.h"
#include "macro.h"
#include "path-util.h"
#include "process-util.h"
#include "sort-util.h"
#include "stat-util.h"
#include "uid-range.h"
@@ -260,6 +261,66 @@ int uid_range_load_userns(UIDRange **ret, const char *path, UIDRangeUsernsMode m
return 0;
}
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);
assert(mode >= 0);
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);
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,
IN_SET(mode, UID_RANGE_USERNS_INSIDE, UID_RANGE_USERNS_OUTSIDE) ? "uid_map" : "gid_map");
return uid_range_load_userns(ret, p, mode);
}
bool uid_range_overlaps(const UIDRange *range, uid_t start, uid_t nr) {
if (!range)
+1
View File
@@ -43,5 +43,6 @@ typedef enum UIDRangeUsernsMode {
} UIDRangeUsernsMode;
int uid_range_load_userns(UIDRange **ret, const char *path, UIDRangeUsernsMode mode);
int uid_range_load_userns_by_fd(int userns_fd, UIDRangeUsernsMode mode, UIDRange **ret);
bool uid_range_overlaps(const UIDRange *range, uid_t start, uid_t nr);