Skip to content

Commit 58472f5

Browse files
author
Jarkko Sakkinen
committed
tpm: validate TPM 2.0 commands
Check for every TPM 2.0 command that the command code is supported and the command buffer has at least the length that can contain the header and the handle area. For ContextSave and FlushContext we mark the body to be part of the handle area. This gives validation for these commands at zero cost, including the body of the command. The more important reason for this is that we can virtualize these commands in the same way as you would virtualize the handle area of a command. Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: James Bottomley <James.Bottomley@HansenPartnership.com> Reviewed-by: James Bottomley <James.Bottomley@HansenPartnership.com>
1 parent 9aa36b3 commit 58472f5

3 files changed

Lines changed: 132 additions & 5 deletions

File tree

drivers/char/tpm/tpm-interface.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,42 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
328328
}
329329
EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
330330

331+
static bool tpm_validate_command(struct tpm_chip *chip, const u8 *cmd,
332+
size_t len)
333+
{
334+
const struct tpm_input_header *header = (const void *)cmd;
335+
int i;
336+
u32 cc;
337+
u32 attrs;
338+
unsigned int nr_handles;
339+
340+
if (len < TPM_HEADER_SIZE)
341+
return false;
342+
343+
if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) {
344+
cc = be32_to_cpu(header->ordinal);
345+
346+
i = tpm2_find_cc(chip, cc);
347+
if (i < 0) {
348+
dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
349+
cc);
350+
return false;
351+
}
352+
353+
attrs = chip->cc_attrs_tbl[i];
354+
nr_handles =
355+
4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0));
356+
if (len < TPM_HEADER_SIZE + 4 * nr_handles)
357+
goto err_len;
358+
}
359+
360+
return true;
361+
err_len:
362+
dev_dbg(&chip->dev,
363+
"%s: insufficient command length %zu", __func__, len);
364+
return false;
365+
}
366+
331367
/**
332368
* tmp_transmit - Internal kernel interface to transmit TPM commands.
333369
*
@@ -348,7 +384,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
348384
u32 count, ordinal;
349385
unsigned long stop;
350386

351-
if (bufsiz < TPM_HEADER_SIZE)
387+
if (!tpm_validate_command(chip, buf, bufsiz))
352388
return -EINVAL;
353389

354390
if (bufsiz > TPM_BUFSIZE)

drivers/char/tpm/tpm.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ enum tpm2_command_codes {
114114
TPM2_CC_CREATE = 0x0153,
115115
TPM2_CC_LOAD = 0x0157,
116116
TPM2_CC_UNSEAL = 0x015E,
117+
TPM2_CC_CONTEXT_SAVE = 0x0162,
117118
TPM2_CC_FLUSH_CONTEXT = 0x0165,
118119
TPM2_CC_GET_CAPABILITY = 0x017A,
119120
TPM2_CC_GET_RANDOM = 0x017B,
@@ -127,15 +128,25 @@ enum tpm2_permanent_handles {
127128
};
128129

129130
enum tpm2_capabilities {
131+
TPM2_CAP_COMMANDS = 2,
130132
TPM2_CAP_PCRS = 5,
131133
TPM2_CAP_TPM_PROPERTIES = 6,
132134
};
133135

136+
enum tpm2_properties {
137+
TPM_PT_TOTAL_COMMANDS = 0x0129,
138+
};
139+
134140
enum tpm2_startup_types {
135141
TPM2_SU_CLEAR = 0x0000,
136142
TPM2_SU_STATE = 0x0001,
137143
};
138144

145+
enum tpm2_cc_attrs {
146+
TPM2_CC_ATTR_CHANDLES = 25,
147+
TPM2_CC_ATTR_RHANDLE = 28,
148+
};
149+
139150
#define TPM_VID_INTEL 0x8086
140151
#define TPM_VID_WINBOND 0x1050
141152
#define TPM_VID_STM 0x104A
@@ -199,6 +210,9 @@ struct tpm_chip {
199210
acpi_handle acpi_dev_handle;
200211
char ppi_version[TPM_PPI_VERSION_LEN + 1];
201212
#endif /* CONFIG_ACPI */
213+
214+
u32 nr_commands;
215+
u32 *cc_attrs_tbl;
202216
};
203217

