xref: /linux/drivers/char/tpm/eventlog/tpm2.c (revision c46f3405692de1ac82240d927b9c7a0f9d6a4a36)
12874c5fdSThomas 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 {
39*c46f3405SMatthew Garrett 	return __calc_tpm2_event_size(event, event_header, false);
400bfb2374SThiebaud Weksteen }
410bfb2374SThiebaud Weksteen 
420bfb2374SThiebaud Weksteen static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
430bfb2374SThiebaud Weksteen {
440bfb2374SThiebaud Weksteen 	struct tpm_chip *chip = m->private;
450bfb2374SThiebaud Weksteen 	struct tpm_bios_log *log = &chip->log;
460bfb2374SThiebaud Weksteen 	void *addr = log->bios_event_log;
470bfb2374SThiebaud Weksteen 	void *limit = log->bios_event_log_end;
480bfb2374SThiebaud Weksteen 	struct tcg_pcr_event *event_header;
49c8faabfcSRoberto Sassu 	struct tcg_pcr_event2_head *event;
500bfb2374SThiebaud Weksteen 	size_t size;
510bfb2374SThiebaud Weksteen 	int i;
520bfb2374SThiebaud Weksteen 
530bfb2374SThiebaud Weksteen 	event_header = addr;
540bfb2374SThiebaud Weksteen 	size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event)
550bfb2374SThiebaud Weksteen 		+ event_header->event_size;
560bfb2374SThiebaud Weksteen 
570bfb2374SThiebaud Weksteen 	if (*pos == 0) {
580bfb2374SThiebaud Weksteen 		if (addr + size < limit) {
590bfb2374SThiebaud Weksteen 			if ((event_header->event_type == 0) &&
600bfb2374SThiebaud Weksteen 			    (event_header->event_size == 0))
610bfb2374SThiebaud Weksteen 				return NULL;
620bfb2374SThiebaud Weksteen 			return SEQ_START_TOKEN;
630bfb2374SThiebaud Weksteen 		}
640bfb2374SThiebaud Weksteen 	}
650bfb2374SThiebaud Weksteen 
660bfb2374SThiebaud Weksteen 	if (*pos > 0) {
670bfb2374SThiebaud Weksteen 		addr += size;
680bfb2374SThiebaud Weksteen 		event = addr;
690bfb2374SThiebaud Weksteen 		size = calc_tpm2_event_size(event, event_header);
700bfb2374SThiebaud Weksteen 		if ((addr + size >=  limit) || (size == 0))
710bfb2374SThiebaud Weksteen 			return NULL;
720bfb2374SThiebaud Weksteen 	}
730bfb2374SThiebaud Weksteen 
740bfb2374SThiebaud Weksteen 	for (i = 0; i < (*pos - 1); i++) {
750bfb2374SThiebaud Weksteen 		event = addr;
760bfb2374SThiebaud Weksteen 		size = calc_tpm2_event_size(event, event_header);
770bfb2374SThiebaud Weksteen 
780bfb2374SThiebaud Weksteen 		if ((addr + size >= limit) || (size == 0))
790bfb2374SThiebaud Weksteen 			return NULL;
800bfb2374SThiebaud Weksteen 		addr += size;
810bfb2374SThiebaud Weksteen 	}
820bfb2374SThiebaud Weksteen 
830bfb2374SThiebaud Weksteen 	return addr;
840bfb2374SThiebaud Weksteen }
850bfb2374SThiebaud Weksteen 
860bfb2374SThiebaud Weksteen static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
870bfb2374SThiebaud Weksteen 					 loff_t *pos)
880bfb2374SThiebaud Weksteen {
890bfb2374SThiebaud Weksteen 	struct tcg_pcr_event *event_header;
90c8faabfcSRoberto Sassu 	struct tcg_pcr_event2_head *event;
910bfb2374SThiebaud Weksteen 	struct tpm_chip *chip = m->private;
920bfb2374SThiebaud Weksteen 	struct tpm_bios_log *log = &chip->log;
930bfb2374SThiebaud Weksteen 	void *limit = log->bios_event_log_end;
940bfb2374SThiebaud Weksteen 	size_t event_size;
950bfb2374SThiebaud Weksteen 	void *marker;
960bfb2374SThiebaud Weksteen 
970bfb2374SThiebaud Weksteen 	event_header = log->bios_event_log;
980bfb2374SThiebaud Weksteen 
990bfb2374SThiebaud Weksteen 	if (v == SEQ_START_TOKEN) {
1000bfb2374SThiebaud Weksteen 		event_size = sizeof(struct tcg_pcr_event) -
1010bfb2374SThiebaud Weksteen 			sizeof(event_header->event) + event_header->event_size;
1020bfb2374SThiebaud Weksteen 		marker = event_header;
1030bfb2374SThiebaud Weksteen 	} else {
1040bfb2374SThiebaud Weksteen 		event = v;
1050bfb2374SThiebaud Weksteen 		event_size = calc_tpm2_event_size(event, event_header);
1060bfb2374SThiebaud Weksteen 		if (event_size == 0)
1070bfb2374SThiebaud Weksteen 			return NULL;
1080bfb2374SThiebaud Weksteen 		marker = event;
1090bfb2374SThiebaud Weksteen 	}
1100bfb2374SThiebaud Weksteen 
1110bfb2374SThiebaud Weksteen 	marker = marker + event_size;
1120bfb2374SThiebaud Weksteen 	if (marker >= limit)
1130bfb2374SThiebaud Weksteen 		return NULL;
1140bfb2374SThiebaud Weksteen 	v = marker;
1150bfb2374SThiebaud Weksteen 	event = v;
1160bfb2374SThiebaud Weksteen 
1170bfb2374SThiebaud Weksteen 	event_size = calc_tpm2_event_size(event, event_header);
1180bfb2374SThiebaud Weksteen 	if (((v + event_size) >= limit) || (event_size == 0))
1190bfb2374SThiebaud Weksteen 		return NULL;
1200bfb2374SThiebaud Weksteen 
1210bfb2374SThiebaud Weksteen 	(*pos)++;
1220bfb2374SThiebaud Weksteen 	return v;
1230bfb2374SThiebaud Weksteen }
1240bfb2374SThiebaud Weksteen 
1250bfb2374SThiebaud Weksteen static void tpm2_bios_measurements_stop(struct seq_file *m, void *v)
1260bfb2374SThiebaud Weksteen {
1270bfb2374SThiebaud Weksteen }
1280bfb2374SThiebaud Weksteen 
1290bfb2374SThiebaud Weksteen static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v)
1300bfb2374SThiebaud Weksteen {
1310bfb2374SThiebaud Weksteen 	struct tpm_chip *chip = m->private;
1320bfb2374SThiebaud Weksteen 	struct tpm_bios_log *log = &chip->log;
1330bfb2374SThiebaud Weksteen 	struct tcg_pcr_event *event_header = log->bios_event_log;
134c8faabfcSRoberto Sassu 	struct tcg_pcr_event2_head *event = v;
1350bfb2374SThiebaud Weksteen 	void *temp_ptr;
1360bfb2374SThiebaud Weksteen 	size_t size;
1370bfb2374SThiebaud Weksteen 
1380bfb2374SThiebaud Weksteen 	if (v == SEQ_START_TOKEN) {
1390bfb2374SThiebaud Weksteen 		size = sizeof(struct tcg_pcr_event) -
1400bfb2374SThiebaud Weksteen 			sizeof(event_header->event) + event_header->event_size;
1410bfb2374SThiebaud Weksteen 
1420bfb2374SThiebaud Weksteen 		temp_ptr = event_header;
1430bfb2374SThiebaud Weksteen 
1440bfb2374SThiebaud Weksteen 		if (size > 0)
1450bfb2374SThiebaud Weksteen 			seq_write(m, temp_ptr, size);
1460bfb2374SThiebaud Weksteen 	} else {
1470bfb2374SThiebaud Weksteen 		size = calc_tpm2_event_size(event, event_header);
1480bfb2374SThiebaud Weksteen 		temp_ptr = event;
1490bfb2374SThiebaud Weksteen 		if (size > 0)
1500bfb2374SThiebaud Weksteen 			seq_write(m, temp_ptr, size);
1510bfb2374SThiebaud Weksteen 	}
1520bfb2374SThiebaud Weksteen 
1530bfb2374SThiebaud Weksteen 	return 0;
1540bfb2374SThiebaud Weksteen }
1550bfb2374SThiebaud Weksteen 
1560bfb2374SThiebaud Weksteen const struct seq_operations tpm2_binary_b_measurements_seqops = {
1570bfb2374SThiebaud Weksteen 	.start = tpm2_bios_measurements_start,
1580bfb2374SThiebaud Weksteen 	.next = tpm2_bios_measurements_next,
1590bfb2374SThiebaud Weksteen 	.stop = tpm2_bios_measurements_stop,
1600bfb2374SThiebaud Weksteen 	.show = tpm2_binary_bios_measurements_show,
1610bfb2374SThiebaud Weksteen };
162