mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
tpm2-util: use LoaderTpm2ActivePcrBanks efi var when figuring out best+good banks to use
We nowadays have clear reporting which PCR banks the firmware is using via LoaderTpm2ActivePcrBanks, hence rely on that.
This commit is contained in:
@@ -15,8 +15,14 @@
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "tpm2-util.h"
|
||||
#include "utf8.h"
|
||||
|
||||
#define EFI_TCG2_BOOT_HASH_ALG_SHA1 0x01
|
||||
#define EFI_TCG2_BOOT_HASH_ALG_SHA256 0x02
|
||||
#define EFI_TCG2_BOOT_HASH_ALG_SHA384 0x04
|
||||
#define EFI_TCG2_BOOT_HASH_ALG_SHA512 0x08
|
||||
|
||||
#define LOAD_OPTION_ACTIVE 0x00000001
|
||||
#define MEDIA_DEVICE_PATH 0x04
|
||||
#define MEDIA_HARDDRIVE_DP 0x01
|
||||
@@ -517,24 +523,59 @@ int efi_get_boot_options(uint16_t **ret_options) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int efi_get_active_pcr_banks(uint32_t *ret) {
|
||||
#if ENABLE_EFI
|
||||
static int loader_has_tpm2(void) {
|
||||
_cleanup_free_ char *active_pcr_banks = NULL;
|
||||
uint32_t active_pcr_banks_value;
|
||||
static uint32_t cache = UINT32_MAX;
|
||||
int r;
|
||||
|
||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderTpm2ActivePcrBanks"), &active_pcr_banks);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to read LoaderTpm2ActivePcrBanks variable: %m");
|
||||
return r;
|
||||
if (cache == UINT32_MAX) {
|
||||
_cleanup_free_ char *active_pcr_banks = NULL;
|
||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderTpm2ActivePcrBanks"), &active_pcr_banks);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to read LoaderTpm2ActivePcrBanks variable: %m");
|
||||
|
||||
uint32_t efi_bits;
|
||||
r = safe_atou32_full(active_pcr_banks, 16, &efi_bits);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse LoaderTpm2ActivePcrBanks variable: %m");
|
||||
|
||||
/* EFI TPM protocol uses different bit values for the hash algorithms, let's convert */
|
||||
static const struct {
|
||||
uint32_t efi;
|
||||
uint32_t tcg;
|
||||
} table[] = {
|
||||
{ EFI_TCG2_BOOT_HASH_ALG_SHA1, 1U << TPM2_ALG_SHA1 },
|
||||
{ EFI_TCG2_BOOT_HASH_ALG_SHA256, 1U << TPM2_ALG_SHA256 },
|
||||
{ EFI_TCG2_BOOT_HASH_ALG_SHA384, 1U << TPM2_ALG_SHA384 },
|
||||
{ EFI_TCG2_BOOT_HASH_ALG_SHA512, 1U << TPM2_ALG_SHA512 },
|
||||
};
|
||||
|
||||
uint32_t tcg_bits = 0;
|
||||
FOREACH_ELEMENT(t, table)
|
||||
SET_FLAG(tcg_bits, t->tcg, efi_bits & t->efi);
|
||||
|
||||
cache = tcg_bits;
|
||||
}
|
||||
|
||||
r = safe_atou32_full(active_pcr_banks, 16, &active_pcr_banks_value);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse LoaderTpm2ActivePcrBanks variable: %m");
|
||||
if (ret)
|
||||
*ret = cache;
|
||||
|
||||
return active_pcr_banks_value != 0;
|
||||
return 0;
|
||||
#else
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ENABLE_EFI
|
||||
static int loader_has_tpm2(void) {
|
||||
uint32_t active_pcr_banks;
|
||||
int r;
|
||||
|
||||
r = efi_get_active_pcr_banks(&active_pcr_banks);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return active_pcr_banks != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ int efi_get_boot_order(uint16_t **ret_order);
|
||||
int efi_set_boot_order(const uint16_t *order, size_t n);
|
||||
int efi_get_boot_options(uint16_t **ret_options);
|
||||
|
||||
int efi_get_active_pcr_banks(uint32_t *ret);
|
||||
bool efi_has_tpm2(void);
|
||||
|
||||
sd_id128_t efi_guid_to_id128(const void *guid);
|
||||
|
||||
@@ -2697,6 +2697,26 @@ int tpm2_get_best_pcr_bank(
|
||||
assert(c);
|
||||
assert(ret);
|
||||
|
||||
uint32_t efi_banks;
|
||||
r = efi_get_active_pcr_banks(&efi_banks);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
return r;
|
||||
|
||||
/* If variable is not set use guesswork below */
|
||||
log_debug("Boot loader didn't set the LoaderTpm2ActivePcrBanks EFI variable, we have to guess the used PCR banks.");
|
||||
} else {
|
||||
if (BIT_SET(efi_banks, TPM2_ALG_SHA256))
|
||||
*ret = TPM2_ALG_SHA256;
|
||||
else if (BIT_SET(efi_banks, TPM2_ALG_SHA1))
|
||||
*ret = TPM2_ALG_SHA1;
|
||||
else
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Firmware reports neither SHA1 nor SHA256 PCR banks, cannot operate.");
|
||||
|
||||
log_debug("Picked best PCR bank %s based on firmware reported banks.", tpm2_hash_alg_to_string(*ret));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pcr_mask == 0) {
|
||||
log_debug("Asked to pick best PCR bank but no PCRs selected we could derive this from. Defaulting to SHA256.");
|
||||
*ret = TPM2_ALG_SHA256; /* if no PCRs are selected this doesn't matter anyway... */
|
||||
@@ -2784,6 +2804,30 @@ int tpm2_get_good_pcr_banks(
|
||||
assert(c);
|
||||
assert(ret);
|
||||
|
||||
uint32_t efi_banks;
|
||||
r = efi_get_active_pcr_banks(&efi_banks);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
return r;
|
||||
|
||||
/* If the variable is not set we have to guess via the code below */
|
||||
log_debug("Boot loader didn't set the LoaderTpm2ActivePcrBanks EFI variable, we have to guess the used PCR banks.");
|
||||
} else {
|
||||
FOREACH_ARRAY(hash, tpm2_hash_algorithms, TPM2_N_HASH_ALGORITHMS) {
|
||||
if (!BIT_SET(efi_banks, *hash))
|
||||
continue;
|
||||
|
||||
if (!GREEDY_REALLOC(good_banks, n_good_banks+1))
|
||||
return log_oom_debug();
|
||||
|
||||
good_banks[n_good_banks++] = *hash;
|
||||
}
|
||||
|
||||
log_debug("Found %zu initialized TPM2 banks reported by firmware.", n_good_banks);
|
||||
*ret = TAKE_PTR(good_banks);
|
||||
return (int) n_good_banks;
|
||||
}
|
||||
|
||||
FOREACH_TPMS_PCR_SELECTION_IN_TPML_PCR_SELECTION(selection, &c->capability_pcrs) {
|
||||
TPMI_ALG_HASH hash = selection->hash;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user