From: Lennart Poettering Date: Mon, 11 Nov 2024 16:45:18 +0000 (+0100) Subject: dissect-image: add client side API wrapper for MountDirectory() varlink call X-Git-Tag: v258-rc1~1502^2~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e57f99305e9ae75848861b6b61cd04eeb82a5f4d;p=thirdparty%2Fsystemd.git dissect-image: add client side API wrapper for MountDirectory() varlink call This is simply a Varlink API client that taks a directory path and userns fd and returns a mount fd. --- diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index ce1fa3a3d4e..e4ae8947821 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -2170,6 +2170,9 @@ int dissected_image_mount( assert(m); + if (FLAGS_SET(flags, DISSECT_IMAGE_FOREIGN_UID)) /* For image based mounts we currently require an identity mapping */ + return -EOPNOTSUPP; + /* If 'where' is NULL then we'll use the new mount API to create fsmount() fds for the mounts and * store them in DissectedPartition.fsmount_fd. * @@ -4409,3 +4412,78 @@ int mountfsd_mount_image( return -EOPNOTSUPP; #endif } + +int mountfsd_mount_directory( + const char *path, + int userns_fd, + DissectImageFlags flags, + int *ret_mount_fd) { + + int r; + + /* Pick one identity, not both, that makes no sense. */ + assert(!FLAGS_SET(flags, DISSECT_IMAGE_FOREIGN_UID|DISSECT_IMAGE_IDENTITY_UID)); + + _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"); + + _cleanup_close_ int directory_fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC); + if (directory_fd < 0) + return log_error_errno(errno, "Failed to open '%s': %m", path); + + r = sd_varlink_push_dup_fd(vl, directory_fd); + if (r < 0) + return log_error_errno(r, "Failed to push image fd into varlink connection: %m"); + + if (userns_fd >= 0) { + r = sd_varlink_push_dup_fd(vl, userns_fd); + if (r < 0) + return log_error_errno(r, "Failed to push image fd into varlink connection: %m"); + } + + sd_json_variant *reply = NULL; + const char *error_id = NULL; + r = sd_varlink_callbo( + vl, + "io.systemd.MountFileSystem.MountDirectory", + &reply, + &error_id, + SD_JSON_BUILD_PAIR_UNSIGNED("directoryFileDescriptor", 0), + SD_JSON_BUILD_PAIR_CONDITION(userns_fd >= 0, "userNamespaceFileDescriptor", SD_JSON_BUILD_UNSIGNED(1)), + SD_JSON_BUILD_PAIR_BOOLEAN("readOnly", FLAGS_SET(flags, DISSECT_IMAGE_MOUNT_READ_ONLY)), + SD_JSON_BUILD_PAIR_STRING("mode", FLAGS_SET(flags, DISSECT_IMAGE_FOREIGN_UID) ? "foreign" : + FLAGS_SET(flags, DISSECT_IMAGE_IDENTITY_UID) ? "identity" : "auto"), + SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", FLAGS_SET(flags, DISSECT_IMAGE_ALLOW_INTERACTIVE_AUTH))); + if (r < 0) + return log_error_errno(r, "Failed to call MountDirectory() varlink call: %m"); + if (!isempty(error_id)) + return log_error_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to call MountDirectory() varlink call: %s", error_id); + + + static const sd_json_dispatch_field dispatch_table[] = { + { "mountFileDescriptor", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint, 0, SD_JSON_MANDATORY }, + {} + }; + + unsigned fsmount_fd_idx = UINT_MAX; + r = sd_json_dispatch(reply, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &fsmount_fd_idx); + if (r < 0) + return log_error_errno(r, "Failed to parse MountImage() reply: %m"); + + _cleanup_close_ int fsmount_fd = sd_varlink_take_fd(vl, fsmount_fd_idx); + if (fsmount_fd < 0) + return log_error_errno(fsmount_fd, "Failed to take mount fd from Varlink connection: %m"); + + *ret_mount_fd = TAKE_FD(fsmount_fd); + return 0; +} diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 2c118b97ef5..c001915e894 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -89,6 +89,8 @@ typedef enum DissectImageFlags { DISSECT_IMAGE_TRY_ATOMIC_MOUNT_EXCHANGE = 1 << 25, /* Try to mount the image beneath the specified mountpoint, rather than on top of it, and then umount the top */ DISSECT_IMAGE_ALLOW_USERSPACE_VERITY = 1 << 26, /* Allow userspace verity keyring in /etc/verity.d/ and related dirs */ DISSECT_IMAGE_ALLOW_INTERACTIVE_AUTH = 1 << 27, /* Allow interactive authorization when going through mountfsd */ + DISSECT_IMAGE_FOREIGN_UID = 1 << 28, /* Request a foreign UID range mapping */ + DISSECT_IMAGE_IDENTITY_UID = 1 << 29, /* Explicitly request an identity UID range mapping */ } DissectImageFlags; struct DissectedImage { @@ -244,3 +246,4 @@ static inline const char* dissected_partition_fstype(const DissectedPartition *m int get_common_dissect_directory(char **ret); int mountfsd_mount_image(const char *path, int userns_fd, const ImagePolicy *image_policy, DissectImageFlags flags, DissectedImage **ret); +int mountfsd_mount_directory(const char *path, int userns_fd, DissectImageFlags flags, int *ret_mount_fd);