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