1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2016 Intel Corporation
6 * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
8 * Maintained by: <tpmdd-devel@lists.sourceforge.net>
10 * This file contains TPM2 protocol implementations of the commands
11 * used by the kernel internally.
14 #include <linux/gfp.h>
15 #include <linux/unaligned.h>
18 enum tpm2_handle_types
{
19 TPM2_HT_HMAC_SESSION
= 0x02000000,
20 TPM2_HT_POLICY_SESSION
= 0x03000000,
21 TPM2_HT_TRANSIENT
= 0x80000000,
31 static void tpm2_flush_sessions(struct tpm_chip
*chip
, struct tpm_space
*space
)
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
]);
41 int tpm2_init_space(struct tpm_space
*space
, unsigned int buf_size
)
43 space
->context_buf
= kzalloc(buf_size
, GFP_KERNEL
);
44 if (!space
->context_buf
)
47 space
->session_buf
= kzalloc(buf_size
, GFP_KERNEL
);
48 if (space
->session_buf
== NULL
) {
49 kfree(space
->context_buf
);
50 /* Prevent caller getting a dangling pointer. */
51 space
->context_buf
= NULL
;
55 space
->buf_size
= buf_size
;
59 void tpm2_del_space(struct tpm_chip
*chip
, struct tpm_space
*space
)
62 if (tpm_try_get_ops(chip
) == 0) {
63 tpm2_flush_sessions(chip
, space
);
67 kfree(space
->context_buf
);
68 kfree(space
->session_buf
);
71 int tpm2_load_context(struct tpm_chip
*chip
, u8
*buf
,
72 unsigned int *offset
, u32
*handle
)
75 struct tpm2_context
*ctx
;
76 unsigned int body_size
;
79 rc
= tpm_buf_init(&tbuf
, TPM2_ST_NO_SESSIONS
, TPM2_CC_CONTEXT_LOAD
);
83 ctx
= (struct tpm2_context
*)&buf
[*offset
];
84 body_size
= sizeof(*ctx
) + be16_to_cpu(ctx
->blob_size
);
85 tpm_buf_append(&tbuf
, &buf
[*offset
], body_size
);
87 rc
= tpm_transmit_cmd(chip
, &tbuf
, 4, NULL
);
89 dev_warn(&chip
->dev
, "%s: failed with a system error %d\n",
91 tpm_buf_destroy(&tbuf
);
93 } else if (tpm2_rc_value(rc
) == TPM2_RC_HANDLE
||
94 rc
== TPM2_RC_REFERENCE_H0
) {
96 * TPM_RC_HANDLE means that the session context can't
97 * be loaded because of an internal counter mismatch
98 * that makes the TPM think there might have been a
99 * replay. This might happen if the context was saved
100 * and loaded outside the space.
102 * TPM_RC_REFERENCE_H0 means the session has been
103 * flushed outside the space
106 tpm_buf_destroy(&tbuf
);
108 } else if (tpm2_rc_value(rc
) == TPM2_RC_INTEGRITY
) {
109 tpm_buf_destroy(&tbuf
);
112 dev_warn(&chip
->dev
, "%s: failed with a TPM error 0x%04X\n",
114 tpm_buf_destroy(&tbuf
);
118 *handle
= be32_to_cpup((__be32
*)&tbuf
.data
[TPM_HEADER_SIZE
]);
119 *offset
+= body_size
;
121 tpm_buf_destroy(&tbuf
);
125 int tpm2_save_context(struct tpm_chip
*chip
, u32 handle
, u8
*buf
,
126 unsigned int buf_size
, unsigned int *offset
)
129 unsigned int body_size
;
132 rc
= tpm_buf_init(&tbuf
, TPM2_ST_NO_SESSIONS
, TPM2_CC_CONTEXT_SAVE
);
136 tpm_buf_append_u32(&tbuf
, handle
);
138 rc
= tpm_transmit_cmd(chip
, &tbuf
, 0, NULL
);
140 dev_warn(&chip
->dev
, "%s: failed with a system error %d\n",
142 tpm_buf_destroy(&tbuf
);
144 } else if (tpm2_rc_value(rc
) == TPM2_RC_REFERENCE_H0
) {
145 tpm_buf_destroy(&tbuf
);
148 dev_warn(&chip
->dev
, "%s: failed with a TPM error 0x%04X\n",
150 tpm_buf_destroy(&tbuf
);
154 body_size
= tpm_buf_length(&tbuf
) - TPM_HEADER_SIZE
;
155 if ((*offset
+ body_size
) > buf_size
) {
156 dev_warn(&chip
->dev
, "%s: out of backing storage\n", __func__
);
157 tpm_buf_destroy(&tbuf
);
161 memcpy(&buf
[*offset
], &tbuf
.data
[TPM_HEADER_SIZE
], body_size
);
162 *offset
+= body_size
;
163 tpm_buf_destroy(&tbuf
);
167 void tpm2_flush_space(struct tpm_chip
*chip
)
169 struct tpm_space
*space
= &chip
->work_space
;
175 for (i
= 0; i
< ARRAY_SIZE(space
->context_tbl
); i
++)
176 if (space
->context_tbl
[i
] && ~space
->context_tbl
[i
])
177 tpm2_flush_context(chip
, space
->context_tbl
[i
]);
179 tpm2_flush_sessions(chip
, space
);
182 static int tpm2_load_space(struct tpm_chip
*chip
)
184 struct tpm_space
*space
= &chip
->work_space
;
189 for (i
= 0, offset
= 0; i
< ARRAY_SIZE(space
->context_tbl
); i
++) {
190 if (!space
->context_tbl
[i
])
193 /* sanity check, should never happen */
194 if (~space
->context_tbl
[i
]) {
195 dev_err(&chip
->dev
, "context table is inconsistent");
199 rc
= tpm2_load_context(chip
, space
->context_buf
, &offset
,
200 &space
->context_tbl
[i
]);
205 for (i
= 0, offset
= 0; i
< ARRAY_SIZE(space
->session_tbl
); i
++) {
208 if (!space
->session_tbl
[i
])
211 rc
= tpm2_load_context(chip
, space
->session_buf
,
214 /* load failed, just forget session */
215 space
->session_tbl
[i
] = 0;
217 tpm2_flush_space(chip
);
220 if (handle
!= space
->session_tbl
[i
]) {
221 dev_warn(&chip
->dev
, "session restored to wrong handle\n");
222 tpm2_flush_space(chip
);
230 static bool tpm2_map_to_phandle(struct tpm_space
*space
, void *handle
)
232 u32 vhandle
= be32_to_cpup((__be32
*)handle
);
236 i
= 0xFFFFFF - (vhandle
& 0xFFFFFF);
237 if (i
>= ARRAY_SIZE(space
->context_tbl
) || !space
->context_tbl
[i
])
240 phandle
= space
->context_tbl
[i
];
241 *((__be32
*)handle
) = cpu_to_be32(phandle
);
245 static int tpm2_map_command(struct tpm_chip
*chip
, u32 cc
, u8
*cmd
)
247 struct tpm_space
*space
= &chip
->work_space
;
248 unsigned int nr_handles
;
253 i
= tpm2_find_cc(chip
, cc
);
257 attrs
= chip
->cc_attrs_tbl
[i
];
258 nr_handles
= (attrs
>> TPM2_CC_ATTR_CHANDLES
) & GENMASK(2, 0);
260 handle
= (__be32
*)&cmd
[TPM_HEADER_SIZE
];
261 for (i
= 0; i
< nr_handles
; i
++, handle
++) {
262 if ((be32_to_cpu(*handle
) & 0xFF000000) == TPM2_HT_TRANSIENT
) {
263 if (!tpm2_map_to_phandle(space
, handle
))
271 static int tpm_find_and_validate_cc(struct tpm_chip
*chip
,
272 struct tpm_space
*space
,
273 const void *cmd
, size_t len
)
275 const struct tpm_header
*header
= (const void *)cmd
;
279 unsigned int nr_handles
;
281 if (len
< TPM_HEADER_SIZE
|| !chip
->nr_commands
)
284 cc
= be32_to_cpu(header
->ordinal
);
286 i
= tpm2_find_cc(chip
, cc
);
288 dev_dbg(&chip
->dev
, "0x%04X is an invalid command\n",
293 attrs
= chip
->cc_attrs_tbl
[i
];
295 4 * ((attrs
>> TPM2_CC_ATTR_CHANDLES
) & GENMASK(2, 0));
296 if (len
< TPM_HEADER_SIZE
+ 4 * nr_handles
)
301 dev_dbg(&chip
->dev
, "%s: insufficient command length %zu", __func__
,
306 int tpm2_prepare_space(struct tpm_chip
*chip
, struct tpm_space
*space
, u8
*cmd
,
315 cc
= tpm_find_and_validate_cc(chip
, space
, cmd
, cmdsiz
);
319 memcpy(&chip
->work_space
.context_tbl
, &space
->context_tbl
,
320 sizeof(space
->context_tbl
));
321 memcpy(&chip
->work_space
.session_tbl
, &space
->session_tbl
,
322 sizeof(space
->session_tbl
));
323 memcpy(chip
->work_space
.context_buf
, space
->context_buf
,
325 memcpy(chip
->work_space
.session_buf
, space
->session_buf
,
328 rc
= tpm2_load_space(chip
);
330 tpm2_flush_space(chip
);
334 rc
= tpm2_map_command(chip
, cc
, cmd
);
336 tpm2_flush_space(chip
);
344 static bool tpm2_add_session(struct tpm_chip
*chip
, u32 handle
)
346 struct tpm_space
*space
= &chip
->work_space
;
349 for (i
= 0; i
< ARRAY_SIZE(space
->session_tbl
); i
++)
350 if (space
->session_tbl
[i
] == 0)
353 if (i
== ARRAY_SIZE(space
->session_tbl
))
356 space
->session_tbl
[i
] = handle
;
360 static u32
tpm2_map_to_vhandle(struct tpm_space
*space
, u32 phandle
, bool alloc
)
364 for (i
= 0; i
< ARRAY_SIZE(space
->context_tbl
); i
++) {
366 if (!space
->context_tbl
[i
]) {
367 space
->context_tbl
[i
] = phandle
;
370 } else if (space
->context_tbl
[i
] == phandle
)
374 if (i
== ARRAY_SIZE(space
->context_tbl
))
377 return TPM2_HT_TRANSIENT
| (0xFFFFFF - i
);
380 static int tpm2_map_response_header(struct tpm_chip
*chip
, u32 cc
, u8
*rsp
,
383 struct tpm_space
*space
= &chip
->work_space
;
384 struct tpm_header
*header
= (struct tpm_header
*)rsp
;
391 if (be32_to_cpu(header
->return_code
) != TPM2_RC_SUCCESS
)
394 i
= tpm2_find_cc(chip
, cc
);
395 /* sanity check, should never happen */
399 attrs
= chip
->cc_attrs_tbl
[i
];
400 if (!((attrs
>> TPM2_CC_ATTR_RHANDLE
) & 1))
403 phandle
= be32_to_cpup((__be32
*)&rsp
[TPM_HEADER_SIZE
]);
404 phandle_type
= phandle
& 0xFF000000;
406 switch (phandle_type
) {
407 case TPM2_HT_TRANSIENT
:
408 vhandle
= tpm2_map_to_vhandle(space
, phandle
, true);
412 *(__be32
*)&rsp
[TPM_HEADER_SIZE
] = cpu_to_be32(vhandle
);
414 case TPM2_HT_HMAC_SESSION
:
415 case TPM2_HT_POLICY_SESSION
:
416 if (!tpm2_add_session(chip
, phandle
))
420 dev_err(&chip
->dev
, "%s: unknown handle 0x%08X\n",
427 tpm2_flush_context(chip
, phandle
);
428 dev_warn(&chip
->dev
, "%s: out of slots for 0x%08X\n", __func__
,
433 struct tpm2_cap_handles
{
440 static int tpm2_map_response_body(struct tpm_chip
*chip
, u32 cc
, u8
*rsp
,
443 struct tpm_space
*space
= &chip
->work_space
;
444 struct tpm_header
*header
= (struct tpm_header
*)rsp
;
445 struct tpm2_cap_handles
*data
;
452 if (cc
!= TPM2_CC_GET_CAPABILITY
||
453 be32_to_cpu(header
->return_code
) != TPM2_RC_SUCCESS
) {
457 if (len
< TPM_HEADER_SIZE
+ 9)
460 data
= (void *)&rsp
[TPM_HEADER_SIZE
];
461 if (be32_to_cpu(data
->capability
) != TPM2_CAP_HANDLES
)
464 if (be32_to_cpu(data
->count
) > (UINT_MAX
- TPM_HEADER_SIZE
- 9) / 4)
467 if (len
!= TPM_HEADER_SIZE
+ 9 + 4 * be32_to_cpu(data
->count
))
470 for (i
= 0, j
= 0; i
< be32_to_cpu(data
->count
); i
++) {
471 phandle
= be32_to_cpup((__be32
*)&data
->handles
[i
]);
472 phandle_type
= phandle
& 0xFF000000;
474 switch (phandle_type
) {
475 case TPM2_HT_TRANSIENT
:
476 vhandle
= tpm2_map_to_vhandle(space
, phandle
, false);
480 data
->handles
[j
] = cpu_to_be32(vhandle
);
485 data
->handles
[j
] = cpu_to_be32(phandle
);
492 header
->length
= cpu_to_be32(TPM_HEADER_SIZE
+ 9 + 4 * j
);
493 data
->count
= cpu_to_be32(j
);
497 static int tpm2_save_space(struct tpm_chip
*chip
)
499 struct tpm_space
*space
= &chip
->work_space
;
504 for (i
= 0, offset
= 0; i
< ARRAY_SIZE(space
->context_tbl
); i
++) {
505 if (!(space
->context_tbl
[i
] && ~space
->context_tbl
[i
]))
508 rc
= tpm2_save_context(chip
, space
->context_tbl
[i
],
509 space
->context_buf
, space
->buf_size
,
512 space
->context_tbl
[i
] = 0;
517 tpm2_flush_context(chip
, space
->context_tbl
[i
]);
518 space
->context_tbl
[i
] = ~0;
521 for (i
= 0, offset
= 0; i
< ARRAY_SIZE(space
->session_tbl
); i
++) {
522 if (!space
->session_tbl
[i
])
525 rc
= tpm2_save_context(chip
, space
->session_tbl
[i
],
526 space
->session_buf
, space
->buf_size
,
529 /* handle error saving session, just forget it */
530 space
->session_tbl
[i
] = 0;
532 tpm2_flush_space(chip
);
540 int tpm2_commit_space(struct tpm_chip
*chip
, struct tpm_space
*space
,
541 void *buf
, size_t *bufsiz
)
543 struct tpm_header
*header
= buf
;
549 rc
= tpm2_map_response_header(chip
, chip
->last_cc
, buf
, *bufsiz
);
551 tpm2_flush_space(chip
);
555 rc
= tpm2_map_response_body(chip
, chip
->last_cc
, buf
, *bufsiz
);
557 tpm2_flush_space(chip
);
561 rc
= tpm2_save_space(chip
);
563 tpm2_flush_space(chip
);
567 *bufsiz
= be32_to_cpu(header
->length
);
569 memcpy(&space
->context_tbl
, &chip
->work_space
.context_tbl
,
570 sizeof(space
->context_tbl
));
571 memcpy(&space
->session_tbl
, &chip
->work_space
.session_tbl
,
572 sizeof(space
->session_tbl
));
573 memcpy(space
->context_buf
, chip
->work_space
.context_buf
,
575 memcpy(space
->session_buf
, chip
->work_space
.session_buf
,
580 dev_err(&chip
->dev
, "%s: error %d\n", __func__
, rc
);
585 * Put the reference to the main device.
587 static void tpm_devs_release(struct device
*dev
)
589 struct tpm_chip
*chip
= container_of(dev
, struct tpm_chip
, devs
);
591 /* release the master device reference */
592 put_device(&chip
->dev
);
596 * Remove the device file for exposed TPM spaces and release the device
597 * reference. This may also release the reference to the master device.
599 void tpm_devs_remove(struct tpm_chip
*chip
)
601 cdev_device_del(&chip
->cdevs
, &chip
->devs
);
602 put_device(&chip
->devs
);
606 * Add a device file to expose TPM spaces. Also take a reference to the
609 int tpm_devs_add(struct tpm_chip
*chip
)
613 device_initialize(&chip
->devs
);
614 chip
->devs
.parent
= chip
->dev
.parent
;
615 chip
->devs
.class = &tpmrm_class
;
618 * Get extra reference on main device to hold on behalf of devs.
619 * This holds the chip structure while cdevs is in use. The
620 * corresponding put is in the tpm_devs_release.
622 get_device(&chip
->dev
);
623 chip
->devs
.release
= tpm_devs_release
;
624 chip
->devs
.devt
= MKDEV(MAJOR(tpm_devt
), chip
->dev_num
+ TPM_NUM_DEVICES
);
625 cdev_init(&chip
->cdevs
, &tpmrm_fops
);
626 chip
->cdevs
.owner
= THIS_MODULE
;
628 rc
= dev_set_name(&chip
->devs
, "tpmrm%d", chip
->dev_num
);
632 rc
= cdev_device_add(&chip
->cdevs
, &chip
->devs
);
635 "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
636 dev_name(&chip
->devs
), MAJOR(chip
->devs
.devt
),
637 MINOR(chip
->devs
.devt
), rc
);
644 put_device(&chip
->devs
);