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:
Zbigniew Jędrzejewski-Szmek
2025-05-27 14:01:05 +02:00
committed by GitHub
11 changed files with 478 additions and 90 deletions
+69
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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);
+7 -2
View File
@@ -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,