Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <James.Bottomley@HansenPartnership.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Tested-by: Jarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>

authored by

James Bottomley and committed by
Jarkko Sakkinen
eb24c978 3d2daf9d

+70 -17
+3
drivers/char/tpm/tpm-chip.c
··· 158 158 { 159 159 int rc = -EIO; 160 160 161 + if (chip->flags & TPM_CHIP_FLAG_DISABLE) 162 + return rc; 163 + 161 164 get_device(&chip->dev); 162 165 163 166 down_read(&chip->ops_sem);
+61 -16
drivers/char/tpm/tpm2-sessions.c
··· 80 80 /* maximum number of names the TPM must remember for authorization */ 81 81 #define AUTH_MAX_NAMES 3 82 82 83 + static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy, 84 + u32 *handle, u8 *name); 85 + 83 86 /* 84 87 * This is the structure that carries all the auth information (like 85 88 * session handle, nonces, session key and auth) from use to use it is ··· 854 851 return 0; 855 852 } 856 853 854 + static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key) 855 + { 856 + int rc; 857 + unsigned int offset = 0; /* dummy offset for null seed context */ 858 + u8 name[SHA256_DIGEST_SIZE + 2]; 859 + 860 + rc = tpm2_load_context(chip, chip->null_key_context, &offset, 861 + null_key); 862 + if (rc != -EINVAL) 863 + return rc; 864 + 865 + /* an integrity failure may mean the TPM has been reset */ 866 + dev_err(&chip->dev, "NULL key integrity failure!\n"); 867 + /* check the null name against what we know */ 868 + tpm2_create_primary(chip, TPM2_RH_NULL, NULL, name); 869 + if (memcmp(name, chip->null_key_name, sizeof(name)) == 0) 870 + /* name unchanged, assume transient integrity failure */ 871 + return rc; 872 + /* 873 + * Fatal TPM failure: the NULL seed has actually changed, so 874 + * the TPM must have been illegally reset. All in-kernel TPM 875 + * operations will fail because the NULL primary can't be 876 + * loaded to salt the sessions, but disable the TPM anyway so 877 + * userspace programmes can't be compromised by it. 878 + */ 879 + dev_err(&chip->dev, "NULL name has changed, disabling TPM due to interference\n"); 880 + chip->flags |= TPM_CHIP_FLAG_DISABLE; 881 + 882 + return rc; 883 + } 884 + 857 885 /** 858 886 * tpm2_start_auth_session() - create a HMAC authentication session with the TPM 859 887 * @chip: the TPM chip structure to create the session with ··· 902 868 struct tpm_buf buf; 903 869 struct tpm2_auth *auth = chip->auth; 904 870 int rc; 905 - /* null seed context has no offset, but we must provide one */ 906 - unsigned int offset = 0; 907 - u32 nullkey; 871 + u32 null_key; 908 872 909 - rc = tpm2_load_context(chip, chip->null_key_context, &offset, 910 - &nullkey); 873 + rc = tpm2_load_null(chip, &null_key); 911 874 if (rc) 912 875 goto out; 913 876 ··· 915 884 goto out; 916 885 917 886 /* salt key handle */ 918 - tpm_buf_append_u32(&buf, nullkey); 887 + tpm_buf_append_u32(&buf, null_key); 919 888 /* bind key handle */ 920 889 tpm_buf_append_u32(&buf, TPM2_RH_NULL); 921 890 /* nonce caller */ ··· 939 908 tpm_buf_append_u16(&buf, TPM_ALG_SHA256); 940 909 941 910 rc = tpm_transmit_cmd(chip, &buf, 0, "start auth session"); 942 - tpm2_flush_context(chip, nullkey); 911 + tpm2_flush_context(chip, null_key); 943 912 944 913 if (rc == TPM2_RC_SUCCESS) 945 914 rc = tpm2_parse_start_auth_session(auth, &buf); ··· 961 930 * @buf: The response buffer from the chip 962 931 * @handle: pointer to be filled in with the return handle of the primary 963 932 * @hierarchy: The hierarchy the primary was created for 933 + * @name: pointer to be filled in with the primary key name 964 934 * 965 935 * Return: 966 936 * * 0 - OK ··· 969 937 * * TPM_RC - A TPM error 970 938 */ 971 939 static int tpm2_parse_create_primary(struct tpm_chip *chip, struct tpm_buf *buf, 972 - u32 *handle, u32 hierarchy) 940 + u32 *handle, u32 hierarchy, u8 *name) 973 941 { 974 942 struct tpm_header *head = (struct tpm_header *)buf->data; 975 943 off_t offset_r = TPM_HEADER_SIZE, offset_t; 976 944 u16 len = TPM_HEADER_SIZE; 977 945 u32 total_len = be32_to_cpu(head->length); 978 - u32 val, param_len; 946 + u32 val, param_len, keyhandle; 979 947 980 - *handle = tpm_buf_read_u32(buf, &offset_r); 948 + keyhandle = tpm_buf_read_u32(buf, &offset_r); 949 + if (handle) 950 + *handle = keyhandle; 951 + else 952 + tpm2_flush_context(chip, keyhandle); 953 + 981 954 param_len = tpm_buf_read_u32(buf, &offset_r); 982 955 /* 983 956 * param_len doesn't include the header, but all the other ··· 995 958 return -EINVAL; 996 959 len = tpm_buf_read_u16(buf, &offset_r); 997 960 offset_t = offset_r; 998 - /* now we have the public area, compute the name of the object */ 999 - put_unaligned_be16(TPM_ALG_SHA256, chip->null_key_name); 1000 - sha256(&buf->data[offset_r], len, chip->null_key_name + 2); 961 + if (name) { 962 + /* 963 + * now we have the public area, compute the name of 964 + * the object 965 + */ 966 + put_unaligned_be16(TPM_ALG_SHA256, name); 967 + sha256(&buf->data[offset_r], len, name + 2); 968 + } 1001 969 1002 970 /* validate the public key */ 1003 971 val = tpm_buf_read_u16(buf, &offset_t); ··· 1131 1089 * @chip: the TPM chip to create under 1132 1090 * @hierarchy: The hierarchy handle to create under 1133 1091 * @handle: The returned volatile handle on success 1092 + * @name: The name of the returned key 1134 1093 * 1135 1094 * For platforms that might not have a persistent primary, this can be 1136 1095 * used to create one quickly on the fly (it uses Elliptic Curve not ··· 1146 1103 * * TPM_RC - A TPM error 1147 1104 */ 1148 1105 static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy, 1149 - u32 *handle) 1106 + u32 *handle, u8 *name) 1150 1107 { 1151 1108 int rc; 1152 1109 struct tpm_buf buf; ··· 1236 1193 "attempting to create NULL primary"); 1237 1194 1238 1195 if (rc == TPM2_RC_SUCCESS) 1239 - rc = tpm2_parse_create_primary(chip, &buf, handle, hierarchy); 1196 + rc = tpm2_parse_create_primary(chip, &buf, handle, hierarchy, 1197 + name); 1240 1198 1241 1199 tpm_buf_destroy(&buf); 1242 1200 ··· 1249 1205 u32 null_key; 1250 1206 int rc; 1251 1207 1252 - rc = tpm2_create_primary(chip, TPM2_RH_NULL, &null_key); 1208 + rc = tpm2_create_primary(chip, TPM2_RH_NULL, &null_key, 1209 + chip->null_key_name); 1253 1210 1254 1211 if (rc == TPM2_RC_SUCCESS) { 1255 1212 unsigned int offset = 0; /* dummy offset for null key context */
+3
drivers/char/tpm/tpm2-space.c
··· 105 105 *handle = 0; 106 106 tpm_buf_destroy(&tbuf); 107 107 return -ENOENT; 108 + } else if (tpm2_rc_value(rc) == TPM2_RC_INTEGRITY) { 109 + tpm_buf_destroy(&tbuf); 110 + return -EINVAL; 108 111 } else if (rc > 0) { 109 112 dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n", 110 113 __func__, rc);
+3 -1
include/linux/tpm.h
··· 248 248 TPM2_RC_SUCCESS = 0x0000, 249 249 TPM2_RC_HASH = 0x0083, /* RC_FMT1 */ 250 250 TPM2_RC_HANDLE = 0x008B, 251 + TPM2_RC_INTEGRITY = 0x009F, 251 252 TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */ 252 253 TPM2_RC_FAILURE = 0x0101, 253 254 TPM2_RC_DISABLED = 0x0120, ··· 347 346 TPM_CHIP_FLAG_FIRMWARE_UPGRADE = BIT(7), 348 347 TPM_CHIP_FLAG_SUSPENDED = BIT(8), 349 348 TPM_CHIP_FLAG_HWRNG_DISABLED = BIT(9), 349 + TPM_CHIP_FLAG_DISABLE = BIT(10), 350 350 }; 351 351 352 352 #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev) ··· 449 447 450 448 static inline u32 tpm2_rc_value(u32 rc) 451 449 { 452 - return (rc & BIT(7)) ? rc & 0xff : rc; 450 + return (rc & BIT(7)) ? rc & 0xbf : rc; 453 451 } 454 452 455 453 #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)