Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2016 Intel Corporation
0004  *
0005  * Authors:
0006  * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
0007  *
0008  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
0009  *
0010  * This file contains TPM2 protocol implementations of the commands
0011  * used by the kernel internally.
0012  */
0013 
0014 #include <linux/gfp.h>
0015 #include <asm/unaligned.h>
0016 #include "tpm.h"
0017 
0018 enum tpm2_handle_types {
0019     TPM2_HT_HMAC_SESSION    = 0x02000000,
0020     TPM2_HT_POLICY_SESSION  = 0x03000000,
0021     TPM2_HT_TRANSIENT   = 0x80000000,
0022 };
0023 
0024 struct tpm2_context {
0025     __be64 sequence;
0026     __be32 saved_handle;
0027     __be32 hierarchy;
0028     __be16 blob_size;
0029 } __packed;
0030 
0031 static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space)
0032 {
0033     int i;
0034 
0035     for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
0036         if (space->session_tbl[i])
0037             tpm2_flush_context(chip, space->session_tbl[i]);
0038     }
0039 }
0040 
0041 int tpm2_init_space(struct tpm_space *space, unsigned int buf_size)
0042 {
0043     space->context_buf = kzalloc(buf_size, GFP_KERNEL);
0044     if (!space->context_buf)
0045         return -ENOMEM;
0046 
0047     space->session_buf = kzalloc(buf_size, GFP_KERNEL);
0048     if (space->session_buf == NULL) {
0049         kfree(space->context_buf);
0050         /* Prevent caller getting a dangling pointer. */
0051         space->context_buf = NULL;
0052         return -ENOMEM;
0053     }
0054 
0055     space->buf_size = buf_size;
0056     return 0;
0057 }
0058 
0059 void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
0060 {
0061 
0062     if (tpm_try_get_ops(chip) == 0) {
0063         tpm2_flush_sessions(chip, space);
0064         tpm_put_ops(chip);
0065     }
0066 
0067     kfree(space->context_buf);
0068     kfree(space->session_buf);
0069 }
0070 
0071 static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
0072                  unsigned int *offset, u32 *handle)
0073 {
0074     struct tpm_buf tbuf;
0075     struct tpm2_context *ctx;
0076     unsigned int body_size;
0077     int rc;
0078 
0079     rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
0080     if (rc)
0081         return rc;
0082 
0083     ctx = (struct tpm2_context *)&buf[*offset];
0084     body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
0085     tpm_buf_append(&tbuf, &buf[*offset], body_size);
0086 
0087     rc = tpm_transmit_cmd(chip, &tbuf, 4, NULL);
0088     if (rc < 0) {
0089         dev_warn(&chip->dev, "%s: failed with a system error %d\n",
0090              __func__, rc);
0091         tpm_buf_destroy(&tbuf);
0092         return -EFAULT;
0093     } else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
0094            rc == TPM2_RC_REFERENCE_H0) {
0095         /*
0096          * TPM_RC_HANDLE means that the session context can't
0097          * be loaded because of an internal counter mismatch
0098          * that makes the TPM think there might have been a
0099          * replay.  This might happen if the context was saved
0100          * and loaded outside the space.
0101          *
0102          * TPM_RC_REFERENCE_H0 means the session has been
0103          * flushed outside the space
0104          */
0105         *handle = 0;
0106         tpm_buf_destroy(&tbuf);
0107         return -ENOENT;
0108     } else if (rc > 0) {
0109         dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
0110              __func__, rc);
0111         tpm_buf_destroy(&tbuf);
0112         return -EFAULT;
0113     }
0114 
0115     *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
0116     *offset += body_size;
0117 
0118     tpm_buf_destroy(&tbuf);
0119     return 0;
0120 }
0121 
0122 static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
0123                  unsigned int buf_size, unsigned int *offset)
0124 {
0125     struct tpm_buf tbuf;
0126     unsigned int body_size;
0127     int rc;
0128 
0129     rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
0130     if (rc)
0131         return rc;
0132 
0133     tpm_buf_append_u32(&tbuf, handle);
0134 
0135     rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
0136     if (rc < 0) {
0137         dev_warn(&chip->dev, "%s: failed with a system error %d\n",
0138              __func__, rc);
0139         tpm_buf_destroy(&tbuf);
0140         return -EFAULT;
0141     } else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
0142         tpm_buf_destroy(&tbuf);
0143         return -ENOENT;
0144     } else if (rc) {
0145         dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
0146              __func__, rc);
0147         tpm_buf_destroy(&tbuf);
0148         return -EFAULT;
0149     }
0150 
0151     body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
0152     if ((*offset + body_size) > buf_size) {
0153         dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
0154         tpm_buf_destroy(&tbuf);
0155         return -ENOMEM;
0156     }
0157 
0158     memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
0159     *offset += body_size;
0160     tpm_buf_destroy(&tbuf);
0161     return 0;
0162 }
0163 
0164 void tpm2_flush_space(struct tpm_chip *chip)
0165 {
0166     struct tpm_space *space = &chip->work_space;
0167     int i;
0168 
0169     for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
0170         if (space->context_tbl[i] && ~space->context_tbl[i])
0171             tpm2_flush_context(chip, space->context_tbl[i]);
0172 
0173     tpm2_flush_sessions(chip, space);
0174 }
0175 
0176 static int tpm2_load_space(struct tpm_chip *chip)
0177 {
0178     struct tpm_space *space = &chip->work_space;
0179     unsigned int offset;
0180     int i;
0181     int rc;
0182 
0183     for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
0184         if (!space->context_tbl[i])
0185             continue;
0186 
0187         /* sanity check, should never happen */
0188         if (~space->context_tbl[i]) {
0189             dev_err(&chip->dev, "context table is inconsistent");
0190             return -EFAULT;
0191         }
0192 
0193         rc = tpm2_load_context(chip, space->context_buf, &offset,
0194                        &space->context_tbl[i]);
0195         if (rc)
0196             return rc;
0197     }
0198 
0199     for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
0200         u32 handle;
0201 
0202         if (!space->session_tbl[i])
0203             continue;
0204 
0205         rc = tpm2_load_context(chip, space->session_buf,
0206                        &offset, &handle);
0207         if (rc == -ENOENT) {
0208             /* load failed, just forget session */
0209             space->session_tbl[i] = 0;
0210         } else if (rc) {
0211             tpm2_flush_space(chip);
0212             return rc;
0213         }
0214         if (handle != space->session_tbl[i]) {
0215             dev_warn(&chip->dev, "session restored to wrong handle\n");
0216             tpm2_flush_space(chip);
0217             return -EFAULT;
0218         }
0219     }
0220 
0221     return 0;
0222 }
0223 
0224 static bool tpm2_map_to_phandle(struct tpm_space *space, void *handle)
0225 {
0226     u32 vhandle = be32_to_cpup((__be32 *)handle);
0227     u32 phandle;
0228     int i;
0229 
0230     i = 0xFFFFFF - (vhandle & 0xFFFFFF);
0231     if (i >= ARRAY_SIZE(space->context_tbl) || !space->context_tbl[i])
0232         return false;
0233 
0234     phandle = space->context_tbl[i];
0235     *((__be32 *)handle) = cpu_to_be32(phandle);
0236     return true;
0237 }
0238 
0239 static int tpm2_map_command(struct tpm_chip *chip, u32 cc, u8 *cmd)
0240 {
0241     struct tpm_space *space = &chip->work_space;
0242     unsigned int nr_handles;
0243     u32 attrs;
0244     __be32 *handle;
0245     int i;
0246 
0247     i = tpm2_find_cc(chip, cc);
0248     if (i < 0)
0249         return -EINVAL;
0250 
0251     attrs = chip->cc_attrs_tbl[i];
0252     nr_handles = (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0);
0253 
0254     handle = (__be32 *)&cmd[TPM_HEADER_SIZE];
0255     for (i = 0; i < nr_handles; i++, handle++) {
0256         if ((be32_to_cpu(*handle) & 0xFF000000) == TPM2_HT_TRANSIENT) {
0257             if (!tpm2_map_to_phandle(space, handle))
0258                 return -EINVAL;
0259         }
0260     }
0261 
0262     return 0;
0263 }
0264 
0265 static int tpm_find_and_validate_cc(struct tpm_chip *chip,
0266                     struct tpm_space *space,
0267                     const void *cmd, size_t len)
0268 {
0269     const struct tpm_header *header = (const void *)cmd;
0270     int i;
0271     u32 cc;
0272     u32 attrs;
0273     unsigned int nr_handles;
0274 
0275     if (len < TPM_HEADER_SIZE || !chip->nr_commands)
0276         return -EINVAL;
0277 
0278     cc = be32_to_cpu(header->ordinal);
0279 
0280     i = tpm2_find_cc(chip, cc);
0281     if (i < 0) {
0282         dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
0283             cc);
0284         return -EOPNOTSUPP;
0285     }
0286 
0287     attrs = chip->cc_attrs_tbl[i];
0288     nr_handles =
0289         4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0));
0290     if (len < TPM_HEADER_SIZE + 4 * nr_handles)
0291         goto err_len;
0292 
0293     return cc;
0294 err_len:
0295     dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__,
0296         len);
0297     return -EINVAL;
0298 }
0299 
0300 int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd,
0301                size_t cmdsiz)
0302 {
0303     int rc;
0304     int cc;
0305 
0306     if (!space)
0307         return 0;
0308 
0309     cc = tpm_find_and_validate_cc(chip, space, cmd, cmdsiz);
0310     if (cc < 0)
0311         return cc;
0312 
0313     memcpy(&chip->work_space.context_tbl, &space->context_tbl,
0314            sizeof(space->context_tbl));
0315     memcpy(&chip->work_space.session_tbl, &space->session_tbl,
0316            sizeof(space->session_tbl));
0317     memcpy(chip->work_space.context_buf, space->context_buf,
0318            space->buf_size);
0319     memcpy(chip->work_space.session_buf, space->session_buf,
0320            space->buf_size);
0321 
0322     rc = tpm2_load_space(chip);
0323     if (rc) {
0324         tpm2_flush_space(chip);
0325         return rc;
0326     }
0327 
0328     rc = tpm2_map_command(chip, cc, cmd);
0329     if (rc) {
0330         tpm2_flush_space(chip);
0331         return rc;
0332     }
0333 
0334     chip->last_cc = cc;
0335     return 0;
0336 }
0337 
0338 static bool tpm2_add_session(struct tpm_chip *chip, u32 handle)
0339 {
0340     struct tpm_space *space = &chip->work_space;
0341     int i;
0342 
0343     for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++)
0344         if (space->session_tbl[i] == 0)
0345             break;
0346 
0347     if (i == ARRAY_SIZE(space->session_tbl))
0348         return false;
0349 
0350     space->session_tbl[i] = handle;
0351     return true;
0352 }
0353 
0354 static u32 tpm2_map_to_vhandle(struct tpm_space *space, u32 phandle, bool alloc)
0355 {
0356     int i;
0357 
0358     for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
0359         if (alloc) {
0360             if (!space->context_tbl[i]) {
0361                 space->context_tbl[i] = phandle;
0362                 break;
0363             }
0364         } else if (space->context_tbl[i] == phandle)
0365             break;
0366     }
0367 
0368     if (i == ARRAY_SIZE(space->context_tbl))
0369         return 0;
0370 
0371     return TPM2_HT_TRANSIENT | (0xFFFFFF - i);
0372 }
0373 
0374 static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
0375                     size_t len)
0376 {
0377     struct tpm_space *space = &chip->work_space;
0378     struct tpm_header *header = (struct tpm_header *)rsp;
0379     u32 phandle;
0380     u32 phandle_type;
0381     u32 vhandle;
0382     u32 attrs;
0383     int i;
0384 
0385     if (be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS)
0386         return 0;
0387 
0388     i = tpm2_find_cc(chip, cc);
0389     /* sanity check, should never happen */
0390     if (i < 0)
0391         return -EFAULT;
0392 
0393     attrs = chip->cc_attrs_tbl[i];
0394     if (!((attrs >> TPM2_CC_ATTR_RHANDLE) & 1))
0395         return 0;
0396 
0397     phandle = be32_to_cpup((__be32 *)&rsp[TPM_HEADER_SIZE]);
0398     phandle_type = phandle & 0xFF000000;
0399 
0400     switch (phandle_type) {
0401     case TPM2_HT_TRANSIENT:
0402         vhandle = tpm2_map_to_vhandle(space, phandle, true);
0403         if (!vhandle)
0404             goto out_no_slots;
0405 
0406         *(__be32 *)&rsp[TPM_HEADER_SIZE] = cpu_to_be32(vhandle);
0407         break;
0408     case TPM2_HT_HMAC_SESSION:
0409     case TPM2_HT_POLICY_SESSION:
0410         if (!tpm2_add_session(chip, phandle))
0411             goto out_no_slots;
0412         break;
0413     default:
0414         dev_err(&chip->dev, "%s: unknown handle 0x%08X\n",
0415             __func__, phandle);
0416         break;
0417     }
0418 
0419     return 0;
0420 out_no_slots:
0421     tpm2_flush_context(chip, phandle);
0422     dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__,
0423          phandle);
0424     return -ENOMEM;
0425 }
0426 
0427 struct tpm2_cap_handles {
0428     u8 more_data;
0429     __be32 capability;
0430     __be32 count;
0431     __be32 handles[];
0432 } __packed;
0433 
0434 static int tpm2_map_response_body(struct tpm_chip *chip, u32 cc, u8 *rsp,
0435                   size_t len)
0436 {
0437     struct tpm_space *space = &chip->work_space;
0438     struct tpm_header *header = (struct tpm_header *)rsp;
0439     struct tpm2_cap_handles *data;
0440     u32 phandle;
0441     u32 phandle_type;
0442     u32 vhandle;
0443     int i;
0444     int j;
0445 
0446     if (cc != TPM2_CC_GET_CAPABILITY ||
0447         be32_to_cpu(header->return_code) != TPM2_RC_SUCCESS) {
0448         return 0;
0449     }
0450 
0451     if (len < TPM_HEADER_SIZE + 9)
0452         return -EFAULT;
0453 
0454     data = (void *)&rsp[TPM_HEADER_SIZE];
0455     if (be32_to_cpu(data->capability) != TPM2_CAP_HANDLES)
0456         return 0;
0457 
0458     if (be32_to_cpu(data->count) > (UINT_MAX - TPM_HEADER_SIZE - 9) / 4)
0459         return -EFAULT;
0460 
0461     if (len != TPM_HEADER_SIZE + 9 + 4 * be32_to_cpu(data->count))
0462         return -EFAULT;
0463 
0464     for (i = 0, j = 0; i < be32_to_cpu(data->count); i++) {
0465         phandle = be32_to_cpup((__be32 *)&data->handles[i]);
0466         phandle_type = phandle & 0xFF000000;
0467 
0468         switch (phandle_type) {
0469         case TPM2_HT_TRANSIENT:
0470             vhandle = tpm2_map_to_vhandle(space, phandle, false);
0471             if (!vhandle)
0472                 break;
0473 
0474             data->handles[j] = cpu_to_be32(vhandle);
0475             j++;
0476             break;
0477 
0478         default:
0479             data->handles[j] = cpu_to_be32(phandle);
0480             j++;
0481             break;
0482         }
0483 
0484     }
0485 
0486     header->length = cpu_to_be32(TPM_HEADER_SIZE + 9 + 4 * j);
0487     data->count = cpu_to_be32(j);
0488     return 0;
0489 }
0490 
0491 static int tpm2_save_space(struct tpm_chip *chip)
0492 {
0493     struct tpm_space *space = &chip->work_space;
0494     unsigned int offset;
0495     int i;
0496     int rc;
0497 
0498     for (i = 0, offset = 0; i < ARRAY_SIZE(space->context_tbl); i++) {
0499         if (!(space->context_tbl[i] && ~space->context_tbl[i]))
0500             continue;
0501 
0502         rc = tpm2_save_context(chip, space->context_tbl[i],
0503                        space->context_buf, space->buf_size,
0504                        &offset);
0505         if (rc == -ENOENT) {
0506             space->context_tbl[i] = 0;
0507             continue;
0508         } else if (rc)
0509             return rc;
0510 
0511         tpm2_flush_context(chip, space->context_tbl[i]);
0512         space->context_tbl[i] = ~0;
0513     }
0514 
0515     for (i = 0, offset = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
0516         if (!space->session_tbl[i])
0517             continue;
0518 
0519         rc = tpm2_save_context(chip, space->session_tbl[i],
0520                        space->session_buf, space->buf_size,
0521                        &offset);
0522         if (rc == -ENOENT) {
0523             /* handle error saving session, just forget it */
0524             space->session_tbl[i] = 0;
0525         } else if (rc < 0) {
0526             tpm2_flush_space(chip);
0527             return rc;
0528         }
0529     }
0530 
0531     return 0;
0532 }
0533 
0534 int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
0535               void *buf, size_t *bufsiz)
0536 {
0537     struct tpm_header *header = buf;
0538     int rc;
0539 
0540     if (!space)
0541         return 0;
0542 
0543     rc = tpm2_map_response_header(chip, chip->last_cc, buf, *bufsiz);
0544     if (rc) {
0545         tpm2_flush_space(chip);
0546         goto out;
0547     }
0548 
0549     rc = tpm2_map_response_body(chip, chip->last_cc, buf, *bufsiz);
0550     if (rc) {
0551         tpm2_flush_space(chip);
0552         goto out;
0553     }
0554 
0555     rc = tpm2_save_space(chip);
0556     if (rc) {
0557         tpm2_flush_space(chip);
0558         goto out;
0559     }
0560 
0561     *bufsiz = be32_to_cpu(header->length);
0562 
0563     memcpy(&space->context_tbl, &chip->work_space.context_tbl,
0564            sizeof(space->context_tbl));
0565     memcpy(&space->session_tbl, &chip->work_space.session_tbl,
0566            sizeof(space->session_tbl));
0567     memcpy(space->context_buf, chip->work_space.context_buf,
0568            space->buf_size);
0569     memcpy(space->session_buf, chip->work_space.session_buf,
0570            space->buf_size);
0571 
0572     return 0;
0573 out:
0574     dev_err(&chip->dev, "%s: error %d\n", __func__, rc);
0575     return rc;
0576 }
0577 
0578 /*
0579  * Put the reference to the main device.
0580  */
0581 static void tpm_devs_release(struct device *dev)
0582 {
0583     struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs);
0584 
0585     /* release the master device reference */
0586     put_device(&chip->dev);
0587 }
0588 
0589 /*
0590  * Remove the device file for exposed TPM spaces and release the device
0591  * reference. This may also release the reference to the master device.
0592  */
0593 void tpm_devs_remove(struct tpm_chip *chip)
0594 {
0595     cdev_device_del(&chip->cdevs, &chip->devs);
0596     put_device(&chip->devs);
0597 }
0598 
0599 /*
0600  * Add a device file to expose TPM spaces. Also take a reference to the
0601  * main device.
0602  */
0603 int tpm_devs_add(struct tpm_chip *chip)
0604 {
0605     int rc;
0606 
0607     device_initialize(&chip->devs);
0608     chip->devs.parent = chip->dev.parent;
0609     chip->devs.class = tpmrm_class;
0610 
0611     /*
0612      * Get extra reference on main device to hold on behalf of devs.
0613      * This holds the chip structure while cdevs is in use. The
0614      * corresponding put is in the tpm_devs_release.
0615      */
0616     get_device(&chip->dev);
0617     chip->devs.release = tpm_devs_release;
0618     chip->devs.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES);
0619     cdev_init(&chip->cdevs, &tpmrm_fops);
0620     chip->cdevs.owner = THIS_MODULE;
0621 
0622     rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num);
0623     if (rc)
0624         goto err_put_devs;
0625 
0626     rc = cdev_device_add(&chip->cdevs, &chip->devs);
0627     if (rc) {
0628         dev_err(&chip->devs,
0629             "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
0630             dev_name(&chip->devs), MAJOR(chip->devs.devt),
0631             MINOR(chip->devs.devt), rc);
0632         goto err_put_devs;
0633     }
0634 
0635     return 0;
0636 
0637 err_put_devs:
0638     put_device(&chip->devs);
0639 
0640     return rc;
0641 }