Skip to content

Commit eb24c97

Browse files
James Bottomleyjarkkojs
authored andcommitted
tpm: disable the TPM if NULL name changes
Update tpm2_load_context() to return -EINVAL on integrity failures and use this as a signal when loading the NULL context that something might be wrong. If the signal fails, check the name of the NULL primary against the one stored in the chip data and if there is a mismatch disable the TPM because it is likely to have suffered a reset attack. Signed-off-by: James Bottomley <[email protected]> Reviewed-by: Jarkko Sakkinen <[email protected]> Tested-by: Jarkko Sakkinen <[email protected]> Signed-off-by: Jarkko Sakkinen <[email protected]>
1 parent 3d2daf9 commit eb24c97

File tree

4 files changed

+70
-17
lines changed

4 files changed

+70
-17
lines changed

drivers/char/tpm/tpm-chip.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ int tpm_try_get_ops(struct tpm_chip *chip)
158158
{
159159
int rc = -EIO;
160160

161+
if (chip->flags & TPM_CHIP_FLAG_DISABLE)
162+
return rc;
163+
161164
get_device(&chip->dev);
162165

163166
down_read(&chip->ops_sem);

drivers/char/tpm/tpm2-sessions.c

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@
8080
/* maximum number of names the TPM must remember for authorization */
8181
#define AUTH_MAX_NAMES 3
8282

83+
static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
84+
u32 *handle, u8 *name);
85+
8386
/*
8487
* This is the structure that carries all the auth information (like
8588
* session handle, nonces, session key and auth) from use to use it is
@@ -851,6 +854,37 @@ static int tpm2_parse_start_auth_session(struct tpm2_auth *auth,
851854
return 0;
852855
}
853856

857+
static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
858+
{
859+
int rc;
860+
unsigned int offset = 0; /* dummy offset for null seed context */
861+
u8 name[SHA256_DIGEST_SIZE + 2];
862+
863+
rc = tpm2_load_context(chip, chip->null_key_context, &offset,
864+
null_key);
865+
if (rc != -EINVAL)
866+
return rc;
867+
868+
/* an integrity failure may mean the TPM has been reset */
869+
dev_err(&chip->dev, "NULL key integrity failure!\n");
870+
/* check the null name against what we know */
871+
tpm2_create_primary(chip, TPM2_RH_NULL, NULL, name);
872+
if (memcmp(name, chip->null_key_name, sizeof(name)) == 0)
873+
/* name unchanged, assume transient integrity failure */
874+
return rc;
875+
/*
876+
* Fatal TPM failure: the NULL seed has actually changed, so
877+
* the TPM must have been illegally reset. All in-kernel TPM
878+
* operations will fail because the NULL primary can't be
879+
* loaded to salt the sessions, but disable the TPM anyway so
880+
* userspace programmes can't be compromised by it.
881+
*/
882+
dev_err(&chip->dev, "NULL name has changed, disabling TPM due to interference\n");
883+
chip->flags |= TPM_CHIP_FLAG_DISABLE;
884+
885+
return rc;
886+
}
887+
854888
/**
855889
* tpm2_start_auth_session() - create a HMAC authentication session with the TPM
856890
* @chip: the TPM chip structure to create the session with
@@ -868,12 +902,9 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
868902
struct tpm_buf buf;
869903
struct tpm2_auth *auth = chip->auth;
870904
int rc;
871-
/* null seed context has no offset, but we must provide one */
872-
unsigned int offset = 0;
873-
u32 nullkey;
905+
u32 null_key;
874906

875-
rc = tpm2_load_context(chip, chip->null_key_context, &offset,
876-
&nullkey);
907+
rc = tpm2_load_null(chip, &null_key);
877908
if (rc)
878909
goto out;
879910

@@ -884,7 +915,7 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
884915
goto out;
885916

886917
/* salt key handle */
887-
tpm_buf_append_u32(&buf, nullkey);
918+
tpm_buf_append_u32(&buf, null_key);
888919
/* bind key handle */
889920
tpm_buf_append_u32(&buf, TPM2_RH_NULL);
890921
/* nonce caller */
@@ -908,7 +939,7 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
908939
tpm_buf_append_u16(&buf, TPM_ALG_SHA256);
909940

910941
rc = tpm_transmit_cmd(chip, &buf, 0, "start auth session");
911-
tpm2_flush_context(chip, nullkey);
942+
tpm2_flush_context(chip, null_key);
912943

