1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Handling of TPM command and other buffers.
4 */
5
6 #include <linux/module.h>
7 #include <linux/tpm_command.h>
8 #include <linux/tpm_buf.h>
9
__tpm_buf_size_invariant(struct tpm_buf * buf,u16 buf_size)10 static void __tpm_buf_size_invariant(struct tpm_buf *buf, u16 buf_size)
11 {
12 u32 buf_size_2 = (u32)buf->capacity + (u32)sizeof(*buf);
13
14 if (!buf->capacity) {
15 if (buf_size > TPM_BUFSIZE) {
16 WARN(1, "%s: size overflow: %u\n", __func__, buf_size);
17 buf->flags |= TPM_BUF_INVALID;
18 }
19 } else {
20 if (buf_size != buf_size_2) {
21 WARN(1, "%s: size mismatch: %u != %u\n", __func__,
22 buf_size, buf_size_2);
23 buf->flags |= TPM_BUF_INVALID;
24 }
25 }
26 }
27
__tpm_buf_reset(struct tpm_buf * buf,u16 buf_size,u16 tag,u32 ordinal)28 static void __tpm_buf_reset(struct tpm_buf *buf, u16 buf_size, u16 tag,
29 u32 ordinal)
30 {
31 struct tpm_header *head = (struct tpm_header *)buf->data;
32
33 __tpm_buf_size_invariant(buf, buf_size);
34
35 if (buf->flags & TPM_BUF_INVALID)
36 return;
37
38 WARN_ON(tag != TPM_TAG_RQU_COMMAND && tag != TPM2_ST_NO_SESSIONS &&
39 tag != TPM2_ST_SESSIONS && tag != 0);
40
41 buf->flags = 0;
42 buf->length = sizeof(*head);
43 buf->capacity = buf_size - sizeof(*buf);
44 buf->handles = 0;
45 head->tag = cpu_to_be16(tag);
46 head->length = cpu_to_be32(sizeof(*head));
47 head->ordinal = cpu_to_be32(ordinal);
48 }
49
__tpm_buf_reset_sized(struct tpm_buf * buf,u16 buf_size)50 static void __tpm_buf_reset_sized(struct tpm_buf *buf, u16 buf_size)
51 {
52 __tpm_buf_size_invariant(buf, buf_size);
53
54 if (buf->flags & TPM_BUF_INVALID)
55 return;
56
57 buf->flags = TPM_BUF_TPM2B;
58 buf->length = 2;
59 buf->capacity = buf_size - sizeof(*buf);
60 buf->handles = 0;
61 buf->data[0] = 0;
62 buf->data[1] = 0;
63 }
64
65 /**
66 * tpm_buf_init() - Initialize a TPM command
67 * @buf: A &tpm_buf
68 * @buf_size: Size of the buffer.
69 */
tpm_buf_init(struct tpm_buf * buf,u16 buf_size)70 void tpm_buf_init(struct tpm_buf *buf, u16 buf_size)
71 {
72 memset(buf, 0, buf_size);
73 __tpm_buf_reset(buf, buf_size, TPM_TAG_RQU_COMMAND, 0);
74 }
75 EXPORT_SYMBOL_GPL(tpm_buf_init);
76
77 /**
78 * tpm_buf_init_sized() - Initialize a sized buffer
79 * @buf: A &tpm_buf
80 * @buf_size: Size of the buffer.
81 */
tpm_buf_init_sized(struct tpm_buf * buf,u16 buf_size)82 void tpm_buf_init_sized(struct tpm_buf *buf, u16 buf_size)
83 {
84 memset(buf, 0, buf_size);
85 __tpm_buf_reset_sized(buf, buf_size);
86 }
87 EXPORT_SYMBOL_GPL(tpm_buf_init_sized);
88
89 /**
90 * tpm_buf_reset() - Re-initialize a TPM command
91 * @buf: A &tpm_buf
92 * @tag: TPM_TAG_RQU_COMMAND, TPM2_ST_NO_SESSIONS or TPM2_ST_SESSIONS
93 * @ordinal: A command ordinal
94 */
tpm_buf_reset(struct tpm_buf * buf,u16 tag,u32 ordinal)95 void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
96 {
97 u16 buf_size = buf->capacity + sizeof(*buf);
98
99 __tpm_buf_reset(buf, buf_size, tag, ordinal);
100 }
101 EXPORT_SYMBOL_GPL(tpm_buf_reset);
102
103 /**
104 * tpm_buf_reset_sized() - Re-initialize a sized buffer
105 * @buf: A &tpm_buf
106 */
tpm_buf_reset_sized(struct tpm_buf * buf)107 void tpm_buf_reset_sized(struct tpm_buf *buf)
108 {
109 u16 buf_size = buf->capacity + sizeof(*buf);
110
111 __tpm_buf_reset_sized(buf, buf_size);
112 }
113 EXPORT_SYMBOL_GPL(tpm_buf_reset_sized);
114
115 /**
116 * tpm_buf_length() - Return the number of bytes consumed by the data
117 * @buf: A &tpm_buf
118 *
119 * Return: The number of bytes consumed by the buffer
120 */
tpm_buf_length(struct tpm_buf * buf)121 u16 tpm_buf_length(struct tpm_buf *buf)
122 {
123 return buf->length;
124 }
125 EXPORT_SYMBOL_GPL(tpm_buf_length);
126
127 /**
128 * tpm_buf_append() - Append data to an initialized buffer
129 * @buf: A &tpm_buf
130 * @new_data: A data blob
131 * @new_length: Size of the appended data
132 */
tpm_buf_append(struct tpm_buf * buf,const u8 * new_data,u16 new_length)133 void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length)
134 {
135 u32 total_length = (u32)buf->length + (u32)new_length;
136
137 if (buf->flags & TPM_BUF_INVALID)
138 return;
139
140 if (total_length > (u32)buf->capacity) {
141 WARN(1, "tpm_buf: write overflow\n");
142 buf->flags |= TPM_BUF_INVALID;
143 return;
144 }
145
146 memcpy(&buf->data[buf->length], new_data, new_length);
147 buf->length += new_length;
148
149 if (buf->flags & TPM_BUF_TPM2B)
150 ((__be16 *)buf->data)[0] = cpu_to_be16(buf->length - 2);
151 else
152 ((struct tpm_header *)buf->data)->length = cpu_to_be32(buf->length);
153 }
154 EXPORT_SYMBOL_GPL(tpm_buf_append);
155
tpm_buf_append_u8(struct tpm_buf * buf,const u8 value)156 void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value)
157 {
158 tpm_buf_append(buf, &value, 1);
159 }
160 EXPORT_SYMBOL_GPL(tpm_buf_append_u8);
161
tpm_buf_append_u16(struct tpm_buf * buf,const u16 value)162 void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value)
163 {
164 __be16 value2 = cpu_to_be16(value);
165
166 tpm_buf_append(buf, (u8 *)&value2, 2);
167 }
168 EXPORT_SYMBOL_GPL(tpm_buf_append_u16);
169
tpm_buf_append_u32(struct tpm_buf * buf,const u32 value)170 void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
171 {
172 __be32 value2 = cpu_to_be32(value);
173
174 tpm_buf_append(buf, (u8 *)&value2, 4);
175 }
176 EXPORT_SYMBOL_GPL(tpm_buf_append_u32);
177
178 /**
179 * tpm_buf_append_handle() - Add a handle
180 * @buf: &tpm_buf instance
181 * @handle: a TPM object handle
182 *
183 * Add a handle to the buffer, and increase the count tracking the number of
184 * handles in the command buffer. Works only for command buffers.
185 */
tpm_buf_append_handle(struct tpm_buf * buf,u32 handle)186 void tpm_buf_append_handle(struct tpm_buf *buf, u32 handle)
187 {
188 if (buf->flags & TPM_BUF_INVALID)
189 return;
190
191 if (buf->flags & TPM_BUF_TPM2B) {
192 WARN(1, "tpm-buf: invalid type: TPM2B\n");
193 buf->flags |= TPM_BUF_INVALID;
194 return;
195 }
196
197 tpm_buf_append_u32(buf, handle);
198 buf->handles++;
199 }
200
201 /**
202 * tpm_buf_read() - Read from a TPM buffer
203 * @buf: &tpm_buf instance
204 * @offset: offset within the buffer
205 * @count: the number of bytes to read
206 * @output: the output buffer
207 */
tpm_buf_read(struct tpm_buf * buf,off_t * offset,size_t count,void * output)208 static void tpm_buf_read(struct tpm_buf *buf, off_t *offset, size_t count, void *output)
209 {
210 off_t next_offset;
211
212 if (buf->flags & TPM_BUF_INVALID)
213 return;
214
215 next_offset = *offset + count;
216 if (next_offset > buf->length) {
217 WARN(1, "tpm_buf: read out of boundary\n");
218 buf->flags |= TPM_BUF_INVALID;
219 return;
220 }
221
222 memcpy(output, &buf->data[*offset], count);
223 *offset = next_offset;
224 }
225
226 /**
227 * tpm_buf_read_u8() - Read 8-bit word from a TPM buffer
228 * @buf: &tpm_buf instance
229 * @offset: offset within the buffer
230 *
231 * Return: next 8-bit word
232 */
tpm_buf_read_u8(struct tpm_buf * buf,off_t * offset)233 u8 tpm_buf_read_u8(struct tpm_buf *buf, off_t *offset)
234 {
235 u8 value = 0;
236
237 tpm_buf_read(buf, offset, sizeof(value), &value);
238
239 return value;
240 }
241 EXPORT_SYMBOL_GPL(tpm_buf_read_u8);
242
243 /**
244 * tpm_buf_read_u16() - Read 16-bit word from a TPM buffer
245 * @buf: &tpm_buf instance
246 * @offset: offset within the buffer
247 *
248 * Return: next 16-bit word
249 */
tpm_buf_read_u16(struct tpm_buf * buf,off_t * offset)250 u16 tpm_buf_read_u16(struct tpm_buf *buf, off_t *offset)
251 {
252 u16 value = 0;
253
254 tpm_buf_read(buf, offset, sizeof(value), &value);
255
256 return be16_to_cpu(value);
257 }
258 EXPORT_SYMBOL_GPL(tpm_buf_read_u16);
259
260 /**
261 * tpm_buf_read_u32() - Read 32-bit word from a TPM buffer
262 * @buf: &tpm_buf instance
263 * @offset: offset within the buffer
264 *
265 * Return: next 32-bit word
266 */
tpm_buf_read_u32(struct tpm_buf * buf,off_t * offset)267 u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset)
268 {
269 u32 value = 0;
270
271 tpm_buf_read(buf, offset, sizeof(value), &value);
272
273 return be32_to_cpu(value);
274 }
275 EXPORT_SYMBOL_GPL(tpm_buf_read_u32);
276
277
278