Merge tag 'pull-work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[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, unsigned int buf_size)
42 {
43         space->context_buf = kzalloc(buf_size, GFP_KERNEL);
44         if (!space->context_buf)
45                 return -ENOMEM;
46
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;
52                 return -ENOMEM;
53         }
54
55         space->buf_size = buf_size;
56         return 0;
57 }
58
59 void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
60 {
61
62         if (tpm_try_get_ops(chip) == 0) {
63                 tpm2_flush_sessions(chip, space);
64                 tpm_put_ops(chip);
65         }
66
67         kfree(space->context_buf);
68         kfree(space->session_buf);
69 }
70
71 static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
72                              unsigned int *offset, u32 *handle)
73 {
74         struct tpm_buf tbuf;
75         struct tpm2_context *ctx;
76         unsigned int body_size;
77         int rc;
78
79         rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
80         if (rc)
81                 return rc;
82
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);
86
87         rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
88         if (rc < 0) {
89                 dev_warn(&chip->dev, "%s: failed with a system error %d\n",
90                          __func__, rc);
91                 tpm_buf_destroy(&tbuf);
92                 return -EFAULT;
93         } else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
94                    rc == TPM2_RC_REFERENCE_H0) {
95                 /*
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.
101                  *
102                  * TPM_RC_REFERENCE_H0 means the session has been
103                  * flushed outside the space
104                  */
105                 *handle = 0;
106                 tpm_buf_destroy(&tbuf);
107                 return -ENOENT;
108         } else if (rc > 0) {
109                 dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
110                          __func__, rc);
111                 tpm_buf_destroy(&tbuf);
112                 return -EFAULT;
113         }
114
115         *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
116         *offset += body_size;
117
118         tpm_buf_destroy(&tbuf);
119         return 0;
120 }
121
122 static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
123                              unsigned int buf_size, unsigned int *offset)
124 {
125         struct tpm_buf tbuf;
126         unsigned int body_size;
127         int rc;
128
129         rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
130         if (rc)
131                 return rc;
132
133         tpm_buf_append_u32(&tbuf, handle);
134
135         rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
136         if (rc < 0) {
137                 dev_warn(&chip->dev, "%s: failed with a system error %d\n",
138                          __func__, rc);
139                 tpm_buf_destroy(&tbuf);
140                 return -EFAULT;
141         } else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
142                 tpm_buf_destroy(&tbuf);
143                 return -ENOENT;
144         } else if (rc) {
145                 dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
146                          __func__, rc);
147                 tpm_buf_destroy(&tbuf);
148                 return -EFAULT;
149         }
150
151         body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
152         if ((*offset + body_size) > buf_size) {
153                 dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
154                 tpm_buf_destroy(&tbuf);
155                 return -ENOMEM;
156         }
157
158         memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
159         *offset += body_size;
160         tpm_buf_destroy(&tbuf);
161         return 0;
162 }
163
164 void tpm2_flush_space(struct tpm_chip *chip)
165 {
166         struct tpm_space *space = &chip->work_space;
167         int i;
168
169         for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
170                 if (space->context_tbl[i] && ~space->context_tbl[i])
171                         tpm2_flush_context(chip, space->context_tbl[i]);
172
173         tpm2_flush_sessions(chip, space);
174 }
175
176 static int tpm2_load_space(struct tpm_chip *chip)
177 {
178         struct tpm_space *space = &chip->work_space;
179         unsigned int offset;
180         int i;
181         int rc;
182
183         for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
184                 if (!space->context_tbl[i])
185                         continue;
186
187                 /* sanity check, should never happen */
188                 if (~space->context_tbl[i]) {
189                         dev_err(&chip->dev, "context table is inconsistent");
190                         return -EFAULT;
191                 }
192
193                 rc = tpm2_load_context(chip, space->context_buf, &offset,
194                                        &space->context_tbl[i]);
195                 if (rc)
196                         return rc;
197         }
198
199         for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
200                 u32 handle;
201
202                 if (!space->session_tbl[i])
203                         continue;
204
205                 rc = tpm2_load_context(chip, space->session_buf,
206                                        &offset, &handle);
207                 if (rc == -ENOENT) {
208                         /* load failed, just forget session */
209                         space->session_tbl[i] = 0;
210                 } else if (rc) {
211                         tpm2_flush_space(chip);
212                         return rc;
213                 }
214                 if (handle != space->session_tbl[i]) {
215                         dev_warn(&chip->dev, "session restored to wrong handle\n");
216                         tpm2_flush_space(chip);
217                         return -EFAULT;
218                 }
219         }
220
221         return 0;
222 }
223
224 static bool tpm2_map_to_phandle(struct tpm_space *space, void *handle)
225 {
226         u32 vhandle = be32_to_cpup((__be32 *)handle);
227         u32 phandle;
228         int i;
229
230         i = 0xFFFFFF - (vhandle & 0xFFFFFF);
231         if (i >= ARRAY_SIZE(space->context_tbl) || !space->context_tbl[i])
232                 return false;
233
234         phandle = space->context_tbl[i];
235         *((__be32 *)handle) = cpu_to_be32(phandle);
236         return true;
237 }
238
239 static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
240 {
241         struct tpm_space *space = &chip->work_space;
242         unsigned int nr_handles;
243         u32 attrs;
244         __be32 *handle;
245         int i;
246
247         i = tpm2_find_cc(chip, cc);
248         if (i < 0)
249                 return -EINVAL;
250
251         attrs = chip->cc_attrs_tbl[i];
252         nr_handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0);
253
254         handle = (__be32 *)&cmd[TPM_HEADER_SIZE];
255         for (i = 0; i < nr_handles; i++, handle++) {
256                 if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) {
257                         if (!tpm2_map_to_phandle(space, handle))
258                                 return -EINVAL;
259                 }
260         }
261
262         return 0;
263 }
264
265 static int tpm_find_and_validate_cc(struct tpm_chip *chip,
266                                     struct tpm_space *space,
267                                     const void *cmd, size_t len)
268 {
269         const struct tpm_header *header = (const void *)cmd;
270         int i;
271         u32 cc;
272         u32 attrs;
273         unsigned int nr_handles;
274
275         if (len < TPM_HEADER_SIZE || !chip->nr_commands)
276                 return -EINVAL;
277
278         cc = be32_to_cpu(header->ordinal);
279
280         i = tpm2_find_cc(chip, cc);
281         if (i < 0) {
282                 dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
283                         cc);
284                 return -EOPNOTSUPP;
285         }
286
287         attrs = chip->cc_attrs_tbl[i];
288         nr_handles =
289                 4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0));
290         if (len < TPM_HEADER_SIZE + 4 * nr_handles)
291                 goto err_len;
292
293         return cc;
294 err_len:
295         dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__,
296                 len);
297         return -EINVAL;
298 }
299
300 int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd,
301                        size_t cmdsiz)
302 {
303         int rc;
304         int cc;
305
306         if (!space)
307                 return 0;
308
309         cc = tpm_find_and_validate_cc(chip, space, cmd, cmdsiz);
310         if (cc < 0)
311                 return cc;
312
313         memcpy(&chip->work_space.context_tbl, &space->context_tbl,
314                sizeof(space->context_tbl));
315         memcpy(&chip->work_space.session_tbl, &space->session_tbl,
316                sizeof(space->session_tbl));
317         memcpy(chip->work_space.context_buf, space->context_buf,
318                space->buf_size);
319         memcpy(chip->work_space.session_buf, space->session_buf,
320                space->buf_size);
321
322         rc = tpm2_load_space(chip);
323         if (rc) {
324                 tpm2_flush_space(chip);
325                 return rc;
326         }
327
328         rc = tpm2_map_command(chip, cc, cmd);
329         if (rc) {
330                 tpm2_flush_space(chip);
331                 return rc;
332         }
333
334         chip->last_cc = cc;
335         return 0;
336 }
337
338 static bool tpm2_add_session(struct tpm_chip *chip, u32 handle)
339 {
340         struct tpm_space *space = &chip->work_space;
341         int i;
342
343         for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++)
344                 if (space->session_tbl[i] == 0)
345                         break;
346
347         if (i == ARRAY_SIZE(space->session_tbl))
348                 return false;
349
350         space->session_tbl[i] = handle;
351         return true;
352 }
353
354 static u32 tpm2_map_to_vhandle(struct tpm_space *space, u32 phandle, bool alloc)
355 {
356         int i;
357
358         for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
359                 if (alloc) {
360                         if (!space->context_tbl[i]) {
361                                 space->context_tbl[i] = phandle;
362                                 break;
363                         }
364                 } else if (space->context_tbl[i] == phandle)
365                         break;
366         }
367
368         if (i == ARRAY_SIZE(space->context_tbl))
369                 return 0;
370
371         return TPM2_HT_TRANSIENT | (0xFFFFFF - i);
372 }
373
374 static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
375                                     size_t len)
376 {
377         struct tpm_space *space = &chip->work_space;
378         struct tpm_header *header = (struct tpm_header *)rsp;
379         u32 phandle;
380         u32 phandle_type;
381         u32 vhandle;
382         u32 attrs;
383         int i;
384
385         if (be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS)
386                 return 0;
387
388         i = tpm2_find_cc(chip, cc);
389         /* sanity check, should never happen */
390         if (i < 0)
391                 return -EFAULT;
392
393         attrs = chip->cc_attrs_tbl[i];
394         if (!((attrs >> TPM2_CC_ATTR_RHANDLE) & 1))
395                 return 0;
396
397         phandle = be32_to_cpup((__be32 *)&rsp[TPM_HEADER_SIZE]);
398         phandle_type = phandle & 0xFF000000;
399
400         switch (phandle_type) {
401         case TPM2_HT_TRANSIENT:
402                 vhandle = tpm2_map_to_vhandle(space, phandle, true);
403                 if (!vhandle)
404                         goto out_no_slots;
405
406                 *(__be32 *)&rsp[TPM_HEADER_SIZE] = cpu_to_be32(vhandle);
407                 break;
408         case TPM2_HT_HMAC_SESSION:
409         case TPM2_HT_POLICY_SESSION:
410                 if (!tpm2_add_session(chip, phandle))
411                         goto out_no_slots;
412                 break;
413         default:
414                 dev_err(&chip->dev, "%s: unknown handle 0x%08X\n",
415                         __func__, phandle);
416                 break;
417         }
418
419         return 0;
420 out_no_slots:
421         tpm2_flush_context(chip, phandle);
422         dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__,
423                  phandle);
424         return -ENOMEM;
425 }
426
427 struct tpm2_cap_handles {
428         u8 more_data;
429         __be32 capability;
430         __be32 count;
431         __be32 handles[];
432 } __packed;
433
434 static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp,
435                                   size_t len)
436 {
437         struct tpm_space *space = &chip->work_space;
438         struct tpm_header *header = (struct tpm_header *)rsp;
439         struct tpm2_cap_handles *data;
440         u32 phandle;
441         u32 phandle_type;
442         u32 vhandle;
443         int i;
444         int j;
445
446         if (cc != TPM2_CC_GET_CAPABILITY ||
447             be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS) {
448                 return 0;
449         }
450
451         if (len < TPM_HEADER_SIZE + 9)
452                 return -EFAULT;
453
454         data = (void *)&rsp[TPM_HEADER_SIZE];
455         if (be32_to_cpu(data->capability) != TPM2_CAP_HANDLES)
456                 return 0;
457
458         if (be32_to_cpu(data->count) > (UINT_MAX - TPM_HEADER_SIZE - 9) / 4)
459                 return -EFAULT;
460
461         if (len != TPM_HEADER_SIZE + 9 + 4 * be32_to_cpu(data->count))
462                 return -EFAULT;
463
464         for (i = 0, j = 0; i < be32_to_cpu(data->count); i++) {
465                 phandle = be32_to_cpup((__be32 *)&data->handles[i]);
466                 phandle_type = phandle & 0xFF000000;
467
468                 switch (phandle_type) {
469                 case TPM2_HT_TRANSIENT:
470                         vhandle = tpm2_map_to_vhandle(space, phandle, false);
471                         if (!vhandle)
472                                 break;
473
474                         data->handles[j] = cpu_to_be32(vhandle);
475                         j++;
476                         break;
477
478                 default:
479                         data->handles[j] = cpu_to_be32(phandle);
480                         j++;
481                         break;
482                 }
483
484         }
485
486         header->length = cpu_to_be32(TPM_HEADER_SIZE + 9 + 4 * j);
487         data->count = cpu_to_be32(j);
488         return 0;
489 }
490
491 static int tpm2_save_space(struct tpm_chip *chip)
492 {
493         struct tpm_space *space = &chip->work_space;
494         unsigned int offset;
495         int i;
496         int rc;
497
498         for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
499                 if (!(space->context_tbl[i] && ~space->context_tbl[i]))
500                         continue;
501
502                 rc = tpm2_save_context(chip, space->context_tbl[i],
503                                        space->context_buf, space->buf_size,
504                                        &offset);
505                 if (rc == -ENOENT) {
506                         space->context_tbl[i] = 0;
507                         continue;
508                 } else if (rc)
509                         return rc;
510
511                 tpm2_flush_context(chip, space->context_tbl[i]);
512                 space->context_tbl[i] = ~0;
513         }
514
515         for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
516                 if (!space->session_tbl[i])
517                         continue;
518
519                 rc = tpm2_save_context(chip, space->session_tbl[i],
520                                        space->session_buf, space->buf_size,
521                                        &offset);
522                 if (rc == -ENOENT) {
523                         /* handle error saving session, just forget it */
524                         space->session_tbl[i] = 0;
525                 } else if (rc < 0) {
526                         tpm2_flush_space(chip);
527                         return rc;
528                 }
529         }
530
531         return 0;
532 }
533
534 int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
535                       void *buf, size_t *bufsiz)
536 {
537         struct tpm_header *header = buf;
538         int rc;
539
540         if (!space)
541                 return 0;
542
543         rc = tpm2_map_response_header(chip, chip->last_cc, buf, *bufsiz);
544         if (rc) {
545                 tpm2_flush_space(chip);
546                 goto out;
547         }
548
549         rc = tpm2_map_response_body(chip, chip->last_cc, buf, *bufsiz);
550         if (rc) {
551                 tpm2_flush_space(chip);
552                 goto out;
553         }
554
555         rc = tpm2_save_space(chip);
556         if (rc) {
557                 tpm2_flush_space(chip);
558                 goto out;
559         }
560
561         *bufsiz = be32_to_cpu(header->length);
562
563         memcpy(&space->context_tbl, &chip->work_space.context_tbl,
564                sizeof(space->context_tbl));
565         memcpy(&space->session_tbl, &chip->work_space.session_tbl,
566                sizeof(space->session_tbl));
567         memcpy(space->context_buf, chip->work_space.context_buf,
568                space->buf_size);
569         memcpy(space->session_buf, chip->work_space.session_buf,
570                space->buf_size);
571
572         return 0;
573 out:
574         dev_err(&chip->dev, "%s: error %d\n", __func__, rc);
575         return rc;
576 }
577
578 /*
579  * Put the reference to the main device.
580  */
581 static void tpm_devs_release(struct device *dev)
582 {
583         struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs);
584
585         /* release the master device reference */
586         put_device(&chip->dev);
587 }
588
589 /*
590  * Remove the device file for exposed TPM spaces and release the device
591  * reference. This may also release the reference to the master device.
592  */
593 void tpm_devs_remove(struct tpm_chip *chip)
594 {
595         cdev_device_del(&chip->cdevs, &chip->devs);
596         put_device(&chip->devs);
597 }
598
599 /*
600  * Add a device file to expose TPM spaces. Also take a reference to the
601  * main device.
602  */
603 int tpm_devs_add(struct tpm_chip *chip)
604 {
605         int rc;
606
607         device_initialize(&chip->devs);
608         chip->devs.parent = chip->dev.parent;
609         chip->devs.class = tpmrm_class;
610
611         /*
612          * Get extra reference on main device to hold on behalf of devs.
613          * This holds the chip structure while cdevs is in use. The
614          * corresponding put is in the tpm_devs_release.
615          */
616         get_device(&chip->dev);
617         chip->devs.release = tpm_devs_release;
618         chip->devs.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES);
619         cdev_init(&chip->cdevs, &tpmrm_fops);
620         chip->cdevs.owner = THIS_MODULE;
621
622         rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num);
623         if (rc)
624                 goto err_put_devs;
625
626         rc = cdev_device_add(&chip->cdevs, &chip->devs);
627         if (rc) {
628                 dev_err(&chip->devs,
629                         "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
630                         dev_name(&chip->devs), MAJOR(chip->devs.devt),
631                         MINOR(chip->devs.devt), rc);
632                 goto err_put_devs;
633         }
634
635         return 0;
636
637 err_put_devs:
638         put_device(&chip->devs);
639
640         return rc;
641 }