treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 441
[linux-2.6-microblaze.git] / drivers / char / tpm / tpm2-space.c
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 }