xref: /linux/drivers/char/tpm/tpm-buf.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
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 
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 
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 
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  */
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  */
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  */
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  */
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  */
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  */
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 
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 
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 
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  */
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  */
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  */
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  */
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  */
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