tpmdd updates for Linux v5.3
-----BEGIN PGP SIGNATURE----- iJYEABYIAD4WIQRE6pSOnaBC00OEHEIaerohdGur0gUCXRGG5iAcamFya2tvLnNh a2tpbmVuQGxpbnV4LmludGVsLmNvbQAKCRAaerohdGur0lcRAP9xHUuaHm7/d6Qh nAa1Sm+99aO1D/9WfEc4pjy3hASyOAEAwIecBZ5t8JceXXaYEv/rYNJCpogvZyyf mdU4p9sc8AU= =lzfE -----END PGP SIGNATURE----- Merge tag 'tpmdd-next-20190625' of git://git.infradead.org/users/jjs/linux-tpmdd Pull tpm updates from Jarkko Sakkinen: "This contains two critical bug fixes and support for obtaining TPM events triggered by ExitBootServices(). For the latter I have to give a quite verbose explanation not least because I had to revisit all the details myself to remember what was going on in Matthew's patches. The preboot software stack maintains an event log that gets entries every time something gets hashed to any of the PCR registers. What gets hashed could be a component to be run or perhaps log of some actions taken just to give couple of coarse examples. In general, anything relevant for the boot process that the preboot software does gets hashed and a log entry with a specific event type [1]. The main application for this is remote attestation and the reason why it is useful is nicely put in the very first section of [1]: "Attestation is used to provide information about the platform’s state to a challenger. However, PCR contents are difficult to interpret; therefore, attestation is typically more useful when the PCR contents are accompanied by a measurement log. While not trusted on their own, the measurement log contains a richer set of information than do the PCR contents. The PCR contents are used to provide the validation of the measurement log." Because EFI_TCG2_PROTOCOL.GetEventLog() is not available after calling ExitBootServices(), Linux EFI stub copies the event log to a custom configuration table. Unfortunately, ExitBootServices() also generates events and obviously these events do not get copied to that table. Luckily firmware does this for us by providing a configuration table identified by EFI_TCG2_FINAL_EVENTS_TABLE_GUID. This essentially contains necessary changes to provide the full event log for the use the user space that is concatenated from these two partial event logs [2]" [1] https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/ [2] The final concatenation is done in drivers/char/tpm/eventlog/efi.c * tag 'tpmdd-next-20190625' of git://git.infradead.org/users/jjs/linux-tpmdd: tpm: Don't duplicate events from the final event log in the TCG2 log Abstract out support for locating an EFI config table tpm: Fix TPM 1.2 Shutdown sequence to prevent future TPM operations efi: Attempt to get the TCG2 event log in the boot stub tpm: Append the final event log to the TPM event log tpm: Reserve the TPM final events table tpm: Abstract crypto agile event size calculations tpm: Actually fail on TPM errors during "get random"
This commit is contained in:
commit
884922591e
|
@ -16,10 +16,13 @@
|
|||
int tpm_read_log_efi(struct tpm_chip *chip)
|
||||
{
|
||||
|
||||
struct efi_tcg2_final_events_table *final_tbl = NULL;
|
||||
struct linux_efi_tpm_eventlog *log_tbl;
|
||||
struct tpm_bios_log *log;
|
||||
u32 log_size;
|
||||
u8 tpm_log_version;
|
||||
void *tmp;
|
||||
int ret;
|
||||
|
||||
if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
|
||||
return -ENODEV;
|
||||
|
@ -47,15 +50,57 @@ int tpm_read_log_efi(struct tpm_chip *chip)
|
|||
|
||||
/* malloc EventLog space */
|
||||
log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL);
|
||||
if (!log->bios_event_log)
|
||||
goto err_memunmap;
|
||||
if (!log->bios_event_log) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
log->bios_event_log_end = log->bios_event_log + log_size;
|
||||
|
||||
tpm_log_version = log_tbl->version;
|
||||
memunmap(log_tbl);
|
||||
return tpm_log_version;
|
||||
|
||||
err_memunmap:
|
||||
ret = tpm_log_version;
|
||||
|
||||
if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR ||
|
||||
efi_tpm_final_log_size == 0 ||
|
||||
tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
|
||||
goto out;
|
||||
|
||||
final_tbl = memremap(efi.tpm_final_log,
|
||||
sizeof(*final_tbl) + efi_tpm_final_log_size,
|
||||
MEMREMAP_WB);
|
||||
if (!final_tbl) {
|
||||
pr_err("Could not map UEFI TPM final log\n");
|
||||
kfree(log->bios_event_log);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
efi_tpm_final_log_size -= log_tbl->final_events_preboot_size;
|
||||
|
||||
tmp = krealloc(log->bios_event_log,
|
||||
log_size + efi_tpm_final_log_size,
|
||||
GFP_KERNEL);
|
||||
if (!tmp) {
|
||||
kfree(log->bios_event_log);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
log->bios_event_log = tmp;
|
||||
|
||||
/*
|
||||
* Copy any of the final events log that didn't also end up in the
|
||||
* main log. Events can be logged in both if events are generated
|
||||
* between GetEventLog() and ExitBootServices().
|
||||
*/
|
||||
memcpy((void *)log->bios_event_log + log_size,
|
||||
final_tbl->events + log_tbl->final_events_preboot_size,
|
||||
efi_tpm_final_log_size);
|
||||
log->bios_event_log_end = log->bios_event_log +
|
||||
log_size + efi_tpm_final_log_size;
|
||||
|
||||
out:
|
||||
memunmap(final_tbl);
|
||||
memunmap(log_tbl);
|
||||
return -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -36,52 +36,7 @@
|
|||
static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
|
||||
struct tcg_pcr_event *event_header)
|
||||
{
|
||||
struct tcg_efi_specid_event_head *efispecid;
|
||||
struct tcg_event_field *event_field;
|
||||
void *marker;
|
||||
void *marker_start;
|
||||
u32 halg_size;
|
||||
size_t size;
|
||||
u16 halg;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
marker = event;
|
||||
marker_start = marker;
|
||||
marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
|
||||
+ sizeof(event->count);
|
||||
|
||||
efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
|
||||
|
||||
/* Check if event is malformed. */
|
||||
if (event->count > efispecid->num_algs)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < event->count; i++) {
|
||||
halg_size = sizeof(event->digests[i].alg_id);
|
||||
memcpy(&halg, marker, halg_size);
|
||||
marker = marker + halg_size;
|
||||
for (j = 0; j < efispecid->num_algs; j++) {
|
||||
if (halg == efispecid->digest_sizes[j].alg_id) {
|
||||
marker +=
|
||||
efispecid->digest_sizes[j].digest_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Algorithm without known length. Such event is unparseable. */
|
||||
if (j == efispecid->num_algs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
event_field = (struct tcg_event_field *)marker;
|
||||
marker = marker + sizeof(event_field->event_size)
|
||||
+ event_field->event_size;
|
||||
size = marker - marker_start;
|
||||
|
||||
if ((event->event_type == 0) && (event_field->event_size == 0))
|
||||
return 0;
|
||||
|
||||
return size;
|
||||
return __calc_tpm2_event_size(event, event_header, false);
|
||||
}
|
||||
|
||||
static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
|
||||
|
|
|
@ -289,15 +289,15 @@ static int tpm_class_shutdown(struct device *dev)
|
|||
{
|
||||
struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
|
||||
|
||||
down_write(&chip->ops_sem);
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
down_write(&chip->ops_sem);
|
||||
if (!tpm_chip_start(chip)) {
|
||||
tpm2_shutdown(chip, TPM2_SU_CLEAR);
|
||||
tpm_chip_stop(chip);
|
||||
}
|
||||
chip->ops = NULL;
|
||||
up_write(&chip->ops_sem);
|
||||
}
|
||||
chip->ops = NULL;
|
||||
up_write(&chip->ops_sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -510,7 +510,7 @@ struct tpm1_get_random_out {
|
|||
*
|
||||
* Return:
|
||||
* * number of bytes read
|
||||
* * -errno or a TPM return code otherwise
|
||||
* * -errno (positive TPM return codes are masked to -EIO)
|
||||
*/
|
||||
int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
|
||||
{
|
||||
|
@ -531,8 +531,11 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
|
|||
|
||||
rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
|
||||
"attempting get random");
|
||||
if (rc)
|
||||
if (rc) {
|
||||
if (rc > 0)
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];
|
||||
|
||||
|
|
|
@ -297,7 +297,7 @@ struct tpm2_get_random_out {
|
|||
*
|
||||
* Return:
|
||||
* size of the buffer on success,
|
||||
* -errno otherwise
|
||||
* -errno otherwise (positive TPM return codes are masked to -EIO)
|
||||
*/
|
||||
int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
|
||||
{
|
||||
|
@ -324,8 +324,11 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
|
|||
offsetof(struct tpm2_get_random_out,
|
||||
buffer),
|
||||
"attempting get random");
|
||||
if (err)
|
||||
if (err) {
|
||||
if (err > 0)
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out = (struct tpm2_get_random_out *)
|
||||
&buf.data[TPM_HEADER_SIZE];
|
||||
|
|
|
@ -52,6 +52,7 @@ struct efi __read_mostly efi = {
|
|||
.mem_attr_table = EFI_INVALID_TABLE_ADDR,
|
||||
.rng_seed = EFI_INVALID_TABLE_ADDR,
|
||||
.tpm_log = EFI_INVALID_TABLE_ADDR,
|
||||
.tpm_final_log = EFI_INVALID_TABLE_ADDR,
|
||||
.mem_reserve = EFI_INVALID_TABLE_ADDR,
|
||||
};
|
||||
EXPORT_SYMBOL(efi);
|
||||
|
@ -484,6 +485,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
|
|||
{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
|
||||
{LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
|
||||
{LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
|
||||
{LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log},
|
||||
{LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
|
||||
{NULL_GUID, NULL, NULL},
|
||||
};
|
||||
|
|
|
@ -926,3 +926,18 @@ free_map:
|
|||
fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid)
|
||||
{
|
||||
efi_config_table_t *tables = (efi_config_table_t *)sys_table->tables;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sys_table->nr_tables; i++) {
|
||||
if (efi_guidcmp(tables[i].guid, guid) != 0)
|
||||
continue;
|
||||
|
||||
return (void *)tables[i].table;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,8 @@ efi_status_t check_platform_features(efi_system_table_t *sys_table_arg);
|
|||
|
||||
efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg);
|
||||
|
||||
void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid);
|
||||
|
||||
/* Helper macros for the usual case of using simple C variables: */
|
||||
#ifndef fdt_setprop_inplace_var
|
||||
#define fdt_setprop_inplace_var(fdt, node_offset, name, var) \
|
||||
|
|
|
@ -363,26 +363,17 @@ fail:
|
|||
|
||||
void *get_fdt(efi_system_table_t *sys_table, unsigned long *fdt_size)
|
||||
{
|
||||
efi_guid_t fdt_guid = DEVICE_TREE_GUID;
|
||||
efi_config_table_t *tables;
|
||||
int i;
|
||||
void *fdt;
|
||||
|
||||
tables = (efi_config_table_t *)sys_table->tables;
|
||||
fdt = get_efi_config_table(sys_table, DEVICE_TREE_GUID);
|
||||
|
||||
for (i = 0; i < sys_table->nr_tables; i++) {
|
||||
void *fdt;
|
||||
if (!fdt)
|
||||
return NULL;
|
||||
|
||||
if (efi_guidcmp(tables[i].guid, fdt_guid) != 0)
|
||||
continue;
|
||||
|
||||
fdt = (void *)tables[i].table;
|
||||
if (fdt_check_header(fdt) != 0) {
|
||||
pr_efi_err(sys_table, "Invalid header detected on UEFI supplied FDT, ignoring ...\n");
|
||||
return NULL;
|
||||
}
|
||||
*fdt_size = fdt_totalsize(fdt);
|
||||
return fdt;
|
||||
if (fdt_check_header(fdt) != 0) {
|
||||
pr_efi_err(sys_table, "Invalid header detected on UEFI supplied FDT, ignoring ...\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
*fdt_size = fdt_totalsize(fdt);
|
||||
return fdt;
|
||||
}
|
||||
|
|
|
@ -57,31 +57,40 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg)
|
|||
|
||||
#endif
|
||||
|
||||
static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
|
||||
void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
|
||||
{
|
||||
efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
|
||||
efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
|
||||
efi_status_t status;
|
||||
efi_physical_addr_t log_location = 0, log_last_entry = 0;
|
||||
struct linux_efi_tpm_eventlog *log_tbl = NULL;
|
||||
struct efi_tcg2_final_events_table *final_events_table;
|
||||
unsigned long first_entry_addr, last_entry_addr;
|
||||
size_t log_size, last_entry_size;
|
||||
efi_bool_t truncated;
|
||||
int version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
|
||||
void *tcg2_protocol = NULL;
|
||||
int final_events_size = 0;
|
||||
|
||||
status = efi_call_early(locate_protocol, &tcg2_guid, NULL,
|
||||
&tcg2_protocol);
|
||||
if (status != EFI_SUCCESS)
|
||||
return;
|
||||
|
||||
status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol,
|
||||
EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2,
|
||||
&log_location, &log_last_entry, &truncated);
|
||||
if (status != EFI_SUCCESS)
|
||||
return;
|
||||
status = efi_call_proto(efi_tcg2_protocol, get_event_log,
|
||||
tcg2_protocol, version, &log_location,
|
||||
&log_last_entry, &truncated);
|
||||
|
||||
if (status != EFI_SUCCESS || !log_location) {
|
||||
version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
|
||||
status = efi_call_proto(efi_tcg2_protocol, get_event_log,
|
||||
tcg2_protocol, version, &log_location,
|
||||
&log_last_entry, &truncated);
|
||||
if (status != EFI_SUCCESS || !log_location)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (!log_location)
|
||||
return;
|
||||
first_entry_addr = (unsigned long) log_location;
|
||||
|
||||
/*
|
||||
|
@ -96,8 +105,23 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
|
|||
* We need to calculate its size to deduce the full size of
|
||||
* the logs.
|
||||
*/
|
||||
last_entry_size = sizeof(struct tcpa_event) +
|
||||
((struct tcpa_event *) last_entry_addr)->event_size;
|
||||
if (version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) {
|
||||
/*
|
||||
* The TCG2 log format has variable length entries,
|
||||
* and the information to decode the hash algorithms
|
||||
* back into a size is contained in the first entry -
|
||||
* pass a pointer to the final entry (to calculate its
|
||||
* size) and the first entry (so we know how long each
|
||||
* digest is)
|
||||
*/
|
||||
last_entry_size =
|
||||
__calc_tpm2_event_size((void *)last_entry_addr,
|
||||
(void *)(long)log_location,
|
||||
false);
|
||||
} else {
|
||||
last_entry_size = sizeof(struct tcpa_event) +
|
||||
((struct tcpa_event *) last_entry_addr)->event_size;
|
||||
}
|
||||
log_size = log_last_entry - log_location + last_entry_size;
|
||||
}
|
||||
|
||||
|
@ -112,9 +136,37 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out whether any events have already been logged to the
|
||||
* final events structure, and if so how much space they take up
|
||||
*/
|
||||
final_events_table = get_efi_config_table(sys_table_arg,
|
||||
LINUX_EFI_TPM_FINAL_LOG_GUID);
|
||||
if (final_events_table && final_events_table->nr_events) {
|
||||
struct tcg_pcr_event2_head *header;
|
||||
int offset;
|
||||
void *data;
|
||||
int event_size;
|
||||
int i = final_events_table->nr_events;
|
||||
|
||||
data = (void *)final_events_table;
|
||||
offset = sizeof(final_events_table->version) +
|
||||
sizeof(final_events_table->nr_events);
|
||||
|
||||
while (i > 0) {
|
||||
header = data + offset + final_events_size;
|
||||
event_size = __calc_tpm2_event_size(header,
|
||||
(void *)(long)log_location,
|
||||
false);
|
||||
final_events_size += event_size;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
memset(log_tbl, 0, sizeof(*log_tbl) + log_size);
|
||||
log_tbl->size = log_size;
|
||||
log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
|
||||
log_tbl->final_events_preboot_size = final_events_size;
|
||||
log_tbl->version = version;
|
||||
memcpy(log_tbl->log, (void *) first_entry_addr, log_size);
|
||||
|
||||
status = efi_call_early(install_configuration_table,
|
||||
|
@ -126,9 +178,3 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
|
|||
err_free:
|
||||
efi_call_early(free_pool, log_tbl);
|
||||
}
|
||||
|
||||
void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
|
||||
{
|
||||
/* Only try to retrieve the logs in 1.2 format. */
|
||||
efi_retrieve_tpm2_eventlog_1_2(sys_table_arg);
|
||||
}
|
||||
|
|
|
@ -4,11 +4,34 @@
|
|||
* Thiebaud Weksteen <tweek@google.com>
|
||||
*/
|
||||
|
||||
#define TPM_MEMREMAP(start, size) early_memremap(start, size)
|
||||
#define TPM_MEMUNMAP(start, size) early_memunmap(start, size)
|
||||
|
||||
#include <asm/early_ioremap.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/tpm_eventlog.h>
|
||||
|
||||
#include <asm/early_ioremap.h>
|
||||
int efi_tpm_final_log_size;
|
||||
EXPORT_SYMBOL(efi_tpm_final_log_size);
|
||||
|
||||
static int tpm2_calc_event_log_size(void *data, int count, void *size_info)
|
||||
{
|
||||
struct tcg_pcr_event2_head *header;
|
||||
int event_size, size = 0;
|
||||
|
||||
while (count > 0) {
|
||||
header = data + size;
|
||||
event_size = __calc_tpm2_event_size(header, size_info, true);
|
||||
if (event_size == 0)
|
||||
return -1;
|
||||
size += event_size;
|
||||
count--;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reserve the memory associated with the TPM Event Log configuration table.
|
||||
|
@ -16,22 +39,54 @@
|
|||
int __init efi_tpm_eventlog_init(void)
|
||||
{
|
||||
struct linux_efi_tpm_eventlog *log_tbl;
|
||||
struct efi_tcg2_final_events_table *final_tbl;
|
||||
unsigned int tbl_size;
|
||||
int ret = 0;
|
||||
|
||||
if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
|
||||
if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) {
|
||||
/*
|
||||
* We can't calculate the size of the final events without the
|
||||
* first entry in the TPM log, so bail here.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl));
|
||||
if (!log_tbl) {
|
||||
pr_err("Failed to map TPM Event Log table @ 0x%lx\n",
|
||||
efi.tpm_log);
|
||||
efi.tpm_log);
|
||||
efi.tpm_log = EFI_INVALID_TABLE_ADDR;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tbl_size = sizeof(*log_tbl) + log_tbl->size;
|
||||
memblock_reserve(efi.tpm_log, tbl_size);
|
||||
|
||||
if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR)
|
||||
goto out;
|
||||
|
||||
final_tbl = early_memremap(efi.tpm_final_log, sizeof(*final_tbl));
|
||||
|
||||
if (!final_tbl) {
|
||||
pr_err("Failed to map TPM Final Event Log table @ 0x%lx\n",
|
||||
efi.tpm_final_log);
|
||||
efi.tpm_final_log = EFI_INVALID_TABLE_ADDR;
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tbl_size = tpm2_calc_event_log_size((void *)efi.tpm_final_log
|
||||
+ sizeof(final_tbl->version)
|
||||
+ sizeof(final_tbl->nr_events),
|
||||
final_tbl->nr_events,
|
||||
log_tbl->log);
|
||||
memblock_reserve((unsigned long)final_tbl,
|
||||
tbl_size + sizeof(*final_tbl));
|
||||
early_memunmap(final_tbl, sizeof(*final_tbl));
|
||||
efi_tpm_final_log_size = tbl_size;
|
||||
|
||||
out:
|
||||
early_memunmap(log_tbl, sizeof(*log_tbl));
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -689,6 +689,7 @@ void efi_native_runtime_setup(void);
|
|||
#define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
|
||||
#define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
|
||||
#define LINUX_EFI_TPM_EVENT_LOG_GUID EFI_GUID(0xb7799cb0, 0xeca2, 0x4943, 0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa)
|
||||
#define LINUX_EFI_TPM_FINAL_LOG_GUID EFI_GUID(0x1e2ed096, 0x30e2, 0x4254, 0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25)
|
||||
#define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2)
|
||||
|
||||
typedef struct {
|
||||
|
@ -996,6 +997,7 @@ extern struct efi {
|
|||
unsigned long mem_attr_table; /* memory attributes table */
|
||||
unsigned long rng_seed; /* UEFI firmware random seed */
|
||||
unsigned long tpm_log; /* TPM2 Event Log table */
|
||||
unsigned long tpm_final_log; /* TPM2 Final Events Log table */
|
||||
unsigned long mem_reserve; /* Linux EFI memreserve table */
|
||||
efi_get_time_t *get_time;
|
||||
efi_set_time_t *set_time;
|
||||
|
@ -1706,12 +1708,20 @@ struct linux_efi_random_seed {
|
|||
|
||||
struct linux_efi_tpm_eventlog {
|
||||
u32 size;
|
||||
u32 final_events_preboot_size;
|
||||
u8 version;
|
||||
u8 log[];
|
||||
};
|
||||
|
||||
extern int efi_tpm_eventlog_init(void);
|
||||
|
||||
struct efi_tcg2_final_events_table {
|
||||
u64 version;
|
||||
u64 nr_events;
|
||||
u8 events[];
|
||||
};
|
||||
extern int efi_tpm_final_log_size;
|
||||
|
||||
/*
|
||||
* efi_runtime_service() function identifiers.
|
||||
* "NONE" is used by efi_recover_from_page_fault() to check if the page
|
||||
|
|
|
@ -112,4 +112,156 @@ struct tcg_pcr_event2_head {
|
|||
struct tpm_digest digests[];
|
||||
} __packed;
|
||||
|
||||
struct tcg_algorithm_size {
|
||||
u16 algorithm_id;
|
||||
u16 algorithm_size;
|
||||
};
|
||||
|
||||
struct tcg_algorithm_info {
|
||||
u8 signature[16];
|
||||
u32 platform_class;
|
||||
u8 spec_version_minor;
|
||||
u8 spec_version_major;
|
||||
u8 spec_errata;
|
||||
u8 uintn_size;
|
||||
u32 number_of_algorithms;
|
||||
struct tcg_algorithm_size digest_sizes[];
|
||||
};
|
||||
|
||||
#ifndef TPM_MEMREMAP
|
||||
#define TPM_MEMREMAP(start, size) NULL
|
||||
#endif
|
||||
|
||||
#ifndef TPM_MEMUNMAP
|
||||
#define TPM_MEMUNMAP(start, size) do{} while(0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* __calc_tpm2_event_size - calculate the size of a TPM2 event log entry
|
||||
* @event: Pointer to the event whose size should be calculated
|
||||
* @event_header: Pointer to the initial event containing the digest lengths
|
||||
* @do_mapping: Whether or not the event needs to be mapped
|
||||
*
|
||||
* The TPM2 event log format can contain multiple digests corresponding to
|
||||
* separate PCR banks, and also contains a variable length of the data that
|
||||
* was measured. This requires knowledge of how long each digest type is,
|
||||
* and this information is contained within the first event in the log.
|
||||
*
|
||||
* We calculate the length by examining the number of events, and then looking
|
||||
* at each event in turn to determine how much space is used for events in
|
||||
* total. Once we've done this we know the offset of the data length field,
|
||||
* and can calculate the total size of the event.
|
||||
*
|
||||
* Return: size of the event on success, <0 on failure
|
||||
*/
|
||||
|
||||
static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
|
||||
struct tcg_pcr_event *event_header,
|
||||
bool do_mapping)
|
||||
{
|
||||
struct tcg_efi_specid_event_head *efispecid;
|
||||
struct tcg_event_field *event_field;
|
||||
void *mapping = NULL;
|
||||
int mapping_size;
|
||||
void *marker;
|
||||
void *marker_start;
|
||||
u32 halg_size;
|
||||
size_t size;
|
||||
u16 halg;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
marker = event;
|
||||
marker_start = marker;
|
||||
marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
|
||||
+ sizeof(event->count);
|
||||
|
||||
/* Map the event header */
|
||||
if (do_mapping) {
|
||||
mapping_size = marker - marker_start;
|
||||
mapping = TPM_MEMREMAP((unsigned long)marker_start,
|
||||
mapping_size);
|
||||
if (!mapping) {
|
||||
size = 0;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
mapping = marker_start;
|
||||
}
|
||||
|
||||
event = (struct tcg_pcr_event2_head *)mapping;
|
||||
|
||||
efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
|
||||
|
||||
/* Check if event is malformed. */
|
||||
if (event->count > efispecid->num_algs) {
|
||||
size = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < event->count; i++) {
|
||||
halg_size = sizeof(event->digests[i].alg_id);
|
||||
|
||||
/* Map the digest's algorithm identifier */
|
||||
if (do_mapping) {
|
||||
TPM_MEMUNMAP(mapping, mapping_size);
|
||||
mapping_size = halg_size;
|
||||
mapping = TPM_MEMREMAP((unsigned long)marker,
|
||||
mapping_size);
|
||||
if (!mapping) {
|
||||
size = 0;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
mapping = marker;
|
||||
}
|
||||
|
||||
memcpy(&halg, mapping, halg_size);
|
||||
marker = marker + halg_size;
|
||||
|
||||
for (j = 0; j < efispecid->num_algs; j++) {
|
||||
if (halg == efispecid->digest_sizes[j].alg_id) {
|
||||
marker +=
|
||||
efispecid->digest_sizes[j].digest_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Algorithm without known length. Such event is unparseable. */
|
||||
if (j == efispecid->num_algs) {
|
||||
size = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the event size - we don't read from the event itself, so
|
||||
* we don't need to map it
|
||||
*/
|
||||
if (do_mapping) {
|
||||
TPM_MEMUNMAP(mapping, mapping_size);
|
||||
mapping_size += sizeof(event_field->event_size);
|
||||
mapping = TPM_MEMREMAP((unsigned long)marker,
|
||||
mapping_size);
|
||||
if (!mapping) {
|
||||
size = 0;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
mapping = marker;
|
||||
}
|
||||
|
||||
event_field = (struct tcg_event_field *)mapping;
|
||||
|
||||
marker = marker + sizeof(event_field->event_size)
|
||||
+ event_field->event_size;
|
||||
size = marker - marker_start;
|
||||
|
||||
if ((event->event_type == 0) && (event_field->event_size == 0))
|
||||
size = 0;
|
||||
out:
|
||||
if (do_mapping)
|
||||
TPM_MEMUNMAP(mapping, mapping_size);
|
||||
return size;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue