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 *) |
38 | { |
39 | return __calc_tpm2_event_size(event, event_header, do_mapping: false); |
40 | } |
41 | |
42 | static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos) |
43 | { |
44 | struct tpm_chip *chip = m->private; |
45 | struct tpm_bios_log *log = &chip->log; |
46 | void *addr = log->bios_event_log; |
47 | void *limit = log->bios_event_log_end; |
48 | struct tcg_pcr_event *; |
49 | struct tcg_pcr_event2_head *event; |
50 | size_t size; |
51 | int i; |
52 | |
53 | event_header = addr; |
54 | size = struct_size(event_header, event, event_header->event_size); |
55 | |
56 | if (*pos == 0) { |
57 | if (addr + size < limit) { |
58 | if ((event_header->event_type == 0) && |
59 | (event_header->event_size == 0)) |
60 | return NULL; |
61 | return SEQ_START_TOKEN; |
62 | } |
63 | } |
64 | |
65 | if (*pos > 0) { |
66 | addr += size; |
67 | event = addr; |
68 | size = calc_tpm2_event_size(event, event_header); |
69 | if ((addr + size >= limit) || (size == 0)) |
70 | return NULL; |
71 | } |
72 | |
73 | for (i = 0; i < (*pos - 1); i++) { |
74 | event = addr; |
75 | size = calc_tpm2_event_size(event, event_header); |
76 | |
77 | if ((addr + size >= limit) || (size == 0)) |
78 | return NULL; |
79 | addr += size; |
80 | } |
81 | |
82 | return addr; |
83 | } |
84 | |
85 | static void *tpm2_bios_measurements_next(struct seq_file *m, void *v, |
86 | loff_t *pos) |
87 | { |
88 | struct tcg_pcr_event *; |
89 | struct tcg_pcr_event2_head *event; |
90 | struct tpm_chip *chip = m->private; |
91 | struct tpm_bios_log *log = &chip->log; |
92 | void *limit = log->bios_event_log_end; |
93 | size_t event_size; |
94 | void *marker; |
95 | |
96 | (*pos)++; |
97 | event_header = log->bios_event_log; |
98 | |
99 | if (v == SEQ_START_TOKEN) { |
100 | event_size = struct_size(event_header, event, |
101 | event_header->event_size); |
102 | marker = event_header; |
103 | } else { |
104 | event = v; |
105 | event_size = calc_tpm2_event_size(event, event_header); |
106 | if (event_size == 0) |
107 | return NULL; |
108 | marker = event; |
109 | } |
110 | |
111 | marker = marker + event_size; |
112 | if (marker >= limit) |
113 | return NULL; |
114 | v = marker; |
115 | event = v; |
116 | |
117 | event_size = calc_tpm2_event_size(event, event_header); |
118 | if (((v + event_size) >= limit) || (event_size == 0)) |
119 | return NULL; |
120 | |
121 | return v; |
122 | } |
123 | |
124 | static void tpm2_bios_measurements_stop(struct seq_file *m, void *v) |
125 | { |
126 | } |
127 | |
128 | static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v) |
129 | { |
130 | struct tpm_chip *chip = m->private; |
131 | struct tpm_bios_log *log = &chip->log; |
132 | struct tcg_pcr_event * = log->bios_event_log; |
133 | struct tcg_pcr_event2_head *event = v; |
134 | void *temp_ptr; |
135 | size_t size; |
136 | |
137 | if (v == SEQ_START_TOKEN) { |
138 | size = struct_size(event_header, event, |
139 | event_header->event_size); |
140 | temp_ptr = event_header; |
141 | |
142 | if (size > 0) |
143 | seq_write(seq: m, data: temp_ptr, len: size); |
144 | } else { |
145 | size = calc_tpm2_event_size(event, event_header); |
146 | temp_ptr = event; |
147 | if (size > 0) |
148 | seq_write(seq: m, data: temp_ptr, len: size); |
149 | } |
150 | |
151 | return 0; |
152 | } |
153 | |
154 | const struct seq_operations tpm2_binary_b_measurements_seqops = { |
155 | .start = tpm2_bios_measurements_start, |
156 | .next = tpm2_bios_measurements_next, |
157 | .stop = tpm2_bios_measurements_stop, |
158 | .show = tpm2_binary_bios_measurements_show, |
159 | }; |
160 | |