18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2016 IBM Corporation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Authors:
68c2ecf20Sopenharmony_ci *      Nayna Jain <nayna@linux.vnet.ibm.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Access to TPM 2.0 event log as written by Firmware.
98c2ecf20Sopenharmony_ci * It assumes that writer of event log has followed TCG Specification
108c2ecf20Sopenharmony_ci * for Family "2.0" and written the event data in little endian.
118c2ecf20Sopenharmony_ci * With that, it doesn't need any endian conversion for structure
128c2ecf20Sopenharmony_ci * content.
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
168c2ecf20Sopenharmony_ci#include <linux/fs.h>
178c2ecf20Sopenharmony_ci#include <linux/security.h>
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci#include <linux/tpm_eventlog.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "../tpm.h"
238c2ecf20Sopenharmony_ci#include "common.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/*
268c2ecf20Sopenharmony_ci * calc_tpm2_event_size() - calculate the event size, where event
278c2ecf20Sopenharmony_ci * is an entry in the TPM 2.0 event log. The event is of type Crypto
288c2ecf20Sopenharmony_ci * Agile Log Entry Format as defined in TCG EFI Protocol Specification
298c2ecf20Sopenharmony_ci * Family "2.0".
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci * @event: event whose size is to be calculated.
328c2ecf20Sopenharmony_ci * @event_header: the first event in the event log.
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci * Returns size of the event. If it is an invalid event, returns 0.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_cistatic size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
378c2ecf20Sopenharmony_ci				   struct tcg_pcr_event *event_header)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	return __calc_tpm2_event_size(event, event_header, false);
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	struct tpm_chip *chip = m->private;
458c2ecf20Sopenharmony_ci	struct tpm_bios_log *log = &chip->log;
468c2ecf20Sopenharmony_ci	void *addr = log->bios_event_log;
478c2ecf20Sopenharmony_ci	void *limit = log->bios_event_log_end;
488c2ecf20Sopenharmony_ci	struct tcg_pcr_event *event_header;
498c2ecf20Sopenharmony_ci	struct tcg_pcr_event2_head *event;
508c2ecf20Sopenharmony_ci	size_t size;
518c2ecf20Sopenharmony_ci	int i;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	event_header = addr;
548c2ecf20Sopenharmony_ci	size = struct_size(event_header, event, event_header->event_size);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (*pos == 0) {
578c2ecf20Sopenharmony_ci		if (addr + size < limit) {
588c2ecf20Sopenharmony_ci			if ((event_header->event_type == 0) &&
598c2ecf20Sopenharmony_ci			    (event_header->event_size == 0))
608c2ecf20Sopenharmony_ci				return NULL;
618c2ecf20Sopenharmony_ci			return SEQ_START_TOKEN;
628c2ecf20Sopenharmony_ci		}
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	if (*pos > 0) {
668c2ecf20Sopenharmony_ci		addr += size;
678c2ecf20Sopenharmony_ci		event = addr;
688c2ecf20Sopenharmony_ci		size = calc_tpm2_event_size(event, event_header);
698c2ecf20Sopenharmony_ci		if ((addr + size >=  limit) || (size == 0))
708c2ecf20Sopenharmony_ci			return NULL;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	for (i = 0; i < (*pos - 1); i++) {
748c2ecf20Sopenharmony_ci		event = addr;
758c2ecf20Sopenharmony_ci		size = calc_tpm2_event_size(event, event_header);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci		if ((addr + size >= limit) || (size == 0))
788c2ecf20Sopenharmony_ci			return NULL;
798c2ecf20Sopenharmony_ci		addr += size;
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return addr;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
868c2ecf20Sopenharmony_ci					 loff_t *pos)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	struct tcg_pcr_event *event_header;
898c2ecf20Sopenharmony_ci	struct tcg_pcr_event2_head *event;
908c2ecf20Sopenharmony_ci	struct tpm_chip *chip = m->private;
918c2ecf20Sopenharmony_ci	struct tpm_bios_log *log = &chip->log;
928c2ecf20Sopenharmony_ci	void *limit = log->bios_event_log_end;
938c2ecf20Sopenharmony_ci	size_t event_size;
948c2ecf20Sopenharmony_ci	void *marker;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	(*pos)++;
978c2ecf20Sopenharmony_ci	event_header = log->bios_event_log;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (v == SEQ_START_TOKEN) {
1008c2ecf20Sopenharmony_ci		event_size = struct_size(event_header, event,
1018c2ecf20Sopenharmony_ci					 event_header->event_size);
1028c2ecf20Sopenharmony_ci		marker = event_header;
1038c2ecf20Sopenharmony_ci	} else {
1048c2ecf20Sopenharmony_ci		event = v;
1058c2ecf20Sopenharmony_ci		event_size = calc_tpm2_event_size(event, event_header);
1068c2ecf20Sopenharmony_ci		if (event_size == 0)
1078c2ecf20Sopenharmony_ci			return NULL;
1088c2ecf20Sopenharmony_ci		marker = event;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	marker = marker + event_size;
1128c2ecf20Sopenharmony_ci	if (marker >= limit)
1138c2ecf20Sopenharmony_ci		return NULL;
1148c2ecf20Sopenharmony_ci	v = marker;
1158c2ecf20Sopenharmony_ci	event = v;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	event_size = calc_tpm2_event_size(event, event_header);
1188c2ecf20Sopenharmony_ci	if (((v + event_size) >= limit) || (event_size == 0))
1198c2ecf20Sopenharmony_ci		return NULL;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return v;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic void tpm2_bios_measurements_stop(struct seq_file *m, void *v)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	struct tpm_chip *chip = m->private;
1318c2ecf20Sopenharmony_ci	struct tpm_bios_log *log = &chip->log;
1328c2ecf20Sopenharmony_ci	struct tcg_pcr_event *event_header = log->bios_event_log;
1338c2ecf20Sopenharmony_ci	struct tcg_pcr_event2_head *event = v;
1348c2ecf20Sopenharmony_ci	void *temp_ptr;
1358c2ecf20Sopenharmony_ci	size_t size;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	if (v == SEQ_START_TOKEN) {
1388c2ecf20Sopenharmony_ci		size = struct_size(event_header, event,
1398c2ecf20Sopenharmony_ci				   event_header->event_size);
1408c2ecf20Sopenharmony_ci		temp_ptr = event_header;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci		if (size > 0)
1438c2ecf20Sopenharmony_ci			seq_write(m, temp_ptr, size);
1448c2ecf20Sopenharmony_ci	} else {
1458c2ecf20Sopenharmony_ci		size = calc_tpm2_event_size(event, event_header);
1468c2ecf20Sopenharmony_ci		temp_ptr = event;
1478c2ecf20Sopenharmony_ci		if (size > 0)
1488c2ecf20Sopenharmony_ci			seq_write(m, temp_ptr, size);
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	return 0;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ciconst struct seq_operations tpm2_binary_b_measurements_seqops = {
1558c2ecf20Sopenharmony_ci	.start = tpm2_bios_measurements_start,
1568c2ecf20Sopenharmony_ci	.next = tpm2_bios_measurements_next,
1578c2ecf20Sopenharmony_ci	.stop = tpm2_bios_measurements_stop,
1588c2ecf20Sopenharmony_ci	.show = tpm2_binary_bios_measurements_show,
1598c2ecf20Sopenharmony_ci};
160