]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
4d23cc32 NJ |
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. | |
4d23cc32 NJ |
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> | |
fd3ec366 | 20 | #include <linux/tpm_eventlog.h> |
4d23cc32 | 21 | |
0bfb2374 | 22 | #include "../tpm.h" |
75d647f5 | 23 | #include "common.h" |
4d23cc32 NJ |
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 | */ | |
b9d0a85d YH |
36 | static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event, |
37 | struct tcg_pcr_event *event_header) | |
4d23cc32 | 38 | { |
c8faabfc | 39 | struct tcg_efi_specid_event_head *efispecid; |
4d23cc32 NJ |
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 | ||
c8faabfc | 54 | efispecid = (struct tcg_efi_specid_event_head *)event_header->event; |
4d23cc32 | 55 | |
fd5c7869 PV |
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++) { | |
4d23cc32 NJ |
61 | halg_size = sizeof(event->digests[i].alg_id); |
62 | memcpy(&halg, marker, halg_size); | |
63 | marker = marker + halg_size; | |
fd5c7869 | 64 | for (j = 0; j < efispecid->num_algs; j++) { |
4d23cc32 | 65 | if (halg == efispecid->digest_sizes[j].alg_id) { |
fd5c7869 | 66 | marker += |
4d23cc32 NJ |
67 | efispecid->digest_sizes[j].digest_size; |
68 | break; | |
69 | } | |
70 | } | |
fd5c7869 PV |
71 | /* Algorithm without known length. Such event is unparseable. */ |
72 | if (j == efispecid->num_algs) | |
73 | return 0; | |
4d23cc32 NJ |
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; | |
c8faabfc | 94 | struct tcg_pcr_event2_head *event; |
4d23cc32 NJ |
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; | |
c8faabfc | 135 | struct tcg_pcr_event2_head *event; |
4d23cc32 NJ |
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; | |
c8faabfc | 179 | struct tcg_pcr_event2_head *event = v; |
4d23cc32 NJ |
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 | }; |