From 0ace7828c28b38a4512ef88060ee16a95fb223d7 Mon Sep 17 00:00:00 2001 From: Allison Karlitskaya Date: Mon, 2 Dec 2024 10:50:02 +0100 Subject: [PATCH] repart: add 'fsverity' flag for CopyFiles= lines We currently pass the CopyFlags that we use to populate the temporary directory in the form of a constant at each of the copy_tree_at() call sites. De-duplicate that and move it into the `CopyFilesLine` struct, initializing it from the parser. Add our first non-constant flag: `fsverity=`. This can be set to `off` (the default) or `copy`, in which case we copy the fs-verity state from the source files. This arrangement is amenable to the introduction of more flags to `CopyFiles=` lines, if we want to add them in the future. Update the `repart.d(5)` manpage. Closes #35352 Signed-off-by: Allison Karlitskaya --- man/repart.d.xml | 46 +++++++++++++++++++++++++++++++++------------ src/repart/repart.c | 40 ++++++++++++++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/man/repart.d.xml b/man/repart.d.xml index 204fc162081ad..9edab10b0ca6e 100644 --- a/man/repart.d.xml +++ b/man/repart.d.xml @@ -426,18 +426,40 @@ CopyFiles= - Takes a pair of colon separated absolute file system paths. The first path refers to - a source file or directory on the host, the second path refers to a target in the file system of the - newly created partition and formatted file system. This setting may be used to copy files or - directories from the host into the file system that is created due to the Format= - option. If CopyFiles= is used without Format= specified - explicitly, Format= with a suitable default is implied (currently - vfat for ESP and XBOOTLDR partitions, and - ext4 otherwise, but this may change in the future). This option may be used - multiple times to copy multiple files or directories from host into the newly formatted file system. - The colon and second path may be omitted in which case the source path is also used as the target - path (relative to the root of the newly created file system). If the source path refers to a - directory it is copied recursively. + Takes a colon-separated triplet in the form + source[:target[:options]]. + source is an absolute path which refers to a source file or directory on the host. + target is an absolute path in the file system of the newly created partition and + formatted file system. options is a comma-separated list of options where each + option is in the form key[=value]. + + This setting may be used to copy files or directories from the host into the file system that + is created due to the Format= option. If CopyFiles= is used + without Format= specified explicitly, Format= with a suitable + default is implied (currently vfat for ESP and + XBOOTLDR partitions, and ext4 otherwise, but this may change in + the future). This option may be used multiple times to copy multiple files or directories from host + into the newly formatted file system. + + The target path may be omitted in which case the source + path is also used as the target path (relative to the root of the newly created file system). If + the source path refers to a directory it is copied recursively. + + The options may contain the following values: + + + + fsverity= + May be set to the value off (the default if the option is not + present) or copy. If set to off then no files copied into + the filesystem from this source will have fs-verity enabled. If set to copy + then the fs-verity information for each file will be copied from the corresponding source + file. + + + + + This option has no effect if the partition already exists: it cannot be used to copy additional files into an existing partition, it may only be used to populate a file system created anew. diff --git a/src/repart/repart.c b/src/repart/repart.c index 6232fa9073fe9..c8a5ab93a4508 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -267,6 +267,7 @@ static PartitionEncryptedVolume* partition_encrypted_volume_free(PartitionEncryp typedef struct CopyFilesLine { char *source; char *target; + CopyFlags flags; } CopyFilesLine; static void copy_files_line_free_many(CopyFilesLine *f, size_t n) { @@ -398,6 +399,7 @@ typedef struct Partition { CopyFilesLine *copy_files; size_t n_copy_files; + bool need_fsverity; uint64_t gpt_flags; int no_auto; @@ -1769,9 +1771,36 @@ static int config_parse_copy_files( else target = buffer; + r = extract_first_word(&p, &options, ":", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS); if (!isempty(p)) return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Too many arguments: %s", rvalue); + CopyFlags flags = COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE|COPY_RESTORE_DIRECTORY_TIMESTAMPS; + for (const char *opts = options;;) { + _cleanup_free_ char *word = NULL; + char *val; + + r = extract_first_word(&opts, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS); + if (r < 0) + return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CopyFile options: %s", options); + if (r == 0) + break; + + if (isempty(word)) + continue; + + if ((val = startswith(word, "fsverity="))) { + if (!STR_IN_SET(val, "off", "copy")) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "fsverity= expects either 'off' or 'copy'"); + + if (strcmp(val, "off") != 0) { + partition->need_fsverity = true; + flags |= COPY_FS_VERITY; + } + } else + log_syntax(unit, LOG_WARNING, filename, line, r, "Encountered unknown option '%s', ignoring.", word); + } + r = specifier_printf(source, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved_source); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, @@ -1800,6 +1829,7 @@ static int config_parse_copy_files( partition->copy_files[partition->n_copy_files++] = (CopyFilesLine) { .source = TAKE_PTR(resolved_source), .target = TAKE_PTR(resolved_target), + .flags = flags, }; return 0; @@ -5677,14 +5707,14 @@ static int do_copy_files(Context *context, Partition *p, const char *root) { sfd, ".", pfd, fn, UID_INVALID, GID_INVALID, - COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE|COPY_RESTORE_DIRECTORY_TIMESTAMPS, + line->flags, denylist, subvolumes_by_source_inode); } else r = copy_tree_at( sfd, ".", tfd, ".", UID_INVALID, GID_INVALID, - COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE|COPY_RESTORE_DIRECTORY_TIMESTAMPS, + line->flags, denylist, subvolumes_by_source_inode); if (r < 0) return log_error_errno(r, "Failed to copy '%s%s' to '%s%s': %m", @@ -6027,7 +6057,7 @@ static int context_mkfs(Context *context) { return r; r = make_filesystem(partition_target_path(t), p->format, strempty(p->new_label), root, - p->fs_uuid, arg_discard, /* fsverity = */ false, /* quiet = */ false, + p->fs_uuid, arg_discard, p->need_fsverity, /* quiet = */ false, context->fs_sector_size, p->compression, p->compression_level, extra_mkfs_options); if (r < 0) @@ -7592,7 +7622,7 @@ static int context_minimize(Context *context) { root, fs_uuid, arg_discard, - /* fsverity = */ false, + p->need_fsverity, /* quiet = */ false, context->fs_sector_size, p->compression, @@ -7676,7 +7706,7 @@ static int context_minimize(Context *context) { root, p->fs_uuid, arg_discard, - /* fsverity = */ false, + p->need_fsverity, /* quiet = */ false, context->fs_sector_size, p->compression,