gpt-auto-generator: add support for setting up verity partitions automatically

So far the gpt-auto-generator would only cover unprotected and encrypted
partitions. Teach it handling of verity too.
This commit is contained in:
Lennart Poettering
2025-03-17 21:38:12 +01:00
parent 7852e301e0
commit 0a64b7ba6e
2 changed files with 131 additions and 5 deletions

View File

@@ -24,6 +24,7 @@
#include "fstab-util.h"
#include "generator.h"
#include "gpt.h"
#include "hexdecoct.h"
#include "image-policy.h"
#include "initrd-util.h"
#include "mountpoint-util.h"
@@ -184,6 +185,106 @@ static int add_cryptsetup(
#endif
}
#if ENABLE_EFI
static int add_veritysetup(
const char *id,
const char *data_what,
const char *hash_what,
const char *mount_opts) {
#if HAVE_LIBCRYPTSETUP
int r;
assert(id);
assert(data_what);
assert(hash_what);
_cleanup_free_ char *dd = NULL;
r = unit_name_from_path(data_what, ".device", &dd);
if (r < 0)
return log_error_errno(r, "Failed to generate data device unit name: %m");
_cleanup_free_ char *dh = NULL;
r = unit_name_from_path(hash_what, ".device", &dh);
if (r < 0)
return log_error_errno(r, "Failed to generate hash device unit name: %m");
_cleanup_free_ char *e = unit_name_escape(id);
if (!e)
return log_oom();
_cleanup_free_ char *n = NULL;
r = unit_name_build("systemd-veritysetup", e, ".service", &n);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
_cleanup_fclose_ FILE *f = NULL;
r = generator_open_unit_file(arg_dest, /* source= */ NULL, n, &f);
if (r < 0)
return r;
r = generator_write_veritysetup_unit_section(f, /* source= */ NULL);
if (r < 0)
return r;
fprintf(f,
"Before=veritysetup.target\n"
"BindsTo=%1$s %2$s\n"
"After=%1$s %2$s\n",
dd, dh);
r = generator_write_veritysetup_service_section(
f,
id,
data_what,
hash_what,
/* roothash= */ NULL, /* NULL means: derive root hash from udev property ID_DISSECT_PART_ROOTHASH */
"root-hash-signature=auto"); /* auto means: derive signature from udev property ID_DISSECT_PART_ROOTHASH_SIG */
if (r < 0)
return r;
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write file %s: %m", n);
r = generator_write_device_timeout(arg_dest, data_what, mount_opts, /* filtered= */ NULL);
if (r < 0)
return r;
r = generator_write_device_timeout(arg_dest, hash_what, mount_opts, /* filtered= */ NULL);
if (r < 0)
return r;
r = generator_add_symlink(arg_dest, dd, "wants", n);
if (r < 0)
return r;
r = generator_add_symlink(arg_dest, dh, "wants", n);
if (r < 0)
return r;
_cleanup_free_ char *dmname = NULL;
dmname = strjoin("dev-mapper-", e, ".device");
if (!dmname)
return log_oom();
r = write_drop_in_format(
arg_dest,
dmname, 50, "job-timeout",
"# Automatically generated by systemd-gpt-auto-generator\n\n"
"[Unit]\n"
"JobTimeoutSec=infinity"); /* the binary handles timeouts anyway */
if (r < 0)
return log_error_errno(r, "Failed to write device timeout drop-in: %m");
return 0;
#else
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Partition is Verity protected, but systemd-gpt-auto-generator was compiled without libcryptsetup support.");
#endif
}
#endif
static int add_mount(
const char *id,
const char *what,
@@ -757,6 +858,18 @@ static int add_root_mount(void) {
r = add_root_cryptsetup();
if (r < 0)
return r;
/* If a device /dev/disk/by-designator/root-verity or
* /dev/disk/by-designator/root-verity-data appears, then make it pull in
* systemd-cryptsetup@root.service, which sets it up, and causes /dev/disk/by-designator/root
* to appear. */
r = add_veritysetup(
"root",
"/dev/disk/by-designator/root-verity-data",
"/dev/disk/by-designator/root-verity",
arg_root_options);
if (r < 0)
return r;
}
/* Note that we do not need to enable systemd-remount-fs.service here. If /etc/fstab exists,
@@ -793,7 +906,6 @@ static int add_root_mount(void) {
#endif
}
static int add_usr_mount(void) {
#if ENABLE_EFI
int r;
@@ -828,6 +940,18 @@ static int add_usr_mount(void) {
/* ret_device= */ NULL);
if (r < 0)
return r;
/* If a device /dev/disk/by-designator/usr-verity or
* /dev/disk/by-designator/usr-verity-data appears, then make it pull in
* systemd-cryptsetup@usr.service, which sets it up, and causes /dev/disk/by-designator/usr
* to appear. */
r = add_veritysetup(
"usr",
"/dev/disk/by-designator/usr-verity-data",
"/dev/disk/by-designator/usr-verity",
arg_usr_options);
if (r < 0)
return r;
}
_cleanup_free_ char *options = NULL;

View File

@@ -1026,9 +1026,11 @@ int generator_write_veritysetup_service_section(
if (!hash_what_escaped)
return log_oom();
roothash_escaped = specifier_escape(roothash);
if (!roothash_escaped)
return log_oom();
if (roothash) {
roothash_escaped = specifier_escape(roothash);
if (!roothash_escaped)
return log_oom();
}
if (options) {
options_escaped = specifier_escape(options);
@@ -1043,7 +1045,7 @@ int generator_write_veritysetup_service_section(
"RemainAfterExit=yes\n"
"ExecStart=" SYSTEMD_VERITYSETUP_PATH " attach '%s' '%s' '%s' '%s' '%s'\n"
"ExecStop=" SYSTEMD_VERITYSETUP_PATH " detach '%s'\n",
name_escaped, data_what_escaped, hash_what_escaped, roothash_escaped, strempty(options_escaped),
name_escaped, data_what_escaped, hash_what_escaped, empty_to_dash(roothash_escaped), strempty(options_escaped),
name_escaped);
return 0;