xref: /linux/drivers/char/tpm/eventlog/tpm2.c (revision 4e95bc268b915c3a19ec8b9110f61e4ea41a1ed0)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2016 IBM Corporation
4  *
5  * Authors:
6  *      Nayna Jain <nayna@linux.vnet.ibm.com>
7  *
8  * Access to TPM 2.0 event log as written by Firmware.
9  * It assumes that writer of event log has followed TCG Specification
10  * for Family "2.0" and written the event data in little endian.
11  * With that, it doesn't need any endian conversion for structure
12  * content.
13  */
14 
15 #include <linux/seq_file.h>
16 #include <linux/fs.h>
17 #include <linux/security.h>
18 #include <linux/module.h>
19 #include <linux/slab.h>
20 #include <linux/tpm_eventlog.h>
21 
22 #include "../tpm.h"
23 #include "common.h"
24 
25 /*
26  * calc_tpm2_event_size() - calculate the event size, where event
27  * is an entry in the TPM 2.0 event log. The event is of type Crypto
28  * Agile Log Entry Format as defined in TCG EFI Protocol Specification
29  * Family "2.0".
30 
31  * @event: event whose size is to be calculated.
32  * @event_header: the first event in the event log.
33  *
34  * Returns size of the event. If it is an invalid event, returns 0.
35  */
36 static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
37 				   struct tcg_pcr_event *event_header)
38 {
39 	struct tcg_efi_specid_event_head *efispecid;
40 	struct tcg_event_field *event_field;
41 	void *marker;
42 	void *marker_start;
43 	u32 halg_size;
44 	size_t size;
45 	u16 halg;
46 	int i;
47 	int j;
48 
49 	marker = event;
50 	marker_start = marker;
51 	marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
52 		+ sizeof(event->count);
53 
54 	efispecid = (struct tcg_efi_specid_event_head *)event_header->event;
55 
56 	/* Check if event is malformed. */
57 	if (event->count > efispecid->num_algs)
58 		return 0;
59 
60 	for (i = 0; i < event->count; i++) {
61 		halg_size = sizeof(event->digests[i].alg_id);
62 		memcpy(&halg, marker, halg_size);
63 		marker = marker + halg_size;
64 		for (j = 0; j < efispecid->num_algs; j++) {
65 			if (halg == efispecid->digest_sizes[j].alg_id) {
66 				marker +=
67 					efispecid->digest_sizes[j].digest_size;
68 				break;
69 			}
70 		}
71 		/* Algorithm without known length. Such event is unparseable. */
72 		if (j == efispecid->num_algs)
73 			return 0;
74 	}
75 
76 	event_field = (struct tcg_event_field *)marker;
77 	marker = marker + sizeof(event_field->event_size)
78 		+ event_field->event_size;
79 	size = marker - marker_start;
80 
81 	if ((event->event_type == 0) && (event_field->event_size == 0))
82 		return 0;
83 
84 	return size;
85 }
86 
87 static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
88 {
89 	struct tpm_chip *chip = m->private;
90 	struct tpm_bios_log *log = &chip->log;
91 	void *addr = log->bios_event_log;
92 	void *limit = log->bios_event_log_end;
93 	struct tcg_pcr_event *event_header;
94 	struct tcg_pcr_event2_head *event;
95 	size_t size;
96 	int i;
97 
98 	event_header = addr;
99 	size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event)
100 		+ event_header->event_size;
101 
102 	if (*pos == 0) {
103 		if (addr + size < limit) {
104 			if ((event_header->event_type == 0) &&
105 			    (event_header->event_size == 0))
106 				return NULL;
107 			return SEQ_START_TOKEN;
108 		}
109 	}
110 
111 	if (*pos > 0) {
112 		addr += size;
113 		event = addr;
114 		size = calc_tpm2_event_size(event, event_header);
115 		if ((addr + size >=  limit) || (size == 0))
116 			return NULL;
117 	}
118 
119 	for (i = 0; i < (*pos - 1); i++) {
120 		event = addr;
121 		size = calc_tpm2_event_size(event, event_header);
122 
123 		if ((addr + size >= limit) || (size == 0))
124 			return NULL;
125 		addr += size;
126 	}
127 
128 	return addr;
129 }
130 
131 static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
132 					 loff_t *pos)
133 {
134 	struct tcg_pcr_event *event_header;
135 	struct tcg_pcr_event2_head *event;
136 	struct tpm_chip *chip = m->private;
137 	struct tpm_bios_log *log = &chip->log;
138 	void *limit = log->bios_event_log_end;
139 	size_t event_size;
140 	void *marker;
141 
142 	event_header = log->bios_event_log;
143 
144 	if (v == SEQ_START_TOKEN) {
145 		event_size = sizeof(struct tcg_pcr_event) -
146 			sizeof(event_header->event) + event_header->event_size;
147 		marker = event_header;
148 	} else {
149 		event = v;
150 		event_size = calc_tpm2_event_size(event, event_header);
151 		if (event_size == 0)
152 			return NULL;
153 		marker = event;
154 	}
155 
156 	marker = marker + event_size;
157 	if (marker >= limit)
158 		return NULL;
159 	v = marker;
160 	event = v;
161 
162 	event_size = calc_tpm2_event_size(event, event_header);
163 	if (((v + event_size) >= limit) || (event_size == 0))
164 		return NULL;
165 
166 	(*pos)++;
167 	return v;
168 }
169 
170 static void tpm2_bios_measurements_stop(struct seq_file *m, void *v)
171 {
172 }
173 
174 static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v)
175 {
176 	struct tpm_chip *chip = m->private;
177 	struct tpm_bios_log *log = &chip->log;
178 	struct tcg_pcr_event *event_header = log->bios_event_log;
179 	struct tcg_pcr_event2_head *event = v;
180 	void *temp_ptr;
181 	size_t size;
182 
183 	if (v == SEQ_START_TOKEN) {
184 		size = sizeof(struct tcg_pcr_event) -
185 			sizeof(event_header->event) + event_header->event_size;
186 
187 		temp_ptr = event_header;
188 
189 		if (size > 0)
190 			seq_write(m, temp_ptr, size);
191 	} else {
192 		size = calc_tpm2_event_size(event, event_header);
193 		temp_ptr = event;
194 		if (size > 0)
195 			seq_write(m, temp_ptr, size);
196 	}
197 
198 	return 0;
199 }
200 
201 const struct seq_operations tpm2_binary_b_measurements_seqops = {
202 	.start = tpm2_bios_measurements_start,
203 	.next = tpm2_bios_measurements_next,
204 	.stop = tpm2_bios_measurements_stop,
205 	.show = tpm2_binary_bios_measurements_show,
206 };
207