Merge pull request #27889 from poettering/no-usr-verity-detach

veritysetup: make sure we don't try to detach /usr/ verity on shutdown
This commit is contained in:
Lennart Poettering
2023-06-02 06:24:13 +02:00
committed by GitHub
9 changed files with 114 additions and 99 deletions
+23 -11
View File
@@ -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);
+3 -3
View File
@@ -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);
+1 -1
View File
@@ -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;
+67 -79
View File
@@ -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,
+4 -4
View File
@@ -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);
+1
View File
@@ -10,4 +10,5 @@
[Unit]
Description=Block Device Preparation for %f
Documentation=man:systemd.special(7)
DefaultDependencies=no
StopWhenUnneeded=yes
+1
View File
@@ -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', ''],
+1 -1
View File
@@ -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
+13
View File
@@ -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