repart: support generating LUKS+Verity partitions
For various cases it is interesting to both sign and encrypted a file system, for example to prepare it on one host and provide it to another. Let's explicitly support preparing this in systemd-repart via setting both Verity= and Encrypt=.
This commit is contained in:
+17
-1
@@ -709,6 +709,10 @@
|
||||
|
||||
<para>This option has no effect if the partition already exists.</para>
|
||||
|
||||
<para>This option may be combined with <varname>Verity=data</varname> in order to place the
|
||||
encrypted partition inside a dm-verity protection envelope, see the description of
|
||||
<varname>Verity=</varname> below.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v247"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -773,7 +777,19 @@
|
||||
|
||||
<para>This option has no effect if the partition already exists.</para>
|
||||
|
||||
<para>Usage of this option in combination with <varname>Encrypt=</varname> is not supported.</para>
|
||||
<para><literal>data</literal> may be combined with <varname>Encrypt=</varname>, in which case the
|
||||
partition is first encrypted with LUKS2 and the verity hash data is then generated from the
|
||||
resulting ciphertext, i.e. Verity is the outer protection envelope and LUKS2 the inner. Tools such
|
||||
as <citerefentry><refentrytitle>systemd-dissect</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
will then set up the dm-verity device first, and open the LUKS2 volume on top of it, so that all
|
||||
encrypted data read is also authenticated via the verity root hash. Note that in this case the
|
||||
verity hashes necessarily cover freshly generated ciphertext, hence the root hash (and thus the
|
||||
default partition UUIDs derived from it) will change on every build, even if the plaintext contents
|
||||
are fully reproducible. <varname>Encrypt=</varname> may not be combined with
|
||||
<literal>Verity=hash</literal> or <literal>Verity=signature</literal>. Since the ciphertext is only
|
||||
generated while the final image is built, <varname>Minimize=</varname> cannot be used for the hash
|
||||
partition of an encrypted data partition; use <varname>SizeMaxBytes=</varname> on the data partition
|
||||
to size the hash partition instead.</para>
|
||||
|
||||
<para>For each unique <varname>VerityMatchKey=</varname> value, a single verity data partition
|
||||
(<literal>Verity=data</literal>) and a single verity hash partition (<literal>Verity=hash</literal>)
|
||||
|
||||
+28
-2
@@ -3138,9 +3138,9 @@ static int partition_read_definition(
|
||||
verity_mode_to_string(p->verity));
|
||||
}
|
||||
|
||||
if (p->verity != VERITY_OFF && p->encrypt != ENCRYPT_OFF)
|
||||
if (IN_SET(p->verity, VERITY_HASH, VERITY_SIG) && p->encrypt != ENCRYPT_OFF)
|
||||
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Encrypting verity hash/data partitions is not supported.");
|
||||
"Encrypting verity hash/signature partitions is not supported.");
|
||||
|
||||
if (p->verity == VERITY_SIG && (p->size_min != UINT64_MAX || p->size_max != UINT64_MAX))
|
||||
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
|
||||
@@ -3667,6 +3667,13 @@ static int context_read_definitions(Context *context) {
|
||||
if (dp->minimize == MINIMIZE_OFF && !(dp->copy_blocks_path || dp->copy_blocks_auto))
|
||||
return log_syntax(NULL, LOG_ERR, p->definition_path, 1, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Minimize= set for verity hash partition but data partition does not set CopyBlocks= or Minimize=.");
|
||||
|
||||
/* The verity hash of an encrypted data partition covers the ciphertext, which is generated
|
||||
* with a fresh volume key only when the final image is built, hence it cannot be
|
||||
* precalculated for minimizing purposes. */
|
||||
if (dp->encrypt != ENCRYPT_OFF)
|
||||
return log_syntax(NULL, LOG_ERR, p->definition_path, 1, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Minimize= cannot be set for verity hash partitions whose data partition is encrypted, use SizeMaxBytes= on the data partition instead.");
|
||||
}
|
||||
|
||||
LIST_FOREACH(partitions, p, context->partitions) {
|
||||
@@ -5323,6 +5330,15 @@ static int partition_target_prepare(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void partition_target_drop_decrypted(PartitionTarget *t) {
|
||||
assert(t);
|
||||
|
||||
/* Deactivate the dm-crypt device again, so that subsequent access to the target reaches the
|
||||
* encrypted data as it is stored on disk (i.e. the ciphertext). Requires the target to have been
|
||||
* sync'ed first. */
|
||||
t->decrypted = decrypted_partition_target_free(t->decrypted);
|
||||
}
|
||||
|
||||
static int partition_target_grow(PartitionTarget *t, uint64_t size) {
|
||||
int r;
|
||||
|
||||
@@ -6411,6 +6427,11 @@ static int context_copy_blocks(Context *context) {
|
||||
p->partno, FORMAT_TIMESPAN(time_spent, 0));
|
||||
|
||||
if (p->siblings[VERITY_HASH] && !partition_defer(context, p->siblings[VERITY_HASH])) {
|
||||
/* The verity hash must cover the partition contents as stored on disk, i.e. the
|
||||
* ciphertext if the partition is encrypted, hence tear down the dm-crypt device
|
||||
* first. */
|
||||
partition_target_drop_decrypted(t);
|
||||
|
||||
r = partition_format_verity_hash(context, p->siblings[VERITY_HASH],
|
||||
/* node= */ NULL, partition_target_path(t));
|
||||
if (r < 0)
|
||||
@@ -7600,6 +7621,11 @@ static int context_mkfs(Context *context) {
|
||||
return r;
|
||||
|
||||
if (p->siblings[VERITY_HASH] && !partition_defer(context, p->siblings[VERITY_HASH])) {
|
||||
/* The verity hash must cover the partition contents as stored on disk, i.e. the
|
||||
* ciphertext if the partition is encrypted, hence tear down the dm-crypt device
|
||||
* first. */
|
||||
partition_target_drop_decrypted(t);
|
||||
|
||||
r = partition_format_verity_hash(context, p->siblings[VERITY_HASH],
|
||||
/* node= */ NULL, partition_target_path(t));
|
||||
if (r < 0)
|
||||
|
||||
Reference in New Issue
Block a user