xref: /openbmc/linux/drivers/char/tpm/tpm2-space.c (revision 55fd7e02)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2016 Intel Corporation
4  *
5  * Authors:
6  * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
7  *
8  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
9  *
10  * This file contains TPM2 protocol implementations of the commands
11  * used by the kernel internally.
12  */
13 
14 #include <linux/gfp.h>
15 #include <asm/unaligned.h>
16 #include "tpm.h"
17 
18 enum tpm2_handle_types {
19 	TPM2_HT_HMAC_SESSION	= 0x02000000,
20 	TPM2_HT_POLICY_SESSION	= 0x03000000,
21 	TPM2_HT_TRANSIENT	= 0x80000000,
22 };
23 
24 struct tpm2_context {
25 	__be64 sequence;
26 	__be32 saved_handle;
27 	__be32 hierarchy;
28 	__be16 blob_size;
29 } __packed;
30 
31 static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space)
32 {
33 	int i;
34 
35 	for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
36 		if (space->session_tbl[i])
37 			tpm2_flush_context(chip, space->session_tbl[i]);
38 	}
39 }
40 
41 int tpm2_init_space(struct tpm_space *space)
42 {
43 	space->context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
44 	if (!space->context_buf)
45 		return -ENOMEM;
46 
47 	space->session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
48 	if (space->session_buf == NULL) {
49 		kfree(space->context_buf);
50 		return -ENOMEM;
51 	}
52 
53 	return 0;
54 }
55 
56 void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
57 {
58 	mutex_lock(&chip->tpm_mutex);
59 	if (!tpm_chip_start(chip)) {
60 		tpm2_flush_sessions(chip, space);
61 		tpm_chip_stop(chip);
62 	}
63 	mutex_unlock(&chip->tpm_mutex);
64 	kfree(space->context_buf);
65 	kfree(space->session_buf);
66 }
67 
68 static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
69 			     unsigned int *offset, u32 *handle)
70 {
71 	struct tpm_buf tbuf;
72 	struct tpm2_context *ctx;
73 	unsigned int body_size;
74 	int rc;
75 
76 	rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
77 	if (rc)
78 		return rc;
79 
80 	ctx = (struct tpm2_context *)&buf[*offset];
81 	body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
82 	tpm_buf_append(&tbuf, &buf[*offset], body_size);
83 
84 	rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
85 	if (rc < 0) {
86 		dev_warn(&chip->dev, "%s: failed with a system error %d\n",
87 			 __func__, rc);
88 		tpm_buf_destroy(&tbuf);
89 		return -EFAULT;
90 	} else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
91 		   rc == TPM2_RC_REFERENCE_H0) {
92 		/*
93 		 * TPM_RC_HANDLE means that the session context can't
94 		 * be loaded because of an internal counter mismatch
95 		 * that makes the TPM think there might have been a
96 		 * replay.  This might happen if the context was saved
97 		 * and loaded outside the space.
98 		 *
99 		 * TPM_RC_REFERENCE_H0 means the session has been
100 		 * flushed outside the space
101 		 */
102 		*handle = 0;
103 		tpm_buf_destroy(&tbuf);
104 		return -ENOENT;
105 	} else if (rc > 0) {
106 		dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
107 			 __func__, rc);
108 		tpm_buf_destroy(&tbuf);
109 		return -EFAULT;
110 	}
111 
112 	*handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
113 	*offset += body_size;
114 
115 	tpm_buf_destroy(&tbuf);
116 	return 0;
117 }
118 
119 static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
120 			     unsigned int buf_size, unsigned int *offset)
121 {
122 	struct tpm_buf tbuf;
123 	unsigned int body_size;
124 	int rc;
125 
126 	rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
127 	if (rc)
128 		return rc;
129 
130 	tpm_buf_append_u32(&tbuf, handle);
131 
132 	rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
133 	if (rc < 0) {
134 		dev_warn(&chip->dev, "%s: failed with a system error %d\n",
135 			 __func__, rc);
136 		tpm_buf_destroy(&tbuf);
137 		return -EFAULT;
138 	} else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
139 		tpm_buf_destroy(&tbuf);
140 		return -ENOENT;
141 	} else if (rc) {
142 		dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
143 			 __func__, rc);
144 		tpm_buf_destroy(&tbuf);
145 		return -EFAULT;
146 	}
147 
148 	body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
149 	if ((*offset + body_size) > buf_size) {
150 		dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
151 		tpm_buf_destroy(&tbuf);
152 		return -ENOMEM;
153 	}
154 
155 	memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
156 	*offset += body_size;
157 	tpm_buf_destroy(&tbuf);
158 	return 0;
159 }
160 
161 void tpm2_flush_space(struct tpm_chip *chip)
162 {
163 	struct tpm_space *space = &chip->work_space;
164 	int i;
165 
166 	for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
167 		if (space->context_tbl[i] && ~space->context_tbl[i])
168 			tpm2_flush_context(chip, space->context_tbl[i]);
169 
170 	tpm2_flush_sessions(chip, space);
171 }
172 
173 static int tpm2_load_space(struct tpm_chip *chip)
174 {
175 	struct tpm_space *space = &chip->work_space;
176 	unsigned int offset;
177 	int i;
178 	int rc;
179 
180 	for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
181 		if (!space->context_tbl[i])
182 			continue;
183 
184 		/* sanity check, should never happen */
185 		if (~space->context_tbl[i]) {
186 			dev_err(&chip->dev, "context table is inconsistent");
187 			return -EFAULT;
188 		}
189 
190 		rc = tpm2_load_context(chip, space->context_buf, &offset,
191 				       &space->context_tbl[i]);
192 		if (rc)
193 			return rc;
194 	}
195 
196 	for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
197 		u32 handle;
198 
199 		if (!space->session_tbl[i])
200 			continue;
201 
202 		rc = tpm2_load_context(chip, space->session_buf,
203 				       &offset, &handle);
204 		if (rc == -ENOENT) {
205 			/* load failed, just forget session */
206 			space->session_tbl[i] = 0;
207 		} else if (rc) {
208 			tpm2_flush_space(chip);
209 			return rc;
210 		}
211 		if (handle != space->session_tbl[i]) {
212 			dev_warn(&chip->dev, "session restored to wrong handle\n");
213 			tpm2_flush_space(chip);
214 			return -EFAULT;
215 		}
216 	}
217 
218 	return 0;
219 }
220 
221 static bool tpm2_map_to_phandle(struct tpm_space *space, void *handle)
222 {
223 	u32 vhandle = be32_to_cpup((__be32 *)handle);
224 	u32 phandle;
225 	int i;
226 
227 	i = 0xFFFFFF - (vhandle & 0xFFFFFF);
228 	if (i >= ARRAY_SIZE(space->context_tbl) || !space->context_tbl[i])
229 		return false;
230 
231 	phandle = space->context_tbl[i];
232 	*((__be32 *)handle) = cpu_to_be32(phandle);
233 	return true;
234 }
235 
236 static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
237 {
238 	struct tpm_space *space = &chip->work_space;
239 	unsigned int nr_handles;
240 	u32 attrs;
241 	__be32 *handle;
242 	int i;
243 
244 	i = tpm2_find_cc(chip, cc);
245 	if (i < 0)
246 		return -EINVAL;
247 
248 	attrs = chip->cc_attrs_tbl[i];
249 	nr_handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0);
250 
251 	handle = (__be32 *)&cmd[TPM_HEADER_SIZE];
252 	for (i = 0; i < nr_handles; i++, handle++) {
253 		if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) {
254 			if (!tpm2_map_to_phandle(space, handle))
255 				return -EINVAL;
256 		}
257 	}
258 
259 	return 0;
260 }
261 
262 static int tpm_find_and_validate_cc(struct tpm_chip *chip,
263 				    struct tpm_space *space,
264 				    const void *cmd, size_t len)
265 {
266 	const struct tpm_header *header = (const void *)cmd;
267 	int i;
268 	u32 cc;
269 	u32 attrs;
270 	unsigned int nr_handles;
271 
272 	if (len < TPM_HEADER_SIZE || !chip->nr_commands)
273 		return -EINVAL;
274 
275 	cc = be32_to_cpu(header->ordinal);
276 
277 	i = tpm2_find_cc(chip, cc);
278 	if (i < 0) {
279 		dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
280 			cc);
281 		return -EOPNOTSUPP;
282 	}
283 
284 	attrs = chip->cc_attrs_tbl[i];
285 	nr_handles =
286 		4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0));
287 	if (len < TPM_HEADER_SIZE + 4 * nr_handles)
288 		goto err_len;
289 
290 	return cc;
291 err_len:
292 	dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__,
293 		len);
294 	return -EINVAL;
295 }
296 
297 int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd,
298 		       size_t cmdsiz)
299 {
300 	int rc;
301 	int cc;
302 
303 	if (!space)
304 		return 0;
305 
306 	cc = tpm_find_and_validate_cc(chip, space, cmd, cmdsiz);
307 	if (cc < 0)
308 		return cc;
309 
310 	memcpy(&chip->work_space.context_tbl, &space->context_tbl,
311 	       sizeof(space->context_tbl));
312 	memcpy(&chip->work_space.session_tbl, &space->session_tbl,
313 	       sizeof(space->session_tbl));
314 	memcpy(chip->work_space.context_buf, space->context_buf, PAGE_SIZE);
315 	memcpy(chip->work_space.session_buf, space->session_buf, PAGE_SIZE);
316 
317 	rc = tpm2_load_space(chip);
318 	if (rc) {
319 		tpm2_flush_space(chip);
320 		return rc;
321 	}
322 
323 	rc = tpm2_map_command(chip, cc, cmd);
324 	if (rc) {
325 		tpm2_flush_space(chip);
326 		return rc;
327 	}
328 
329 	chip->last_cc = cc;
330 	return 0;
331 }
332 
333 static bool tpm2_add_session(struct tpm_chip *chip, u32 handle)
334 {
335 	struct tpm_space *space = &chip->work_space;
336 	int i;
337 
338 	for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++)
339 		if (space->session_tbl[i] == 0)
340 			break;
341 
342 	if (i == ARRAY_SIZE(space->session_tbl))
343 		return false;
344 
345 	space->session_tbl[i] = handle;
346 	return true;
347 }
348 
349 static u32 tpm2_map_to_vhandle(struct tpm_space *space, u32 phandle, bool alloc)
350 {
351 	int i;
352 
353 	for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
354 		if (alloc) {
355 			if (!space->context_tbl[i]) {
356 				space->context_tbl[i] = phandle;
357 				break;
358 			}
359 		} else if (space->context_tbl[i] == phandle)
360 			break;
361 	}
362 
363 	if (i == ARRAY_SIZE(space->context_tbl))
364 		return 0;
365 
366 	return TPM2_HT_TRANSIENT | (0xFFFFFF - i);
367 }
368 
369 static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
370 				    size_t len)
371 {
372 	struct tpm_space *space = &chip->work_space;
373 	struct tpm_header *header = (struct tpm_header *)rsp;
374 	u32 phandle;
375 	u32 phandle_type;
376 	u32 vhandle;
377 	u32 attrs;
378 	int i;
379 
380 	if (be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS)
381 		return 0;
382 
383 	i = tpm2_find_cc(chip, cc);
384 	/* sanity check, should never happen */
385 	if (i < 0)
386 		return -EFAULT;
387 
388 	attrs = chip->cc_attrs_tbl[i];
389 	if (!((attrs >> TPM2_CC_ATTR_RHANDLE) & 1))
390 		return 0;
391 
392 	phandle = be32_to_cpup((__be32 *)&rsp[TPM_HEADER_SIZE]);
393 	phandle_type = phandle & 0xFF000000;
394 
395 	switch (phandle_type) {
396 	case TPM2_HT_TRANSIENT:
397 		vhandle = tpm2_map_to_vhandle(space, phandle, true);
398 		if (!vhandle)
399 			goto out_no_slots;
400 
401 		*(__be32 *)&rsp[TPM_HEADER_SIZE] = cpu_to_be32(vhandle);
402 		break;
403 	case TPM2_HT_HMAC_SESSION:
404 	case TPM2_HT_POLICY_SESSION:
405 		if (!tpm2_add_session(chip, phandle))
406 			goto out_no_slots;
407 		break;
408 	default:
409 		dev_err(&chip->dev, "%s: unknown handle 0x%08X\n",
410 			__func__, phandle);
411 		break;
412 	}
413 
414 	return 0;
415 out_no_slots:
416 	tpm2_flush_context(chip, phandle);
417 	dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__,
418 		 phandle);
419 	return -ENOMEM;
420 }
421 
422 struct tpm2_cap_handles {
423 	u8 more_data;
424 	__be32 capability;
425 	__be32 count;
426 	__be32 handles[];
427 } __packed;
428 
429 static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp,
430 				  size_t len)
431 {
432 	struct tpm_space *space = &chip->work_space;
433 	struct tpm_header *header = (struct tpm_header *)rsp;
434 	struct tpm2_cap_handles *data;
435 	u32 phandle;
436 	u32 phandle_type;
437 	u32 vhandle;
438 	int i;
439 	int j;
440 
441 	if (cc != TPM2_CC_GET_CAPABILITY ||
442 	    be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS) {
443 		return 0;
444 	}
445 
446 	if (len < TPM_HEADER_SIZE + 9)
447 		return -EFAULT;
448 
449 	data = (void *)&rsp[TPM_HEADER_SIZE];
450 	if (be32_to_cpu(data->capability) != TPM2_CAP_HANDLES)
451 		return 0;
452 
453 	if (len != TPM_HEADER_SIZE + 9 + 4 * be32_to_cpu(data->count))
454 		return -EFAULT;
455 
456 	for (i = 0, j = 0; i < be32_to_cpu(data->count); i++) {
457 		phandle = be32_to_cpup((__be32 *)&data->handles[i]);
458 		phandle_type = phandle & 0xFF000000;
459 
460 		switch (phandle_type) {
461 		case TPM2_HT_TRANSIENT:
462 			vhandle = tpm2_map_to_vhandle(space, phandle, false);
463 			if (!vhandle)
464 				break;
465 
466 			data->handles[j] = cpu_to_be32(vhandle);
467 			j++;
468 			break;
469 
470 		default:
471 			data->handles[j] = cpu_to_be32(phandle);
472 			j++;
473 			break;
474 		}
475 
476 	}
477 
478 	header->length = cpu_to_be32(TPM_HEADER_SIZE + 9 + 4 * j);
479 	data->count = cpu_to_be32(j);
480 	return 0;
481 }
482 
483 static int tpm2_save_space(struct tpm_chip *chip)
484 {
485 	struct tpm_space *space = &chip->work_space;
486 	unsigned int offset;
487 	int i;
488 	int rc;
489 
490 	for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
491 		if (!(space->context_tbl[i] && ~space->context_tbl[i]))
492 			continue;
493 
494 		rc = tpm2_save_context(chip, space->context_tbl[i],
495 				       space->context_buf, PAGE_SIZE,
496 				       &offset);
497 		if (rc == -ENOENT) {
498 			space->context_tbl[i] = 0;
499 			continue;
500 		} else if (rc)
501 			return rc;
502 
503 		tpm2_flush_context(chip, space->context_tbl[i]);
504 		space->context_tbl[i] = ~0;
505 	}
506 
507 	for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
508 		if (!space->session_tbl[i])
509 			continue;
510 
511 		rc = tpm2_save_context(chip, space->session_tbl[i],
512 				       space->session_buf, PAGE_SIZE,
513 				       &offset);
514 
515 		if (rc == -ENOENT) {
516 			/* handle error saving session, just forget it */
517 			space->session_tbl[i] = 0;
518 		} else if (rc < 0) {
519 			tpm2_flush_space(chip);
520 			return rc;
521 		}
522 	}
523 
524 	return 0;
525 }
526 
527 int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
528 		      void *buf, size_t *bufsiz)
529 {
530 	struct tpm_header *header = buf;
531 	int rc;
532 
533 	if (!space)
534 		return 0;
535 
536 	rc = tpm2_map_response_header(chip, chip->last_cc, buf, *bufsiz);
537 	if (rc) {
538 		tpm2_flush_space(chip);
539 		goto out;
540 	}
541 
542 	rc = tpm2_map_response_body(chip, chip->last_cc, buf, *bufsiz);
543 	if (rc) {
544 		tpm2_flush_space(chip);
545 		goto out;
546 	}
547 
548 	rc = tpm2_save_space(chip);
549 	if (rc) {
550 		tpm2_flush_space(chip);
551 		goto out;
552 	}
553 
554 	*bufsiz = be32_to_cpu(header->length);
555 
556 	memcpy(&space->context_tbl, &chip->work_space.context_tbl,
557 	       sizeof(space->context_tbl));
558 	memcpy(&space->session_tbl, &chip->work_space.session_tbl,
559 	       sizeof(space->session_tbl));
560 	memcpy(space->context_buf, chip->work_space.context_buf, PAGE_SIZE);
561 	memcpy(space->session_buf, chip->work_space.session_buf, PAGE_SIZE);
562 
563 	return 0;
564 out:
565 	dev_err(&chip->dev, "%s: error %d\n", __func__, rc);
566 	return rc;
567 }
568