From: Emanuele Giuseppe Esposito Date: Mon, 14 Jul 2025 09:51:49 +0000 (-0400) Subject: repart: make --key-file also configurable in repart.d/* X-Git-Tag: v259-rc1~533^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb44fa4d198d1da11c998f77bc88f95aaf67e186;p=thirdparty%2Fsystemd.git repart: make --key-file also configurable in repart.d/* 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. --- diff --git a/man/repart.d.xml b/man/repart.d.xml index 0eaf22f9ae2..9d8372fa302 100644 --- a/man/repart.d.xml +++ b/man/repart.d.xml @@ -880,6 +880,18 @@ + + KeyFile= + + 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 + Encrypt=key-file setting in partition files. Please refer to the documentation of + --key-file= for more details. This option will be overridden by the global + --key-file= option. + + + + Compression= diff --git a/man/systemd-repart.xml b/man/systemd-repart.xml index 7a739752eb4..317ae05826a 100644 --- a/man/systemd-repart.xml +++ b/man/systemd-repart.xml @@ -338,9 +338,9 @@ volumes configured with the Encrypt=key-file setting in partition files. Should refer to a regular file containing the key, or an AF_UNIX 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. + is not specified, and no KeyFile= 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. diff --git a/src/repart/repart.c b/src/repart/repart.c index 19a339be29e..4b6fbb829ad 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -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; }