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