204218
#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
@@ -556,4 +570,5 @@ int tpm2_auto_startup(struct tpm_chip *chip);
556570
void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
557571
unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
558572
int tpm2_probe(struct tpm_chip *chip);
573+
int tpm2_find_cc(struct tpm_chip *chip, u32 cc);
559574
#endif

drivers/char/tpm/tpm2-cmd.c

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,15 +1063,76 @@ static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
10631063
return rc;
10641064
}
10651065

1066+
static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
1067+
{
1068+
struct tpm_buf buf;
1069+
u32 nr_commands;
1070+
u32 *attrs;
1071+
u32 cc;
1072+
int i;
1073+
int rc;
1074+
1075+
rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL);
1076+
if (rc)
1077+
goto out;
1078+
1079+
if (nr_commands > 0xFFFFF) {
1080+
rc = -EFAULT;
1081+
goto out;
1082+
}
1083+
1084+
chip->cc_attrs_tbl = devm_kzalloc(&chip->dev, 4 * nr_commands,
1085+
GFP_KERNEL);
1086+
1087+
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
1088+
if (rc)
1089+
goto out;
1090+
1091+
tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS);
1092+
tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
1093+
tpm_buf_append_u32(&buf, nr_commands);
1094+
1095+
rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 9 + 4 * nr_commands,
1096+
0, NULL);
1097+
if (rc) {
1098+
tpm_buf_destroy(&buf);
1099+
goto out;
1100+
}
1101+
1102+
if (nr_commands !=
1103+
be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
1104+
tpm_buf_destroy(&buf);
1105+
goto out;
1106+
}
1107+
1108+
chip->nr_commands = nr_commands;
1109+
1110+
attrs = (u32 *)&buf.data[TPM_HEADER_SIZE + 9];
1111+
for (i = 0; i < nr_commands; i++, attrs++) {
1112+
chip->cc_attrs_tbl[i] = be32_to_cpup(attrs);
1113+
cc = chip->cc_attrs_tbl[i] & 0xFFFF;
1114+
1115+
if (cc == TPM2_CC_CONTEXT_SAVE || cc == TPM2_CC_FLUSH_CONTEXT) {
1116+
chip->cc_attrs_tbl[i] &=
1117+
~(GENMASK(2, 0) << TPM2_CC_ATTR_CHANDLES);
1118+
chip->cc_attrs_tbl[i] |= 1 << TPM2_CC_ATTR_CHANDLES;
1119+
}
1120+
}
1121+
1122+
tpm_buf_destroy(&buf);
1123+
1124+
out:
1125+
if (rc > 0)
1126+
rc = -ENODEV;
1127+
return rc;
1128+
}
1129+
10661130
/**
10671131
* tpm2_auto_startup - Perform the standard automatic TPM initialization
10681132
* sequence
10691133
* @chip: TPM chip to use
10701134
*
1071-
* Initializes timeout values for operation and command durations, conducts
1072-
* a self-test and reads the list of active PCR banks.
1073-
*
1074-
* Return: 0 on success. Otherwise, a system error code is returned.
1135+
* Returns 0 on success, < 0 in case of fatal error.
10751136
*/
10761137
int tpm2_auto_startup(struct tpm_chip *chip)
10771138
{
@@ -1100,9 +1161,24 @@ int tpm2_auto_startup(struct tpm_chip *chip)
11001161
}
11011162

11021163
rc = tpm2_get_pcr_allocation(chip);
1164+
if (rc)
1165+
goto out;
1166+
1167+
rc = tpm2_get_cc_attrs_tbl(chip);
11031168

11041169
out:
11051170
if (rc > 0)
11061171
rc = -ENODEV;
11071172
return rc;
11081173
}
1174+
1175+
int tpm2_find_cc(struct tpm_chip *chip, u32 cc)
1176+
{
1177+
int i;
1178+
1179+
for (i = 0; i < chip->nr_commands; i++)
1180+
if (cc == (chip->cc_attrs_tbl[i] & GENMASK(15, 0)))
1181+
return i;
1182+
1183+
return -1;
1184+
}

0 commit comments

Comments
 (0)