diff options
author | Rajiv Andrade <srajiv@linux.vnet.ibm.com> | 2010-03-24 23:55:32 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-03-25 18:30:03 -0400 |
commit | 225a9be24d799aa16d543c31fb09f0c9ed1d9caa (patch) | |
tree | e2db049524c7f153457e55506d1ef4cec0ccf39c /drivers/char/tpm | |
parent | 310de047eef6685274045db1e6b39c9f313df428 (diff) |
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>
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r-- | drivers/char/tpm/tpm.c | 47 |
1 files changed, 40 insertions, 7 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index f06bb37defb1..5c447c991bd5 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -1067,6 +1067,27 @@ void tpm_remove_hardware(struct device *dev) | |||
1067 | } | 1067 | } |
1068 | EXPORT_SYMBOL_GPL(tpm_remove_hardware); | 1068 | EXPORT_SYMBOL_GPL(tpm_remove_hardware); |
1069 | 1069 | ||
1070 | #define TPM_ORD_SAVESTATE cpu_to_be32(152) | ||
1071 | #define SAVESTATE_RESULT_SIZE 10 | ||
1072 | |||
1073 | static struct tpm_input_header savestate_header = { | ||
1074 | .tag = TPM_TAG_RQU_COMMAND, | ||
1075 | .length = cpu_to_be32(10), | ||
1076 | .ordinal = TPM_ORD_SAVESTATE | ||
1077 | }; | ||
1078 | |||
1079 | /* Bug workaround - some TPM's don't flush the most | ||
1080 | * recently changed pcr on suspend, so force the flush | ||
1081 | * with an extend to the selected _unused_ non-volatile pcr. | ||
1082 | */ | ||
1083 | static int tpm_suspend_pcr; | ||
1084 | static int __init tpm_suspend_setup(char *str) | ||
1085 | { | ||
1086 | get_option(&str, &tpm_suspend_pcr); | ||
1087 | return 1; | ||
1088 | } | ||
1089 | __setup("tpm_suspend_pcr=", tpm_suspend_setup); | ||
1090 | |||
1070 | /* | 1091 | /* |
1071 | * We are about to suspend. Save the TPM state | 1092 | * We are about to suspend. Save the TPM state |
1072 | * so that it can be restored. | 1093 | * so that it can be restored. |
@@ -1074,17 +1095,29 @@ EXPORT_SYMBOL_GPL(tpm_remove_hardware); | |||
1074 | int tpm_pm_suspend(struct device *dev, pm_message_t pm_state) | 1095 | int tpm_pm_suspend(struct device *dev, pm_message_t pm_state) |
1075 | { | 1096 | { |
1076 | struct tpm_chip *chip = dev_get_drvdata(dev); | 1097 | struct tpm_chip *chip = dev_get_drvdata(dev); |
1077 | u8 savestate[] = { | 1098 | struct tpm_cmd_t cmd; |
1078 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 1099 | int rc; |
1079 | 0, 0, 0, 10, /* blob length (in bytes) */ | 1100 | |
1080 | 0, 0, 0, 152 /* TPM_ORD_SaveState */ | 1101 | u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 }; |
1081 | }; | ||
1082 | 1102 | ||
1083 | if (chip == NULL) | 1103 | if (chip == NULL) |
1084 | return -ENODEV; | 1104 | return -ENODEV; |
1085 | 1105 | ||
1086 | tpm_transmit(chip, savestate, sizeof(savestate)); | 1106 | /* for buggy tpm, flush pcrs with extend to selected dummy */ |
1087 | return 0; | 1107 | if (tpm_suspend_pcr) { |
1108 | cmd.header.in = pcrextend_header; | ||
1109 | cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr); | ||
1110 | memcpy(cmd.params.pcrextend_in.hash, dummy_hash, | ||
1111 | TPM_DIGEST_SIZE); | ||
1112 | rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, | ||
1113 | "extending dummy pcr before suspend"); | ||
1114 | } | ||
1115 | |||
1116 | /* now do the actual savestate */ | ||
1117 | cmd.header.in = savestate_header; | ||
1118 | rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, | ||
1119 | "sending savestate before suspend"); | ||
1120 | return rc; | ||
1088 | } | 1121 | } |
1089 | EXPORT_SYMBOL_GPL(tpm_pm_suspend); | 1122 | EXPORT_SYMBOL_GPL(tpm_pm_suspend); |
1090 | 1123 | ||