diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 51adaca9d0..97dbcaac66 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -15,6 +15,7 @@ #include "fileio.h" #include "filesystems.h" #include "fs-util.h" +#include "hash-funcs.h" #include "macro.h" #include "missing_fs.h" #include "missing_magic.h" @@ -441,3 +442,20 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s return 0; } + +void inode_hash_func(const struct stat *q, struct siphash *state) { + siphash24_compress(&q->st_dev, sizeof(q->st_dev), state); + siphash24_compress(&q->st_ino, sizeof(q->st_ino), state); +} + +int inode_compare_func(const struct stat *a, const struct stat *b) { + int r; + + r = CMP(a->st_dev, b->st_dev); + if (r != 0) + return r; + + return CMP(a->st_ino, b->st_ino); +} + +DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(inode_hash_ops, struct stat, inode_hash_func, inode_compare_func, free); diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index f9519d8cbd..de11c0cf7c 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -11,6 +11,7 @@ #include "macro.h" #include "missing_stat.h" +#include "siphash24.h" int is_symlink(const char *path); int is_dir_full(int atfd, const char *fname, bool follow); @@ -96,3 +97,7 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s struct new_statx nsx; \ } var #endif + +void inode_hash_func(const struct stat *q, struct siphash *state); +int inode_compare_func(const struct stat *a, const struct stat *b); +extern const struct hash_ops inode_hash_ops; diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index 1ee4119d4f..4ff86ba1de 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -1126,9 +1126,9 @@ static int action_list_or_mtree_or_copy(DissectedImage *m, LoopDevice *d) { if (errno != ENOENT) return log_error_errno(errno, "Failed to open destination '%s': %m", arg_target); - r = copy_tree_at(source_fd, ".", dfd, bn, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS); + r = copy_tree_at(source_fd, ".", dfd, bn, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, NULL); } else - r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS); + r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, NULL); if (r < 0) return log_error_errno(r, "Failed to copy '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image); diff --git a/src/home/homework.c b/src/home/homework.c index c41866cd41..bc38437f2c 100644 --- a/src/home/homework.c +++ b/src/home/homework.c @@ -1036,7 +1036,7 @@ static int copy_skel(int root_fd, const char *skel) { assert(root_fd >= 0); - r = copy_tree_at(AT_FDCWD, skel, root_fd, ".", UID_INVALID, GID_INVALID, COPY_MERGE|COPY_REPLACE); + r = copy_tree_at(AT_FDCWD, skel, root_fd, ".", UID_INVALID, GID_INVALID, COPY_MERGE|COPY_REPLACE, NULL); if (r == -ENOENT) { log_info("Skeleton directory %s missing, ignoring.", skel); return 0; diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index cf18461db3..d3a1179ebc 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -245,7 +245,7 @@ static int tar_pull_make_local_copy(TarPull *i) { BTRFS_SNAPSHOT_FALLBACK_DIRECTORY| BTRFS_SNAPSHOT_RECURSIVE); else - r = copy_tree(i->final_path, t, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_HARDLINKS); + r = copy_tree(i->final_path, t, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_HARDLINKS, NULL); if (r < 0) return log_error_errno(r, "Failed to create local image: %m"); diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 0a245247ec..75f397dd6b 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -1014,9 +1014,9 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy * the UID/GIDs as they are. */ if (copy_from) - r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags); + r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags, NULL); else - r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID : uid_shift, uid_shift == 0 ? GID_INVALID : uid_shift, copy_flags); + r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID : uid_shift, uid_shift == 0 ? GID_INVALID : uid_shift, copy_flags, NULL); hostfd = safe_close(hostfd); containerfd = safe_close(containerfd); diff --git a/src/partition/repart.c b/src/partition/repart.c index a037d7be1d..46eda6bb08 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -51,6 +51,7 @@ #include "mkfs-util.h" #include "mount-util.h" #include "mountpoint-util.h" +#include "nulstr-util.h" #include "openssl-util.h" #include "parse-argument.h" #include "parse-helpers.h" @@ -3227,7 +3228,7 @@ static int context_copy_blocks(Context *context) { return 0; } -static int do_copy_files(Partition *p, const char *root) { +static int do_copy_files(Partition *p, const char *root, const Set *denylist) { int r; assert(p); @@ -3273,13 +3274,15 @@ static int do_copy_files(Partition *p, const char *root) { sfd, ".", pfd, fn, UID_INVALID, GID_INVALID, - COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS); + COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS, + denylist); } else r = copy_tree_at( sfd, ".", tfd, ".", UID_INVALID, GID_INVALID, - COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS); + COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS, + denylist); if (r < 0) return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target); } else { @@ -3339,7 +3342,7 @@ static int do_make_directories(Partition *p, const char *root) { return 0; } -static int partition_populate_directory(Partition *p, char **ret_root, char **ret_tmp_root) { +static int partition_populate_directory(Partition *p, const Set *denylist, char **ret_root, char **ret_tmp_root) { _cleanup_(rm_rf_physical_and_freep) char *root = NULL; int r; @@ -3362,7 +3365,8 @@ static int partition_populate_directory(Partition *p, char **ret_root, char **re * allocate a temporary directory, it's stored in "ret_tmp_root" to indicate it should be removed. * Otherwise, we return the directory to use in "root" to indicate it should not be removed. */ - if (strv_length(p->copy_files) == 2 && strv_length(p->make_directories) == 0 && streq(p->copy_files[1], "/")) { + if (strv_length(p->copy_files) == 2 && strv_length(p->make_directories) == 0 && + streq(p->copy_files[1], "/") && set_isempty(denylist)) { _cleanup_free_ char *s = NULL; r = chase_symlinks(p->copy_files[0], arg_root, CHASE_PREFIX_ROOT, &s, NULL); @@ -3378,7 +3382,7 @@ static int partition_populate_directory(Partition *p, char **ret_root, char **re if (r < 0) return log_error_errno(r, "Failed to create temporary directory: %m"); - r = do_copy_files(p, root); + r = do_copy_files(p, root, denylist); if (r < 0) return r; @@ -3391,7 +3395,7 @@ static int partition_populate_directory(Partition *p, char **ret_root, char **re return 0; } -static int partition_populate_filesystem(Partition *p, const char *node) { +static int partition_populate_filesystem(Partition *p, const char *node, const Set *denylist) { int r; assert(p); @@ -3425,7 +3429,7 @@ static int partition_populate_filesystem(Partition *p, const char *node) { if (mount_nofollow_verbose(LOG_ERR, node, fs, p->format, MS_NOATIME|MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL) < 0) _exit(EXIT_FAILURE); - if (do_copy_files(p, fs) < 0) + if (do_copy_files(p, fs, denylist) < 0) _exit(EXIT_FAILURE); if (do_make_directories(p, fs) < 0) @@ -3444,13 +3448,60 @@ static int partition_populate_filesystem(Partition *p, const char *node) { return 0; } +static int make_copy_files_denylist(Context *context, Set **ret) { + _cleanup_set_free_ Set *denylist = NULL; + int r; + + assert(context); + assert(ret); + + LIST_FOREACH(partitions, p, context->partitions) { + const char *s; + + const char *sources = gpt_partition_type_mountpoint_nulstr(p->type_uuid); + if (!sources) + continue; + + NULSTR_FOREACH(s, sources) { + _cleanup_free_ char *d = NULL; + struct stat st; + + r = chase_symlinks_and_stat(s, arg_root, CHASE_PREFIX_ROOT, NULL, &st, NULL); + if (r == -ENOENT) + continue; + if (r < 0) + return log_error_errno(r, "Failed to stat source file '%s%s': %m", + strempty(arg_root), s); + + if (set_contains(denylist, &st)) + continue; + + d = memdup(&st, sizeof(st)); + if (!d) + return log_oom(); + if (set_ensure_put(&denylist, &inode_hash_ops, d) < 0) + return log_oom(); + + TAKE_PTR(d); + } + } + + *ret = TAKE_PTR(denylist); + return 0; +} + static int context_mkfs(Context *context) { + _cleanup_set_free_ Set *denylist = NULL; int fd = -1, r; assert(context); /* Make a file system */ + r = make_copy_files_denylist(context, &denylist); + if (r < 0) + return r; + LIST_FOREACH(partitions, p, context->partitions) { _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL; _cleanup_(loop_device_unrefp) LoopDevice *d = NULL; @@ -3507,7 +3558,7 @@ static int context_mkfs(Context *context) { * using read-only filesystems such as squashfs, we can't populate after creating the * filesystem because it's read-only, so instead we create a temporary root to use as the * source tree when generating the read-only filesystem. */ - r = partition_populate_directory(p, &root, &tmp_root); + r = partition_populate_directory(p, denylist, &root, &tmp_root); if (r < 0) return r; @@ -3526,7 +3577,7 @@ static int context_mkfs(Context *context) { return log_error_errno(errno, "Failed to unlock LUKS device: %m"); /* Now, we can populate all the other filesystems that aren't read-only. */ - r = partition_populate_filesystem(p, fsdev); + r = partition_populate_filesystem(p, fsdev, denylist); if (r < 0) { encrypted_dev_fd = safe_close(encrypted_dev_fd); (void) deactivate_luks(cd, encrypted); diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 6a34b10c04..c3015487c5 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -19,6 +19,7 @@ #include "pretty-print.h" #include "recurse-dir.h" #include "sort-util.h" +#include "stat-util.h" #include "string-table.h" #include "strv.h" #include "terminal-util.h" @@ -543,23 +544,6 @@ static int boot_entry_compare(const BootEntry *a, const BootEntry *b) { return -strverscmp_improved(a->id, b->id); } -static void inode_hash_func(const struct stat *q, struct siphash *state) { - siphash24_compress(&q->st_dev, sizeof(q->st_dev), state); - siphash24_compress(&q->st_ino, sizeof(q->st_ino), state); -} - -static int inode_compare_func(const struct stat *a, const struct stat *b) { - int r; - - r = CMP(a->st_dev, b->st_dev); - if (r != 0) - return r; - - return CMP(a->st_ino, b->st_ino); -} - -DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(inode_hash_ops, struct stat, inode_hash_func, inode_compare_func, free); - static int config_check_inode_relevant_and_unseen(BootConfig *config, int fd, const char *fname) { _cleanup_free_ char *d = NULL; struct stat st; diff --git a/src/shared/copy.c b/src/shared/copy.c index 182544a206..49d2fd9400 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -687,6 +687,7 @@ static int fd_copy_tree_generic( uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, + const Set *denylist, HardlinkContext *hardlink_context, const char *display_path, copy_progress_path_t progress_path, @@ -877,6 +878,7 @@ static int fd_copy_directory( uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, + const Set *denylist, HardlinkContext *hardlink_context, const char *display_path, copy_progress_path_t progress_path, @@ -979,6 +981,11 @@ static int fd_copy_directory( return r; } + if (set_contains(denylist, &buf)) { + log_debug("%s/%s is in the denylist, skipping", from, de->d_name); + continue; + } + if (S_ISDIR(buf.st_mode)) { /* * Don't descend into directories on other file systems, if this is requested. We do a simple @@ -1011,7 +1018,10 @@ static int fd_copy_directory( } } - q = fd_copy_tree_generic(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, depth_left-1, override_uid, override_gid, copy_flags, hardlink_context, child_display_path, progress_path, progress_bytes, userdata); + q = fd_copy_tree_generic(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, + depth_left-1, override_uid, override_gid, copy_flags, denylist, + hardlink_context, child_display_path, progress_path, progress_bytes, + userdata); if (q == -EINTR) /* Propagate SIGINT/SIGTERM up instantly */ return q; @@ -1082,6 +1092,7 @@ static int fd_copy_tree_generic( uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, + const Set *denylist, HardlinkContext *hardlink_context, const char *display_path, copy_progress_path_t progress_path, @@ -1090,7 +1101,9 @@ static int fd_copy_tree_generic( int r; if (S_ISDIR(st->st_mode)) - return fd_copy_directory(df, from, st, dt, to, original_device, depth_left-1, override_uid, override_gid, copy_flags, hardlink_context, display_path, progress_path, progress_bytes, userdata); + return fd_copy_directory(df, from, st, dt, to, original_device, depth_left-1, override_uid, + override_gid, copy_flags, denylist, hardlink_context, display_path, + progress_path, progress_bytes, userdata); r = fd_copy_leaf(df, from, st, dt, to, override_uid, override_gid, copy_flags, hardlink_context, display_path, progress_bytes, userdata); /* We just tried to copy a leaf node of the tree. If it failed because the node already exists *and* the COPY_REPLACE flag has been provided, we should unlink the node and re-copy. */ @@ -1113,6 +1126,7 @@ int copy_tree_at_full( uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, + const Set *denylist, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata) { @@ -1126,7 +1140,9 @@ int copy_tree_at_full( if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0) return -errno; - r = fd_copy_tree_generic(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata); + r = fd_copy_tree_generic(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, + override_gid, copy_flags, denylist, NULL, NULL, progress_path, + progress_bytes, userdata); if (r < 0) return r; @@ -1188,7 +1204,7 @@ int copy_directory_fd_full( COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, - NULL, NULL, + NULL, NULL, NULL, progress_path, progress_bytes, userdata); @@ -1231,7 +1247,7 @@ int copy_directory_full( COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, - NULL, NULL, + NULL, NULL, NULL, progress_path, progress_bytes, userdata); diff --git a/src/shared/copy.h b/src/shared/copy.h index d755916bd9..d19361c9a2 100644 --- a/src/shared/copy.h +++ b/src/shared/copy.h @@ -9,6 +9,8 @@ #include #include +#include "set.h" + typedef enum CopyFlags { COPY_REFLINK = 1 << 0, /* Try to reflink */ COPY_MERGE = 1 << 1, /* Merge existing trees with our new one to copy */ @@ -45,12 +47,12 @@ static inline int copy_file_atomic(const char *from, const char *to, mode_t mode return copy_file_atomic_full(from, to, mode, chattr_flags, chattr_mask, copy_flags, NULL, NULL); } -int copy_tree_at_full(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata); -static inline int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) { - return copy_tree_at_full(fdf, from, fdt, to, override_uid, override_gid, copy_flags, NULL, NULL, NULL); +int copy_tree_at_full(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, const Set *denylist, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata); +static inline int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, const Set *denylist) { + return copy_tree_at_full(fdf, from, fdt, to, override_uid, override_gid, copy_flags, denylist, NULL, NULL, NULL); } -static inline int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) { - return copy_tree_at_full(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags, NULL, NULL, NULL); +static inline int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, const Set *denylist) { + return copy_tree_at_full(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags, denylist, NULL, NULL, NULL); } int copy_directory_fd_full(int dirfd, const char *to, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 1d338fe352..1214a17263 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -688,7 +688,7 @@ static int dissect_image( continue; assert_se((architecture = gpt_partition_type_uuid_to_arch(type_id)) >= 0); - designator = PARTITION_ROOT_OF_ARCH(architecture); + designator = partition_root_of_arch(architecture); rw = !(pflags & SD_GPT_FLAG_READ_ONLY); growfs = FLAGS_SET(pflags, SD_GPT_FLAG_GROWFS); @@ -713,7 +713,7 @@ static int dissect_image( continue; assert_se((architecture = gpt_partition_type_uuid_to_arch(type_id)) >= 0); - designator = PARTITION_VERITY_OF(PARTITION_ROOT_OF_ARCH(architecture)); + designator = partition_verity_of(partition_root_of_arch(architecture)); fstype = "DM_verity_hash"; rw = false; @@ -733,7 +733,7 @@ static int dissect_image( continue; assert_se((architecture = gpt_partition_type_uuid_to_arch(type_id)) >= 0); - designator = PARTITION_VERITY_SIG_OF(PARTITION_ROOT_OF_ARCH(architecture)); + designator = partition_verity_sig_of(partition_root_of_arch(architecture)); fstype = "verity_hash_signature"; rw = false; @@ -750,7 +750,7 @@ static int dissect_image( continue; assert_se((architecture = gpt_partition_type_uuid_to_arch(type_id)) >= 0); - designator = PARTITION_USR_OF_ARCH(architecture); + designator = partition_usr_of_arch(architecture); rw = !(pflags & SD_GPT_FLAG_READ_ONLY); growfs = FLAGS_SET(pflags, SD_GPT_FLAG_GROWFS); @@ -774,7 +774,7 @@ static int dissect_image( continue; assert_se((architecture = gpt_partition_type_uuid_to_arch(type_id)) >= 0); - designator = PARTITION_VERITY_OF(PARTITION_USR_OF_ARCH(architecture)); + designator = partition_verity_of(partition_usr_of_arch(architecture)); fstype = "DM_verity_hash"; rw = false; @@ -794,7 +794,7 @@ static int dissect_image( continue; assert_se((architecture = gpt_partition_type_uuid_to_arch(type_id)) >= 0); - designator = PARTITION_VERITY_SIG_OF(PARTITION_USR_OF_ARCH(architecture)); + designator = partition_verity_sig_of(partition_usr_of_arch(architecture)); fstype = "verity_hash_signature"; rw = false; @@ -884,7 +884,7 @@ static int dissect_image( * let the newest version win. This permits a simple A/B versioning * scheme in OS images. */ - if (!PARTITION_DESIGNATOR_VERSIONED(designator) || + if (!partition_designator_is_versioned(designator) || strverscmp_improved(m->partitions[designator].label, label) >= 0) continue; @@ -2369,7 +2369,7 @@ int dissected_image_decrypt( if (r < 0) return r; - k = PARTITION_VERITY_OF(i); + k = partition_verity_of(i); if (k >= 0) { r = verity_partition(i, p, m->partitions + k, verity, flags | DISSECT_IMAGE_VERITY_SHARE, d); if (r < 0) @@ -2711,7 +2711,7 @@ int dissected_image_load_verity_sig_partition( if (r == 0) return 0; - d = PARTITION_VERITY_SIG_OF(verity->designator < 0 ? PARTITION_ROOT : verity->designator); + d = partition_verity_sig_of(verity->designator < 0 ? PARTITION_ROOT : verity->designator); assert(d >= 0); p = m->partitions + d; @@ -3170,7 +3170,7 @@ bool dissected_image_verity_candidate(const DissectedImage *image, PartitionDesi if (image->single_file_system) return partition_designator == PARTITION_ROOT && image->has_verity; - return PARTITION_VERITY_OF(partition_designator) >= 0; + return partition_verity_of(partition_designator) >= 0; } bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignator partition_designator) { @@ -3187,7 +3187,7 @@ bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignat if (image->single_file_system) return partition_designator == PARTITION_ROOT; - k = PARTITION_VERITY_OF(partition_designator); + k = partition_verity_of(partition_designator); return k >= 0 && image->partitions[k].found; } @@ -3204,7 +3204,7 @@ bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesi if (image->single_file_system) return partition_designator == PARTITION_ROOT; - k = PARTITION_VERITY_SIG_OF(partition_designator); + k = partition_verity_sig_of(partition_designator); return k >= 0 && image->partitions[k].found; } @@ -3306,34 +3306,6 @@ int mount_image_privately_interactively( return 0; } -static const char *const partition_designator_table[] = { - [PARTITION_ROOT] = "root", - [PARTITION_ROOT_SECONDARY] = "root-secondary", - [PARTITION_ROOT_OTHER] = "root-other", - [PARTITION_USR] = "usr", - [PARTITION_USR_SECONDARY] = "usr-secondary", - [PARTITION_USR_OTHER] = "usr-other", - [PARTITION_HOME] = "home", - [PARTITION_SRV] = "srv", - [PARTITION_ESP] = "esp", - [PARTITION_XBOOTLDR] = "xbootldr", - [PARTITION_SWAP] = "swap", - [PARTITION_ROOT_VERITY] = "root-verity", - [PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity", - [PARTITION_ROOT_OTHER_VERITY] = "root-other-verity", - [PARTITION_USR_VERITY] = "usr-verity", - [PARTITION_USR_SECONDARY_VERITY] = "usr-secondary-verity", - [PARTITION_USR_OTHER_VERITY] = "usr-other-verity", - [PARTITION_ROOT_VERITY_SIG] = "root-verity-sig", - [PARTITION_ROOT_SECONDARY_VERITY_SIG] = "root-secondary-verity-sig", - [PARTITION_ROOT_OTHER_VERITY_SIG] = "root-other-verity-sig", - [PARTITION_USR_VERITY_SIG] = "usr-verity-sig", - [PARTITION_USR_SECONDARY_VERITY_SIG] = "usr-secondary-verity-sig", - [PARTITION_USR_OTHER_VERITY_SIG] = "usr-other-verity-sig", - [PARTITION_TMP] = "tmp", - [PARTITION_VAR] = "var", -}; - static bool mount_options_relax_extension_release_checks(const MountOptions *options) { if (!options) return false; @@ -3461,5 +3433,3 @@ int verity_dissect_and_mount( return 0; } - -DEFINE_STRING_TABLE_LOOKUP(partition_designator, PartitionDesignator); diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index ccdc4d6f35..af043297b9 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -6,6 +6,7 @@ #include "sd-id128.h" #include "architecture.h" +#include "gpt.h" #include "list.h" #include "loop-util.h" #include "macro.h" @@ -41,147 +42,6 @@ struct DissectedPartition { .mount_node_fd = -1, \ }) -typedef enum PartitionDesignator { - PARTITION_ROOT, - PARTITION_ROOT_SECONDARY, /* Secondary architecture */ - PARTITION_ROOT_OTHER, - PARTITION_USR, - PARTITION_USR_SECONDARY, - PARTITION_USR_OTHER, - PARTITION_HOME, - PARTITION_SRV, - PARTITION_ESP, - PARTITION_XBOOTLDR, - PARTITION_SWAP, - PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */ - PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */ - PARTITION_ROOT_OTHER_VERITY, - PARTITION_USR_VERITY, - PARTITION_USR_SECONDARY_VERITY, - PARTITION_USR_OTHER_VERITY, - PARTITION_ROOT_VERITY_SIG, /* PKCS#7 signature for root hash for the PARTITION_ROOT partition */ - PARTITION_ROOT_SECONDARY_VERITY_SIG, /* ditto for the PARTITION_ROOT_SECONDARY partition */ - PARTITION_ROOT_OTHER_VERITY_SIG, - PARTITION_USR_VERITY_SIG, - PARTITION_USR_SECONDARY_VERITY_SIG, - PARTITION_USR_OTHER_VERITY_SIG, - PARTITION_TMP, - PARTITION_VAR, - _PARTITION_DESIGNATOR_MAX, - _PARTITION_DESIGNATOR_INVALID = -EINVAL, -} PartitionDesignator; - -static inline bool PARTITION_DESIGNATOR_VERSIONED(PartitionDesignator d) { - /* Returns true for all designators where we want to support a concept of "versioning", i.e. which - * likely contain software binaries (or hashes thereof) that make sense to be versioned as a - * whole. We use this check to automatically pick the newest version of these partitions, by version - * comparing the partition labels. */ - - return IN_SET(d, - PARTITION_ROOT, - PARTITION_ROOT_SECONDARY, - PARTITION_ROOT_OTHER, - PARTITION_USR, - PARTITION_USR_SECONDARY, - PARTITION_USR_OTHER, - PARTITION_ROOT_VERITY, - PARTITION_ROOT_SECONDARY_VERITY, - PARTITION_ROOT_OTHER_VERITY, - PARTITION_USR_VERITY, - PARTITION_USR_SECONDARY_VERITY, - PARTITION_USR_OTHER_VERITY, - PARTITION_ROOT_VERITY_SIG, - PARTITION_ROOT_SECONDARY_VERITY_SIG, - PARTITION_ROOT_OTHER_VERITY_SIG, - PARTITION_USR_VERITY_SIG, - PARTITION_USR_SECONDARY_VERITY_SIG, - PARTITION_USR_OTHER_VERITY_SIG); -} - -static inline PartitionDesignator PARTITION_VERITY_OF(PartitionDesignator p) { - switch (p) { - - case PARTITION_ROOT: - return PARTITION_ROOT_VERITY; - - case PARTITION_ROOT_SECONDARY: - return PARTITION_ROOT_SECONDARY_VERITY; - - case PARTITION_ROOT_OTHER: - return PARTITION_ROOT_OTHER_VERITY; - - case PARTITION_USR: - return PARTITION_USR_VERITY; - - case PARTITION_USR_SECONDARY: - return PARTITION_USR_SECONDARY_VERITY; - - case PARTITION_USR_OTHER: - return PARTITION_USR_OTHER_VERITY; - - default: - return _PARTITION_DESIGNATOR_INVALID; - } -} - -static inline PartitionDesignator PARTITION_VERITY_SIG_OF(PartitionDesignator p) { - switch (p) { - - case PARTITION_ROOT: - return PARTITION_ROOT_VERITY_SIG; - - case PARTITION_ROOT_SECONDARY: - return PARTITION_ROOT_SECONDARY_VERITY_SIG; - - case PARTITION_ROOT_OTHER: - return PARTITION_ROOT_OTHER_VERITY_SIG; - - case PARTITION_USR: - return PARTITION_USR_VERITY_SIG; - - case PARTITION_USR_SECONDARY: - return PARTITION_USR_SECONDARY_VERITY_SIG; - - case PARTITION_USR_OTHER: - return PARTITION_USR_OTHER_VERITY_SIG; - - default: - return _PARTITION_DESIGNATOR_INVALID; - } -} - -static inline PartitionDesignator PARTITION_ROOT_OF_ARCH(Architecture arch) { - switch (arch) { - - case native_architecture(): - return PARTITION_ROOT; - -#ifdef ARCHITECTURE_SECONDARY - case ARCHITECTURE_SECONDARY: - return PARTITION_ROOT_SECONDARY; -#endif - - default: - return PARTITION_ROOT_OTHER; - } -} - -static inline PartitionDesignator PARTITION_USR_OF_ARCH(Architecture arch) { - switch (arch) { - - case native_architecture(): - return PARTITION_USR; - -#ifdef ARCHITECTURE_SECONDARY - case ARCHITECTURE_SECONDARY: - return PARTITION_USR_SECONDARY; -#endif - - default: - return PARTITION_USR_OTHER; - } -} - typedef enum DissectImageFlags { DISSECT_IMAGE_DEVICE_READ_ONLY = 1 << 0, /* Make device read-only */ DISSECT_IMAGE_DISCARD_ON_LOOP = 1 << 1, /* Turn on "discard" if on a loop device and file system supports it */ @@ -298,9 +158,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DecryptedImage*, decrypted_image_unref); int dissected_image_relinquish(DissectedImage *m); -const char* partition_designator_to_string(PartitionDesignator d) _const_; -PartitionDesignator partition_designator_from_string(const char *name) _pure_; - int verity_settings_load(VeritySettings *verity, const char *image, const char *root_hash_path, const char *root_hash_sig_path); void verity_settings_done(VeritySettings *verity); diff --git a/src/shared/gpt.c b/src/shared/gpt.c index a15833b21d..af969ff9d5 100644 --- a/src/shared/gpt.c +++ b/src/shared/gpt.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "gpt.h" +#include "string-table.h" #include "string-util.h" #include "utf8.h" @@ -14,13 +15,173 @@ #pragma message "Please define GPT partition types for your architecture." #endif +bool partition_designator_is_versioned(PartitionDesignator d) { + /* Returns true for all designators where we want to support a concept of "versioning", i.e. which + * likely contain software binaries (or hashes thereof) that make sense to be versioned as a + * whole. We use this check to automatically pick the newest version of these partitions, by version + * comparing the partition labels. */ + + return IN_SET(d, + PARTITION_ROOT, + PARTITION_ROOT_SECONDARY, + PARTITION_ROOT_OTHER, + PARTITION_USR, + PARTITION_USR_SECONDARY, + PARTITION_USR_OTHER, + PARTITION_ROOT_VERITY, + PARTITION_ROOT_SECONDARY_VERITY, + PARTITION_ROOT_OTHER_VERITY, + PARTITION_USR_VERITY, + PARTITION_USR_SECONDARY_VERITY, + PARTITION_USR_OTHER_VERITY, + PARTITION_ROOT_VERITY_SIG, + PARTITION_ROOT_SECONDARY_VERITY_SIG, + PARTITION_ROOT_OTHER_VERITY_SIG, + PARTITION_USR_VERITY_SIG, + PARTITION_USR_SECONDARY_VERITY_SIG, + PARTITION_USR_OTHER_VERITY_SIG); +} + +PartitionDesignator partition_verity_of(PartitionDesignator p) { + switch (p) { + + case PARTITION_ROOT: + return PARTITION_ROOT_VERITY; + + case PARTITION_ROOT_SECONDARY: + return PARTITION_ROOT_SECONDARY_VERITY; + + case PARTITION_ROOT_OTHER: + return PARTITION_ROOT_OTHER_VERITY; + + case PARTITION_USR: + return PARTITION_USR_VERITY; + + case PARTITION_USR_SECONDARY: + return PARTITION_USR_SECONDARY_VERITY; + + case PARTITION_USR_OTHER: + return PARTITION_USR_OTHER_VERITY; + + default: + return _PARTITION_DESIGNATOR_INVALID; + } +} + +PartitionDesignator partition_verity_sig_of(PartitionDesignator p) { + switch (p) { + + case PARTITION_ROOT: + return PARTITION_ROOT_VERITY_SIG; + + case PARTITION_ROOT_SECONDARY: + return PARTITION_ROOT_SECONDARY_VERITY_SIG; + + case PARTITION_ROOT_OTHER: + return PARTITION_ROOT_OTHER_VERITY_SIG; + + case PARTITION_USR: + return PARTITION_USR_VERITY_SIG; + + case PARTITION_USR_SECONDARY: + return PARTITION_USR_SECONDARY_VERITY_SIG; + + case PARTITION_USR_OTHER: + return PARTITION_USR_OTHER_VERITY_SIG; + + default: + return _PARTITION_DESIGNATOR_INVALID; + } +} + +PartitionDesignator partition_root_of_arch(Architecture arch) { + switch (arch) { + + case native_architecture(): + return PARTITION_ROOT; + +#ifdef ARCHITECTURE_SECONDARY + case ARCHITECTURE_SECONDARY: + return PARTITION_ROOT_SECONDARY; +#endif + + default: + return PARTITION_ROOT_OTHER; + } +} + +PartitionDesignator partition_usr_of_arch(Architecture arch) { + switch (arch) { + + case native_architecture(): + return PARTITION_USR; + +#ifdef ARCHITECTURE_SECONDARY + case ARCHITECTURE_SECONDARY: + return PARTITION_USR_SECONDARY; +#endif + + default: + return PARTITION_USR_OTHER; + } +} + +static const char *const partition_designator_table[] = { + [PARTITION_ROOT] = "root", + [PARTITION_ROOT_SECONDARY] = "root-secondary", + [PARTITION_ROOT_OTHER] = "root-other", + [PARTITION_USR] = "usr", + [PARTITION_USR_SECONDARY] = "usr-secondary", + [PARTITION_USR_OTHER] = "usr-other", + [PARTITION_HOME] = "home", + [PARTITION_SRV] = "srv", + [PARTITION_ESP] = "esp", + [PARTITION_XBOOTLDR] = "xbootldr", + [PARTITION_SWAP] = "swap", + [PARTITION_ROOT_VERITY] = "root-verity", + [PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity", + [PARTITION_ROOT_OTHER_VERITY] = "root-other-verity", + [PARTITION_USR_VERITY] = "usr-verity", + [PARTITION_USR_SECONDARY_VERITY] = "usr-secondary-verity", + [PARTITION_USR_OTHER_VERITY] = "usr-other-verity", + [PARTITION_ROOT_VERITY_SIG] = "root-verity-sig", + [PARTITION_ROOT_SECONDARY_VERITY_SIG] = "root-secondary-verity-sig", + [PARTITION_ROOT_OTHER_VERITY_SIG] = "root-other-verity-sig", + [PARTITION_USR_VERITY_SIG] = "usr-verity-sig", + [PARTITION_USR_SECONDARY_VERITY_SIG] = "usr-secondary-verity-sig", + [PARTITION_USR_OTHER_VERITY_SIG] = "usr-other-verity-sig", + [PARTITION_TMP] = "tmp", + [PARTITION_VAR] = "var", + [PARTITION_USER_HOME] = "user-home", + [PARTITION_LINUX_GENERIC] = "linux-generic", +}; + +DEFINE_STRING_TABLE_LOOKUP(partition_designator, PartitionDesignator); + +static const char *const partition_mountpoint_table[] = { + [PARTITION_ROOT] = "/\0", + [PARTITION_ROOT_SECONDARY] = "/\0", + [PARTITION_ROOT_OTHER] = "/\0", + [PARTITION_USR] = "/usr\0", + [PARTITION_USR_SECONDARY] = "/usr\0", + [PARTITION_USR_OTHER] = "/usr\0", + [PARTITION_HOME] = "/home\0", + [PARTITION_SRV] = "/srv\0", + [PARTITION_ESP] = "/efi\0/boot\0", + [PARTITION_XBOOTLDR] = "/boot\0", + [PARTITION_TMP] = "/var/tmp\0", + [PARTITION_VAR] = "/var\0", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(partition_mountpoint, PartitionDesignator); + #define _GPT_ARCH_SEXTET(arch, name) \ - { SD_GPT_ROOT_##arch, "root-" name, ARCHITECTURE_##arch, .is_root = true }, \ - { SD_GPT_ROOT_##arch##_VERITY, "root-" name "-verity", ARCHITECTURE_##arch, .is_root_verity = true }, \ - { SD_GPT_ROOT_##arch##_VERITY_SIG, "root-" name "-verity-sig", ARCHITECTURE_##arch, .is_root_verity_sig = true }, \ - { SD_GPT_USR_##arch, "usr-" name, ARCHITECTURE_##arch, .is_usr = true }, \ - { SD_GPT_USR_##arch##_VERITY, "usr-" name "-verity", ARCHITECTURE_##arch, .is_usr_verity = true }, \ - { SD_GPT_USR_##arch##_VERITY_SIG, "usr-" name "-verity-sig", ARCHITECTURE_##arch, .is_usr_verity_sig = true } + { SD_GPT_ROOT_##arch, "root-" name, ARCHITECTURE_##arch, .designator = PARTITION_ROOT_OTHER }, \ + { SD_GPT_ROOT_##arch##_VERITY, "root-" name "-verity", ARCHITECTURE_##arch, .designator = PARTITION_ROOT_OTHER_VERITY }, \ + { SD_GPT_ROOT_##arch##_VERITY_SIG, "root-" name "-verity-sig", ARCHITECTURE_##arch, .designator = PARTITION_ROOT_OTHER_VERITY_SIG }, \ + { SD_GPT_USR_##arch, "usr-" name, ARCHITECTURE_##arch, .designator = PARTITION_USR_OTHER }, \ + { SD_GPT_USR_##arch##_VERITY, "usr-" name "-verity", ARCHITECTURE_##arch, .designator = PARTITION_USR_OTHER_VERITY }, \ + { SD_GPT_USR_##arch##_VERITY_SIG, "usr-" name "-verity-sig", ARCHITECTURE_##arch, .designator = PARTITION_USR_OTHER_VERITY_SIG } const GptPartitionType gpt_partition_type_table[] = { _GPT_ARCH_SEXTET(ALPHA, "alpha"), @@ -43,26 +204,31 @@ const GptPartitionType gpt_partition_type_table[] = { _GPT_ARCH_SEXTET(X86, "x86"), _GPT_ARCH_SEXTET(X86_64, "x86-64"), #ifdef SD_GPT_ROOT_NATIVE - { SD_GPT_ROOT_NATIVE, "root", native_architecture(), .is_root = true }, - { SD_GPT_ROOT_NATIVE_VERITY, "root-verity", native_architecture(), .is_root_verity = true }, - { SD_GPT_ROOT_NATIVE_VERITY_SIG, "root-verity-sig", native_architecture(), .is_root_verity_sig = true }, - { SD_GPT_USR_NATIVE, "usr", native_architecture(), .is_usr = true }, - { SD_GPT_USR_NATIVE_VERITY, "usr-verity", native_architecture(), .is_usr_verity = true }, - { SD_GPT_USR_NATIVE_VERITY_SIG, "usr-verity-sig", native_architecture(), .is_usr_verity_sig = true }, + { SD_GPT_ROOT_NATIVE, "root", native_architecture(), .designator = PARTITION_ROOT }, + { SD_GPT_ROOT_NATIVE_VERITY, "root-verity", native_architecture(), .designator = PARTITION_ROOT_VERITY }, + { SD_GPT_ROOT_NATIVE_VERITY_SIG, "root-verity-sig", native_architecture(), .designator = PARTITION_ROOT_VERITY_SIG }, + { SD_GPT_USR_NATIVE, "usr", native_architecture(), .designator = PARTITION_USR }, + { SD_GPT_USR_NATIVE_VERITY, "usr-verity", native_architecture(), .designator = PARTITION_USR_VERITY }, + { SD_GPT_USR_NATIVE_VERITY_SIG, "usr-verity-sig", native_architecture(), .designator = PARTITION_USR_VERITY_SIG }, #endif #ifdef SD_GPT_ROOT_SECONDARY - _GPT_ARCH_SEXTET(SECONDARY, "secondary"), + { SD_GPT_ROOT_NATIVE, "root-secondary", native_architecture(), .designator = PARTITION_ROOT_SECONDARY }, + { SD_GPT_ROOT_NATIVE_VERITY, "root-secondary-verity", native_architecture(), .designator = PARTITION_ROOT_SECONDARY_VERITY }, + { SD_GPT_ROOT_NATIVE_VERITY_SIG, "root-secondary-verity-sig", native_architecture(), .designator = PARTITION_ROOT_SECONDARY_VERITY_SIG }, + { SD_GPT_USR_NATIVE, "usr-secondary", native_architecture(), .designator = PARTITION_USR_SECONDARY }, + { SD_GPT_USR_NATIVE_VERITY, "usr-secondary-verity", native_architecture(), .designator = PARTITION_USR_SECONDARY_VERITY }, + { SD_GPT_USR_NATIVE_VERITY_SIG, "usr-secondary-verity-sig", native_architecture(), .designator = PARTITION_USR_SECONDARY_VERITY_SIG }, #endif - { SD_GPT_ESP, "esp", _ARCHITECTURE_INVALID }, - { SD_GPT_XBOOTLDR, "xbootldr", _ARCHITECTURE_INVALID }, - { SD_GPT_SWAP, "swap", _ARCHITECTURE_INVALID }, - { SD_GPT_HOME, "home", _ARCHITECTURE_INVALID }, - { SD_GPT_SRV, "srv", _ARCHITECTURE_INVALID }, - { SD_GPT_VAR, "var", _ARCHITECTURE_INVALID }, - { SD_GPT_TMP, "tmp", _ARCHITECTURE_INVALID }, - { SD_GPT_USER_HOME, "user-home", _ARCHITECTURE_INVALID }, - { SD_GPT_LINUX_GENERIC, "linux-generic", _ARCHITECTURE_INVALID }, + { SD_GPT_ESP, "esp", _ARCHITECTURE_INVALID, .designator = PARTITION_ESP }, + { SD_GPT_XBOOTLDR, "xbootldr", _ARCHITECTURE_INVALID, .designator = PARTITION_XBOOTLDR }, + { SD_GPT_SWAP, "swap", _ARCHITECTURE_INVALID, .designator = PARTITION_SWAP }, + { SD_GPT_HOME, "home", _ARCHITECTURE_INVALID, .designator = PARTITION_HOME }, + { SD_GPT_SRV, "srv", _ARCHITECTURE_INVALID, .designator = PARTITION_SRV }, + { SD_GPT_VAR, "var", _ARCHITECTURE_INVALID, .designator = PARTITION_VAR }, + { SD_GPT_TMP, "tmp", _ARCHITECTURE_INVALID, .designator = PARTITION_TMP }, + { SD_GPT_USER_HOME, "user-home", _ARCHITECTURE_INVALID, .designator = PARTITION_USER_HOME }, + { SD_GPT_LINUX_GENERIC, "linux-generic", _ARCHITECTURE_INVALID, .designator = PARTITION_LINUX_GENERIC }, {} }; @@ -140,55 +306,86 @@ static GptPartitionType gpt_partition_type_from_uuid(sd_id128_t id) { if (pt) return *pt; - return (GptPartitionType) { .uuid = id, .arch = _ARCHITECTURE_INVALID }; + return (GptPartitionType) { + .uuid = id, + .arch = _ARCHITECTURE_INVALID, + .designator = _PARTITION_DESIGNATOR_INVALID, + }; } bool gpt_partition_type_is_root(sd_id128_t id) { - return gpt_partition_type_from_uuid(id).is_root; + return IN_SET(gpt_partition_type_from_uuid(id).designator, + PARTITION_ROOT, + PARTITION_ROOT_SECONDARY, + PARTITION_ROOT_OTHER); } bool gpt_partition_type_is_root_verity(sd_id128_t id) { - return gpt_partition_type_from_uuid(id).is_root_verity; + return IN_SET(gpt_partition_type_from_uuid(id).designator, + PARTITION_ROOT_VERITY, + PARTITION_ROOT_SECONDARY_VERITY, + PARTITION_ROOT_OTHER_VERITY); } bool gpt_partition_type_is_root_verity_sig(sd_id128_t id) { - return gpt_partition_type_from_uuid(id).is_root_verity_sig; + return IN_SET(gpt_partition_type_from_uuid(id).designator, + PARTITION_ROOT_VERITY_SIG, + PARTITION_ROOT_SECONDARY_VERITY_SIG, + PARTITION_ROOT_OTHER_VERITY_SIG); } bool gpt_partition_type_is_usr(sd_id128_t id) { - return gpt_partition_type_from_uuid(id).is_usr; + return IN_SET(gpt_partition_type_from_uuid(id).designator, + PARTITION_USR, + PARTITION_USR_SECONDARY, + PARTITION_USR_OTHER); } bool gpt_partition_type_is_usr_verity(sd_id128_t id) { - return gpt_partition_type_from_uuid(id).is_usr_verity; + return IN_SET(gpt_partition_type_from_uuid(id).designator, + PARTITION_USR_VERITY, + PARTITION_USR_SECONDARY_VERITY, + PARTITION_USR_OTHER_VERITY); } bool gpt_partition_type_is_usr_verity_sig(sd_id128_t id) { - return gpt_partition_type_from_uuid(id).is_usr_verity_sig; + return IN_SET(gpt_partition_type_from_uuid(id).designator, + PARTITION_USR_VERITY_SIG, + PARTITION_USR_SECONDARY_VERITY_SIG, + PARTITION_USR_OTHER_VERITY_SIG); +} + +const char *gpt_partition_type_mountpoint_nulstr(sd_id128_t id) { + PartitionDesignator d = gpt_partition_type_from_uuid(id).designator; + if (d < 0) + return NULL; + + return partition_mountpoint_to_string(d); } bool gpt_partition_type_knows_read_only(sd_id128_t id) { return gpt_partition_type_is_root(id) || gpt_partition_type_is_usr(id) || - sd_id128_in_set(id, - SD_GPT_HOME, - SD_GPT_SRV, - SD_GPT_VAR, - SD_GPT_TMP, - SD_GPT_XBOOTLDR) || - gpt_partition_type_is_root_verity(id) || /* pretty much implied, but let's set the bit to make things really clear */ - gpt_partition_type_is_usr_verity(id); /* ditto */ + /* pretty much implied, but let's set the bit to make things really clear */ + gpt_partition_type_is_root_verity(id) || + gpt_partition_type_is_usr_verity(id) || + IN_SET(gpt_partition_type_from_uuid(id).designator, + PARTITION_HOME, + PARTITION_SRV, + PARTITION_VAR, + PARTITION_TMP, + PARTITION_XBOOTLDR); } bool gpt_partition_type_knows_growfs(sd_id128_t id) { return gpt_partition_type_is_root(id) || gpt_partition_type_is_usr(id) || - sd_id128_in_set(id, - SD_GPT_HOME, - SD_GPT_SRV, - SD_GPT_VAR, - SD_GPT_TMP, - SD_GPT_XBOOTLDR); + IN_SET(gpt_partition_type_from_uuid(id).designator, + PARTITION_HOME, + PARTITION_SRV, + PARTITION_VAR, + PARTITION_TMP, + PARTITION_XBOOTLDR); } bool gpt_partition_type_knows_no_auto(sd_id128_t id) { @@ -196,11 +393,11 @@ bool gpt_partition_type_knows_no_auto(sd_id128_t id) { gpt_partition_type_is_root_verity(id) || gpt_partition_type_is_usr(id) || gpt_partition_type_is_usr_verity(id) || - sd_id128_in_set(id, - SD_GPT_HOME, - SD_GPT_SRV, - SD_GPT_VAR, - SD_GPT_TMP, - SD_GPT_XBOOTLDR, - SD_GPT_SWAP); + IN_SET(gpt_partition_type_from_uuid(id).designator, + PARTITION_HOME, + PARTITION_SRV, + PARTITION_VAR, + PARTITION_TMP, + PARTITION_XBOOTLDR, + PARTITION_SWAP); } diff --git a/src/shared/gpt.h b/src/shared/gpt.h index f673194d4a..e0ab44a642 100644 --- a/src/shared/gpt.h +++ b/src/shared/gpt.h @@ -10,6 +10,48 @@ /* maximum length of gpt label */ #define GPT_LABEL_MAX 36 +typedef enum PartitionDesignator { + PARTITION_ROOT, /* Primary architecture */ + PARTITION_ROOT_SECONDARY, /* Secondary architecture */ + PARTITION_ROOT_OTHER, /* Any architecture not covered by the primary or secondary architecture. */ + PARTITION_USR, + PARTITION_USR_SECONDARY, + PARTITION_USR_OTHER, + PARTITION_HOME, + PARTITION_SRV, + PARTITION_ESP, + PARTITION_XBOOTLDR, + PARTITION_SWAP, + PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */ + PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */ + PARTITION_ROOT_OTHER_VERITY, + PARTITION_USR_VERITY, + PARTITION_USR_SECONDARY_VERITY, + PARTITION_USR_OTHER_VERITY, + PARTITION_ROOT_VERITY_SIG, /* PKCS#7 signature for root hash for the PARTITION_ROOT partition */ + PARTITION_ROOT_SECONDARY_VERITY_SIG, /* ditto for the PARTITION_ROOT_SECONDARY partition */ + PARTITION_ROOT_OTHER_VERITY_SIG, + PARTITION_USR_VERITY_SIG, + PARTITION_USR_SECONDARY_VERITY_SIG, + PARTITION_USR_OTHER_VERITY_SIG, + PARTITION_TMP, + PARTITION_VAR, + PARTITION_USER_HOME, + PARTITION_LINUX_GENERIC, + _PARTITION_DESIGNATOR_MAX, + _PARTITION_DESIGNATOR_INVALID = -EINVAL, +} PartitionDesignator; + +bool partition_designator_is_versioned(PartitionDesignator d); + +PartitionDesignator partition_verity_of(PartitionDesignator p); +PartitionDesignator partition_verity_sig_of(PartitionDesignator p); +PartitionDesignator partition_root_of_arch(Architecture arch); +PartitionDesignator partition_usr_of_arch(Architecture arch); + +const char* partition_designator_to_string(PartitionDesignator d) _const_; +PartitionDesignator partition_designator_from_string(const char *name) _pure_; + const char *gpt_partition_type_uuid_to_string(sd_id128_t id); const char *gpt_partition_type_uuid_to_string_harder( sd_id128_t id, @@ -25,13 +67,7 @@ typedef struct GptPartitionType { sd_id128_t uuid; const char *name; Architecture arch; - - bool is_root:1; - bool is_root_verity:1; - bool is_root_verity_sig:1; - bool is_usr:1; - bool is_usr_verity:1; - bool is_usr_verity_sig:1; + PartitionDesignator designator; } GptPartitionType; extern const GptPartitionType gpt_partition_type_table[]; @@ -45,6 +81,8 @@ bool gpt_partition_type_is_usr(sd_id128_t id); bool gpt_partition_type_is_usr_verity(sd_id128_t id); bool gpt_partition_type_is_usr_verity_sig(sd_id128_t id); +const char *gpt_partition_type_mountpoint_nulstr(sd_id128_t id); + bool gpt_partition_type_knows_read_only(sd_id128_t id); bool gpt_partition_type_knows_growfs(sd_id128_t id); bool gpt_partition_type_knows_no_auto(sd_id128_t id); diff --git a/src/test/test-copy.c b/src/test/test-copy.c index 00a38b18f6..103f7ca73c 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -67,11 +67,11 @@ TEST(copy_tree_replace_file) { /* The file exists- now overwrite original contents, and test the COPY_REPLACE flag. */ - assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK) == -EEXIST); + assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK, NULL) == -EEXIST); assert_se(read_file_at_and_streq(AT_FDCWD, dst, "foo foo foo\n")); - assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE) == 0); + assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE, NULL) == 0); assert_se(read_file_at_and_streq(AT_FDCWD, dst, "bar bar\n")); } @@ -91,14 +91,14 @@ TEST(copy_tree_replace_dirs) { assert_se(write_string_file_at(dst, "bar", "dest file 2", WRITE_STRING_FILE_CREATE) == 0); /* Copying without COPY_REPLACE should fail because the destination file already exists. */ - assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK) == -EEXIST); + assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK, NULL) == -EEXIST); assert_se(read_file_at_and_streq(src, "foo", "src file 1\n")); assert_se(read_file_at_and_streq(src, "bar", "src file 2\n")); assert_se(read_file_at_and_streq(dst, "foo", "dest file 1\n")); assert_se(read_file_at_and_streq(dst, "bar", "dest file 2\n")); - assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE) == 0); + assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE, NULL) == 0); assert_se(read_file_at_and_streq(src, "foo", "src file 1\n")); assert_se(read_file_at_and_streq(src, "bar", "src file 2\n")); @@ -131,6 +131,8 @@ TEST(copy_file_fd) { } TEST(copy_tree) { + _cleanup_set_free_ Set *denylist = NULL; + _cleanup_free_ char *cp = NULL; char original_dir[] = "/tmp/test-copy_tree/"; char copy_dir[] = "/tmp/test-copy_tree-copy/"; char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file"); @@ -138,7 +140,7 @@ TEST(copy_tree) { "link2", "dir1/file"); char **hardlinks = STRV_MAKE("hlink", "file", "hlink2", "dir1/file"); - const char *unixsockp; + const char *unixsockp, *ignorep; struct stat st; int xattr_worked = -1; /* xattr support is optional in temporary directories, hence use it if we can, * but don't fail if we can't */ @@ -184,7 +186,14 @@ TEST(copy_tree) { unixsockp = strjoina(original_dir, "unixsock"); assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0); - assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS) == 0); + ignorep = strjoina(original_dir, "ignore/file"); + assert_se(write_string_file(ignorep, "ignore", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) == 0); + assert_se(RET_NERRNO(stat(ignorep, &st)) >= 0); + assert_se(cp = memdup(&st, sizeof(st))); + assert_se(set_ensure_put(&denylist, &inode_hash_ops, cp) >= 0); + TAKE_PTR(cp); + + assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS, denylist) == 0); STRV_FOREACH(p, files) { _cleanup_free_ char *buf, *f, *c = NULL; @@ -236,8 +245,11 @@ TEST(copy_tree) { assert_se(stat(unixsockp, &st) >= 0); assert_se(S_ISSOCK(st.st_mode)); - assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK) < 0); - assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK) < 0); + assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK, denylist) < 0); + assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK, denylist) < 0); + + ignorep = strjoina(copy_dir, "ignore/file"); + assert_se(RET_NERRNO(access(ignorep, F_OK)) == -ENOENT); (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL); (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 1fec6d4831..d3258ec701 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1637,7 +1637,8 @@ static int copy_files(Item *i) { dfd, bn, i->uid_set ? i->uid : UID_INVALID, i->gid_set ? i->gid : GID_INVALID, - COPY_REFLINK | COPY_MERGE_EMPTY | COPY_MAC_CREATE | COPY_HARDLINKS); + COPY_REFLINK | COPY_MERGE_EMPTY | COPY_MAC_CREATE | COPY_HARDLINKS, + NULL); fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH); if (fd < 0) { diff --git a/test/units/testsuite-58.sh b/test/units/testsuite-58.sh index 5a515d9c01..640b8440dc 100755 --- a/test/units/testsuite-58.sh +++ b/test/units/testsuite-58.sh @@ -777,6 +777,60 @@ EOF systemd-dissect -U "$imgs/mnt" } +test_issue_24786() { + local defs imgs root output + + if systemd-detect-virt --quiet --container; then + echo "Skipping verity test in container." + return + fi + + defs="$(mktemp --directory "/tmp/test-repart.XXXXXXXXXX")" + imgs="$(mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")" + root="$(mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")" + # shellcheck disable=SC2064 + trap "rm -rf '$defs' '$imgs' '$root'" RETURN + + touch "$root/abc" + mkdir "$root/usr" + touch "$root/usr/def" + + cat >"$defs/00-root.conf" <"$defs/10-usr.conf" <= 512 and <= PAGE_SIZE, and # must be powers of 2. Which leaves exactly four different ones to test on