From: Emanuele Giuseppe Esposito Date: Thu, 3 Jul 2025 12:08:53 +0000 (-0400) Subject: repart: make --tpm2-pcrs also configurable in repart.d/* X-Git-Tag: v259-rc1~533^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=49dcc89ddc15651ebca8da7a13e5c5b08ec247cb;p=thirdparty%2Fsystemd.git repart: make --tpm2-pcrs also configurable in repart.d/* Add repart.d TPM2PCRs= option with the same syntax as --tpm2-pcrs. This allows a per-partition pcr binding, and not rely on a global config applicable to all partitions. The global --tpm2-pcrs overrides TPM2PCRs config. If none of them is defined, rely on default. --- diff --git a/man/repart.d.xml b/man/repart.d.xml index 8be41db0ecd..0eaf22f9ae2 100644 --- a/man/repart.d.xml +++ b/man/repart.d.xml @@ -867,6 +867,19 @@ + + TPM2PCRs= + + Configures the list of PCRs to use for LUKS2 volumes configured with + the Encrypt=tpm2 setting in partition files. + This option take the same parameters as the similary named options to + systemd-cryptenroll1 + and have the same effect on partitions where TPM2 enrollment is requested. + This option will be overridden by the global --tpm2-pcrs= option. + + + + Compression= diff --git a/src/repart/repart.c b/src/repart/repart.c index 34e9986918a..19a339be29e 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -411,6 +411,8 @@ typedef struct Partition { OrderedHashmap *subvolumes; char *default_subvolume; EncryptMode encrypt; + Tpm2PCRValue *tpm2_hash_pcr_values; + size_t tpm2_n_hash_pcr_values; VerityMode verity; char *verity_match_key; MinimizeMode minimize; @@ -674,6 +676,7 @@ static Partition* partition_free(Partition *p) { strv_free(p->make_symlinks); ordered_hashmap_free(p->subvolumes); free(p->default_subvolume); + free(p->tpm2_hash_pcr_values); free(p->verity_match_key); free(p->compression); free(p->compression_level); @@ -715,6 +718,7 @@ static void partition_foreignize(Partition *p) { p->make_symlinks = strv_free(p->make_symlinks); p->subvolumes = ordered_hashmap_free(p->subvolumes); p->default_subvolume = mfree(p->default_subvolume); + p->tpm2_hash_pcr_values = mfree(p->tpm2_hash_pcr_values); p->verity_match_key = mfree(p->verity_match_key); p->compression = mfree(p->compression); p->compression_level = mfree(p->compression_level); @@ -2465,6 +2469,33 @@ static int config_parse_encrypted_volume( return 0; } +static int config_parse_tpm2_pcrs( + 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(data); + + assert(rvalue); + + if (isempty(rvalue)) { + /* Clear existing PCR values if empty */ + partition->tpm2_hash_pcr_values = mfree(partition->tpm2_hash_pcr_values); + partition->tpm2_n_hash_pcr_values = 0; + return 0; + } + + return tpm2_parse_pcr_argument_append(rvalue, &partition->tpm2_hash_pcr_values, + &partition->tpm2_n_hash_pcr_values); +} + 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); @@ -2570,6 +2601,7 @@ static int partition_read_definition(Partition *p, const char *path, const char { "Partition", "VerityHashBlockSizeBytes", config_parse_block_size, 0, &p->verity_hash_block_size }, { "Partition", "MountPoint", config_parse_mountpoint, 0, p }, { "Partition", "EncryptedVolume", config_parse_encrypted_volume, 0, p }, + { "Partition", "TPM2PCRs", config_parse_tpm2_pcrs, 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 }, @@ -4813,8 +4845,10 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta ssize_t base64_encoded_size; int keyslot; TPM2Flags flags = 0; + Tpm2PCRValue *pcr_values = arg_tpm2_n_hash_pcr_values > 0 ? arg_tpm2_hash_pcr_values : p->tpm2_hash_pcr_values; + size_t n_pcr_values = arg_tpm2_n_hash_pcr_values > 0 ? arg_tpm2_n_hash_pcr_values : p->tpm2_n_hash_pcr_values; - if (arg_tpm2_n_hash_pcr_values == 0 && + if (n_pcr_values == 0 && arg_tpm2_public_key_pcr_mask == 0 && !arg_tpm2_pcrlock) log_notice("Notice: encrypting future partition %" PRIu64 ", locking against TPM2 with an empty policy, i.e. without any state or access restrictions.\n" @@ -4854,7 +4888,7 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta if (r < 0) return r; - if (!tpm2_pcr_values_has_all_values(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values)) + if (!tpm2_pcr_values_has_all_values(pcr_values, n_pcr_values)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Must provide all PCR values when using TPM2 device key."); } else { @@ -4862,8 +4896,8 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta if (r < 0) return r; - if (!tpm2_pcr_values_has_all_values(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values)) { - r = tpm2_pcr_read_missing_values(tpm2_context, arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values); + if (!tpm2_pcr_values_has_all_values(pcr_values, n_pcr_values)) { + r = tpm2_pcr_read_missing_values(tpm2_context, pcr_values, n_pcr_values); if (r < 0) return log_error_errno(r, "Could not read pcr values: %m"); } @@ -4871,17 +4905,17 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta uint16_t hash_pcr_bank = 0; uint32_t hash_pcr_mask = 0; - if (arg_tpm2_n_hash_pcr_values > 0) { + if (n_pcr_values > 0) { size_t hash_count; - r = tpm2_pcr_values_hash_count(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, &hash_count); + r = tpm2_pcr_values_hash_count(pcr_values, n_pcr_values, &hash_count); if (r < 0) return log_error_errno(r, "Could not get hash count: %m"); if (hash_count > 1) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Multiple PCR banks selected."); - hash_pcr_bank = arg_tpm2_hash_pcr_values[0].hash; - r = tpm2_pcr_values_to_mask(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, hash_pcr_bank, &hash_pcr_mask); + hash_pcr_bank = pcr_values[0].hash; + r = tpm2_pcr_values_to_mask(pcr_values, n_pcr_values, hash_pcr_bank, &hash_pcr_mask); if (r < 0) return log_error_errno(r, "Could not get hash mask: %m"); } @@ -4894,8 +4928,8 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta /* If both PCR public key unlock and pcrlock unlock is selected, then shard the encryption key. */ r = tpm2_calculate_sealing_policy( - arg_tpm2_hash_pcr_values, - arg_tpm2_n_hash_pcr_values, + pcr_values, + n_pcr_values, iovec_is_set(&pubkey) ? &public : NULL, /* use_pin= */ false, arg_tpm2_pcrlock && !iovec_is_set(&pubkey) ? &pcrlock_policy : NULL, @@ -4905,8 +4939,8 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta if (arg_tpm2_pcrlock && iovec_is_set(&pubkey)) { r = tpm2_calculate_sealing_policy( - arg_tpm2_hash_pcr_values, - arg_tpm2_n_hash_pcr_values, + pcr_values, + n_pcr_values, /* public= */ NULL, /* Turn this one off for the 2nd shard */ /* use_pin= */ false, &pcrlock_policy, /* But turn this one on */