浏览代码

TPM: workaround to enforce PCR updates across suspends

Add a workaround for TPM's which fail to flush last written
PCR values in a TPM_SaveState, in preparation for suspend.

Signed-off-by: David Safford <safford@watson.ibm.com>
Acked-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>
Rajiv Andrade 15 年之前
父节点
当前提交
225a9be24d
共有 2 个文件被更改,包括 50 次插入7 次删除
  1. 10 0
      Documentation/kernel-parameters.txt
  2. 40 7
      drivers/char/tpm/tpm.c

+ 10 - 0
Documentation/kernel-parameters.txt

@@ -99,6 +99,7 @@ parameter is applicable:
 	SWSUSP	Software suspend (hibernation) is enabled.
 	SWSUSP	Software suspend (hibernation) is enabled.
 	SUSPEND	System suspend states are enabled.
 	SUSPEND	System suspend states are enabled.
 	FTRACE	Function tracing enabled.
 	FTRACE	Function tracing enabled.
+	TPM	TPM drivers are enabled.
 	TS	Appropriate touchscreen support is enabled.
 	TS	Appropriate touchscreen support is enabled.
 	UMS	USB Mass Storage support is enabled.
 	UMS	USB Mass Storage support is enabled.
 	USB	USB support is enabled.
 	USB	USB support is enabled.
@@ -2619,6 +2620,15 @@ and is between 256 and 4096 characters. It is defined in the file
 
 
 	tp720=		[HW,PS2]
 	tp720=		[HW,PS2]
 
 
+	tpm_suspend_pcr=[HW,TPM]
+			Format: integer pcr id
+			Specify that at suspend time, the tpm driver
+			should extend the specified pcr with zeros,
+			as a workaround for some chips which fail to
+			flush the last written pcr on TPM_SaveState.
+			This will guarantee that all the other pcrs
+			are saved.
+
 	trace_buf_size=nn[KMG]
 	trace_buf_size=nn[KMG]
 			[FTRACE] will set tracing buffer size.
 			[FTRACE] will set tracing buffer size.
 
 

+ 40 - 7
drivers/char/tpm/tpm.c

@@ -1067,6 +1067,27 @@ void tpm_remove_hardware(struct device *dev)
 }
 }
 EXPORT_SYMBOL_GPL(tpm_remove_hardware);
 EXPORT_SYMBOL_GPL(tpm_remove_hardware);
 
 
+#define TPM_ORD_SAVESTATE cpu_to_be32(152)
+#define SAVESTATE_RESULT_SIZE 10
+
+static struct tpm_input_header savestate_header = {
+	.tag = TPM_TAG_RQU_COMMAND,
+	.length = cpu_to_be32(10),
+	.ordinal = TPM_ORD_SAVESTATE
+};
+
+/* Bug workaround - some TPM's don't flush the most
+ * recently changed pcr on suspend, so force the flush
+ * with an extend to the selected _unused_ non-volatile pcr.
+ */
+static int tpm_suspend_pcr;
+static int __init tpm_suspend_setup(char *str)
+{
+	get_option(&str, &tpm_suspend_pcr);
+	return 1;
+}
+__setup("tpm_suspend_pcr=", tpm_suspend_setup);
+
 /*
 /*
  * We are about to suspend. Save the TPM state
  * We are about to suspend. Save the TPM state
  * so that it can be restored.
  * so that it can be restored.
@@ -1074,17 +1095,29 @@ EXPORT_SYMBOL_GPL(tpm_remove_hardware);
 int tpm_pm_suspend(struct device *dev, pm_message_t pm_state)
 int tpm_pm_suspend(struct device *dev, pm_message_t pm_state)
 {
 {
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-	u8 savestate[] = {
-		0, 193,		/* TPM_TAG_RQU_COMMAND */
-		0, 0, 0, 10,	/* blob length (in bytes) */
-		0, 0, 0, 152	/* TPM_ORD_SaveState */
-	};
+	struct tpm_cmd_t cmd;
+	int rc;
+
+	u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
 
 
 	if (chip == NULL)
 	if (chip == NULL)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	tpm_transmit(chip, savestate, sizeof(savestate));
-	return 0;
+	/* for buggy tpm, flush pcrs with extend to selected dummy */
+	if (tpm_suspend_pcr) {
+		cmd.header.in = pcrextend_header;
+		cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
+		memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
+		       TPM_DIGEST_SIZE);
+		rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+				  "extending dummy pcr before suspend");
+	}
+
+	/* now do the actual savestate */
+	cmd.header.in = savestate_header;
+	rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE,
+			  "sending savestate before suspend");
+	return rc;
 }
 }
 EXPORT_SYMBOL_GPL(tpm_pm_suspend);
 EXPORT_SYMBOL_GPL(tpm_pm_suspend);