diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index 083878e42a..a22d932342 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -282,6 +282,18 @@ static int print_dependencies(FILE *f, const char* device_path, const char* time return 0; } +static bool attach_in_initrd(const char *name, const char *options) { + assert(name); + + /* Imply x-initrd.attach in case the volume name is among those defined in the Discoverable Partition + * Specification for partitions that we require to be mounted during the initrd → host transition, + * i.e. for the root fs itself, and /usr/. This mirrors similar behaviour in + * systemd-fstab-generator. */ + + return fstab_test_option(options, "x-initrd.attach\0") || + STR_IN_SET(name, "root", "usr"); +} + static int create_disk( const char *name, const char *device, @@ -297,7 +309,7 @@ static int create_disk( *tmp_fstype = NULL, *filtered_header = NULL, *headerdev_mount = NULL; _cleanup_fclose_ FILE *f = NULL; const char *dmname; - bool noauto, nofail, swap, netdev, attach_in_initrd; + bool noauto, nofail, swap, netdev; int r, detached_header, keyfile_can_timeout, tmp; assert(name); @@ -307,7 +319,6 @@ static int create_disk( nofail = fstab_test_yes_no_option(options, "nofail\0" "fail\0"); swap = fstab_test_option(options, "swap\0"); netdev = fstab_test_option(options, "_netdev\0"); - attach_in_initrd = fstab_test_option(options, "x-initrd.attach\0"); keyfile_can_timeout = fstab_filter_options(options, "keyfile-timeout\0", @@ -374,8 +385,10 @@ static int create_disk( fprintf(f, "After=remote-fs-pre.target\n"); /* If initrd takes care of attaching the disk then it should also detach it during shutdown. */ - if (!attach_in_initrd) - fprintf(f, "Conflicts=umount.target\n"); + if (!attach_in_initrd(name, options)) + fprintf(f, + "Conflicts=umount.target\n" + "Before=umount.target\n"); if (keydev) { _cleanup_free_ char *unit = NULL, *umount_unit = NULL; @@ -490,17 +503,16 @@ static int create_disk( if (path_startswith(u, "/dev/")) fprintf(f, "BindsTo=%s\n" - "After=%s\n" - "Before=umount.target\n", + "After=%s\n", d, d); else - /* For loopback devices, add systemd-tmpfiles-setup-dev.service - dependency to ensure that loopback support is available in - the kernel (/dev/loop-control needs to exist) */ + /* For loopback devices make sure to explicitly load loop.ko, as this code might run very + * early where device nodes created via systemd-tmpfiles-setup-dev.service might not be + * around yet. Hence let's sync on the module itself. */ fprintf(f, "RequiresMountsFor=%s\n" - "Requires=systemd-tmpfiles-setup-dev.service\n" - "After=systemd-tmpfiles-setup-dev.service\n", + "Wants=modprobe@loop.service\n" + "After=modprobe@loop.service\n", u_escaped); r = generator_write_timeouts(arg_dest, device, name, options, &filtered); diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 3dadf83d62..d58defcc42 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -986,7 +986,7 @@ static int attach_tcrypt( if (arg_tcrypt_veracrypt) params.flags |= CRYPT_TCRYPT_VERA_MODES; - + if (arg_tcrypt_veracrypt && arg_tcrypt_veracrypt_pim != 0) params.veracrypt_pim = arg_tcrypt_veracrypt_pim; @@ -2324,13 +2324,13 @@ static int run(int argc, char *argv[]) { return 0; } if (r < 0) - return log_error_errno(r, "crypt_init_by_name() failed: %m"); + return log_error_errno(r, "crypt_init_by_name() for volume '%s' failed: %m", volume); cryptsetup_enable_logging(cd); r = crypt_deactivate(cd, volume); if (r < 0) - return log_error_errno(r, "Failed to deactivate: %m"); + return log_error_errno(r, "Failed to deactivate '%s': %m", volume); } else return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", verb); diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c index 164e71a150..d22cff2d82 100644 --- a/src/shared/fstab-util.c +++ b/src/shared/fstab-util.c @@ -54,7 +54,7 @@ bool fstab_is_extrinsic(const char *mount, const char *opts) { /* If this is an initrd mount, and we are not in the initrd, then leave * this around forever, too. */ - if (opts && fstab_test_option(opts, "x-initrd.mount\0") && !in_initrd()) + if (fstab_test_option(opts, "x-initrd.mount\0") && !in_initrd()) return true; return false; diff --git a/src/veritysetup/veritysetup-generator.c b/src/veritysetup/veritysetup-generator.c index 3481362e5f..303e0ced6d 100644 --- a/src/veritysetup/veritysetup-generator.c +++ b/src/veritysetup/veritysetup-generator.c @@ -47,39 +47,39 @@ STATIC_DESTRUCTOR_REGISTER(arg_usr_data_what, freep); STATIC_DESTRUCTOR_REGISTER(arg_usr_hash_what, freep); STATIC_DESTRUCTOR_REGISTER(arg_usr_options, freep); -static int create_device( +static int create_special_device( const char *name, const char *service, - const char *hash, + const char *roothash, const char *data_what, const char *hash_what, const char *options) { - _cleanup_free_ char *u = NULL, *v = NULL, *d = NULL, *e = NULL, *u_escaped = NULL, *v_escaped = NULL, - *hash_escaped = NULL, *options_escaped = NULL; + _cleanup_free_ char *u = NULL, *v = NULL, *d = NULL, *e = NULL; _cleanup_fclose_ FILE *f = NULL; - const char *to, *from; int r; + /* Creates a systemd-veritysetup@.service instance for the special kernel cmdline specified root + usr devices. */ + assert(name); assert(service); /* If all three pieces of information are missing, then verity is turned off */ - if (!hash && !data_what && !hash_what) + if (!roothash && !data_what && !hash_what) return 0; /* if one of them is missing however, the data is simply incomplete and this is an error */ - if (!hash) - log_error("Verity information for %s incomplete, hash unspecified.", name); + if (!roothash) + log_error("Verity information for %s incomplete, root hash unspecified.", name); if (!data_what) log_error("Verity information for %s incomplete, data device unspecified.", name); if (!hash_what) log_error("Verity information for %s incomplete, hash device unspecified.", name); - if (!hash || !data_what || !hash_what) + if (!roothash || !data_what || !hash_what) return -EINVAL; - log_debug("Using %s verity data device %s, hash device %s, options %s, and hash %s.", name, data_what, hash_what, options, hash); + log_debug("Using %s verity data device %s, hash device %s, options %s, and hash %s.", name, data_what, hash_what, options, roothash); u = fstab_node_to_udev_node(data_what); if (!u) @@ -88,13 +88,6 @@ static int create_device( if (!v) return log_oom(); - u_escaped = specifier_escape(u); - if (!u_escaped) - return log_oom(); - v_escaped = specifier_escape(v); - if (!v_escaped) - return log_oom(); - r = unit_name_from_path(u, ".device", &d); if (r < 0) return log_error_errno(r, "Failed to generate unit name: %m"); @@ -102,59 +95,42 @@ static int create_device( if (r < 0) return log_error_errno(r, "Failed to generate unit name: %m"); - options_escaped = specifier_escape(strempty(options)); - if (!options_escaped) - return log_oom(); - - hash_escaped = specifier_escape(hash); - if (!hash_escaped) - return log_oom(); - r = generator_open_unit_file(arg_dest, NULL, service, &f); if (r < 0) return r; + r = generator_write_veritysetup_unit_section(f, "/proc/cmdline"); + if (r < 0) + return r; + fprintf(f, - "[Unit]\n" - "Description=Verity Protection Setup for %%I\n" - "Documentation=man:systemd-veritysetup-generator(8) man:systemd-veritysetup@.service(8)\n" - "SourcePath=/proc/cmdline\n" - "DefaultDependencies=no\n" - "Conflicts=umount.target\n" + "Before=veritysetup.target\n" "BindsTo=%s %s\n" - "IgnoreOnIsolate=true\n" - "After=veritysetup-pre.target systemd-udevd-kernel.socket %s %s\n" - "Before=veritysetup.target umount.target\n" - "\n[Service]\n" - "Type=oneshot\n" - "RemainAfterExit=yes\n" - "ExecStart=" ROOTLIBEXECDIR "/systemd-veritysetup attach '%s' '%s' '%s' '%s' '%s'\n" - "ExecStop=" ROOTLIBEXECDIR "/systemd-veritysetup detach '%s' \n", + "After=%s %s\n", d, e, - d, e, - name, u_escaped, v_escaped, hash_escaped, options_escaped, - name); + d, e); + + r = generator_write_veritysetup_service_section(f, name, u, v, roothash, options); + if (r < 0) + return r; r = fflush_and_check(f); if (r < 0) return log_error_errno(r, "Failed to write file unit %s: %m", service); - to = strjoina(arg_dest, "/veritysetup.target.requires/", service); - from = strjoina("../", service); - - (void) mkdir_parents(to, 0755); - if (symlink(from, to) < 0) - return log_error_errno(errno, "Failed to create symlink %s: %m", to); + r = generator_add_symlink(arg_dest, "veritysetup.target", "requires", service); + if (r < 0) + return r; return 0; } static int create_root_device(void) { - return create_device("root", SYSTEMD_VERITYSETUP_SERVICE_ROOT, arg_root_hash, arg_root_data_what, arg_root_hash_what, arg_root_options); + return create_special_device("root", SYSTEMD_VERITYSETUP_SERVICE_ROOT, arg_root_hash, arg_root_data_what, arg_root_hash_what, arg_root_options); } static int create_usr_device(void) { - return create_device("usr", SYSTEMD_VERITYSETUP_SERVICE_USR, arg_usr_hash, arg_usr_data_what, arg_usr_hash_what, arg_usr_options); + return create_special_device("usr", SYSTEMD_VERITYSETUP_SERVICE_USR, arg_usr_hash, arg_usr_data_what, arg_usr_hash_what, arg_usr_options); } static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { @@ -313,7 +289,19 @@ static int determine_devices(void) { return determine_device("usr", arg_usr_hash, &arg_usr_data_what, &arg_usr_hash_what); } -static int create_disk( +static bool attach_in_initrd(const char *name, const char *options) { + assert(name); + + /* Imply x-initrd.attach in case the volume name is among those defined in the Discoverable Partition + * Specification for partitions that we require to be mounted during the initrd → host transition, + * i.e. for the root fs itself, and /usr/. This mirrors similar behaviour in + * systemd-fstab-generator. */ + + return fstab_test_option(options, "x-initrd.attach\0") || + STR_IN_SET(name, "root", "usr"); +} + +static int create_veritytab_device( const char *name, const char *data_device, const char *hash_device, @@ -325,9 +313,11 @@ static int create_disk( *du_escaped = NULL, *hu_escaped = NULL, *name_escaped = NULL; _cleanup_fclose_ FILE *f = NULL; const char *dmname; - bool noauto, nofail, netdev, attach_in_initrd; + bool noauto, nofail, netdev, need_loop = false; int r; + /* Creates a systemd-veritysetup@.service instance for volumes specified in /etc/veritytab. */ + assert(name); assert(data_device); assert(hash_device); @@ -336,7 +326,6 @@ static int create_disk( noauto = fstab_test_yes_no_option(options, "noauto\0" "auto\0"); nofail = fstab_test_yes_no_option(options, "nofail\0" "fail\0"); netdev = fstab_test_option(options, "_netdev\0"); - attach_in_initrd = fstab_test_option(options, "x-initrd.attach\0"); name_escaped = specifier_escape(name); if (!name_escaped) @@ -386,8 +375,10 @@ static int create_disk( fprintf(f, "After=remote-fs-pre.target\n"); /* If initrd takes care of attaching the disk then it should also detach it during shutdown. */ - if (!attach_in_initrd) - fprintf(f, "Conflicts=umount.target\n"); + if (!attach_in_initrd(name, options)) + fprintf(f, + "Conflicts=umount.target\n" + "Before=umount.target\n"); if (!nofail) fprintf(f, @@ -397,36 +388,32 @@ static int create_disk( if (path_startswith(du, "/dev/")) fprintf(f, "BindsTo=%s\n" - "After=%s\n" - "Before=umount.target\n", + "After=%s\n", dd, dd); - else - /* For loopback devices, add systemd-tmpfiles-setup-dev.service - dependency to ensure that loopback support is available in - the kernel (/dev/loop-control needs to exist) */ - fprintf(f, - "RequiresMountsFor=%s\n" - "Requires=systemd-tmpfiles-setup-dev.service\n" - "After=systemd-tmpfiles-setup-dev.service\n", - du_escaped); + else { + fprintf(f, "RequiresMountsFor=%s\n", du_escaped); + need_loop = true; + } if (path_startswith(hu, "/dev/")) fprintf(f, "BindsTo=%s\n" - "After=%s\n" - "Before=umount.target\n", + "After=%s\n", hd, hd); - else - /* For loopback devices, add systemd-tmpfiles-setup-dev.service - dependency to ensure that loopback support is available in - the kernel (/dev/loop-control needs to exist) */ - fprintf(f, - "RequiresMountsFor=%s\n" - "Requires=systemd-tmpfiles-setup-dev.service\n" - "After=systemd-tmpfiles-setup-dev.service\n", - hu_escaped); + else { + fprintf(f, "RequiresMountsFor=%s\n", hu_escaped); + need_loop = true; + } - r = generator_write_veritysetup_service_section(f, name, du_escaped, hu_escaped, roothash, options); + if (need_loop) + /* For loopback devices make sure to explicitly load loop.ko, as this code might run very + * early where device nodes created via systemd-tmpfiles-setup-dev.service might not be + * around yet. Hence let's sync on the module itself. */ + fprintf(f, + "Wants=modprobe@loop.service\n" + "After=modprobe@loop.service\n"); + + r = generator_write_veritysetup_service_section(f, name, du, hu, roothash, options); if (r < 0) return r; @@ -492,7 +479,8 @@ static int add_veritytab_devices(void) { if (!hash_uuid) hash_uuid = path_startswith(hash_device, "/dev/disk/by-uuid/"); - r = create_disk(name, + r = create_veritytab_device( + name, data_device, hash_device, roothash, diff --git a/src/veritysetup/veritysetup.c b/src/veritysetup/veritysetup.c index be95c1f206..d73c2d39fb 100644 --- a/src/veritysetup/veritysetup.c +++ b/src/veritysetup/veritysetup.c @@ -398,7 +398,7 @@ static int run(int argc, char *argv[]) { } else r = crypt_activate_by_volume_key(cd, volume, m, l, arg_activate_flags); if (r < 0) - return log_error_errno(r, "Failed to set up verity device: %m"); + return log_error_errno(r, "Failed to set up verity device '%s': %m", volume); } else if (streq(verb, "detach")) { const char *volume; @@ -410,17 +410,17 @@ static int run(int argc, char *argv[]) { r = crypt_init_by_name(&cd, volume); if (r == -ENODEV) { - log_info("Volume %s already inactive.", volume); + log_info("Volume %s 'already' inactive.", volume); return 0; } if (r < 0) - return log_error_errno(r, "crypt_init_by_name() failed: %m"); + return log_error_errno(r, "crypt_init_by_name() for volume '%s' failed: %m", volume); cryptsetup_enable_logging(cd); r = crypt_deactivate(cd, volume); if (r < 0) - return log_error_errno(r, "Failed to deactivate: %m"); + return log_error_errno(r, "Failed to deactivate volume '%s': %m", volume); } else return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", verb); diff --git a/units/blockdev@.target b/units/blockdev@.target index ddc85bf890..1c86506351 100644 --- a/units/blockdev@.target +++ b/units/blockdev@.target @@ -10,4 +10,5 @@ [Unit] Description=Block Device Preparation for %f Documentation=man:systemd.special(7) +DefaultDependencies=no StopWhenUnneeded=yes diff --git a/units/meson.build b/units/meson.build index e6eb300661..fa76946ddb 100644 --- a/units/meson.build +++ b/units/meson.build @@ -96,6 +96,7 @@ units = [ ['sysinit.target', ''], ['syslog.socket', ''], ['system-systemd\\x2dcryptsetup.slice', 'HAVE_LIBCRYPTSETUP'], + ['system-systemd\\x2dveritysetup.slice','HAVE_LIBCRYPTSETUP'], ['system-update.target', ''], ['system-update-pre.target', ''], ['system-update-cleanup.service', ''], diff --git "a/units/system-systemd\\x2dcryptsetup.slice" "b/units/system-systemd\\x2dcryptsetup.slice" index 98206a9d06..e81925d587 100644 --- "a/units/system-systemd\\x2dcryptsetup.slice" +++ "b/units/system-systemd\\x2dcryptsetup.slice" @@ -8,6 +8,6 @@ # (at your option) any later version. [Unit] -Description=Cryptsetup Units Slice +Description=Encrypted Volume Units Service Slice Documentation=man:systemd-cryptsetup@.service(8) DefaultDependencies=no diff --git "a/units/system-systemd\\x2dveritysetup.slice" "b/units/system-systemd\\x2dveritysetup.slice" new file mode 100644 index 0000000000..8ccaac90e6 --- /dev/null +++ "b/units/system-systemd\\x2dveritysetup.slice" @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Verity Protection Service Slice +Documentation=man:systemd-cryptsetup@.service(8) +DefaultDependencies=no