importd: support unpacking tarballs to foreign UID range
When invoked unprivileged, let's use a transiently allocated userns, so that we can properly untar UIDs/GIDs so that the trees appear owned by the foreign UID/GID range.
This commit is contained in:
+159
-2
@@ -6,21 +6,26 @@
|
|||||||
#include "sd-event.h"
|
#include "sd-event.h"
|
||||||
|
|
||||||
#include "capability-util.h"
|
#include "capability-util.h"
|
||||||
|
#include "copy.h"
|
||||||
#include "dirent-util.h"
|
#include "dirent-util.h"
|
||||||
|
#include "dissect-image.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "import-common.h"
|
#include "import-common.h"
|
||||||
#include "libarchive-util.h"
|
#include "libarchive-util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "namespace-util.h"
|
||||||
|
#include "nsresource.h"
|
||||||
#include "os-util.h"
|
#include "os-util.h"
|
||||||
#include "pidref.h"
|
#include "pidref.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
|
#include "rm-rf.h"
|
||||||
#include "selinux-util.h"
|
#include "selinux-util.h"
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
#include "tar-util.h"
|
#include "tar-util.h"
|
||||||
#include "tmpfile-util.h"
|
#include "tmpfile-util.h"
|
||||||
|
|
||||||
int import_fork_tar_x(int tree_fd, PidRef *ret_pid) {
|
int import_fork_tar_x(int tree_fd, int userns_fd, PidRef *ret_pid) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(tree_fd >= 0);
|
assert(tree_fd >= 0);
|
||||||
@@ -41,7 +46,7 @@ int import_fork_tar_x(int tree_fd, PidRef *ret_pid) {
|
|||||||
r = pidref_safe_fork_full(
|
r = pidref_safe_fork_full(
|
||||||
"tar-x",
|
"tar-x",
|
||||||
/* stdio_fds= */ NULL,
|
/* stdio_fds= */ NULL,
|
||||||
(int[]) { tree_fd, pipefd[0] }, 2,
|
(int[]) { tree_fd, pipefd[0], userns_fd }, userns_fd >= 0 ? 3 : 2,
|
||||||
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_REOPEN_LOG,
|
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_REOPEN_LOG,
|
||||||
ret_pid);
|
ret_pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@@ -58,6 +63,14 @@ int import_fork_tar_x(int tree_fd, PidRef *ret_pid) {
|
|||||||
|
|
||||||
/* Child */
|
/* Child */
|
||||||
|
|
||||||
|
if (userns_fd >= 0) {
|
||||||
|
r = detach_mount_namespace_userns(userns_fd);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error_errno(r, "Failed to join user namespace: %m");
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (unshare(CLONE_NEWNET) < 0)
|
if (unshare(CLONE_NEWNET) < 0)
|
||||||
log_warning_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
|
log_warning_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
|
||||||
|
|
||||||
@@ -291,3 +304,147 @@ int import_allocate_event_with_signals(sd_event **ret) {
|
|||||||
*ret = TAKE_PTR(event);
|
*ret = TAKE_PTR(event);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int import_make_foreign_userns(int *userns_fd) {
|
||||||
|
assert(userns_fd);
|
||||||
|
|
||||||
|
if (*userns_fd >= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*userns_fd = nsresource_allocate_userns(/* name= */ NULL, NSRESOURCE_UIDS_64K); /* allocate 64K users */
|
||||||
|
if (*userns_fd < 0)
|
||||||
|
return log_error_errno(*userns_fd, "Failed to allocate transient user namespace: %m");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int import_copy_foreign(
|
||||||
|
int source_fd,
|
||||||
|
int target_fd,
|
||||||
|
int *userns_fd) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(source_fd >= 0);
|
||||||
|
assert(target_fd >= 0);
|
||||||
|
assert(userns_fd);
|
||||||
|
|
||||||
|
/* Copies dir referenced by source_fd into dir referenced by source_fd, moves to the specified userns
|
||||||
|
* for that (allocated if needed), which should be foreign UID range */
|
||||||
|
|
||||||
|
r = import_make_foreign_userns(userns_fd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = safe_fork_full(
|
||||||
|
"copy-tree",
|
||||||
|
/* stdio_fds= */ NULL,
|
||||||
|
(int[]) { *userns_fd, source_fd, target_fd }, 3,
|
||||||
|
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) {
|
||||||
|
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 = copy_tree_at(
|
||||||
|
source_fd, /* from= */ NULL,
|
||||||
|
target_fd, /* to = */ NULL,
|
||||||
|
/* override_uid= */ UID_INVALID,
|
||||||
|
/* override_gid= */ GID_INVALID,
|
||||||
|
COPY_REFLINK|COPY_HARDLINKS|COPY_MERGE_EMPTY|COPY_MERGE_APPLY_STAT|COPY_SAME_MOUNT|COPY_ALL_XATTRS,
|
||||||
|
/* denylist= */ NULL,
|
||||||
|
/* subvolumes= */ NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error_errno(r, "Failed to copy tree: %m");
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
_exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int import_remove_tree_foreign(const char *path, int *userns_fd) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(path);
|
||||||
|
assert(userns_fd);
|
||||||
|
|
||||||
|
r = import_make_foreign_userns(userns_fd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
_cleanup_close_ int tree_fd = -EBADF;
|
||||||
|
r = mountfsd_mount_directory(
|
||||||
|
path,
|
||||||
|
*userns_fd,
|
||||||
|
DISSECT_IMAGE_FOREIGN_UID,
|
||||||
|
&tree_fd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = safe_fork_full(
|
||||||
|
"rm-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);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup_close_ int dfd = fd_reopen(tree_fd, O_DIRECTORY|O_CLOEXEC);
|
||||||
|
if (dfd < 0) {
|
||||||
|
log_error_errno(r, "Failed to reopen tree fd: %m");
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = rm_rf_children(dfd, REMOVE_PHYSICAL|REMOVE_SUBVOLUME|REMOVE_CHMOD, /* root_dev= */ NULL);
|
||||||
|
if (r < 0)
|
||||||
|
log_warning_errno(r, "Failed to empty '%s' directory in foreign UID mode, ignoring: %m", path);
|
||||||
|
|
||||||
|
_exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int import_remove_tree(const char *path, int *userns_fd, ImportFlags flags) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(path);
|
||||||
|
assert(userns_fd);
|
||||||
|
|
||||||
|
/* Try the userns dance first, to remove foreign UID range owned trees */
|
||||||
|
if (FLAGS_SET(flags, IMPORT_FOREIGN_UID))
|
||||||
|
(void) import_remove_tree_foreign(path, userns_fd);
|
||||||
|
|
||||||
|
r = rm_rf(path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME|REMOVE_MISSING_OK|REMOVE_CHMOD);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to remove '%s': %m", path);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,15 +15,16 @@ typedef enum ImportFlags {
|
|||||||
IMPORT_CONVERT_QCOW2 = 1 << 5, /* raw: if we detect a qcow2 image, unpack it */
|
IMPORT_CONVERT_QCOW2 = 1 << 5, /* raw: if we detect a qcow2 image, unpack it */
|
||||||
IMPORT_DIRECT = 1 << 6, /* import without rename games */
|
IMPORT_DIRECT = 1 << 6, /* import without rename games */
|
||||||
IMPORT_SYNC = 1 << 7, /* fsync() right before we are done */
|
IMPORT_SYNC = 1 << 7, /* fsync() right before we are done */
|
||||||
|
IMPORT_FOREIGN_UID = 1 << 8, /* tar: go via nsresourced/mountfsd and make owned by foreign UID */
|
||||||
|
|
||||||
/* When pulling these flags are defined too */
|
/* When pulling these flags are defined too */
|
||||||
IMPORT_PULL_SETTINGS = 1 << 8, /* download .nspawn settings file */
|
IMPORT_PULL_SETTINGS = 1 << 9, /* download .nspawn settings file */
|
||||||
IMPORT_PULL_ROOTHASH = 1 << 9, /* only for raw: download .roothash file for verity */
|
IMPORT_PULL_ROOTHASH = 1 << 10, /* only for raw: download .roothash file for verity */
|
||||||
IMPORT_PULL_ROOTHASH_SIGNATURE = 1 << 10, /* only for raw: download .roothash.p7s file for verity */
|
IMPORT_PULL_ROOTHASH_SIGNATURE = 1 << 11, /* only for raw: download .roothash.p7s file for verity */
|
||||||
IMPORT_PULL_VERITY = 1 << 11, /* only for raw: download .verity file for verity */
|
IMPORT_PULL_VERITY = 1 << 12, /* only for raw: download .verity file for verity */
|
||||||
|
|
||||||
/* The supported flags for the tar and the raw importing */
|
/* The supported flags for the tar and the raw importing */
|
||||||
IMPORT_FLAGS_MASK_TAR = IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_BTRFS_SUBVOL|IMPORT_BTRFS_QUOTA|IMPORT_DIRECT|IMPORT_SYNC,
|
IMPORT_FLAGS_MASK_TAR = IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_BTRFS_SUBVOL|IMPORT_BTRFS_QUOTA|IMPORT_DIRECT|IMPORT_SYNC|IMPORT_FOREIGN_UID,
|
||||||
IMPORT_FLAGS_MASK_RAW = IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_CONVERT_QCOW2|IMPORT_DIRECT|IMPORT_SYNC,
|
IMPORT_FLAGS_MASK_RAW = IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_CONVERT_QCOW2|IMPORT_DIRECT|IMPORT_SYNC,
|
||||||
|
|
||||||
/* The supported flags for the tar and the raw pulling */
|
/* The supported flags for the tar and the raw pulling */
|
||||||
@@ -34,7 +35,7 @@ typedef enum ImportFlags {
|
|||||||
} ImportFlags;
|
} ImportFlags;
|
||||||
|
|
||||||
int import_fork_tar_c(const char *path, PidRef *ret);
|
int import_fork_tar_c(const char *path, PidRef *ret);
|
||||||
int import_fork_tar_x(int tree_fd, PidRef *ret_pid);
|
int import_fork_tar_x(int tree_fd, int userns_fd, PidRef *ret_pid);
|
||||||
|
|
||||||
int import_mangle_os_tree(const char *path);
|
int import_mangle_os_tree(const char *path);
|
||||||
|
|
||||||
@@ -42,4 +43,11 @@ bool import_validate_local(const char *name, ImportFlags flags);
|
|||||||
|
|
||||||
int import_allocate_event_with_signals(sd_event **ret);
|
int import_allocate_event_with_signals(sd_event **ret);
|
||||||
|
|
||||||
|
int import_make_foreign_userns(int *userns_fd);
|
||||||
|
|
||||||
|
int import_copy_foreign(int source_fd, int target_fd, int *userns_fd);
|
||||||
|
|
||||||
|
int import_remove_tree_foreign(const char *path, int *userns_fd);
|
||||||
|
int import_remove_tree(const char *path, int *userns_fd, ImportFlags flags);
|
||||||
|
|
||||||
#define IMPORT_BUFFER_SIZE (128U*1024U)
|
#define IMPORT_BUFFER_SIZE (128U*1024U)
|
||||||
|
|||||||
+43
-21
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "btrfs-util.h"
|
#include "btrfs-util.h"
|
||||||
|
#include "dissect-image.h"
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
@@ -46,6 +47,7 @@ typedef struct TarImport {
|
|||||||
int input_fd;
|
int input_fd;
|
||||||
int tar_fd;
|
int tar_fd;
|
||||||
int tree_fd;
|
int tree_fd;
|
||||||
|
int userns_fd;
|
||||||
|
|
||||||
ImportCompress compress;
|
ImportCompress compress;
|
||||||
|
|
||||||
@@ -73,7 +75,10 @@ TarImport* tar_import_unref(TarImport *i) {
|
|||||||
|
|
||||||
pidref_done_sigkill_wait(&i->tar_pid);
|
pidref_done_sigkill_wait(&i->tar_pid);
|
||||||
|
|
||||||
rm_rf_subvolume_and_free(i->temp_path);
|
if (i->temp_path) {
|
||||||
|
import_remove_tree(i->temp_path, &i->userns_fd, i->flags);
|
||||||
|
free(i->temp_path);
|
||||||
|
}
|
||||||
|
|
||||||
import_compress_free(&i->compress);
|
import_compress_free(&i->compress);
|
||||||
|
|
||||||
@@ -81,6 +86,7 @@ TarImport* tar_import_unref(TarImport *i) {
|
|||||||
|
|
||||||
safe_close(i->tar_fd);
|
safe_close(i->tar_fd);
|
||||||
safe_close(i->tree_fd);
|
safe_close(i->tree_fd);
|
||||||
|
safe_close(i->userns_fd);
|
||||||
|
|
||||||
free(i->final_path);
|
free(i->final_path);
|
||||||
free(i->image_root);
|
free(i->image_root);
|
||||||
@@ -114,6 +120,7 @@ int tar_import_new(
|
|||||||
.input_fd = -EBADF,
|
.input_fd = -EBADF,
|
||||||
.tar_fd = -EBADF,
|
.tar_fd = -EBADF,
|
||||||
.tree_fd = -EBADF,
|
.tree_fd = -EBADF,
|
||||||
|
.userns_fd = -EBADF,
|
||||||
.on_finished = on_finished,
|
.on_finished = on_finished,
|
||||||
.userdata = userdata,
|
.userdata = userdata,
|
||||||
.last_percent = UINT_MAX,
|
.last_percent = UINT_MAX,
|
||||||
@@ -200,8 +207,8 @@ static int tar_import_finish(TarImport *i) {
|
|||||||
AT_FDCWD, d,
|
AT_FDCWD, d,
|
||||||
AT_FDCWD, i->final_path,
|
AT_FDCWD, i->final_path,
|
||||||
(i->flags & IMPORT_FORCE ? INSTALL_REPLACE : 0) |
|
(i->flags & IMPORT_FORCE ? INSTALL_REPLACE : 0) |
|
||||||
(i->flags & IMPORT_READ_ONLY ? INSTALL_READ_ONLY : 0) |
|
(i->flags & IMPORT_READ_ONLY ? INSTALL_READ_ONLY|INSTALL_GRACEFUL : 0) |
|
||||||
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
|
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS|INSTALL_GRACEFUL : 0));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to move '%s' into place: %m", i->final_path ?: i->local);
|
return log_error_errno(r, "Failed to move '%s' into place: %m", i->final_path ?: i->local);
|
||||||
|
|
||||||
@@ -244,26 +251,41 @@ static int tar_import_fork_tar(TarImport *i) {
|
|||||||
if (FLAGS_SET(i->flags, IMPORT_DIRECT|IMPORT_FORCE))
|
if (FLAGS_SET(i->flags, IMPORT_DIRECT|IMPORT_FORCE))
|
||||||
(void) rm_rf(d, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
|
(void) rm_rf(d, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
|
||||||
|
|
||||||
if (i->flags & IMPORT_BTRFS_SUBVOL)
|
if (FLAGS_SET(i->flags, IMPORT_FOREIGN_UID)) {
|
||||||
r = btrfs_subvol_make_fallback(AT_FDCWD, d, 0755);
|
r = import_make_foreign_userns(&i->userns_fd);
|
||||||
else
|
if (r < 0)
|
||||||
r = RET_NERRNO(mkdir(d, 0755));
|
return r;
|
||||||
if (r == -EEXIST && (i->flags & IMPORT_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
|
|
||||||
* because in that case our temporary path collided */
|
_cleanup_close_ int directory_fd = -EBADF;
|
||||||
r = 0;
|
r = mountfsd_make_directory(d, /* flags= */ 0, &directory_fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to create directory/subvolume %s: %m", d);
|
return r;
|
||||||
if (r > 0 && (i->flags & IMPORT_BTRFS_QUOTA)) { /* actually btrfs subvol */
|
|
||||||
if (!(i->flags & IMPORT_DIRECT))
|
r = mountfsd_mount_directory_fd(directory_fd, i->userns_fd, DISSECT_IMAGE_FOREIGN_UID, &i->tree_fd);
|
||||||
(void) import_assign_pool_quota_and_warn(root);
|
if (r < 0)
|
||||||
(void) import_assign_pool_quota_and_warn(d);
|
return r;
|
||||||
|
} else {
|
||||||
|
if (i->flags & IMPORT_BTRFS_SUBVOL)
|
||||||
|
r = btrfs_subvol_make_fallback(AT_FDCWD, d, 0755);
|
||||||
|
else
|
||||||
|
r = RET_NERRNO(mkdir(d, 0755));
|
||||||
|
if (r == -EEXIST && (i->flags & IMPORT_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
|
||||||
|
* because in that case our temporary path collided */
|
||||||
|
r = 0;
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to create directory/subvolume %s: %m", d);
|
||||||
|
if (r > 0 && (i->flags & IMPORT_BTRFS_QUOTA)) { /* actually btrfs subvol */
|
||||||
|
if (!(i->flags & IMPORT_DIRECT))
|
||||||
|
(void) import_assign_pool_quota_and_warn(root);
|
||||||
|
(void) import_assign_pool_quota_and_warn(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
i->tree_fd = open(d, O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
|
||||||
|
if (i->tree_fd < 0)
|
||||||
|
return log_error_errno(errno, "Failed to open '%s': %m", d);
|
||||||
}
|
}
|
||||||
|
|
||||||
i->tree_fd = open(d, O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
|
i->tar_fd = import_fork_tar_x(i->tree_fd, i->userns_fd, &i->tar_pid);
|
||||||
if (i->tree_fd < 0)
|
|
||||||
return log_error_errno(errno, "Failed to open '%s': %m", d);
|
|
||||||
|
|
||||||
i->tar_fd = import_fork_tar_x(i->tree_fd, &i->tar_pid);
|
|
||||||
if (i->tar_fd < 0)
|
if (i->tar_fd < 0)
|
||||||
return i->tar_fd;
|
return i->tar_fd;
|
||||||
|
|
||||||
|
|||||||
@@ -471,6 +471,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
return log_error_errno(r, "Failed to pick image root: %m");
|
return log_error_errno(r, "Failed to pick image root: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg_runtime_scope == RUNTIME_SCOPE_USER)
|
||||||
|
arg_import_flags |= IMPORT_FOREIGN_UID;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+108
-40
@@ -9,11 +9,10 @@
|
|||||||
#include "btrfs-util.h"
|
#include "btrfs-util.h"
|
||||||
#include "copy.h"
|
#include "copy.h"
|
||||||
#include "curl-util.h"
|
#include "curl-util.h"
|
||||||
|
#include "dissect-image.h"
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "import-common.h"
|
|
||||||
#include "import-util.h"
|
|
||||||
#include "install-file.h"
|
#include "install-file.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "mkdir-label.h"
|
#include "mkdir-label.h"
|
||||||
@@ -26,6 +25,7 @@
|
|||||||
#include "rm-rf.h"
|
#include "rm-rf.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "tmpfile-util.h"
|
#include "tmpfile-util.h"
|
||||||
|
#include "uid-classification.h"
|
||||||
#include "web-util.h"
|
#include "web-util.h"
|
||||||
|
|
||||||
typedef enum TarProgress {
|
typedef enum TarProgress {
|
||||||
@@ -64,6 +64,7 @@ typedef struct TarPull {
|
|||||||
char *checksum;
|
char *checksum;
|
||||||
|
|
||||||
int tree_fd;
|
int tree_fd;
|
||||||
|
int userns_fd;
|
||||||
} TarPull;
|
} TarPull;
|
||||||
|
|
||||||
TarPull* tar_pull_unref(TarPull *i) {
|
TarPull* tar_pull_unref(TarPull *i) {
|
||||||
@@ -80,7 +81,10 @@ TarPull* tar_pull_unref(TarPull *i) {
|
|||||||
curl_glue_unref(i->glue);
|
curl_glue_unref(i->glue);
|
||||||
sd_event_unref(i->event);
|
sd_event_unref(i->event);
|
||||||
|
|
||||||
rm_rf_subvolume_and_free(i->temp_path);
|
if (i->temp_path) {
|
||||||
|
import_remove_tree(i->temp_path, &i->userns_fd, i->flags);
|
||||||
|
free(i->temp_path);
|
||||||
|
}
|
||||||
unlink_and_free(i->settings_temp_path);
|
unlink_and_free(i->settings_temp_path);
|
||||||
|
|
||||||
free(i->final_path);
|
free(i->final_path);
|
||||||
@@ -90,6 +94,7 @@ TarPull* tar_pull_unref(TarPull *i) {
|
|||||||
free(i->checksum);
|
free(i->checksum);
|
||||||
|
|
||||||
safe_close(i->tree_fd);
|
safe_close(i->tree_fd);
|
||||||
|
safe_close(i->userns_fd);
|
||||||
|
|
||||||
return mfree(i);
|
return mfree(i);
|
||||||
}
|
}
|
||||||
@@ -138,6 +143,7 @@ int tar_pull_new(
|
|||||||
.glue = TAKE_PTR(g),
|
.glue = TAKE_PTR(g),
|
||||||
.tar_pid = PIDREF_NULL,
|
.tar_pid = PIDREF_NULL,
|
||||||
.tree_fd = -EBADF,
|
.tree_fd = -EBADF,
|
||||||
|
.userns_fd = -EBADF,
|
||||||
};
|
};
|
||||||
|
|
||||||
i->glue->on_finished = pull_job_curl_on_finished;
|
i->glue->on_finished = pull_job_curl_on_finished;
|
||||||
@@ -233,6 +239,9 @@ static int tar_pull_make_local_copy(TarPull *i) {
|
|||||||
if (!i->local)
|
if (!i->local)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Creates a copy/clone of the original downloaded version (which is supposed to remain untouched)
|
||||||
|
* under a local image name (which may then be modified) */
|
||||||
|
|
||||||
assert(i->final_path);
|
assert(i->final_path);
|
||||||
|
|
||||||
p = path_join(i->image_root, i->local);
|
p = path_join(i->image_root, i->local);
|
||||||
@@ -244,18 +253,61 @@ static int tar_pull_make_local_copy(TarPull *i) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to generate temporary filename for %s: %m", p);
|
return log_error_errno(r, "Failed to generate temporary filename for %s: %m", p);
|
||||||
|
|
||||||
if (i->flags & IMPORT_BTRFS_SUBVOL)
|
if (FLAGS_SET(i->flags, IMPORT_FOREIGN_UID)) {
|
||||||
r = btrfs_subvol_snapshot_at(
|
/* Copy in userns */
|
||||||
AT_FDCWD, i->final_path,
|
|
||||||
AT_FDCWD, t,
|
r = import_make_foreign_userns(&i->userns_fd);
|
||||||
(i->flags & IMPORT_BTRFS_QUOTA ? BTRFS_SNAPSHOT_QUOTA : 0)|
|
if (r < 0)
|
||||||
BTRFS_SNAPSHOT_FALLBACK_COPY|
|
return r;
|
||||||
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
|
|
||||||
BTRFS_SNAPSHOT_RECURSIVE);
|
/* Usually, tar_pull_job_on_open_disk_tar() would allocate ->tree_fd for us, but if
|
||||||
else
|
* already downloaded the image before, and are just making a copy of the original
|
||||||
r = copy_tree(i->final_path, t, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_HARDLINKS, NULL, NULL);
|
* download, we need to open ->tree_fd now */
|
||||||
if (r < 0)
|
if (i->tree_fd < 0) {
|
||||||
return log_error_errno(r, "Failed to create local image: %m");
|
_cleanup_close_ int directory_fd = open(i->final_path, O_DIRECTORY|O_CLOEXEC);
|
||||||
|
if (directory_fd < 0)
|
||||||
|
return log_error_errno(errno, "Failed to open '%s': %m", i->final_path);
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (fstat(directory_fd, &st) < 0)
|
||||||
|
return log_error_errno(errno, "Failed to stat '%s': %m", i->final_path);
|
||||||
|
|
||||||
|
if (uid_is_foreign(st.st_uid)) {
|
||||||
|
r = mountfsd_mount_directory_fd(directory_fd, i->userns_fd, DISSECT_IMAGE_FOREIGN_UID, &i->tree_fd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
i->tree_fd = TAKE_FD(directory_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup_close_ int directory_fd = -EBADF;
|
||||||
|
r = mountfsd_make_directory(t, /* flags= */ 0, &directory_fd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
_cleanup_close_ int copy_fd = -EBADF;
|
||||||
|
r = mountfsd_mount_directory_fd(directory_fd, i->userns_fd, DISSECT_IMAGE_FOREIGN_UID, ©_fd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = import_copy_foreign(i->tree_fd, copy_fd, &i->userns_fd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
} else {
|
||||||
|
/* Copy locally */
|
||||||
|
if (i->flags & IMPORT_BTRFS_SUBVOL)
|
||||||
|
r = btrfs_subvol_snapshot_at(
|
||||||
|
AT_FDCWD, i->final_path,
|
||||||
|
AT_FDCWD, t,
|
||||||
|
(i->flags & IMPORT_BTRFS_QUOTA ? BTRFS_SNAPSHOT_QUOTA : 0)|
|
||||||
|
BTRFS_SNAPSHOT_FALLBACK_COPY|
|
||||||
|
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
|
||||||
|
BTRFS_SNAPSHOT_RECURSIVE);
|
||||||
|
else
|
||||||
|
r = copy_tree(i->final_path, t, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_HARDLINKS, NULL, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to create original download image: %m");
|
||||||
|
}
|
||||||
|
|
||||||
source = t;
|
source = t;
|
||||||
} else
|
} else
|
||||||
@@ -264,8 +316,8 @@ static int tar_pull_make_local_copy(TarPull *i) {
|
|||||||
r = install_file(AT_FDCWD, source,
|
r = install_file(AT_FDCWD, source,
|
||||||
AT_FDCWD, p,
|
AT_FDCWD, p,
|
||||||
(i->flags & IMPORT_FORCE ? INSTALL_REPLACE : 0) |
|
(i->flags & IMPORT_FORCE ? INSTALL_REPLACE : 0) |
|
||||||
(i->flags & IMPORT_READ_ONLY ? INSTALL_READ_ONLY : 0) |
|
(i->flags & IMPORT_READ_ONLY ? INSTALL_READ_ONLY|INSTALL_GRACEFUL : 0) |
|
||||||
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
|
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS|INSTALL_GRACEFUL : 0));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to install local image '%s': %m", p);
|
return log_error_errno(r, "Failed to install local image '%s': %m", p);
|
||||||
|
|
||||||
@@ -427,8 +479,8 @@ static void tar_pull_job_on_finished(PullJob *j) {
|
|||||||
r = install_file(
|
r = install_file(
|
||||||
AT_FDCWD, i->local,
|
AT_FDCWD, i->local,
|
||||||
AT_FDCWD, NULL,
|
AT_FDCWD, NULL,
|
||||||
(i->flags & IMPORT_READ_ONLY ? INSTALL_READ_ONLY : 0) |
|
(i->flags & IMPORT_READ_ONLY ? INSTALL_READ_ONLY|INSTALL_GRACEFUL : 0) |
|
||||||
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
|
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS|INSTALL_GRACEFUL : 0));
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to finalize '%s': %m", i->local);
|
log_error_errno(r, "Failed to finalize '%s': %m", i->local);
|
||||||
goto finish;
|
goto finish;
|
||||||
@@ -453,8 +505,8 @@ static void tar_pull_job_on_finished(PullJob *j) {
|
|||||||
r = install_file(
|
r = install_file(
|
||||||
AT_FDCWD, i->temp_path,
|
AT_FDCWD, i->temp_path,
|
||||||
AT_FDCWD, i->final_path,
|
AT_FDCWD, i->final_path,
|
||||||
(i->flags & IMPORT_PULL_KEEP_DOWNLOAD ? INSTALL_READ_ONLY : 0) |
|
(i->flags & IMPORT_PULL_KEEP_DOWNLOAD ? INSTALL_READ_ONLY|INSTALL_GRACEFUL : 0) |
|
||||||
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
|
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS|INSTALL_GRACEFUL : 0));
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to rename to final image name to %s: %m", i->final_path);
|
log_error_errno(r, "Failed to rename to final image name to %s: %m", i->final_path);
|
||||||
goto finish;
|
goto finish;
|
||||||
@@ -480,7 +532,7 @@ static void tar_pull_job_on_finished(PullJob *j) {
|
|||||||
r = install_file(
|
r = install_file(
|
||||||
AT_FDCWD, i->settings_temp_path,
|
AT_FDCWD, i->settings_temp_path,
|
||||||
AT_FDCWD, i->settings_path,
|
AT_FDCWD, i->settings_path,
|
||||||
INSTALL_READ_ONLY|
|
INSTALL_READ_ONLY|INSTALL_GRACEFUL|
|
||||||
(i->flags & IMPORT_SYNC ? INSTALL_FSYNC_FULL : 0));
|
(i->flags & IMPORT_SYNC ? INSTALL_FSYNC_FULL : 0));
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to rename settings file to %s: %m", i->settings_path);
|
log_error_errno(r, "Failed to rename settings file to %s: %m", i->settings_path);
|
||||||
@@ -537,26 +589,42 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
|
|||||||
if (FLAGS_SET(i->flags, IMPORT_DIRECT|IMPORT_FORCE))
|
if (FLAGS_SET(i->flags, IMPORT_DIRECT|IMPORT_FORCE))
|
||||||
(void) rm_rf(where, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
|
(void) rm_rf(where, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
|
||||||
|
|
||||||
if (i->flags & IMPORT_BTRFS_SUBVOL)
|
if (FLAGS_SET(i->flags, IMPORT_FOREIGN_UID)) {
|
||||||
r = btrfs_subvol_make_fallback(AT_FDCWD, where, 0755);
|
r = import_make_foreign_userns(&i->userns_fd);
|
||||||
else
|
if (r < 0)
|
||||||
r = RET_NERRNO(mkdir(where, 0755));
|
return r;
|
||||||
if (r == -EEXIST && (i->flags & IMPORT_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
|
|
||||||
* because in that case our temporary path collided */
|
_cleanup_close_ int directory_fd = -EBADF;
|
||||||
r = 0;
|
r = mountfsd_make_directory(where, /* flags= */ 0, &directory_fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to create directory/subvolume %s: %m", where);
|
return r;
|
||||||
if (r > 0 && (i->flags & IMPORT_BTRFS_QUOTA)) { /* actually btrfs subvol */
|
|
||||||
if (!(i->flags & IMPORT_DIRECT))
|
r = mountfsd_mount_directory_fd(directory_fd, i->userns_fd, DISSECT_IMAGE_FOREIGN_UID, &i->tree_fd);
|
||||||
(void) import_assign_pool_quota_and_warn(i->image_root);
|
if (r < 0)
|
||||||
(void) import_assign_pool_quota_and_warn(where);
|
return r;
|
||||||
|
} else {
|
||||||
|
if (i->flags & IMPORT_BTRFS_SUBVOL)
|
||||||
|
r = btrfs_subvol_make_fallback(AT_FDCWD, where, 0755);
|
||||||
|
else
|
||||||
|
r = RET_NERRNO(mkdir(where, 0755));
|
||||||
|
if (r == -EEXIST && (i->flags & IMPORT_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
|
||||||
|
* because in that case our temporary path collided */
|
||||||
|
r = 0;
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to create directory/subvolume %s: %m", where);
|
||||||
|
|
||||||
|
if (r > 0 && (i->flags & IMPORT_BTRFS_QUOTA)) { /* actually btrfs subvol */
|
||||||
|
if (!(i->flags & IMPORT_DIRECT))
|
||||||
|
(void) import_assign_pool_quota_and_warn(i->image_root);
|
||||||
|
(void) import_assign_pool_quota_and_warn(where);
|
||||||
|
}
|
||||||
|
|
||||||
|
i->tree_fd = open(where, O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
|
||||||
|
if (i->tree_fd < 0)
|
||||||
|
return log_error_errno(errno, "Failed to open '%s': %m", where);
|
||||||
}
|
}
|
||||||
|
|
||||||
i->tree_fd = open(where, O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
|
j->disk_fd = import_fork_tar_x(i->tree_fd, i->userns_fd, &i->tar_pid);
|
||||||
if (i->tree_fd < 0)
|
|
||||||
return log_error_errno(errno, "Failed to open '%s': %m", where);
|
|
||||||
|
|
||||||
j->disk_fd = import_fork_tar_x(i->tree_fd, &i->tar_pid);
|
|
||||||
if (j->disk_fd < 0)
|
if (j->disk_fd < 0)
|
||||||
return j->disk_fd;
|
return j->disk_fd;
|
||||||
|
|
||||||
|
|||||||
@@ -560,6 +560,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
if (auto_keep_download)
|
if (auto_keep_download)
|
||||||
SET_FLAG(arg_import_flags, IMPORT_PULL_KEEP_DOWNLOAD, arg_class == IMAGE_MACHINE);
|
SET_FLAG(arg_import_flags, IMPORT_PULL_KEEP_DOWNLOAD, arg_class == IMAGE_MACHINE);
|
||||||
|
|
||||||
|
if (arg_runtime_scope == RUNTIME_SCOPE_USER)
|
||||||
|
arg_import_flags |= IMPORT_FOREIGN_UID;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+105
-6
@@ -4848,14 +4848,17 @@ int mountfsd_mount_image(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int mountfsd_mount_directory(
|
int mountfsd_mount_directory_fd(
|
||||||
const char *path,
|
int directory_fd,
|
||||||
int userns_fd,
|
int userns_fd,
|
||||||
DissectImageFlags flags,
|
DissectImageFlags flags,
|
||||||
int *ret_mount_fd) {
|
int *ret_mount_fd) {
|
||||||
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
assert(directory_fd >= 0);
|
||||||
|
assert(ret_mount_fd);
|
||||||
|
|
||||||
/* Pick one identity, not both, that makes no sense. */
|
/* Pick one identity, not both, that makes no sense. */
|
||||||
assert(!FLAGS_SET(flags, DISSECT_IMAGE_FOREIGN_UID|DISSECT_IMAGE_IDENTITY_UID));
|
assert(!FLAGS_SET(flags, DISSECT_IMAGE_FOREIGN_UID|DISSECT_IMAGE_IDENTITY_UID));
|
||||||
|
|
||||||
@@ -4872,10 +4875,6 @@ int mountfsd_mount_directory(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to enable varlink fd passing for write: %m");
|
return log_error_errno(r, "Failed to enable varlink fd passing for write: %m");
|
||||||
|
|
||||||
_cleanup_close_ int directory_fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH);
|
|
||||||
if (directory_fd < 0)
|
|
||||||
return log_error_errno(errno, "Failed to open '%s': %m", path);
|
|
||||||
|
|
||||||
r = sd_varlink_push_dup_fd(vl, directory_fd);
|
r = sd_varlink_push_dup_fd(vl, directory_fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to push directory fd into varlink connection: %m");
|
return log_error_errno(r, "Failed to push directory fd into varlink connection: %m");
|
||||||
@@ -4919,3 +4918,103 @@ int mountfsd_mount_directory(
|
|||||||
*ret_mount_fd = TAKE_FD(fsmount_fd);
|
*ret_mount_fd = TAKE_FD(fsmount_fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mountfsd_mount_directory(
|
||||||
|
const char *path,
|
||||||
|
int userns_fd,
|
||||||
|
DissectImageFlags flags,
|
||||||
|
int *ret_mount_fd) {
|
||||||
|
|
||||||
|
assert(path);
|
||||||
|
assert(ret_mount_fd);
|
||||||
|
|
||||||
|
_cleanup_close_ int directory_fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH);
|
||||||
|
if (directory_fd < 0)
|
||||||
|
return log_error_errno(errno, "Failed to open '%s': %m", path);
|
||||||
|
|
||||||
|
return mountfsd_mount_directory_fd(directory_fd, userns_fd, flags, ret_mount_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mountfsd_make_directory_fd(
|
||||||
|
int parent_fd,
|
||||||
|
const char *name,
|
||||||
|
DissectImageFlags flags,
|
||||||
|
int *ret_directory_fd) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(parent_fd >= 0);
|
||||||
|
assert(name);
|
||||||
|
assert(ret_directory_fd);
|
||||||
|
|
||||||
|
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
|
||||||
|
r = sd_varlink_connect_address(&vl, "/run/systemd/io.systemd.MountFileSystem");
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to connect to mountfsd: %m");
|
||||||
|
|
||||||
|
r = sd_varlink_set_allow_fd_passing_input(vl, true);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to enable varlink fd passing for read: %m");
|
||||||
|
|
||||||
|
r = sd_varlink_set_allow_fd_passing_output(vl, true);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to enable varlink fd passing for write: %m");
|
||||||
|
|
||||||
|
r = sd_varlink_push_dup_fd(vl, parent_fd);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to push parent fd into varlink connection: %m");
|
||||||
|
|
||||||
|
sd_json_variant *reply = NULL;
|
||||||
|
const char *error_id = NULL;
|
||||||
|
r = varlink_callbo_and_log(
|
||||||
|
vl,
|
||||||
|
"io.systemd.MountFileSystem.MakeDirectory",
|
||||||
|
&reply,
|
||||||
|
&error_id,
|
||||||
|
SD_JSON_BUILD_PAIR_UNSIGNED("parentFileDescriptor", 0),
|
||||||
|
SD_JSON_BUILD_PAIR_STRING("name", name),
|
||||||
|
SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", FLAGS_SET(flags, DISSECT_IMAGE_ALLOW_INTERACTIVE_AUTH)));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
static const sd_json_dispatch_field dispatch_table[] = {
|
||||||
|
{ "directoryFileDescriptor", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint, 0, SD_JSON_MANDATORY },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned directory_fd_idx = UINT_MAX;
|
||||||
|
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &directory_fd_idx);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse MountImage() reply: %m");
|
||||||
|
|
||||||
|
_cleanup_close_ int directory_fd = sd_varlink_take_fd(vl, directory_fd_idx);
|
||||||
|
if (directory_fd < 0)
|
||||||
|
return log_error_errno(directory_fd, "Failed to take directory fd from Varlink connection: %m");
|
||||||
|
|
||||||
|
*ret_directory_fd = TAKE_FD(directory_fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mountfsd_make_directory(
|
||||||
|
const char *path,
|
||||||
|
DissectImageFlags flags,
|
||||||
|
int *ret_directory_fd) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
_cleanup_free_ char *parent = NULL;
|
||||||
|
r = path_extract_directory(path, &parent);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to extract parent directory from '%s': %m", path);
|
||||||
|
|
||||||
|
_cleanup_free_ char *dirname = NULL;
|
||||||
|
r = path_extract_filename(path, &dirname);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to extract directory name from '%s': %m", path);
|
||||||
|
|
||||||
|
_cleanup_close_ int fd = open(parent, O_DIRECTORY|O_CLOEXEC);
|
||||||
|
if (fd < 0)
|
||||||
|
return log_error_errno(r, "Failed to open '%s': %m", parent);
|
||||||
|
|
||||||
|
return mountfsd_make_directory_fd(fd, dirname, flags, ret_directory_fd);
|
||||||
|
}
|
||||||
|
|||||||
@@ -258,4 +258,8 @@ static inline const char* dissected_partition_fstype(const DissectedPartition *m
|
|||||||
int get_common_dissect_directory(char **ret);
|
int get_common_dissect_directory(char **ret);
|
||||||
|
|
||||||
int mountfsd_mount_image(const char *path, int userns_fd, const ImagePolicy *image_policy, const VeritySettings *verity, DissectImageFlags flags, DissectedImage **ret);
|
int mountfsd_mount_image(const char *path, int userns_fd, const ImagePolicy *image_policy, const VeritySettings *verity, DissectImageFlags flags, DissectedImage **ret);
|
||||||
|
int mountfsd_mount_directory_fd(int directory_fd, int userns_fd, DissectImageFlags flags, int *ret_mount_fd);
|
||||||
int mountfsd_mount_directory(const char *path, int userns_fd, DissectImageFlags flags, int *ret_mount_fd);
|
int mountfsd_mount_directory(const char *path, int userns_fd, DissectImageFlags flags, int *ret_mount_fd);
|
||||||
|
|
||||||
|
int mountfsd_make_directory_fd(int parent_fd, const char *name, DissectImageFlags flags, int *ret_directory_fd);
|
||||||
|
int mountfsd_make_directory(const char *path, DissectImageFlags flags, int *ret_directory_fd);
|
||||||
|
|||||||
Reference in New Issue
Block a user