xref: /linux/drivers/char/tpm/eventlog/tpm2.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
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  */
calc_tpm2_event_size(struct tcg_pcr_event2_head * event,struct tcg_pcr_event * event_header)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 {
39c46f3405SMatthew Garrett 	return __calc_tpm2_event_size(event, event_header, false);
400bfb2374SThiebaud Weksteen }
410bfb2374SThiebaud Weksteen 
tpm2_bios_measurements_start(struct seq_file * m,loff_t * pos)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;
54*ab91c2a8SGustavo A. R. Silva 	size = struct_size(event_header, event, event_header->event_size);
550bfb2374SThiebaud Weksteen 
560bfb2374SThiebaud Weksteen 	if (*pos == 0) {
570bfb2374SThiebaud Weksteen 		if (addr + size < limit) {
580bfb2374SThiebaud Weksteen 			if ((event_header->event_type == 0) &&
590bfb2374SThiebaud Weksteen 			    (event_header->event_size == 0))
600bfb2374SThiebaud Weksteen 				return NULL;
610bfb2374SThiebaud Weksteen 			return SEQ_START_TOKEN;
620bfb2374SThiebaud Weksteen 		}
630bfb2374SThiebaud Weksteen 	}
640bfb2374SThiebaud Weksteen 
650bfb2374SThiebaud Weksteen 	if (*pos > 0) {
660bfb2374SThiebaud Weksteen 		addr += size;
670bfb2374SThiebaud Weksteen 		event = addr;
680bfb2374SThiebaud Weksteen 		size = calc_tpm2_event_size(event, event_header);
690bfb2374SThiebaud Weksteen 		if ((addr + size >=  limit) || (size == 0))
700bfb2374SThiebaud Weksteen 			return NULL;
710bfb2374SThiebaud Weksteen 	}
720bfb2374SThiebaud Weksteen 
730bfb2374SThiebaud Weksteen 	for (i = 0; i < (*pos - 1); i++) {
740bfb2374SThiebaud Weksteen 		event = addr;
750bfb2374SThiebaud Weksteen 		size = calc_tpm2_event_size(event, event_header);
760bfb2374SThiebaud Weksteen 
770bfb2374SThiebaud Weksteen 		if ((addr + size >= limit) || (size == 0))
780bfb2374SThiebaud Weksteen 			return NULL;
790bfb2374SThiebaud Weksteen 		addr += size;
800bfb2374SThiebaud Weksteen 	}
810bfb2374SThiebaud Weksteen 
820bfb2374SThiebaud Weksteen 	return addr;
830bfb2374SThiebaud Weksteen }
840bfb2374SThiebaud Weksteen 
tpm2_bios_measurements_next(struct seq_file * m,void * v,loff_t * pos)850bfb2374SThiebaud Weksteen static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
860bfb2374SThiebaud Weksteen 					 loff_t *pos)
870bfb2374SThiebaud Weksteen {
880bfb2374SThiebaud Weksteen 	struct tcg_pcr_event *event_header;
89c8faabfcSRoberto Sassu 	struct tcg_pcr_event2_head *event;
900bfb2374SThiebaud Weksteen 	struct tpm_chip *chip = m->private;
910bfb2374SThiebaud Weksteen 	struct tpm_bios_log *log = &chip->log;
920bfb2374SThiebaud Weksteen 	void *limit = log->bios_event_log_end;
930bfb2374SThiebaud Weksteen 	size_t event_size;
940bfb2374SThiebaud Weksteen 	void *marker;
950bfb2374SThiebaud Weksteen 
96f9bf8adbSVasily Averin 	(*pos)++;
970bfb2374SThiebaud Weksteen 	event_header = log->bios_event_log;
980bfb2374SThiebaud Weksteen 
990bfb2374SThiebaud Weksteen 	if (v == SEQ_START_TOKEN) {
100*ab91c2a8SGustavo A. R. Silva 		event_size = struct_size(event_header, event,
101*ab91c2a8SGustavo A. R. Silva 					 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 	return v;
1220bfb2374SThiebaud Weksteen }
1230bfb2374SThiebaud Weksteen 
tpm2_bios_measurements_stop(struct seq_file * m,void * v)1240bfb2374SThiebaud Weksteen static void tpm2_bios_measurements_stop(struct seq_file *m, void *v)
1250bfb2374SThiebaud Weksteen {
1260bfb2374SThiebaud Weksteen }
1270bfb2374SThiebaud Weksteen 
tpm2_binary_bios_measurements_show(struct seq_file * m,void * v)1280bfb2374SThiebaud Weksteen static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v)
1290bfb2374SThiebaud Weksteen {
1300bfb2374SThiebaud Weksteen 	struct tpm_chip *chip = m->private;
1310bfb2374SThiebaud Weksteen 	struct tpm_bios_log *log = &chip->log;
1320bfb2374SThiebaud Weksteen 	struct tcg_pcr_event *event_header = log->bios_event_log;
133c8faabfcSRoberto Sassu 	struct tcg_pcr_event2_head *event = v;
1340bfb2374SThiebaud Weksteen 	void *temp_ptr;
1350bfb2374SThiebaud Weksteen 	size_t size;
1360bfb2374SThiebaud Weksteen 
1370bfb2374SThiebaud Weksteen 	if (v == SEQ_START_TOKEN) {
138*ab91c2a8SGustavo A. R. Silva 		size = struct_size(event_header, event,
139*ab91c2a8SGustavo A. R. Silva 				   event_header->event_size);
1400bfb2374SThiebaud Weksteen 		temp_ptr = event_header;
1410bfb2374SThiebaud Weksteen 
1420bfb2374SThiebaud Weksteen 		if (size > 0)
1430bfb2374SThiebaud Weksteen 			seq_write(m, temp_ptr, size);
1440bfb2374SThiebaud Weksteen 	} else {
1450bfb2374SThiebaud Weksteen 		size = calc_tpm2_event_size(event, event_header);
1460bfb2374SThiebaud Weksteen 		temp_ptr = event;
1470bfb2374SThiebaud Weksteen 		if (size > 0)
1480bfb2374SThiebaud Weksteen 			seq_write(m, temp_ptr, size);
1490bfb2374SThiebaud Weksteen 	}
1500bfb2374SThiebaud Weksteen 
1510bfb2374SThiebaud Weksteen 	return 0;
1520bfb2374SThiebaud Weksteen }
1530bfb2374SThiebaud Weksteen 
1540bfb2374SThiebaud Weksteen const struct seq_operations tpm2_binary_b_measurements_seqops = {
1550bfb2374SThiebaud Weksteen 	.start = tpm2_bios_measurements_start,
1560bfb2374SThiebaud Weksteen 	.next = tpm2_bios_measurements_next,
1570bfb2374SThiebaud Weksteen 	.stop = tpm2_bios_measurements_stop,
1580bfb2374SThiebaud Weksteen 	.show = tpm2_binary_bios_measurements_show,
1590bfb2374SThiebaud Weksteen };
160