913944
if (rc == TPM2_RC_SUCCESS)
914945
rc = tpm2_parse_start_auth_session(auth, &buf);
@@ -930,22 +961,28 @@ EXPORT_SYMBOL(tpm2_start_auth_session);
930961
* @buf: The response buffer from the chip
931962
* @handle: pointer to be filled in with the return handle of the primary
932963
* @hierarchy: The hierarchy the primary was created for
964+
* @name: pointer to be filled in with the primary key name
933965
*
934966
* Return:
935967
* * 0 - OK
936968
* * -errno - A system error
937969
* * TPM_RC - A TPM error
938970
*/
939971
static int tpm2_parse_create_primary(struct tpm_chip *chip, struct tpm_buf *buf,
940-
u32 *handle, u32 hierarchy)
972+
u32 *handle, u32 hierarchy, u8 *name)
941973
{
942974
struct tpm_header *head = (struct tpm_header *)buf->data;
943975
off_t offset_r = TPM_HEADER_SIZE, offset_t;
944976
u16 len = TPM_HEADER_SIZE;
945977
u32 total_len = be32_to_cpu(head->length);
946-
u32 val, param_len;
978+
u32 val, param_len, keyhandle;
979+
980+
keyhandle = tpm_buf_read_u32(buf, &offset_r);
981+
if (handle)
982+
*handle = keyhandle;
983+
else
984+
tpm2_flush_context(chip, keyhandle);
947985

948-
*handle = tpm_buf_read_u32(buf, &offset_r);
949986
param_len = tpm_buf_read_u32(buf, &offset_r);
950987
/*
951988
* param_len doesn't include the header, but all the other
@@ -958,9 +995,14 @@ static int tpm2_parse_create_primary(struct tpm_chip *chip, struct tpm_buf *buf,
958995
return -EINVAL;
959996
len = tpm_buf_read_u16(buf, &offset_r);
960997
offset_t = offset_r;
961-
/* now we have the public area, compute the name of the object */
962-
put_unaligned_be16(TPM_ALG_SHA256, chip->null_key_name);
963-
sha256(&buf->data[offset_r], len, chip->null_key_name + 2);
998+
if (name) {
999+
/*
1000+
* now we have the public area, compute the name of
1001+
* the object
1002+
*/
1003+
put_unaligned_be16(TPM_ALG_SHA256, name);
1004+
sha256(&buf->data[offset_r], len, name + 2);
1005+
}
9641006

9651007
/* validate the public key */
9661008
val = tpm_buf_read_u16(buf, &offset_t);
@@ -1089,6 +1131,7 @@ static int tpm2_parse_create_primary(struct tpm_chip *chip, struct tpm_buf *buf,
10891131
* @chip: the TPM chip to create under
10901132
* @hierarchy: The hierarchy handle to create under
10911133
* @handle: The returned volatile handle on success
1134+
* @name: The name of the returned key
10921135
*
10931136
* For platforms that might not have a persistent primary, this can be
10941137
* used to create one quickly on the fly (it uses Elliptic Curve not
@@ -1103,7 +1146,7 @@ static int tpm2_parse_create_primary(struct tpm_chip *chip, struct tpm_buf *buf,
11031146
* * TPM_RC - A TPM error
11041147
*/
11051148
static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
1106-
u32 *handle)
1149+
u32 *handle, u8 *name)
11071150
{
11081151
int rc;
11091152
struct tpm_buf buf;
@@ -1193,7 +1236,8 @@ static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
11931236
"attempting to create NULL primary");
11941237

11951238
if (rc == TPM2_RC_SUCCESS)
1196-
rc = tpm2_parse_create_primary(chip, &buf, handle, hierarchy);
1239+
rc = tpm2_parse_create_primary(chip, &buf, handle, hierarchy,
1240+
name);
11971241

11981242
tpm_buf_destroy(&buf);
11991243

@@ -1205,7 +1249,8 @@ static int tpm2_create_null_primary(struct tpm_chip *chip)
12051249
u32 null_key;
12061250
int rc;
12071251

1208-
rc = tpm2_create_primary(chip, TPM2_RH_NULL, &null_key);
1252+
rc = tpm2_create_primary(chip, TPM2_RH_NULL, &null_key,
1253+
chip->null_key_name);
12091254

12101255
if (rc == TPM2_RC_SUCCESS) {
12111256
unsigned int offset = 0; /* dummy offset for null key context */

drivers/char/tpm/tpm2-space.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
105105
*handle = 0;
106106
tpm_buf_destroy(&tbuf);
107107
return -ENOENT;
108+
} else if (tpm2_rc_value(rc) == TPM2_RC_INTEGRITY) {
109+
tpm_buf_destroy(&tbuf);
110+
return -EINVAL;
108111
} else if (rc > 0) {
109112
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
110113
__func__, rc);

include/linux/tpm.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ enum tpm2_return_codes {
248248
TPM2_RC_SUCCESS = 0x0000,
249249
TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
250250
TPM2_RC_HANDLE = 0x008B,
251+
TPM2_RC_INTEGRITY = 0x009F,
251252
TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
252253
TPM2_RC_FAILURE = 0x0101,
253254
TPM2_RC_DISABLED = 0x0120,
@@ -346,6 +347,7 @@ enum tpm_chip_flags {
346347
TPM_CHIP_FLAG_FIRMWARE_UPGRADE = BIT(7),
347348
TPM_CHIP_FLAG_SUSPENDED = BIT(8),
348349
TPM_CHIP_FLAG_HWRNG_DISABLED = BIT(9),
350+
TPM_CHIP_FLAG_DISABLE = BIT(10),
349351
};
350352

351353
#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
@@ -447,7 +449,7 @@ static inline bool tpm_is_firmware_upgrade(struct tpm_chip *chip)
447449

448450
static inline u32 tpm2_rc_value(u32 rc)
449451
{
450-
return (rc & BIT(7)) ? rc & 0xff : rc;
452+
return (rc & BIT(7)) ? rc & 0xbf : rc;
451453
}
452454

453455
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)

0 commit comments

Comments
 (0)