hc
2023-12-09 b22da3d8526a935aa31e086e63f60ff3246cb61c
kernel/drivers/char/tpm/tpm2-space.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (C) 2016 Intel Corporation
34 *
....@@ -8,11 +9,6 @@
89 *
910 * This file contains TPM2 protocol implementations of the commands
1011 * 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.
1612 */
1713
1814 #include <linux/gfp.h>
....@@ -38,8 +34,7 @@
3834
3935 for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
4036 if (space->session_tbl[i])
41
- tpm2_flush_context_cmd(chip, space->session_tbl[i],
42
- TPM_TRANSMIT_NESTED);
37
+ tpm2_flush_context(chip, space->session_tbl[i]);
4338 }
4439 }
4540
....@@ -63,9 +58,12 @@
6358
6459 void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
6560 {
66
- mutex_lock(&chip->tpm_mutex);
67
- tpm2_flush_sessions(chip, space);
68
- mutex_unlock(&chip->tpm_mutex);
61
+
62
+ if (tpm_try_get_ops(chip) == 0) {
63
+ tpm2_flush_sessions(chip, space);
64
+ tpm_put_ops(chip);
65
+ }
66
+
6967 kfree(space->context_buf);
7068 kfree(space->session_buf);
7169 }
....@@ -86,8 +84,7 @@
8684 body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
8785 tpm_buf_append(&tbuf, &buf[*offset], body_size);
8886
89
- rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4,
90
- TPM_TRANSMIT_NESTED, NULL);
87
+ rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
9188 if (rc < 0) {
9289 dev_warn(&chip->dev, "%s: failed with a system error %d\n",
9390 __func__, rc);
....@@ -135,8 +132,7 @@
135132
136133 tpm_buf_append_u32(&tbuf, handle);
137134
138
- rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0,
139
- TPM_TRANSMIT_NESTED, NULL);
135
+ rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
140136 if (rc < 0) {
141137 dev_warn(&chip->dev, "%s: failed with a system error %d\n",
142138 __func__, rc);
....@@ -165,15 +161,14 @@
165161 return 0;
166162 }
167163
168
-static void tpm2_flush_space(struct tpm_chip *chip)
164
+void tpm2_flush_space(struct tpm_chip *chip)
169165 {
170166 struct tpm_space *space = &chip->work_space;
171167 int i;
172168
173169 for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
174170 if (space->context_tbl[i] && ~space->context_tbl[i])
175
- tpm2_flush_context_cmd(chip, space->context_tbl[i],
176
- TPM_TRANSMIT_NESTED);
171
+ tpm2_flush_context(chip, space->context_tbl[i]);
177172
178173 tpm2_flush_sessions(chip, space);
179174 }
....@@ -267,13 +262,53 @@
267262 return 0;
268263 }
269264
270
-int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
271
- u8 *cmd)
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)
272302 {
273303 int rc;
304
+ int cc;
274305
275306 if (!space)
276307 return 0;
308
+
309
+ cc = tpm_find_and_validate_cc(chip, space, cmd, cmdsiz);
310
+ if (cc < 0)
311
+ return cc;
277312
278313 memcpy(&chip->work_space.context_tbl, &space->context_tbl,
279314 sizeof(space->context_tbl));
....@@ -296,6 +331,7 @@
296331 return rc;
297332 }
298333
334
+ chip->last_cc = cc;
299335 return 0;
300336 }
301337
....@@ -339,7 +375,7 @@
339375 size_t len)
340376 {
341377 struct tpm_space *space = &chip->work_space;
342
- struct tpm_output_header *header = (void *)rsp;
378
+ struct tpm_header *header = (struct tpm_header *)rsp;
343379 u32 phandle;
344380 u32 phandle_type;
345381 u32 vhandle;
....@@ -378,11 +414,11 @@
378414 dev_err(&chip->dev, "%s: unknown handle 0x%08X\n",
379415 __func__, phandle);
380416 break;
381
- };
417
+ }
382418
383419 return 0;
384420 out_no_slots:
385
- tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_NESTED);
421
+ tpm2_flush_context(chip, phandle);
386422 dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__,
387423 phandle);
388424 return -ENOMEM;
....@@ -399,7 +435,7 @@
399435 size_t len)
400436 {
401437 struct tpm_space *space = &chip->work_space;
402
- struct tpm_output_header *header = (void *)rsp;
438
+ struct tpm_header *header = (struct tpm_header *)rsp;
403439 struct tpm2_cap_handles *data;
404440 u32 phandle;
405441 u32 phandle_type;
....@@ -472,8 +508,7 @@
472508 } else if (rc)
473509 return rc;
474510
475
- tpm2_flush_context_cmd(chip, space->context_tbl[i],
476
- TPM_TRANSMIT_NESTED);
511
+ tpm2_flush_context(chip, space->context_tbl[i]);
477512 space->context_tbl[i] = ~0;
478513 }
479514
....@@ -497,30 +532,30 @@
497532 }
498533
499534 int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
500
- u32 cc, u8 *buf, size_t *bufsiz)
535
+ void *buf, size_t *bufsiz)
501536 {
502
- struct tpm_output_header *header = (void *)buf;
537
+ struct tpm_header *header = buf;
503538 int rc;
504539
505540 if (!space)
506541 return 0;
507542
508
- rc = tpm2_map_response_header(chip, cc, buf, *bufsiz);
543
+ rc = tpm2_map_response_header(chip, chip->last_cc, buf, *bufsiz);
509544 if (rc) {
510545 tpm2_flush_space(chip);
511
- return rc;
546
+ goto out;
512547 }
513548
514
- rc = tpm2_map_response_body(chip, cc, buf, *bufsiz);
549
+ rc = tpm2_map_response_body(chip, chip->last_cc, buf, *bufsiz);
515550 if (rc) {
516551 tpm2_flush_space(chip);
517
- return rc;
552
+ goto out;
518553 }
519554
520555 rc = tpm2_save_space(chip);
521556 if (rc) {
522557 tpm2_flush_space(chip);
523
- return rc;
558
+ goto out;
524559 }
525560
526561 *bufsiz = be32_to_cpu(header->length);
....@@ -535,4 +570,72 @@
535570 space->buf_size);
536571
537572 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;
538641 }