]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: make --key-file also configurable in repart.d/* 38052/head
authorEmanuele Giuseppe Esposito <eesposit@redhat.com>
Mon, 14 Jul 2025 09:51:49 +0000 (05:51 -0400)
committerEmanuele Giuseppe Esposito <eesposit@redhat.com>
Tue, 26 Aug 2025 11:17:12 +0000 (07:17 -0400)
Add repart.d KeyFile= option with the same syntax as --key-file.
This allows a per-partition key file encryption, and not rely on a global key
applicable to all partitions.

The global --key-file overrides KeyFile config. If none of them is
defined, rely on default.

man/repart.d.xml
man/systemd-repart.xml
src/repart/repart.c

index 0eaf22f9ae2558d4f8341fbd730d57228c092597..9d8372fa302fefa01b8d295f8563a375ffa3f329 100644 (file)
         <xi:include href="version-info.xml" xpointer="v259"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>KeyFile=</varname></term>
+
+        <listitem><para>Takes a file system path. This path must be absolute, otherwise the option is ignored.
+        Configures the encryption key to use when setting up LUKS2 volumes configured with the
+        <varname>Encrypt=key-file</varname> setting in partition files. Please refer to the documentation of
+        <varname>--key-file=</varname> for more details. This option will be overridden by the global
+        <varname>--key-file=</varname> option.</para>
+
+        <xi:include href="version-info.xml" xpointer="v259"/></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>Compression=</varname></term>
 
index 7a739752eb4dc29423c1a93b98d261ce5d3ea09b..317ae05826a82a9ba21034f004a33732d80ebb1c 100644 (file)
         volumes configured with the <varname>Encrypt=key-file</varname> setting in partition files. Should
         refer to a regular file containing the key, or an <constant>AF_UNIX</constant> stream socket in the
         file system. In the latter case, a connection is made to it and the key read from it. If this switch
-        is not specified, the empty key (i.e. zero length key) is used. This behaviour is useful for setting
-        up encrypted partitions during early first boot that receive their user-supplied password only in a
-        later setup step.</para>
+        is not specified, and no <varname>KeyFile=</varname> is specified in the partition file, the empty
+        key (i.e. zero length key) is used. This behaviour is useful for setting up encrypted partitions during
+        early first boot that receive their user-supplied password only in a later setup step.</para>
 
         <xi:include href="version-info.xml" xpointer="v247"/></listitem>
       </varlistentry>
index 19a339be29e4830dbb7b4f1df4e7f2a86d06754e..4b6fbb829adbc44a3ac1bbd82d521d1f0d7c8385 100644 (file)
@@ -411,6 +411,7 @@ typedef struct Partition {
         OrderedHashmap *subvolumes;
         char *default_subvolume;
         EncryptMode encrypt;
+        struct iovec key;
         Tpm2PCRValue *tpm2_hash_pcr_values;
         size_t tpm2_n_hash_pcr_values;
         VerityMode verity;
@@ -681,6 +682,8 @@ static Partition* partition_free(Partition *p) {
         free(p->compression);
         free(p->compression_level);
 
+        iovec_done_erase(&p->key);
+
         copy_files_free_many(p->copy_files, p->n_copy_files);
 
         iovec_done(&p->roothash);
@@ -723,6 +726,8 @@ static void partition_foreignize(Partition *p) {
         p->compression = mfree(p->compression);
         p->compression_level = mfree(p->compression_level);
 
+        iovec_done_erase(&p->key);
+
         copy_files_free_many(p->copy_files, p->n_copy_files);
         p->copy_files = NULL;
         p->n_copy_files = 0;
@@ -2496,6 +2501,51 @@ static int config_parse_tpm2_pcrs(
                                               &partition->tpm2_n_hash_pcr_values);
 }
 
+static int parse_key_file(const char *filename, struct iovec *key) {
+        _cleanup_(erase_and_freep) char *k = NULL;
+        size_t n = 0;
+        int r;
+
+        r = read_full_file_full(
+                        AT_FDCWD, filename,
+                        /* offset= */ UINT64_MAX,
+                        /* size= */ SIZE_MAX,
+                        READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
+                        /* bind_name= */ NULL,
+                        &k, &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to read key file '%s': %m", filename);
+
+        iovec_done_erase(key);
+        *key = IOVEC_MAKE(TAKE_PTR(k), n);
+
+        return 0;
+}
+
+static int config_parse_key_file(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Partition *partition = ASSERT_PTR(userdata);
+
+        assert(rvalue);
+
+        if (isempty(rvalue)) {
+                iovec_done_erase(&partition->key);
+                return 0;
+        }
+
+        return parse_key_file(rvalue, &partition->key);
+}
+
 static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_verity, verity_mode, VerityMode, VERITY_OFF);
 static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_minimize, minimize_mode, MinimizeMode, MINIMIZE_OFF);
 
