1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-11 20:58:27 +03:00

Merge pull request #29339 from bluca/mount_namespace_new_api

Use new mount API for bind/image mount tunnel
This commit is contained in:
Luca Boccassi 2023-10-02 16:04:26 +01:00 committed by GitHub
commit df3e378a5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 640 additions and 203 deletions

View File

@ -674,6 +674,21 @@ bool mount_propagation_flag_is_valid(unsigned long flag) {
return IN_SET(flag, 0, MS_SHARED, MS_PRIVATE, MS_SLAVE);
}
bool mount_new_api_supported(void) {
static int cache = -1;
int r;
if (cache >= 0)
return cache;
/* This is the newer API among the ones we use, so use it as boundary */
r = RET_NERRNO(mount_setattr(-EBADF, NULL, 0, NULL, 0));
if (r == 0 || ERRNO_IS_NOT_SUPPORTED(r)) /* This should return an error if it is working properly */
return (cache = false);
return (cache = true);
}
unsigned long ms_nosymfollow_supported(void) {
_cleanup_close_ int fsfd = -EBADF, mntfd = -EBADF;
static int cache = -1;
@ -683,6 +698,9 @@ unsigned long ms_nosymfollow_supported(void) {
if (cache >= 0)
return cache ? MS_NOSYMFOLLOW : 0;
if (!mount_new_api_supported())
goto not_supported;
/* Checks if MS_NOSYMFOLLOW is supported (which was added in 5.10). We use the new mount API's
* mount_setattr() call for that, which was added in 5.12, which is close enough. */

View File

@ -65,6 +65,7 @@ const char *mount_propagation_flag_to_string(unsigned long flags);
int mount_propagation_flag_from_string(const char *name, unsigned long *ret);
bool mount_propagation_flag_is_valid(unsigned long flag);
bool mount_new_api_supported(void);
unsigned long ms_nosymfollow_supported(void);
int mount_option_supported(const char *fstype, const char *key, const char *value);

View File

@ -1311,7 +1311,8 @@ static int mount_image(
host_os_release_id,
host_os_release_version_id,
host_os_release_level,
NULL);
/* required_sysext_scope= */ NULL,
/* ret_image= */ NULL);
if (r == -ENOENT && m->ignore)
return 0;
if (r == -ESTALE && host_os_release_id)
@ -2494,7 +2495,13 @@ int setup_namespace(
if (root_image) {
/* A root image is specified, mount it to the right place */
r = dissected_image_mount(dissected_image, root, UID_INVALID, UID_INVALID, dissect_image_flags);
r = dissected_image_mount(
dissected_image,
root,
/* uid_shift= */ UID_INVALID,
/* uid_range= */ UID_INVALID,
/* userns_fd= */ -EBADF,
dissect_image_flags);
if (r < 0) {
log_debug_errno(r, "Failed to mount root image: %m");
goto finish;

View File

@ -1063,7 +1063,13 @@ static int action_mount(DissectedImage *m, LoopDevice *d) {
assert(d);
assert(arg_action == ACTION_MOUNT);
r = dissected_image_mount_and_warn(m, arg_path, UID_INVALID, UID_INVALID, arg_flags);
r = dissected_image_mount_and_warn(
m,
arg_path,
/* uid_shift= */ UID_INVALID,
/* uid_range= */ UID_INVALID,
/* userns_fd= */ -EBADF,
arg_flags);
if (r < 0)
return r;
@ -1298,7 +1304,13 @@ static int action_list_or_mtree_or_copy(DissectedImage *m, LoopDevice *d) {
created_dir = TAKE_PTR(temp);
r = dissected_image_mount_and_warn(m, created_dir, UID_INVALID, UID_INVALID, arg_flags);
r = dissected_image_mount_and_warn(
m,
created_dir,
/* uid_shift= */ UID_INVALID,
/* uid_range= */ UID_INVALID,
/* userns_fd= */ -EBADF,
arg_flags);
if (r < 0)
return r;
@ -1549,7 +1561,13 @@ static int action_with(DissectedImage *m, LoopDevice *d) {
created_dir = TAKE_PTR(temp);
r = dissected_image_mount_and_warn(m, created_dir, UID_INVALID, UID_INVALID, arg_flags);
r = dissected_image_mount_and_warn(
m,
created_dir,
/* uid_shift= */ UID_INVALID,
/* uid_range= */ UID_INVALID,
/* userns_fd= */ -EBADF,
arg_flags);
if (r < 0)
return r;

View File

@ -3681,6 +3681,7 @@ static int outer_child(
directory,
arg_uid_shift,
arg_uid_range,
/* userns_fd= */ -EBADF,
DISSECT_IMAGE_MOUNT_ROOT_ONLY|
DISSECT_IMAGE_DISCARD_ON_LOOP|
DISSECT_IMAGE_USR_NO_ROOT|
@ -3845,6 +3846,7 @@ static int outer_child(
directory,
arg_uid_shift,
arg_uid_range,
/* userns_fd= */ -EBADF,
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY|
DISSECT_IMAGE_DISCARD_ON_LOOP|
DISSECT_IMAGE_USR_NO_ROOT|

View File

@ -424,7 +424,13 @@ static int portable_extract_by_path(
else
flags |= DISSECT_IMAGE_VALIDATE_OS;
r = dissected_image_mount(m, tmpdir, UID_INVALID, UID_INVALID, flags);
r = dissected_image_mount(
m,
tmpdir,
/* uid_shift= */ UID_INVALID,
/* uid_range= */ UID_INVALID,
/* userns_fd= */ -EBADF,
flags);
if (r < 0) {
log_debug_errno(r, "Failed to mount dissected image: %m");
goto child_finish;

View File

@ -51,6 +51,7 @@
#include "import-util.h"
#include "io-util.h"
#include "missing_mount.h"
#include "missing_syscall.h"
#include "mkdir-label.h"
#include "mount-util.h"
#include "mountpoint-util.h"
@ -515,6 +516,7 @@ static void dissected_partition_done(DissectedPartition *p) {
free(p->decrypted_node);
free(p->mount_options);
safe_close(p->mount_node_fd);
safe_close(p->fsmount_fd);
*p = DISSECTED_PARTITION_NULL;
}
@ -836,6 +838,7 @@ static int dissect_image(
.mount_node_fd = TAKE_FD(mount_node_fd),
.offset = 0,
.size = UINT64_MAX,
.fsmount_fd = -EBADF,
};
return 0;
@ -1252,6 +1255,7 @@ static int dissect_image(
.offset = (uint64_t) start * 512,
.size = (uint64_t) size * 512,
.gpt_flags = pflags,
.fsmount_fd = -EBADF,
};
}
@ -1326,6 +1330,7 @@ static int dissect_image(
.mount_node_fd = TAKE_FD(mount_node_fd),
.offset = (uint64_t) start * 512,
.size = (uint64_t) size * 512,
.fsmount_fd = -EBADF,
};
break;
@ -1416,6 +1421,7 @@ static int dissect_image(
.mount_node_fd = TAKE_FD(mount_node_fd),
.offset = UINT64_MAX,
.size = UINT64_MAX,
.fsmount_fd = -EBADF,
};
}
}
@ -1739,11 +1745,15 @@ static int run_fsck(int node_fd, const char *fstype) {
return 0;
}
static int fs_grow(const char *node_path, const char *mount_path) {
_cleanup_close_ int mount_fd = -EBADF, node_fd = -EBADF;
static int fs_grow(const char *node_path, int mount_fd, const char *mount_path) {
_cleanup_close_ int _mount_fd = -EBADF, node_fd = -EBADF;
uint64_t size, newsize;
const char *id;
int r;
assert(node_path);
assert(mount_fd >= 0 || mount_path);
node_fd = open(node_path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (node_fd < 0)
return log_debug_errno(errno, "Failed to open node device %s: %m", node_path);
@ -1751,22 +1761,34 @@ static int fs_grow(const char *node_path, const char *mount_path) {
if (ioctl(node_fd, BLKGETSIZE64, &size) != 0)
return log_debug_errno(errno, "Failed to get block device size of %s: %m", node_path);
mount_fd = open(mount_path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
if (mount_fd < 0)
return log_debug_errno(errno, "Failed to open mountd file system %s: %m", mount_path);
if (mount_fd < 0) {
assert(mount_path);
log_debug("Resizing \"%s\" to %"PRIu64" bytes...", mount_path, size);
_mount_fd = open(mount_path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
if (_mount_fd < 0)
return log_debug_errno(errno, "Failed to open mounted file system %s: %m", mount_path);
mount_fd = _mount_fd;
} else {
mount_fd = fd_reopen_condition(mount_fd, O_RDONLY|O_DIRECTORY|O_CLOEXEC, O_RDONLY|O_DIRECTORY|O_CLOEXEC, &_mount_fd);
if (mount_fd < 0)
return log_debug_errno(errno, "Failed to reopen mount node: %m");
}
id = mount_path ?: node_path;
log_debug("Resizing \"%s\" to %"PRIu64" bytes...", id, size);
r = resize_fs(mount_fd, size, &newsize);
if (r < 0)
return log_debug_errno(r, "Failed to resize \"%s\" to %"PRIu64" bytes: %m", mount_path, size);
return log_debug_errno(r, "Failed to resize \"%s\" to %"PRIu64" bytes: %m", id, size);
if (newsize == size)
log_debug("Successfully resized \"%s\" to %s bytes.",
mount_path, FORMAT_BYTES(newsize));
id, FORMAT_BYTES(newsize));
else {
assert(newsize < size);
log_debug("Successfully resized \"%s\" to %s bytes (%"PRIu64" bytes lost due to blocksize).",
mount_path, FORMAT_BYTES(newsize), size - newsize);
id, FORMAT_BYTES(newsize), size - newsize);
}
return 0;
@ -1863,6 +1885,14 @@ int partition_pick_mount_options(
return 0;
}
static bool need_user_mapping(uid_t uid_shift, uid_t uid_range) {
if (!uid_is_valid(uid_shift))
return false;
return uid_shift != 0 || uid_range != UINT32_MAX;
}
static int mount_partition(
PartitionDesignator d,
DissectedPartition *m,
@ -1870,81 +1900,92 @@ static int mount_partition(
const char *directory,
uid_t uid_shift,
uid_t uid_range,
int userns_fd,
DissectImageFlags flags) {
_cleanup_free_ char *chased = NULL, *options = NULL;
bool rw, discard, remap_uid_gid = false;
const char *p, *node, *fstype;
const char *p = NULL, *node, *fstype = NULL;
bool rw, discard, grow;
unsigned long ms_flags;
int r;
assert(m);
assert(where);
if (m->mount_node_fd < 0)
if (!m->found)
return 0;
/* Use decrypted node and matching fstype if available, otherwise use the original device */
node = FORMAT_PROC_FD_PATH(m->mount_node_fd);
fstype = dissected_partition_fstype(m);
/* Check the various combinations when we can't do anything anymore */
if (m->fsmount_fd < 0 && m->mount_node_fd < 0)
return 0;
if (m->fsmount_fd >= 0 && !where)
return 0;
if (!where && m->mount_node_fd < 0)
return 0;
if (!fstype)
return -EAFNOSUPPORT;
if (m->fsmount_fd < 0) {
fstype = dissected_partition_fstype(m);
if (!fstype)
return -EAFNOSUPPORT;
/* We are looking at an encrypted partition? This either means stacked encryption, or the caller
* didn't call dissected_image_decrypt() beforehand. Let's return a recognizable error for this
* case. */
if (streq(fstype, "crypto_LUKS"))
return -EUNATCH;
/* We are looking at an encrypted partition? This either means stacked encryption, or the
* caller didn't call dissected_image_decrypt() beforehand. Let's return a recognizable error
* for this case. */
if (streq(fstype, "crypto_LUKS"))
return -EUNATCH;
r = dissect_fstype_ok(fstype);
if (r < 0)
return r;
if (!r)
return -EIDRM; /* Recognizable error */
r = dissect_fstype_ok(fstype);
if (r < 0)
return r;
if (!r)
return -EIDRM; /* Recognizable error */
}
node = m->mount_node_fd < 0 ? NULL : FORMAT_PROC_FD_PATH(m->mount_node_fd);
rw = m->rw && !(flags & DISSECT_IMAGE_MOUNT_READ_ONLY);
discard = ((flags & DISSECT_IMAGE_DISCARD) ||
((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node) > 0));
((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && (m->node && is_loop_device(m->node) > 0)));
if (FLAGS_SET(flags, DISSECT_IMAGE_FSCK) && rw) {
grow = rw && m->growfs && FLAGS_SET(flags, DISSECT_IMAGE_GROWFS);
if (FLAGS_SET(flags, DISSECT_IMAGE_FSCK) && rw && m->mount_node_fd >= 0 && m->fsmount_fd < 0) {
r = run_fsck(m->mount_node_fd, fstype);
if (r < 0)
return r;
}
if (directory) {
/* Automatically create missing mount points inside the image, if necessary. */
r = mkdir_p_root(where, directory, uid_shift, (gid_t) uid_shift, 0755, NULL);
if (r < 0 && r != -EROFS)
return r;
if (where) {
if (directory) {
/* Automatically create missing mount points inside the image, if necessary. */
r = mkdir_p_root(where, directory, uid_shift, (gid_t) uid_shift, 0755, NULL);
if (r < 0 && r != -EROFS)
return r;
r = chase(directory, where, CHASE_PREFIX_ROOT, &chased, NULL);
r = chase(directory, where, CHASE_PREFIX_ROOT, &chased, NULL);
if (r < 0)
return r;
p = chased;
} else {
/* Create top-level mount if missing but only if this is asked for. This won't modify the
* image (as the branch above does) but the host hierarchy, and the created directory might
* survive our mount in the host hierarchy hence. */
if (FLAGS_SET(flags, DISSECT_IMAGE_MKDIR)) {
r = mkdir_p(where, 0755);
if (r < 0)
return r;
}
p = where;
}
}
if (m->fsmount_fd < 0) {
r = partition_pick_mount_options(d, fstype, rw, discard, &options, &ms_flags);
if (r < 0)
return r;
p = chased;
} else {
/* Create top-level mount if missing but only if this is asked for. This won't modify the
* image (as the branch above does) but the host hierarchy, and the created directory might
* survive our mount in the host hierarchy hence. */
if (FLAGS_SET(flags, DISSECT_IMAGE_MKDIR)) {
r = mkdir_p(where, 0755);
if (r < 0)
return r;
}
p = where;
}
r = partition_pick_mount_options(d, dissected_partition_fstype(m), rw, discard, &options, &ms_flags);
if (r < 0)
return r;
if (uid_is_valid(uid_shift) && uid_shift != 0) {
if (fstype_can_uid_gid(fstype)) {
if (need_user_mapping(uid_shift, uid_range) && fstype_can_uid_gid(fstype)) {
_cleanup_free_ char *uid_option = NULL;
if (asprintf(&uid_option, "uid=" UID_FMT ",gid=" GID_FMT, uid_shift, (gid_t) uid_shift) < 0)
@ -1952,31 +1993,56 @@ static int mount_partition(
if (!strextend_with_separator(&options, ",", uid_option))
return -ENOMEM;
} else if (FLAGS_SET(flags, DISSECT_IMAGE_MOUNT_IDMAPPED))
remap_uid_gid = true;
userns_fd = -EBADF; /* Not needed */
}
if (!isempty(m->mount_options))
if (!strextend_with_separator(&options, ",", m->mount_options))
return -ENOMEM;
}
if (!isempty(m->mount_options))
if (!strextend_with_separator(&options, ",", m->mount_options))
return -ENOMEM;
if (p) {
if (m->fsmount_fd >= 0) {
/* Case #1: Attach existing fsmount fd to the file system */
r = mount_nofollow_verbose(LOG_DEBUG, node, p, fstype, ms_flags, options);
if (r < 0)
return r;
if (move_mount(m->fsmount_fd, "", -EBADF, p, MOVE_MOUNT_F_EMPTY_PATH) < 0)
return -errno;
if (rw && m->growfs && FLAGS_SET(flags, DISSECT_IMAGE_GROWFS))
(void) fs_grow(node, p);
} else {
assert(node);
if (remap_uid_gid) {
r = remount_idmap(p, uid_shift, uid_range, UID_INVALID, REMOUNT_IDMAPPING_HOST_ROOT);
if (r < 0)
return r;
/* Case #2: Mount directly into place */
r = mount_nofollow_verbose(LOG_DEBUG, node, p, fstype, ms_flags, options);
if (r < 0)
return r;
if (grow)
(void) fs_grow(node, -EBADF, p);
if (userns_fd >= 0) {
r = remount_idmap_fd(p, userns_fd);
if (r < 0)
return r;
}
}
} else {
assert(node);
/* Case #3: Create fsmount fd */
m->fsmount_fd = make_fsmount(LOG_DEBUG, node, fstype, ms_flags, options, userns_fd);
if (m->fsmount_fd < 0)
return m->fsmount_fd;
if (grow)
(void) fs_grow(node, m->fsmount_fd, NULL);
}
return 1;
}
static int mount_root_tmpfs(const char *where, uid_t uid_shift, DissectImageFlags flags) {
static int mount_root_tmpfs(const char *where, uid_t uid_shift, uid_t uid_range, DissectImageFlags flags) {
_cleanup_free_ char *options = NULL;
int r;
@ -1990,7 +2056,7 @@ static int mount_root_tmpfs(const char *where, uid_t uid_shift, DissectImageFlag
return r;
}
if (uid_is_valid(uid_shift)) {
if (need_user_mapping(uid_shift, uid_range)) {
if (asprintf(&options, "uid=" UID_FMT ",gid=" GID_FMT, uid_shift, (gid_t) uid_shift) < 0)
return -ENOMEM;
}
@ -2028,14 +2094,25 @@ int dissected_image_mount(
const char *where,
uid_t uid_shift,
uid_t uid_range,
int userns_fd,
DissectImageFlags flags) {
_cleanup_close_ int my_userns_fd = -EBADF;
int r;
assert(m);
assert(where);
/* Returns:
/* 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.
*
* If 'where' is not NULL then we'll either mount the partitions to the right places ourselves,
* or use DissectedPartition.fsmount_fd and bind it to the right places.
*
* This allows splitting the setting up up the superblocks and the binding to file systems paths into
* two distinct and differently privileged components: one that gets the fsmount fds, and the other
* that then applies them.
*
* Returns:
*
* -ENXIO No root partition found
* -EMEDIUMTYPE DISSECT_IMAGE_VALIDATE_OS set but no os-release/extension-release file found
@ -2046,82 +2123,103 @@ int dissected_image_mount(
* -EIDRM File system is not among allowlisted "common" file systems
*/
if (!where && (flags & (DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_VALIDATE_OS_EXT)) != 0)
return -EOPNOTSUPP; /* for now, not supported */
if (!(m->partitions[PARTITION_ROOT].found ||
(m->partitions[PARTITION_USR].found && FLAGS_SET(flags, DISSECT_IMAGE_USR_NO_ROOT))))
return -ENXIO; /* Require a root fs or at least a /usr/ fs (the latter is subject to a flag of its own) */
if (userns_fd < 0 && need_user_mapping(uid_shift, uid_range) && FLAGS_SET(flags, DISSECT_IMAGE_MOUNT_IDMAPPED)) {
my_userns_fd = make_userns(uid_shift, uid_range, UID_INVALID, REMOUNT_IDMAPPING_HOST_ROOT);
if (my_userns_fd < 0)
return my_userns_fd;
userns_fd = my_userns_fd;
}
if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY) == 0) {
/* First mount the root fs. If there's none we use a tmpfs. */
if (m->partitions[PARTITION_ROOT].found)
r = mount_partition(PARTITION_ROOT, m->partitions + PARTITION_ROOT, where, NULL, uid_shift, uid_range, flags);
else
r = mount_root_tmpfs(where, uid_shift, flags);
if (r < 0)
return r;
if (m->partitions[PARTITION_ROOT].found) {
r = mount_partition(PARTITION_ROOT, m->partitions + PARTITION_ROOT, where, NULL, uid_shift, uid_range, userns_fd, flags);
if (r < 0)
return r;
} else if (where) {
r = mount_root_tmpfs(where, uid_shift, uid_range, flags);
if (r < 0)
return r;
}
/* For us mounting root always means mounting /usr as well */
r = mount_partition(PARTITION_USR, m->partitions + PARTITION_USR, where, "/usr", uid_shift, uid_range, flags);
r = mount_partition(PARTITION_USR, m->partitions + PARTITION_USR, where, "/usr", uid_shift, uid_range, userns_fd, flags);
if (r < 0)
return r;
}
if ((flags & (DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_VALIDATE_OS_EXT)) != 0) {
/* If either one of the validation flags are set, ensure that the image qualifies
* as one or the other (or both). */
bool ok = false;
if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY) == 0 &&
(flags & (DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_VALIDATE_OS_EXT)) != 0) {
/* If either one of the validation flags are set, ensure that the image qualifies as
* one or the other (or both). */
bool ok = false;
if (FLAGS_SET(flags, DISSECT_IMAGE_VALIDATE_OS)) {
r = path_is_os_tree(where);
assert(where);
if (FLAGS_SET(flags, DISSECT_IMAGE_VALIDATE_OS)) {
r = path_is_os_tree(where);
if (r < 0)
return r;
if (r > 0)
ok = true;
}
if (!ok && FLAGS_SET(flags, DISSECT_IMAGE_VALIDATE_OS_EXT)) {
r = extension_has_forbidden_content(where);
if (r < 0)
return r;
if (r == 0) {
r = path_is_extension_tree(IMAGE_SYSEXT, where, m->image_name, FLAGS_SET(flags, DISSECT_IMAGE_RELAX_EXTENSION_CHECK));
if (r == 0)
r = path_is_extension_tree(IMAGE_CONFEXT, where, m->image_name, FLAGS_SET(flags, DISSECT_IMAGE_RELAX_EXTENSION_CHECK));
if (r < 0)
return r;
if (r > 0)
ok = true;
}
if (!ok && FLAGS_SET(flags, DISSECT_IMAGE_VALIDATE_OS_EXT)) {
r = extension_has_forbidden_content(where);
if (r < 0)
return r;
if (r == 0) {
r = path_is_extension_tree(IMAGE_SYSEXT, where, m->image_name, FLAGS_SET(flags, DISSECT_IMAGE_RELAX_EXTENSION_CHECK));
if (r == 0)
r = path_is_extension_tree(IMAGE_CONFEXT, where, m->image_name, FLAGS_SET(flags, DISSECT_IMAGE_RELAX_EXTENSION_CHECK));
if (r < 0)
return r;
if (r > 0)
ok = true;
}
}
if (!ok)
return -ENOMEDIUM;
}
if (!ok)
return -ENOMEDIUM;
}
if (flags & DISSECT_IMAGE_MOUNT_ROOT_ONLY)
return 0;
r = mount_partition(PARTITION_HOME, m->partitions + PARTITION_HOME, where, "/home", uid_shift, uid_range, flags);
r = mount_partition(PARTITION_HOME, m->partitions + PARTITION_HOME, where, "/home", uid_shift, uid_range, userns_fd, flags);
if (r < 0)
return r;
r = mount_partition(PARTITION_SRV, m->partitions + PARTITION_SRV, where, "/srv", uid_shift, uid_range, flags);
r = mount_partition(PARTITION_SRV, m->partitions + PARTITION_SRV, where, "/srv", uid_shift, uid_range, userns_fd, flags);
if (r < 0)
return r;
r = mount_partition(PARTITION_VAR, m->partitions + PARTITION_VAR, where, "/var", uid_shift, uid_range, flags);
r = mount_partition(PARTITION_VAR, m->partitions + PARTITION_VAR, where, "/var", uid_shift, uid_range, userns_fd, flags);
if (r < 0)
return r;
r = mount_partition(PARTITION_TMP, m->partitions + PARTITION_TMP, where, "/var/tmp", uid_shift, uid_range, flags);
r = mount_partition(PARTITION_TMP, m->partitions + PARTITION_TMP, where, "/var/tmp", uid_shift, uid_range, userns_fd, flags);
if (r < 0)
return r;
int slash_boot_is_available;
r = slash_boot_is_available = mount_point_is_available(where, "/boot", /* missing_ok = */ true);
if (r < 0)
return r;
if (r > 0) {
r = mount_partition(PARTITION_XBOOTLDR, m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, uid_range, flags);
int slash_boot_is_available = 0;
if (where) {
r = slash_boot_is_available = mount_point_is_available(where, "/boot", /* missing_ok = */ true);
if (r < 0)
return r;
}
if (!where || slash_boot_is_available) {
r = mount_partition(PARTITION_XBOOTLDR, m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, uid_range, userns_fd, flags);
if (r < 0)
return r;
slash_boot_is_available = !r;
@ -2130,31 +2228,32 @@ int dissected_image_mount(
if (m->partitions[PARTITION_ESP].found) {
const char *esp_path = NULL;
/* Mount the ESP to /boot/ if it exists and is empty and we didn't already mount the XBOOTLDR
* partition into it. Otherwise, use /efi instead, but only if it exists and is empty. */
if (where) {
/* Mount the ESP to /boot/ if it exists and is empty and we didn't already mount the
* XBOOTLDR partition into it. Otherwise, use /efi instead, but only if it exists
* and is empty. */
if (slash_boot_is_available) {
r = mount_point_is_available(where, "/boot", /* missing_ok = */ false);
if (r < 0)
return r;
if (r > 0)
esp_path = "/boot";
if (slash_boot_is_available) {
r = mount_point_is_available(where, "/boot", /* missing_ok = */ false);
if (r < 0)
return r;
if (r > 0)
esp_path = "/boot";
}
if (!esp_path) {
r = mount_point_is_available(where, "/efi", /* missing_ok = */ true);
if (r < 0)
return r;
if (r > 0)
esp_path = "/efi";
}
}
if (!esp_path) {
r = mount_point_is_available(where, "/efi", /* missing_ok = */ true);
if (r < 0)
return r;
if (r > 0)
esp_path = "/efi";
}
if (esp_path) {
/* OK, let's mount the ESP now (possibly creating the dir if missing) */
r = mount_partition(PARTITION_ESP, m->partitions + PARTITION_ESP, where, esp_path, uid_shift, uid_range, flags);
if (r < 0)
return r;
}
/* OK, let's mount the ESP now (possibly creating the dir if missing) */
r = mount_partition(PARTITION_ESP, m->partitions + PARTITION_ESP, where, esp_path, uid_shift, uid_range, userns_fd, flags);
if (r < 0)
return r;
}
return 0;
@ -2165,14 +2264,14 @@ int dissected_image_mount_and_warn(
const char *where,
uid_t uid_shift,
uid_t uid_range,
int userns_fd,
DissectImageFlags flags) {
int r;
assert(m);
assert(where);
r = dissected_image_mount(m, where, uid_shift, uid_range, flags);
r = dissected_image_mount(m, where, uid_shift, uid_range, userns_fd, flags);
if (r == -ENXIO)
return log_error_errno(r, "Not root file system found in image.");
if (r == -EMEDIUMTYPE)
@ -3315,8 +3414,9 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
r = dissected_image_mount(
m,
t,
UID_INVALID,
UID_INVALID,
/* uid_shift= */ UID_INVALID,
/* uid_range= */ UID_INVALID,
/* userns_fd= */ -EBADF,
extra_flags |
DISSECT_IMAGE_READ_ONLY |
DISSECT_IMAGE_MOUNT_ROOT_ONLY |
@ -3755,6 +3855,7 @@ int mount_image_privately_interactively(
"/run/systemd/mount-rootfs",
/* uid_shift= */ UID_INVALID,
/* uid_range= */ UID_INVALID,
/* userns_fd= */ -EBADF,
flags);
if (r < 0)
return r;
@ -3808,7 +3909,8 @@ int verity_dissect_and_mount(
const char *required_host_os_release_id,
const char *required_host_os_release_version_id,
const char *required_host_os_release_sysext_level,
const char *required_sysext_scope) {
const char *required_sysext_scope,
DissectedImage **ret_image) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
@ -3818,7 +3920,9 @@ int verity_dissect_and_mount(
int r;
assert(src);
assert(dest);
/* Verifying release metadata requires mounted image for now, so ensure the check is skipped when
* opening an image without mounting it immediately (i.e.: 'dest' is NULL). */
assert(!required_host_os_release_id || dest);
relax_extension_release_check = mount_options_relax_extension_release_checks(options);
@ -3875,14 +3979,22 @@ int verity_dissect_and_mount(
if (r < 0)
return log_debug_errno(r, "Failed to decrypt dissected image: %m");
r = mkdir_p_label(dest, 0755);
if (r < 0)
return log_debug_errno(r, "Failed to create destination directory %s: %m", dest);
r = umount_recursive(dest, 0);
if (r < 0)
return log_debug_errno(r, "Failed to umount under destination directory %s: %m", dest);
if (dest) {
r = mkdir_p_label(dest, 0755);
if (r < 0)
return log_debug_errno(r, "Failed to create destination directory %s: %m", dest);
r = umount_recursive(dest, 0);
if (r < 0)
return log_debug_errno(r, "Failed to umount under destination directory %s: %m", dest);
}
r = dissected_image_mount(dissected_image, dest, UID_INVALID, UID_INVALID, dissect_image_flags);
r = dissected_image_mount(
dissected_image,
dest,
/* uid_shift= */ UID_INVALID,
/* uid_range= */ UID_INVALID,
/* userns_fd= */ -EBADF,
dissect_image_flags);
if (r < 0)
return log_debug_errno(r, "Failed to mount image: %m");
@ -3928,5 +4040,8 @@ int verity_dissect_and_mount(
if (r < 0)
return log_debug_errno(r, "Failed to relinquish dissected image: %m");
if (ret_image)
*ret_image = TAKE_PTR(dissected_image);
return 0;
}

View File

@ -36,6 +36,7 @@ struct DissectedPartition {
uint64_t size;
uint64_t offset;
uint64_t gpt_flags;
int fsmount_fd;
};
#define DISSECTED_PARTITION_NULL \
@ -43,6 +44,7 @@ struct DissectedPartition {
.partno = -1, \
.architecture = _ARCHITECTURE_INVALID, \
.mount_node_fd = -EBADF, \
.fsmount_fd = -EBADF, \
})
#define TAKE_PARTITION(p) \
({ \
@ -160,8 +162,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags);
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags);
int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, uid_t uid_range, DissectImageFlags flags);
int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t uid_shift, uid_t uid_range, DissectImageFlags flags);
int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, uid_t uid_range, int userns_fd, DissectImageFlags flags);
int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t uid_shift, uid_t uid_range, int userns_fd, DissectImageFlags flags);
int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_flags);
@ -192,7 +194,7 @@ bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesi
int mount_image_privately_interactively(const char *path, const ImagePolicy *image_policy, DissectImageFlags flags, char **ret_directory, int *ret_dir_fd, LoopDevice **ret_loop_device);
int verity_dissect_and_mount(int src_fd, const char *src, const char *dest, const MountOptions *options, const ImagePolicy *image_policy, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level, const char *required_sysext_scope);
int verity_dissect_and_mount(int src_fd, const char *src, const char *dest, const MountOptions *options, const ImagePolicy *image_policy, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level, const char *required_sysext_scope, DissectedImage **ret_image);
int dissect_fstype_ok(const char *fstype);

View File

@ -797,12 +797,16 @@ int mount_option_mangle(
return 0;
}
static int mount_in_namespace(
pid_t target,
static int mount_in_namespace_legacy(
const char *chased_src_path,
int chased_src_fd,
struct stat *chased_src_st,
const char *propagate_path,
const char *incoming_path,
const char *src,
const char *dest,
int pidns_fd,
int mntns_fd,
int root_fd,
bool read_only,
bool make_file_or_directory,
const MountOptions *options,
@ -810,52 +814,29 @@ static int mount_in_namespace(
bool is_image) {
_cleanup_close_pair_ int errno_pipe_fd[2] = PIPE_EBADF;
_cleanup_close_ int mntns_fd = -EBADF, root_fd = -EBADF, pidns_fd = -EBADF, chased_src_fd = -EBADF;
char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
bool mount_slave_created = false, mount_slave_mounted = false,
mount_tmp_created = false, mount_tmp_mounted = false,
mount_outside_created = false, mount_outside_mounted = false;
_cleanup_free_ char *chased_src_path = NULL;
struct stat st;
pid_t child;
int r;
assert(target > 0);
assert(chased_src_path);
assert(chased_src_fd >= 0);
assert(chased_src_st);
assert(propagate_path);
assert(incoming_path);
assert(src);
assert(dest);
assert(pidns_fd >= 0);
assert(mntns_fd >= 0);
assert(root_fd >= 0);
assert(!options || is_image);
r = namespace_open(target, &pidns_fd, &mntns_fd, NULL, NULL, &root_fd);
if (r < 0)
return log_debug_errno(r, "Failed to retrieve FDs of the target process' namespace: %m");
r = in_same_namespace(target, 0, NAMESPACE_MOUNT);
if (r < 0)
return log_debug_errno(r, "Failed to determine if mount namespaces are equal: %m");
/* We can't add new mounts at runtime if the process wasn't started in a namespace */
if (r > 0)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to activate bind mount in target, not running in a mount namespace");
/* One day, when bind mounting /proc/self/fd/n works across namespace boundaries we should rework
* this logic to make use of it... */
p = strjoina(propagate_path, "/");
r = laccess(p, F_OK);
if (r < 0)
return log_debug_errno(r == -ENOENT ? SYNTHETIC_ERRNO(EOPNOTSUPP) : r, "Target does not allow propagation of mount points");
r = chase(src, NULL, 0, &chased_src_path, &chased_src_fd);
if (r < 0)
return log_debug_errno(r, "Failed to resolve source path of %s: %m", src);
log_debug("Chased source path of %s to %s", src, chased_src_path);
if (fstat(chased_src_fd, &st) < 0)
return log_debug_errno(errno, "Failed to stat() resolved source path %s: %m", src);
if (S_ISLNK(st.st_mode)) /* This shouldn't really happen, given that we just chased the symlinks above, but let's better be safe… */
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Source directory %s can't be a symbolic link", src);
/* Our goal is to install a new bind mount into the container,
possibly read-only. This is irritatingly complex
unfortunately, currently.
@ -885,7 +866,7 @@ static int mount_in_namespace(
if (is_image)
r = mkdir_p(mount_tmp, 0700);
else
r = make_mount_point_inode_from_stat(&st, mount_tmp, 0700);
r = make_mount_point_inode_from_stat(chased_src_st, mount_tmp, 0700);
if (r < 0) {
log_debug_errno(r, "Failed to create temporary mount point %s: %m", mount_tmp);
goto finish;
@ -894,7 +875,17 @@ static int mount_in_namespace(
mount_tmp_created = true;
if (is_image)
r = verity_dissect_and_mount(chased_src_fd, chased_src_path, mount_tmp, options, image_policy, NULL, NULL, NULL, NULL);
r = verity_dissect_and_mount(
chased_src_fd,
chased_src_path,
mount_tmp,
options,
image_policy,
/* required_host_os_release_id= */ NULL,
/* required_host_os_release_version_id= */ NULL,
/* required_host_os_release_sysext_level= */ NULL,
/* required_sysext_scope= */ NULL,
/* ret_image= */ NULL);
else
r = mount_follow_verbose(LOG_DEBUG, FORMAT_PROC_FD_PATH(chased_src_fd), mount_tmp, NULL, MS_BIND, NULL);
if (r < 0)
@ -913,7 +904,7 @@ static int mount_in_namespace(
* right-away. */
mount_outside = strjoina(propagate_path, "/XXXXXX");
if (is_image || S_ISDIR(st.st_mode))
if (is_image || S_ISDIR(chased_src_st->st_mode))
r = mkdtemp(mount_outside) ? 0 : -errno;
else {
r = mkostemp_safe(mount_outside);
@ -933,7 +924,7 @@ static int mount_in_namespace(
mount_outside_mounted = true;
mount_tmp_mounted = false;
if (is_image || S_ISDIR(st.st_mode))
if (is_image || S_ISDIR(chased_src_st->st_mode))
(void) rmdir(mount_tmp);
else
(void) unlink(mount_tmp);
@ -962,7 +953,7 @@ static int mount_in_namespace(
if (make_file_or_directory) {
if (!is_image) {
(void) mkdir_parents(dest, 0755);
(void) make_mount_point_inode_from_stat(&st, dest, 0700);
(void) make_mount_point_inode_from_stat(chased_src_st, dest, 0700);
} else
(void) mkdir_p(dest, 0755);
}
@ -1012,7 +1003,7 @@ finish:
if (mount_outside_mounted)
(void) umount_verbose(LOG_DEBUG, mount_outside, UMOUNT_NOFOLLOW);
if (mount_outside_created) {
if (is_image || S_ISDIR(st.st_mode))
if (is_image || S_ISDIR(chased_src_st->st_mode))
(void) rmdir(mount_outside);
else
(void) unlink(mount_outside);
@ -1021,7 +1012,7 @@ finish:
if (mount_tmp_mounted)
(void) umount_verbose(LOG_DEBUG, mount_tmp, UMOUNT_NOFOLLOW);
if (mount_tmp_created) {
if (is_image || S_ISDIR(st.st_mode))
if (is_image || S_ISDIR(chased_src_st->st_mode))
(void) rmdir(mount_tmp);
else
(void) unlink(mount_tmp);
@ -1035,6 +1026,183 @@ finish:
return r;
}
static int mount_in_namespace(
pid_t target,
const char *propagate_path,
const char *incoming_path,
const char *src,
const char *dest,
bool read_only,
bool make_file_or_directory,
const MountOptions *options,
const ImagePolicy *image_policy,
bool is_image) {
_cleanup_(dissected_image_unrefp) DissectedImage *img = NULL;
_cleanup_close_pair_ int errno_pipe_fd[2] = PIPE_EBADF;
_cleanup_close_ int mntns_fd = -EBADF, root_fd = -EBADF, pidns_fd = -EBADF, chased_src_fd = -EBADF,
new_mount_fd = -EBADF;
_cleanup_free_ char *chased_src_path = NULL;
struct stat st;
pid_t child;
int r;
assert(target > 0);
assert(propagate_path);
assert(incoming_path);
assert(src);
assert(dest);
assert(!options || is_image);
r = namespace_open(target, &pidns_fd, &mntns_fd, NULL, NULL, &root_fd);
if (r < 0)
return log_debug_errno(r, "Failed to retrieve FDs of the target process' namespace: %m");
r = in_same_namespace(target, 0, NAMESPACE_MOUNT);
if (r < 0)
return log_debug_errno(r, "Failed to determine if mount namespaces are equal: %m");
/* We can't add new mounts at runtime if the process wasn't started in a namespace */
if (r > 0)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to activate bind mount in target, not running in a mount namespace");
r = chase(src, NULL, 0, &chased_src_path, &chased_src_fd);
if (r < 0)
return log_debug_errno(r, "Failed to resolve source path of %s: %m", src);
log_debug("Chased source path of %s to %s", src, chased_src_path);
if (fstat(chased_src_fd, &st) < 0)
return log_debug_errno(errno, "Failed to stat() resolved source path %s: %m", src);
if (S_ISLNK(st.st_mode)) /* This shouldn't really happen, given that we just chased the symlinks above, but let's better be safe… */
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Source directory %s can't be a symbolic link", src);
if (!mount_new_api_supported()) /* Fallback if we can't use the new mount API */
return mount_in_namespace_legacy(
chased_src_path,
chased_src_fd,
&st,
propagate_path,
incoming_path,
dest,
pidns_fd,
mntns_fd,
root_fd,
read_only,
make_file_or_directory,
options,
image_policy,
is_image);
if (is_image) {
r = verity_dissect_and_mount(
chased_src_fd,
chased_src_path,
/* dest= */ NULL,
options,
image_policy,
/* required_host_os_release_id= */ NULL,
/* required_host_os_release_version_id= */ NULL,
/* required_host_os_release_sysext_level= */ NULL,
/* required_sysext_scope= */ NULL,
&img);
if (r < 0)
return log_debug_errno(
r,
"Failed to dissect and mount image %s: %m",
chased_src_path);
} else {
new_mount_fd = open_tree(
chased_src_fd,
"",
OPEN_TREE_CLONE|OPEN_TREE_CLOEXEC|AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH);
if (new_mount_fd < 0)
return log_debug_errno(
errno,
"Failed to open mount point \"%s\": %m",
chased_src_path);
if (read_only && mount_setattr(new_mount_fd, "", AT_EMPTY_PATH,
&(struct mount_attr) {
.attr_set = MOUNT_ATTR_RDONLY,
}, MOUNT_ATTR_SIZE_VER0) < 0)
return log_debug_errno(
errno,
"Failed to set mount flags for \"%s\": %m",
chased_src_path);
}
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return log_debug_errno(errno, "Failed to create pipe: %m");
r = namespace_fork("(sd-bindmnt)",
"(sd-bindmnt-inner)",
/* except_fds= */ NULL,
/* n_except_fds= */ 0,
FORK_RESET_SIGNALS|FORK_DEATHSIG,
pidns_fd,
mntns_fd,
/* netns_fd= */ -1,
/* userns_fd= */ -1,
root_fd,
&child);
if (r < 0)
return log_debug_errno(r, "Failed to fork off: %m");
if (r == 0) {
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
if (make_file_or_directory)
(void) mkdir_parents(dest, 0755);
if (img) {
DissectImageFlags f = 0;
if (make_file_or_directory)
f |= DISSECT_IMAGE_MKDIR;
if (read_only)
f |= DISSECT_IMAGE_READ_ONLY;
r = dissected_image_mount(
img,
dest,
/* uid_shift= */ UID_INVALID,
/* uid_range= */ UID_INVALID,
/* userns_fd= */ -EBADF,
f);
} else {
if (make_file_or_directory)
(void) make_mount_point_inode_from_stat(&st, dest, 0700);
r = RET_NERRNO(move_mount(new_mount_fd,
"",
-EBADF,
dest,
MOVE_MOUNT_F_EMPTY_PATH));
}
if (r < 0) {
(void) write(errno_pipe_fd[1], &r, sizeof(r));
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
_exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
}
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
r = wait_for_terminate_and_check("(sd-bindmnt)", child, 0);
if (r < 0)
return log_debug_errno(r, "Failed to wait for child: %m");
if (r != EXIT_SUCCESS) {
if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
return log_debug_errno(r, "Failed to mount: %m");
return log_debug_errno(SYNTHETIC_ERRNO(EPROTO), "Child failed.");
}
return 0;
}
int bind_mount_in_namespace(
pid_t target,
const char *propagate_path,
@ -1460,3 +1628,88 @@ int mount_credentials_fs(const char *path, size_t size, bool ro) {
credentials_fs_mount_flags(ro),
opts);
}
int make_fsmount(
int error_log_level,
const char *what,
const char *type,
unsigned long flags,
const char *options,
int userns_fd) {
_cleanup_close_ int fs_fd = -EBADF, mnt_fd = -EBADF;
_cleanup_free_ char *o = NULL;
unsigned long f;
int r;
assert(type);
assert(what);
r = mount_option_mangle(options, flags, &f, &o);
if (r < 0)
return log_full_errno(
error_log_level, r, "Failed to mangle mount options %s: %m",
strempty(options));
if (DEBUG_LOGGING) {
_cleanup_free_ char *fl = NULL;
(void) mount_flags_to_string(f, &fl);
log_debug("Creating mount fd for %s (%s) (%s \"%s\")...",
strna(what), strna(type), strnull(fl), strempty(o));
}
fs_fd = fsopen(type, FSOPEN_CLOEXEC);
if (fs_fd < 0)
return log_full_errno(error_log_level, errno, "Failed to open superblock for \"%s\": %m", type);
if (fsconfig(fs_fd, FSCONFIG_SET_STRING, "source", what, 0) < 0)
return log_full_errno(error_log_level, errno, "Failed to set mount source for \"%s\" to \"%s\": %m", type, what);
if (FLAGS_SET(f, MS_RDONLY))
if (fsconfig(fs_fd, FSCONFIG_SET_FLAG, "ro", NULL, 0) < 0)
return log_full_errno(error_log_level, errno, "Failed to set read only mount flag for \"%s\": %m", type);
for (const char *p = o;;) {
_cleanup_free_ char *word = NULL;
char *eq;
r = extract_first_word(&p, &word, ",", EXTRACT_KEEP_QUOTE);
if (r < 0)
return log_full_errno(error_log_level, r, "Failed to parse mount option string \"%s\": %m", o);
if (r == 0)
break;
eq = strchr(word, '=');
if (eq) {
*eq = 0;
eq++;
if (fsconfig(fs_fd, FSCONFIG_SET_STRING, word, eq, 0) < 0)
return log_full_errno(error_log_level, errno, "Failed to set mount option \"%s=%s\" for \"%s\": %m", word, eq, type);
} else {
if (fsconfig(fs_fd, FSCONFIG_SET_FLAG, word, NULL, 0) < 0)
return log_full_errno(error_log_level, errno, "Failed to set mount flag \"%s\" for \"%s\": %m", word, type);
}
}
if (fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0)
return log_full_errno(error_log_level, errno, "Failed to realize fs fd for \"%s\" (\"%s\"): %m", what, type);
mnt_fd = fsmount(fs_fd, FSMOUNT_CLOEXEC, 0);
if (mnt_fd < 0)
return log_full_errno(error_log_level, errno, "Failed to create mount fd for \"%s\" (\"%s\"): %m", what, type);
if (mount_setattr(mnt_fd, "", AT_EMPTY_PATH|AT_RECURSIVE,
&(struct mount_attr) {
.attr_set = ms_flags_to_mount_attr(f) | (userns_fd >= 0 ? MOUNT_ATTR_IDMAP : 0),
.userns_fd = userns_fd,
}, MOUNT_ATTR_SIZE_VER0) < 0)
return log_full_errno(error_log_level,
errno,
"Failed to set mount flags for \"%s\" (\"%s\"): %m",
what,
type);
return TAKE_FD(mnt_fd);
}

View File

@ -136,3 +136,5 @@ int trigger_automount_at(int dir_fd, const char *path);
unsigned long credentials_fs_mount_flags(bool ro);
int mount_credentials_fs(const char *path, size_t size, bool ro);
int make_fsmount(int error_log_level, const char *what, const char *type, unsigned long flags, const char *options, int userns_fd);

View File

@ -712,8 +712,9 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
r = dissected_image_mount_and_warn(
m,
p,
UID_INVALID,
UID_INVALID,
/* uid_shift= */ UID_INVALID,
/* uid_range= */ UID_INVALID,
/* userns_fd= */ -EBADF,
flags);
if (r < 0 && r != -ENOMEDIUM)
return r;

View File

@ -101,7 +101,13 @@ static void* thread_func(void *ptr) {
verify_dissected_image(dissected);
r = dissected_image_mount(dissected, mounted, UID_INVALID, UID_INVALID, DISSECT_IMAGE_READ_ONLY);
r = dissected_image_mount(
dissected,
mounted,
/* uid_shift= */ UID_INVALID,
/* uid_range= */ UID_INVALID,
/* userns_fd= */ -EBADF,
DISSECT_IMAGE_READ_ONLY);
log_notice_errno(r, "Mounted %s → %s: %m", loop->node, mounted);
assert_se(r >= 0);
@ -291,7 +297,13 @@ static int run(int argc, char *argv[]) {
assert_se(detach_mount_namespace() >= 0);
/* This first (writable) mount will initialize the mount point dirs, so that the subsequent read-only ones can work */
assert_se(dissected_image_mount(dissected, mounted, UID_INVALID, UID_INVALID, 0) >= 0);
assert_se(dissected_image_mount(
dissected,
mounted,
/* uid_shift= */ UID_INVALID,
/* uid_range= */ UID_INVALID,
/* usernfs_fd= */ -EBADF,
0) >= 0);
/* Now we mounted everything, the partitions are pinned. Now it's fine to release the lock
* fully. This means udev could now issue BLKRRPART again, but that's OK given this will fail because

View File

@ -351,7 +351,7 @@ MountAPIVFS=yes
PrivateTmp=yes
ExecStart=/bin/sh -c ' \\
systemd-notify --ready; \\
while [[ ! -f /tmp/img/usr/lib/os-release ]] || ! grep -q -F MARKER /tmp/img/usr/lib/os-release; do \\
while [ ! -f /tmp/img/usr/lib/os-release ] || ! grep -q -F MARKER /tmp/img/usr/lib/os-release; do \\
sleep 0.1; \\
done; \\
mount; \\