]> git.proxmox.com Git - mirror_ubuntu-kernels.git/blame - drivers/char/tpm/eventlog/tpm2.c
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 152
[mirror_ubuntu-kernels.git] / drivers / char / tpm / eventlog / tpm2.c
CommitLineData
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
36static 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
87static 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
131static 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
170static void tpm2_bios_measurements_stop(struct seq_file *m, void *v)
171{
172}
173
174static 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
201const 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};