@@ -2602,6 +2652,7 @@ static int partition_read_definition(Partition *p, const char *path, const char
                 { "Partition", "MountPoint",               config_parse_mountpoint,        0,                                  p                           },
                 { "Partition", "EncryptedVolume",          config_parse_encrypted_volume,  0,                                  p                           },
                 { "Partition", "TPM2PCRs",                 config_parse_tpm2_pcrs,         0,                                  p                           },
+                { "Partition", "KeyFile",                  config_parse_key_file,          0,                                  p                           },
                 { "Partition", "Compression",              config_parse_string,            CONFIG_PARSE_STRING_SAFE_AND_ASCII, &p->compression             },
                 { "Partition", "CompressionLevel",         config_parse_string,            CONFIG_PARSE_STRING_SAFE_AND_ASCII, &p->compression_level       },
                 { "Partition", "SupplementFor",            config_parse_string,            0,                                  &p->supplement_for_name     },
@@ -4823,18 +4874,21 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
                 return log_error_errno(r, "Failed to LUKS2 format future partition: %m");
 
         if (IN_SET(p->encrypt, ENCRYPT_KEY_FILE, ENCRYPT_KEY_FILE_TPM2)) {
+                /* Use partition-specific key if available, otherwise fall back to global key */
+                struct iovec *iovec_key = arg_key.iov_base ? &arg_key : &p->key;
+
                 r = sym_crypt_keyslot_add_by_volume_key(
                                 cd,
                                 CRYPT_ANY_SLOT,
                                 NULL,
                                 VOLUME_KEY_SIZE,
-                                strempty(arg_key.iov_base),
-                                arg_key.iov_len);
+                                strempty(iovec_key->iov_base),
+                                iovec_key->iov_len);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add LUKS2 key: %m");
 
-                passphrase = strempty(arg_key.iov_base);
-                passphrase_size = arg_key.iov_len;
+                passphrase = strempty(iovec_key->iov_base);
+                passphrase_size = iovec_key->iov_len;
         }
 
         if (IN_SET(p->encrypt, ENCRYPT_TPM2, ENCRYPT_KEY_FILE_TPM2)) {
@@ -8845,21 +8899,9 @@ static int parse_argv(int argc, char *argv[], X509 **ret_certificate, EVP_PKEY *
                         break;
 
                 case ARG_KEY_FILE: {
-                        struct iovec key = {};
-
-                        r = read_full_file_full(
-                                        AT_FDCWD, optarg,
-                                        /* offset= */ UINT64_MAX,
-                                        /* size= */ SIZE_MAX,
-                                        READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
-                                        /* bind_name= */ NULL,
-                                        (char **) &key.iov_base,
-                                        &key.iov_len);
+                        r = parse_key_file(optarg, &arg_key);
                         if (r < 0)
-                                return log_error_errno(r, "Failed to read key file '%s': %m", optarg);
-
-                        iovec_done_erase(&arg_key);
-                        arg_key = key;
+                                return r;
                         break;
                 }