summaryrefslogtreecommitdiff
path: root/include/linux/tpm_eventlog.h
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@google.com>2019-05-20 23:54:59 +0300
committerJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>2019-06-24 23:57:49 +0300
commitc46f3405692de1ac82240d927b9c7a0f9d6a4a36 (patch)
treea7b4937f49900d4c1f46104326fe9b96b38cfbcf /include/linux/tpm_eventlog.h
parent44038bc514a244fba9d0d6d698b15970185ac251 (diff)
downloadlinux-c46f3405692de1ac82240d927b9c7a0f9d6a4a36.tar.xz
tpm: Reserve the TPM final events table
UEFI systems provide a boot services protocol for obtaining the TPM event log, but this is unusable after ExitBootServices() is called. Unfortunately ExitBootServices() itself triggers additional TPM events that then can't be obtained using this protocol. The platform provides a mechanism for the OS to obtain these events by recording them to a separate UEFI configuration table which the OS can then map. Unfortunately this table isn't self describing in terms of providing its length, so we need to parse the events inside it to figure out how long it is. Since the table isn't mapped at this point, we need to extend the length calculation function to be able to map the event as it goes along. (Fixes by Bartosz Szczepanek <bsz@semihalf.com>) Signed-off-by: Matthew Garrett <mjg59@google.com> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Bartosz Szczepanek <bsz@semihalf.com> Tested-by: Bartosz Szczepanek <bsz@semihalf.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Diffstat (limited to 'include/linux/tpm_eventlog.h')
-rw-r--r--include/linux/tpm_eventlog.h102
1 files changed, 93 insertions, 9 deletions
diff --git a/include/linux/tpm_eventlog.h b/include/linux/tpm_eventlog.h
index 6a86144e13f1..63238c84dc0b 100644
--- a/include/linux/tpm_eventlog.h
+++ b/include/linux/tpm_eventlog.h
@@ -112,10 +112,35 @@ 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
@@ -131,10 +156,13 @@ struct tcg_pcr_event2_head {
*/
static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
- struct tcg_pcr_event *event_header)
+ 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;
@@ -148,16 +176,49 @@ static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
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)
- return 0;
+ 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);
- memcpy(&halg, marker, halg_size);
+
+ /* 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 +=
@@ -166,18 +227,41 @@ static inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
}
}
/* Algorithm without known length. Such event is unparseable. */
- if (j == efispecid->num_algs)
- return 0;
+ 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 *)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))
- return 0;
-
+ size = 0;
+out:
+ if (do_mapping)
+ TPM_MEMUNMAP(mapping, mapping_size);
return size;
}
+
#endif