xref: /linux/drivers/char/tpm/eventlog/tpm2.c (revision b9d0a85d6b2e76630cfd4c475ee3af4109bfd87a)
10bfb2374SThiebaud Weksteen /*
20bfb2374SThiebaud Weksteen  * Copyright (C) 2016 IBM Corporation
30bfb2374SThiebaud Weksteen  *
40bfb2374SThiebaud Weksteen  * Authors:
50bfb2374SThiebaud Weksteen  *      Nayna Jain <nayna@linux.vnet.ibm.com>
60bfb2374SThiebaud Weksteen  *
70bfb2374SThiebaud Weksteen  * Access to TPM 2.0 event log as written by Firmware.
80bfb2374SThiebaud Weksteen  * It assumes that writer of event log has followed TCG Specification
90bfb2374SThiebaud Weksteen  * for Family "2.0" and written the event data in little endian.
100bfb2374SThiebaud Weksteen  * With that, it doesn't need any endian conversion for structure
110bfb2374SThiebaud Weksteen  * content.
120bfb2374SThiebaud Weksteen  *
130bfb2374SThiebaud Weksteen  * This program is free software; you can redistribute it and/or
140bfb2374SThiebaud Weksteen  * modify it under the terms of the GNU General Public License
150bfb2374SThiebaud Weksteen  * as published by the Free Software Foundation; either version
160bfb2374SThiebaud Weksteen  * 2 of the License, or (at your option) any later version.
170bfb2374SThiebaud Weksteen  */
180bfb2374SThiebaud Weksteen 
190bfb2374SThiebaud Weksteen #include <linux/seq_file.h>
200bfb2374SThiebaud Weksteen #include <linux/fs.h>
210bfb2374SThiebaud Weksteen #include <linux/security.h>
220bfb2374SThiebaud Weksteen #include <linux/module.h>
230bfb2374SThiebaud Weksteen #include <linux/slab.h>
240bfb2374SThiebaud Weksteen #include <linux/tpm_eventlog.h>
250bfb2374SThiebaud Weksteen 
260bfb2374SThiebaud Weksteen #include "../tpm.h"
2775d647f5SThiebaud Weksteen #include "common.h"
280bfb2374SThiebaud Weksteen 
290bfb2374SThiebaud Weksteen /*
300bfb2374SThiebaud Weksteen  * calc_tpm2_event_size() - calculate the event size, where event
310bfb2374SThiebaud Weksteen  * is an entry in the TPM 2.0 event log. The event is of type Crypto
320bfb2374SThiebaud Weksteen  * Agile Log Entry Format as defined in TCG EFI Protocol Specification
330bfb2374SThiebaud Weksteen  * Family "2.0".
340bfb2374SThiebaud Weksteen 
350bfb2374SThiebaud Weksteen  * @event: event whose size is to be calculated.
360bfb2374SThiebaud Weksteen  * @event_header: the first event in the event log.
370bfb2374SThiebaud Weksteen  *
380bfb2374SThiebaud Weksteen  * Returns size of the event. If it is an invalid event, returns 0.
390bfb2374SThiebaud Weksteen  */
40*b9d0a85dSYue Haibing static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
410bfb2374SThiebaud Weksteen 				   struct tcg_pcr_event *event_header)
420bfb2374SThiebaud Weksteen {
43c8faabfcSRoberto Sassu 	struct tcg_efi_specid_event_head *efispecid;
440bfb2374SThiebaud Weksteen 	struct tcg_event_field *event_field;
450bfb2374SThiebaud Weksteen 	void *marker;
460bfb2374SThiebaud Weksteen 	void *marker_start;
470bfb2374SThiebaud Weksteen 	u32 halg_size;
480bfb2374SThiebaud Weksteen 	size_t size;
490bfb2374SThiebaud Weksteen 	u16 halg;
500bfb2374SThiebaud Weksteen 	int i;
510bfb2374SThiebaud Weksteen 	int j;
520bfb2374SThiebaud Weksteen 
530bfb2374SThiebaud Weksteen 	marker = event;
540bfb2374SThiebaud Weksteen 	marker_start = marker;
550bfb2374SThiebaud Weksteen 	marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
560bfb2374SThiebaud Weksteen 		+ sizeof(event->count);
570bfb2374SThiebaud Weksteen 
58c8faabfcSRoberto Sassu 	efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
590bfb2374SThiebaud Weksteen 
600bfb2374SThiebaud Weksteen 	/* Check if event is malformed. */
610bfb2374SThiebaud Weksteen 	if (event->count > efispecid->num_algs)
620bfb2374SThiebaud Weksteen 		return 0;
630bfb2374SThiebaud Weksteen 
640bfb2374SThiebaud Weksteen 	for (i = 0; i < event->count; i++) {
650bfb2374SThiebaud Weksteen 		halg_size = sizeof(event->digests[i].alg_id);
660bfb2374SThiebaud Weksteen 		memcpy(&halg, marker, halg_size);
670bfb2374SThiebaud Weksteen 		marker = marker + halg_size;
680bfb2374SThiebaud Weksteen 		for (j = 0; j < efispecid->num_algs; j++) {
690bfb2374SThiebaud Weksteen 			if (halg == efispecid->digest_sizes[j].alg_id) {
700bfb2374SThiebaud Weksteen 				marker +=
710bfb2374SThiebaud Weksteen 					efispecid->digest_sizes[j].digest_size;
720bfb2374SThiebaud Weksteen 				break;
730bfb2374SThiebaud Weksteen 			}
740bfb2374SThiebaud Weksteen 		}
750bfb2374SThiebaud Weksteen 		/* Algorithm without known length. Such event is unparseable. */
760bfb2374SThiebaud Weksteen 		if (j == efispecid->num_algs)
770bfb2374SThiebaud Weksteen 			return 0;
780bfb2374SThiebaud Weksteen 	}
790bfb2374SThiebaud Weksteen 
800bfb2374SThiebaud Weksteen 	event_field = (struct tcg_event_field *)marker;
810bfb2374SThiebaud Weksteen 	marker = marker + sizeof(event_field->event_size)
820bfb2374SThiebaud Weksteen 		+ event_field->event_size;
830bfb2374SThiebaud Weksteen 	size = marker - marker_start;
840bfb2374SThiebaud Weksteen 
850bfb2374SThiebaud Weksteen 	if ((event->event_type == 0) && (event_field->event_size == 0))
860bfb2374SThiebaud Weksteen 		return 0;
870bfb2374SThiebaud Weksteen 
880bfb2374SThiebaud Weksteen 	return size;
890bfb2374SThiebaud Weksteen }
900bfb2374SThiebaud Weksteen 
910bfb2374SThiebaud Weksteen static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
920bfb2374SThiebaud Weksteen {
930bfb2374SThiebaud Weksteen 	struct tpm_chip *chip = m->private;
940bfb2374SThiebaud Weksteen 	struct tpm_bios_log *log = &chip->log;
950bfb2374SThiebaud Weksteen 	void *addr = log->bios_event_log;
960bfb2374SThiebaud Weksteen 	void *limit = log->bios_event_log_end;
970bfb2374SThiebaud Weksteen 	struct tcg_pcr_event *event_header;
98c8faabfcSRoberto Sassu 	struct tcg_pcr_event2_head *event;
990bfb2374SThiebaud Weksteen 	size_t size;
1000bfb2374SThiebaud Weksteen 	int i;
1010bfb2374SThiebaud Weksteen 
1020bfb2374SThiebaud Weksteen 	event_header = addr;
1030bfb2374SThiebaud Weksteen 	size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event)
1040bfb2374SThiebaud Weksteen 		+ event_header->event_size;
1050bfb2374SThiebaud Weksteen 
1060bfb2374SThiebaud Weksteen 	if (*pos == 0) {
1070bfb2374SThiebaud Weksteen 		if (addr + size < limit) {
1080bfb2374SThiebaud Weksteen 			if ((event_header->event_type == 0) &&
1090bfb2374SThiebaud Weksteen 			    (event_header->event_size == 0))
1100bfb2374SThiebaud Weksteen 				return NULL;
1110bfb2374SThiebaud Weksteen 			return SEQ_START_TOKEN;
1120bfb2374SThiebaud Weksteen 		}
1130bfb2374SThiebaud Weksteen 	}
1140bfb2374SThiebaud Weksteen 
1150bfb2374SThiebaud Weksteen 	if (*pos > 0) {
1160bfb2374SThiebaud Weksteen 		addr += size;
1170bfb2374SThiebaud Weksteen 		event = addr;
1180bfb2374SThiebaud Weksteen 		size = calc_tpm2_event_size(event, event_header);
1190bfb2374SThiebaud Weksteen 		if ((addr + size >=  limit) || (size == 0))
1200bfb2374SThiebaud Weksteen 			return NULL;
1210bfb2374SThiebaud Weksteen 	}
1220bfb2374SThiebaud Weksteen 
1230bfb2374SThiebaud Weksteen 	for (i = 0; i < (*pos - 1); i++) {
1240bfb2374SThiebaud Weksteen 		event = addr;
1250bfb2374SThiebaud Weksteen 		size = calc_tpm2_event_size(event, event_header);
1260bfb2374SThiebaud Weksteen 
1270bfb2374SThiebaud Weksteen 		if ((addr + size >= limit) || (size == 0))
1280bfb2374SThiebaud Weksteen 			return NULL;
1290bfb2374SThiebaud Weksteen 		addr += size;
1300bfb2374SThiebaud Weksteen 	}
1310bfb2374SThiebaud Weksteen 
1320bfb2374SThiebaud Weksteen 	return addr;
1330bfb2374SThiebaud Weksteen }
1340bfb2374SThiebaud Weksteen 
1350bfb2374SThiebaud Weksteen static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
1360bfb2374SThiebaud Weksteen 					 loff_t *pos)
1370bfb2374SThiebaud Weksteen {
1380bfb2374SThiebaud Weksteen 	struct tcg_pcr_event *event_header;
139c8faabfcSRoberto Sassu 	struct tcg_pcr_event2_head *event;
1400bfb2374SThiebaud Weksteen 	struct tpm_chip *chip = m->private;
1410bfb2374SThiebaud Weksteen 	struct tpm_bios_log *log = &chip->log;
1420bfb2374SThiebaud Weksteen 	void *limit = log->bios_event_log_end;
1430bfb2374SThiebaud Weksteen 	size_t event_size;
1440bfb2374SThiebaud Weksteen 	void *marker;
1450bfb2374SThiebaud Weksteen 
1460bfb2374SThiebaud Weksteen 	event_header = log->bios_event_log;
1470bfb2374SThiebaud Weksteen 
1480bfb2374SThiebaud Weksteen 	if (v == SEQ_START_TOKEN) {
1490bfb2374SThiebaud Weksteen 		event_size = sizeof(struct tcg_pcr_event) -
1500bfb2374SThiebaud Weksteen 			sizeof(event_header->event) + event_header->event_size;
1510bfb2374SThiebaud Weksteen 		marker = event_header;
1520bfb2374SThiebaud Weksteen 	} else {
1530bfb2374SThiebaud Weksteen 		event = v;
1540bfb2374SThiebaud Weksteen 		event_size = calc_tpm2_event_size(event, event_header);
1550bfb2374SThiebaud Weksteen 		if (event_size == 0)
1560bfb2374SThiebaud Weksteen 			return NULL;
1570bfb2374SThiebaud Weksteen 		marker = event;
1580bfb2374SThiebaud Weksteen 	}
1590bfb2374SThiebaud Weksteen 
1600bfb2374SThiebaud Weksteen 	marker = marker + event_size;
1610bfb2374SThiebaud Weksteen 	if (marker >= limit)
1620bfb2374SThiebaud Weksteen 		return NULL;
1630bfb2374SThiebaud Weksteen 	v = marker;
1640bfb2374SThiebaud Weksteen 	event = v;
1650bfb2374SThiebaud Weksteen 
1660bfb2374SThiebaud Weksteen 	event_size = calc_tpm2_event_size(event, event_header);
1670bfb2374SThiebaud Weksteen 	if (((v + event_size) >= limit) || (event_size == 0))
1680bfb2374SThiebaud Weksteen 		return NULL;
1690bfb2374SThiebaud Weksteen 
1700bfb2374SThiebaud Weksteen 	(*pos)++;
1710bfb2374SThiebaud Weksteen 	return v;
1720bfb2374SThiebaud Weksteen }
1730bfb2374SThiebaud Weksteen 
1740bfb2374SThiebaud Weksteen static void tpm2_bios_measurements_stop(struct seq_file *m, void *v)
1750bfb2374SThiebaud Weksteen {
1760bfb2374SThiebaud Weksteen }
1770bfb2374SThiebaud Weksteen 
1780bfb2374SThiebaud Weksteen static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v)
1790bfb2374SThiebaud Weksteen {
1800bfb2374SThiebaud Weksteen 	struct tpm_chip *chip = m->private;
1810bfb2374SThiebaud Weksteen 	struct tpm_bios_log *log = &chip->log;
1820bfb2374SThiebaud Weksteen 	struct tcg_pcr_event *event_header = log->bios_event_log;
183c8faabfcSRoberto Sassu 	struct tcg_pcr_event2_head *event = v;
1840bfb2374SThiebaud Weksteen 	void *temp_ptr;
1850bfb2374SThiebaud Weksteen 	size_t size;
1860bfb2374SThiebaud Weksteen 
1870bfb2374SThiebaud Weksteen 	if (v == SEQ_START_TOKEN) {
1880bfb2374SThiebaud Weksteen 		size = sizeof(struct tcg_pcr_event) -
1890bfb2374SThiebaud Weksteen 			sizeof(event_header->event) + event_header->event_size;
1900bfb2374SThiebaud Weksteen 
1910bfb2374SThiebaud Weksteen 		temp_ptr = event_header;
1920bfb2374SThiebaud Weksteen 
1930bfb2374SThiebaud Weksteen 		if (size > 0)
1940bfb2374SThiebaud Weksteen 			seq_write(m, temp_ptr, size);
1950bfb2374SThiebaud Weksteen 	} else {
1960bfb2374SThiebaud Weksteen 		size = calc_tpm2_event_size(event, event_header);
1970bfb2374SThiebaud Weksteen 		temp_ptr = event;
1980bfb2374SThiebaud Weksteen 		if (size > 0)
1990bfb2374SThiebaud Weksteen 			seq_write(m, temp_ptr, size);
2000bfb2374SThiebaud Weksteen 	}
2010bfb2374SThiebaud Weksteen 
2020bfb2374SThiebaud Weksteen 	return 0;
2030bfb2374SThiebaud Weksteen }
2040bfb2374SThiebaud Weksteen 
2050bfb2374SThiebaud Weksteen const struct seq_operations tpm2_binary_b_measurements_seqops = {
2060bfb2374SThiebaud Weksteen 	.start = tpm2_bios_measurements_start,
2070bfb2374SThiebaud Weksteen 	.next = tpm2_bios_measurements_next,
2080bfb2374SThiebaud Weksteen 	.stop = tpm2_bios_measurements_stop,
2090bfb2374SThiebaud Weksteen 	.show = tpm2_binary_bios_measurements_show,
2100bfb2374SThiebaud Weksteen };
211