repart: Copy fs-verity status for CopyFiles= (#35401)
When populating a filesytem with CopyFiles=, we first copy the files to a temporary directory. Make sure we use the (new) COPY_FS_VERITY flag when doing that copy so that the `mkfs` that we invoke can see the files with fs-verity enabled. Closes #35352
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/btrfs.h>
|
||||
#include <linux/fsverity.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
@@ -790,6 +792,64 @@ static int prepare_nocow(int fdf, const char *from, int fdt, unsigned *chattr_ma
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copies fs-verity status. May re-open fdt to do its job. */
|
||||
static int copy_fs_verity(int fdf, int *fdt) {
|
||||
int r;
|
||||
|
||||
assert(fdf >= 0);
|
||||
assert(fdt);
|
||||
assert(*fdt >= 0);
|
||||
|
||||
r = fd_verify_regular(fdf);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
struct fsverity_descriptor desc = {};
|
||||
struct fsverity_read_metadata_arg read_arg = {
|
||||
.metadata_type = FS_VERITY_METADATA_TYPE_DESCRIPTOR,
|
||||
.buf_ptr = (uintptr_t) &desc,
|
||||
.length = sizeof(desc),
|
||||
};
|
||||
|
||||
r = ioctl(fdf, FS_IOC_READ_VERITY_METADATA, &read_arg);
|
||||
if (r < 0) {
|
||||
/* ENODATA means that the file doesn't have fs-verity,
|
||||
* so the correct thing to do is to do nothing at all. */
|
||||
if (errno == ENODATA)
|
||||
return 0;
|
||||
return log_error_errno(errno, "Failed to read fs-verity metadata from source file: %m");
|
||||
}
|
||||
|
||||
/* Make sure that the descriptor is completely initialized */
|
||||
assert(r == (int) sizeof desc);
|
||||
|
||||
r = fd_verify_regular(*fdt);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Okay. We're doing this now. We need to re-open fdt as read-only because
|
||||
* we can't enable fs-verity while writable file descriptors are outstanding. */
|
||||
_cleanup_close_ int reopened_fd = -EBADF;
|
||||
r = fd_reopen_condition(*fdt, O_RDONLY|O_CLOEXEC|O_NOCTTY, O_ACCMODE_STRICT|O_PATH, &reopened_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (reopened_fd >= 0)
|
||||
close_and_replace(*fdt, reopened_fd);
|
||||
|
||||
struct fsverity_enable_arg enable_arg = {
|
||||
.version = desc.version,
|
||||
.hash_algorithm = desc.hash_algorithm,
|
||||
.block_size = UINT32_C(1) << desc.log_blocksize,
|
||||
.salt_size = desc.salt_size,
|
||||
.salt_ptr = (uintptr_t) &desc.salt,
|
||||
};
|
||||
|
||||
if (ioctl(*fdt, FS_IOC_ENABLE_VERITY, &enable_arg) < 0)
|
||||
return log_error_errno(errno, "Failed to set fs-verity metadata: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fd_copy_tree_generic(
|
||||
int df,
|
||||
const char *from,
|
||||
@@ -874,6 +934,15 @@ static int fd_copy_regular(
|
||||
return r;
|
||||
}
|
||||
|
||||
/* NB: fs-verity cannot be enabled when a writable file descriptor is outstanding.
|
||||
* copy_fs_verity() may well re-open 'fdt' as O_RDONLY. All code below this point
|
||||
* needs to be able to work with a read-only file descriptor. */
|
||||
if (FLAGS_SET(copy_flags, COPY_PRESERVE_FS_VERITY)) {
|
||||
r = copy_fs_verity(fdf, &fdt);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (copy_flags & COPY_FSYNC) {
|
||||
if (fsync(fdt) < 0) {
|
||||
r = -errno;
|
||||
|
||||
@@ -32,6 +32,7 @@ typedef enum CopyFlags {
|
||||
* copy because reflinking from COW to NOCOW files is not supported.
|
||||
*/
|
||||
COPY_NOCOW_AFTER = 1 << 20,
|
||||
COPY_PRESERVE_FS_VERITY = 1 << 21, /* Preserve fs-verity when copying. */
|
||||
} CopyFlags;
|
||||
|
||||
typedef enum DenyType {
|
||||
|
||||
+24
-19
@@ -322,8 +322,7 @@ int make_filesystem(
|
||||
const char *label,
|
||||
const char *root,
|
||||
sd_id128_t uuid,
|
||||
bool discard,
|
||||
bool quiet,
|
||||
MakeFileSystemFlags flags,
|
||||
uint64_t sector_size,
|
||||
char *compression,
|
||||
char *compression_level,
|
||||
@@ -335,7 +334,7 @@ int make_filesystem(
|
||||
_cleanup_(unlink_and_freep) char *protofile = NULL;
|
||||
char vol_id[CONST_MAX(SD_ID128_UUID_STRING_MAX, 8U + 1U)] = {};
|
||||
int stdio_fds[3] = { -EBADF, STDERR_FILENO, STDERR_FILENO};
|
||||
ForkFlags flags = FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_WAIT|
|
||||
ForkFlags fork_flags = FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_WAIT|
|
||||
FORK_CLOSE_ALL_FDS|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG;
|
||||
int r;
|
||||
|
||||
@@ -424,7 +423,7 @@ int make_filesystem(
|
||||
"-U", vol_id,
|
||||
"-I", "256",
|
||||
"-m", "0",
|
||||
"-E", discard ? "discard,lazy_itable_init=1" : "nodiscard,lazy_itable_init=1",
|
||||
"-E", FLAGS_SET(flags, MKFS_DISCARD) ? "discard,lazy_itable_init=1" : "nodiscard,lazy_itable_init=1",
|
||||
"-b", "4096",
|
||||
"-T", "default");
|
||||
if (!argv)
|
||||
@@ -433,7 +432,10 @@ int make_filesystem(
|
||||
if (root && strv_extend_many(&argv, "-d", root) < 0)
|
||||
return log_oom();
|
||||
|
||||
if (quiet && strv_extend(&argv, "-q") < 0)
|
||||
if (FLAGS_SET(flags, MKFS_QUIET) && strv_extend(&argv, "-q") < 0)
|
||||
return log_oom();
|
||||
|
||||
if (FLAGS_SET(flags, MKFS_FS_VERITY) && strv_extend_many(&argv, "-O", "verity") < 0)
|
||||
return log_oom();
|
||||
|
||||
if (strv_extend(&argv, node) < 0)
|
||||
@@ -454,13 +456,13 @@ int make_filesystem(
|
||||
if (!argv)
|
||||
return log_oom();
|
||||
|
||||
if (!discard && strv_extend(&argv, "--nodiscard") < 0)
|
||||
if (!FLAGS_SET(flags, MKFS_DISCARD) && strv_extend(&argv, "--nodiscard") < 0)
|
||||
return log_oom();
|
||||
|
||||
if (root && strv_extend_many(&argv, "-r", root) < 0)
|
||||
return log_oom();
|
||||
|
||||
if (quiet && strv_extend(&argv, "-q") < 0)
|
||||
if (FLAGS_SET(flags, MKFS_QUIET) && strv_extend(&argv, "-q") < 0)
|
||||
return log_oom();
|
||||
|
||||
if (compression) {
|
||||
@@ -479,7 +481,7 @@ int make_filesystem(
|
||||
|
||||
/* mkfs.btrfs unconditionally warns about several settings changing from v5.15 onwards which
|
||||
* isn't silenced by "-q", so let's redirect stdout to /dev/null as well. */
|
||||
if (quiet)
|
||||
if (FLAGS_SET(flags, MKFS_QUIET))
|
||||
stdio_fds[1] = -EBADF;
|
||||
|
||||
/* mkfs.btrfs expects a sector size of at least 4k bytes. */
|
||||
@@ -495,11 +497,14 @@ int make_filesystem(
|
||||
"-f", /* force override, without this it doesn't seem to want to write to an empty partition */
|
||||
"-l", label,
|
||||
"-U", vol_id,
|
||||
"-t", one_zero(discard));
|
||||
"-t", one_zero(FLAGS_SET(flags, MKFS_DISCARD)));
|
||||
if (!argv)
|
||||
return log_oom();
|
||||
|
||||
if (quiet && strv_extend(&argv, "-q") < 0)
|
||||
if (FLAGS_SET(flags, MKFS_QUIET) && strv_extend(&argv, "-q") < 0)
|
||||
return log_oom();
|
||||
|
||||
if (FLAGS_SET(flags, MKFS_FS_VERITY) && strv_extend_many(&argv, "-O", "verity") < 0)
|
||||
return log_oom();
|
||||
|
||||
if (sector_size > 0) {
|
||||
@@ -525,7 +530,7 @@ int make_filesystem(
|
||||
if (!argv)
|
||||
return log_oom();
|
||||
|
||||
if (!discard && strv_extend(&argv, "-K") < 0)
|
||||
if (!FLAGS_SET(flags, MKFS_DISCARD) && strv_extend(&argv, "-K") < 0)
|
||||
return log_oom();
|
||||
|
||||
if (root) {
|
||||
@@ -557,7 +562,7 @@ int make_filesystem(
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (quiet && strv_extend(&argv, "-q") < 0)
|
||||
if (FLAGS_SET(flags, MKFS_QUIET) && strv_extend(&argv, "-q") < 0)
|
||||
return log_oom();
|
||||
|
||||
if (strv_extend(&argv, node) < 0)
|
||||
@@ -584,7 +589,7 @@ int make_filesystem(
|
||||
return log_oom();
|
||||
|
||||
/* mkfs.vfat does not have a --quiet option so let's redirect stdout to /dev/null instead. */
|
||||
if (quiet)
|
||||
if (FLAGS_SET(flags, MKFS_QUIET))
|
||||
stdio_fds[1] = -EBADF;
|
||||
|
||||
} else if (streq(fstype, "swap")) {
|
||||
@@ -597,7 +602,7 @@ int make_filesystem(
|
||||
if (!argv)
|
||||
return log_oom();
|
||||
|
||||
if (quiet)
|
||||
if (FLAGS_SET(flags, MKFS_QUIET))
|
||||
stdio_fds[1] = -EBADF;
|
||||
|
||||
} else if (streq(fstype, "squashfs")) {
|
||||
@@ -617,7 +622,7 @@ int make_filesystem(
|
||||
}
|
||||
|
||||
/* mksquashfs -quiet option is pretty new so let's redirect stdout to /dev/null instead. */
|
||||
if (quiet)
|
||||
if (FLAGS_SET(flags, MKFS_QUIET))
|
||||
stdio_fds[1] = -EBADF;
|
||||
|
||||
} else if (streq(fstype, "erofs")) {
|
||||
@@ -626,7 +631,7 @@ int make_filesystem(
|
||||
if (!argv)
|
||||
return log_oom();
|
||||
|
||||
if (quiet && strv_extend(&argv, "--quiet") < 0)
|
||||
if (FLAGS_SET(flags, MKFS_QUIET) && strv_extend(&argv, "--quiet") < 0)
|
||||
return log_oom();
|
||||
|
||||
if (compression) {
|
||||
@@ -663,7 +668,7 @@ int make_filesystem(
|
||||
return log_error_errno(r, "Failed to stat '%s': %m", node);
|
||||
|
||||
if (S_ISBLK(st.st_mode))
|
||||
flags |= FORK_NEW_MOUNTNS;
|
||||
fork_flags |= FORK_NEW_MOUNTNS;
|
||||
}
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
@@ -678,7 +683,7 @@ int make_filesystem(
|
||||
stdio_fds,
|
||||
/*except_fds=*/ NULL,
|
||||
/*n_except_fds=*/ 0,
|
||||
flags,
|
||||
fork_flags,
|
||||
/*ret_pid=*/ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -695,7 +700,7 @@ int make_filesystem(
|
||||
* on unformatted free space, so let's trick it and other mkfs tools into thinking no
|
||||
* partitions are mounted. See https://github.com/kdave/btrfs-progs/issues/640 for more
|
||||
° information. */
|
||||
if (flags & FORK_NEW_MOUNTNS)
|
||||
if (fork_flags & FORK_NEW_MOUNTNS)
|
||||
(void) mount_nofollow_verbose(LOG_DEBUG, "/dev/null", "/proc/self/mounts", NULL, MS_BIND, NULL);
|
||||
|
||||
execvp(mkfs, argv);
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
|
||||
#include "forward.h"
|
||||
|
||||
typedef enum MakeFilesystemFlags {
|
||||
MKFS_QUIET = 1 << 0, /* Suppress mkfs command output */
|
||||
MKFS_DISCARD = 1 << 1, /* Enable 'discard' mode on the filesystem */
|
||||
MKFS_FS_VERITY = 1 << 2, /* Enable fs-verity support on the filesystem */
|
||||
} MakeFileSystemFlags;
|
||||
|
||||
int mkfs_exists(const char *fstype);
|
||||
|
||||
int mkfs_supports_root_option(const char *fstype);
|
||||
@@ -15,8 +21,7 @@ int make_filesystem(
|
||||
const char *label,
|
||||
const char *root,
|
||||
sd_id128_t uuid,
|
||||
bool discard,
|
||||
bool quiet,
|
||||
MakeFileSystemFlags flags,
|
||||
uint64_t sector_size,
|
||||
char *compression,
|
||||
char *compression_level,
|
||||
|
||||
Reference in New Issue
Block a user