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:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -10,4 +10,5 @@
|
||||
[Unit]
|
||||
Description=Block Device Preparation for %f
|
||||
Documentation=man:systemd.special(7)
|
||||
DefaultDependencies=no
|
||||
StopWhenUnneeded=yes
|
||||
|
||||
@@ -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', ''],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user