From: Lennart Poettering Date: Mon, 25 Aug 2025 09:34:53 +0000 (+0200) Subject: import: make sure image mangling works unpriv too X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F39406%2Fhead;p=thirdparty%2Fsystemd.git import: make sure image mangling works unpriv too --- diff --git a/src/import/import-common.c b/src/import/import-common.c index 70b3c3be023..11a6c060bb4 100644 --- a/src/import/import-common.c +++ b/src/import/import-common.c @@ -148,7 +148,7 @@ int import_fork_tar_c(int tree_fd, int userns_fd, PidRef *ret_pid) { return TAKE_FD(pipefd[0]); } -int import_mangle_os_tree_fd(int tree_fd) { +int import_mangle_os_tree_fd(int tree_fd, int userns_fd, ImportFlags flags) { _cleanup_free_ char *child = NULL, *t = NULL, *joined = NULL; _cleanup_closedir_ DIR *d = NULL, *cd = NULL; struct dirent *dent; @@ -157,6 +157,9 @@ int import_mangle_os_tree_fd(int tree_fd) { assert(tree_fd >= 0); + if (FLAGS_SET(flags, IMPORT_FOREIGN_UID) && userns_fd >= 0) + return import_mangle_os_tree_fd_foreign(tree_fd, userns_fd); + /* Some tarballs contain a single top-level directory that contains the actual OS directory tree. Try to * recognize this, and move the tree one level up. */ @@ -274,14 +277,58 @@ int import_mangle_os_tree_fd(int tree_fd) { return 0; } -int import_mangle_os_tree(const char *path) { +int import_mangle_os_tree(const char *path, int userns_fd, ImportFlags flags) { assert(path); _cleanup_close_ int fd = open(path, O_DIRECTORY|O_CLOEXEC|O_PATH); if (fd < 0) return log_error_errno(errno, "Failed to open '%s': %m", path); - return import_mangle_os_tree_fd(fd); + return import_mangle_os_tree_fd(fd, userns_fd, flags); +} + +int import_mangle_os_tree_fd_foreign( + int tree_fd, + int userns_fd) { + + int r; + + assert(tree_fd >= 0); + assert(userns_fd >= 0); + + r = safe_fork_full( + "mangle-tree", + /* stdio_fds= */ NULL, + (int[]) { userns_fd, tree_fd }, 2, + FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_REOPEN_LOG|FORK_WAIT, + /* ret_pid= */ NULL); + if (r < 0) + return r; + if (r == 0) { + /* child */ + + r = namespace_enter( + /* pidns_fd= */ -EBADF, + /* mntns_fd= */ -EBADF, + /* netns_fd= */ -EBADF, + userns_fd, + /* root_fd= */ -EBADF); + if (r < 0) { + log_error_errno(r, "Failed to join user namespace: %m"); + _exit(EXIT_FAILURE); + } + + r = import_mangle_os_tree_fd(tree_fd, /* userns_fd= */ -EBADF, /* flags= */ 0); + if (r < 0) { + log_error_errno(r, "Failed to mangle OS tree in foreign UID mode: %m"); + _exit(EXIT_FAILURE); + } + + _exit(EXIT_SUCCESS); + } + + return 0; + } bool import_validate_local(const char *name, ImportFlags flags) { diff --git a/src/import/import-common.h b/src/import/import-common.h index 289b83b4e6b..8fab3f380bb 100644 --- a/src/import/import-common.h +++ b/src/import/import-common.h @@ -37,8 +37,9 @@ typedef enum ImportFlags { int import_fork_tar_c(int tree_fd, int userns_fd, PidRef *ret_pid); int import_fork_tar_x(int tree_fd, int userns_fd, PidRef *ret_pid); -int import_mangle_os_tree_fd(int tree_fd); -int import_mangle_os_tree(const char *path); +int import_mangle_os_tree_fd(int tree_fd, int userns_fd, ImportFlags flags); +int import_mangle_os_tree(const char *path, int userns_fd, ImportFlags flags); +int import_mangle_os_tree_fd_foreign(int tree_fd, int userns_fd); bool import_validate_local(const char *name, ImportFlags flags); diff --git a/src/import/import-fs.c b/src/import/import-fs.c index 537fe46853a..947bc7c9b56 100644 --- a/src/import/import-fs.c +++ b/src/import/import-fs.c @@ -238,7 +238,7 @@ static int import_fs(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to copy directory: %m"); } - r = import_mangle_os_tree(dest); + r = import_mangle_os_tree(dest, /* userns_fd= */ -EBADF, /* flags= */ 0); if (r < 0) return r; diff --git a/src/import/import-tar.c b/src/import/import-tar.c index e30be005fc7..5aa3a98640e 100644 --- a/src/import/import-tar.c +++ b/src/import/import-tar.c @@ -199,7 +199,7 @@ static int tar_import_finish(TarImport *i) { assert_se(d = i->temp_path ?: i->local); - r = import_mangle_os_tree_fd(i->tree_fd); + r = import_mangle_os_tree_fd(i->tree_fd, i->userns_fd, i->flags); if (r < 0) return r; diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index 65f88e7a887..23bdfb186a7 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -497,7 +497,7 @@ static void tar_pull_job_on_finished(PullJob *j) { tar_pull_report_progress(i, TAR_FINALIZING); - r = import_mangle_os_tree_fd(i->tree_fd); + r = import_mangle_os_tree_fd(i->tree_fd, i->userns_fd, i->flags); if (r < 0) goto finish; @@ -523,7 +523,7 @@ static void tar_pull_job_on_finished(PullJob *j) { tar_pull_report_progress(i, TAR_FINALIZING); - r = import_mangle_os_tree_fd(i->tree_fd); + r = import_mangle_os_tree_fd(i->tree_fd, i->userns_fd, i->flags); if (r < 0) goto finish;