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