tpm: validate TPM 2.0 commands
[linux-2.6-microblaze.git] / drivers / char / tpm / tpm2-cmd.c
index 881aea9..ec05ab3 100644 (file)
@@ -418,6 +418,35 @@ static const struct tpm_input_header tpm2_get_tpm_pt_header = {
        .ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY)
 };
 
+/**
+ * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command
+ * @chip: TPM chip to use
+ * @payload: the key data in clear and encrypted form
+ * @options: authentication values and other options
+ *
+ * Return: same as with tpm_transmit_cmd
+ */
+void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
+                           unsigned int flags)
+{
+       struct tpm_buf buf;
+       int rc;
+
+       rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
+       if (rc) {
+               dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
+                        handle);
+               return;
+       }
+
+       tpm_buf_append_u32(&buf, handle);
+
+       (void) tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, flags,
+                               "flushing context");
+
+       tpm_buf_destroy(&buf);
+}
+
 /**
  * tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer.
  *
@@ -627,39 +656,6 @@ out:
        return rc;
 }
 
-/**
- * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command
- *
- * @chip: TPM chip to use
- * @handle: the key data in clear and encrypted form
- * @flags: tpm transmit flags
- *
- * Return: Same as with tpm_transmit_cmd.
- */
-static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
-                                  unsigned int flags)
-{
-       struct tpm_buf buf;
-       int rc;
-
-       rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
-       if (rc) {
-               dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
-                        handle);
-               return;
-       }
-
-       tpm_buf_append_u32(&buf, handle);
-
-       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, flags,
-                             "flushing context");
-       if (rc)
-               dev_warn(&chip->dev, "0x%08x was not flushed, rc=%d\n", handle,
-                        rc);
-
-       tpm_buf_destroy(&buf);
-}
-
 /**
  * tpm2_unseal_cmd() - execute a TPM2_Unload command
  *
@@ -1067,15 +1063,76 @@ out:
        return rc;
 }
 
+static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
+{
+       struct tpm_buf buf;
+       u32 nr_commands;
+       u32 *attrs;
+       u32 cc;
+       int i;
+       int rc;
+
+       rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL);
+       if (rc)
+               goto out;
+
+       if (nr_commands > 0xFFFFF) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       chip->cc_attrs_tbl = devm_kzalloc(&chip->dev, 4 * nr_commands,
+                                         GFP_KERNEL);
+
+       rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+       if (rc)
+               goto out;
+
+       tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS);
+       tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
+       tpm_buf_append_u32(&buf, nr_commands);
+
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 9 + 4 * nr_commands,
+                             0, NULL);
+       if (rc) {
+               tpm_buf_destroy(&buf);
+               goto out;
+       }
+
+       if (nr_commands !=
+           be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
+               tpm_buf_destroy(&buf);
+               goto out;
+       }
+
+       chip->nr_commands = nr_commands;
+
+       attrs = (u32 *)&buf.data[TPM_HEADER_SIZE + 9];
+       for (i = 0; i < nr_commands; i++, attrs++) {
+               chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
+               cc = chip->cc_attrs_tbl[i] & 0xFFFF;
+
+               if (cc == TPM2_CC_CONTEXT_SAVE || cc == TPM2_CC_FLUSH_CONTEXT) {
+                       chip->cc_attrs_tbl[i] &=
+                               ~(GENMASK(2, 0) << TPM2_CC_ATTR_CHANDLES);
+                       chip->cc_attrs_tbl[i] |= 1 << TPM2_CC_ATTR_CHANDLES;
+               }
+       }
+
+       tpm_buf_destroy(&buf);
+
+out:
+       if (rc > 0)
+               rc = -ENODEV;
+       return rc;
+}
+
 /**
  * tpm2_auto_startup - Perform the standard automatic TPM initialization
  *                     sequence
  * @chip: TPM chip to use
  *
- * Initializes timeout values for operation and command durations, conducts
- * a self-test and reads the list of active PCR banks.
- *
- * Return: 0 on success. Otherwise, a system error code is returned.
+ * Returns 0 on success, < 0 in case of fatal error.
  */
 int tpm2_auto_startup(struct tpm_chip *chip)
 {
@@ -1104,9 +1161,24 @@ int tpm2_auto_startup(struct tpm_chip *chip)
        }
 
        rc = tpm2_get_pcr_allocation(chip);
+       if (rc)
+               goto out;
+
+       rc = tpm2_get_cc_attrs_tbl(chip);
 
 out:
        if (rc > 0)
                rc = -ENODEV;
        return rc;
 }
+
+int tpm2_find_cc(struct tpm_chip *chip, u32 cc)
+{
+       int i;
+
+       for (i = 0; i < chip->nr_commands; i++)
+               if (cc == (chip->cc_attrs_tbl[i] & GENMASK(15, 0)))
+                       return i;
+
+       return -1;
+}