Commit c659af78 authored by Stefan Berger's avatar Stefan Berger Committed by Jarkko Sakkinen

tpm: Check size of response before accessing data

Make sure that we have not received less bytes than what is indicated
in the header of the TPM response. Also, check the number of bytes in
the response before accessing its data.
Signed-off-by: default avatarStefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: default avatarJarkko Sakkinen <jarkko.sakkine@linux.intel.com>
Tested-by: default avatarJarkko Sakkinen <jarkko.sakkine@linux.intel.com>
Signed-off-by: default avatarJarkko Sakkinen <jarkko.sakkine@linux.intel.com>
parent 1d70fe9d
...@@ -423,8 +423,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, ...@@ -423,8 +423,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
* The function extracts tpm out header return code * The function extracts tpm out header return code
* *
* @chip: TPM chip to use * @chip: TPM chip to use
* @cmd: TPM command buffer * @buf: TPM command buffer
* @len: length of the TPM command * @bufsiz: length of the buffer
* @min_rsp_body_length: minimum expected length of response body
* @flags: tpm transmit flags - bitmap * @flags: tpm transmit flags - bitmap
* @desc: command description used in the error message * @desc: command description used in the error message
* *
...@@ -433,26 +434,35 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, ...@@ -433,26 +434,35 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
* A negative number for system errors (errno). * A negative number for system errors (errno).
* A positive number for a TPM error. * A positive number for a TPM error.
*/ */
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf,
int len, unsigned int flags, const char *desc) size_t bufsiz, size_t min_rsp_body_length,
unsigned int flags, const char *desc)
{ {
const struct tpm_output_header *header; const struct tpm_output_header *header;
int err; int err;
ssize_t len;
len = tpm_transmit(chip, (const u8 *)cmd, len, flags); len = tpm_transmit(chip, (const u8 *)buf, bufsiz, flags);
if (len < 0) if (len < 0)
return len; return len;
else if (len < TPM_HEADER_SIZE) else if (len < TPM_HEADER_SIZE)
return -EFAULT; return -EFAULT;
header = cmd; header = buf;
if (len != be32_to_cpu(header->length))
return -EFAULT;
err = be32_to_cpu(header->return_code); err = be32_to_cpu(header->return_code);
if (err != 0 && desc) if (err != 0 && desc)
dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err, dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err,
desc); desc);
if (err)
return err; return err;
if (len < min_rsp_body_length + TPM_HEADER_SIZE)
return -EFAULT;
return 0;
} }
#define TPM_DIGEST_SIZE 20 #define TPM_DIGEST_SIZE 20
...@@ -468,7 +478,7 @@ static const struct tpm_input_header tpm_getcap_header = { ...@@ -468,7 +478,7 @@ static const struct tpm_input_header tpm_getcap_header = {
}; };
ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc) const char *desc, size_t min_cap_length)
{ {
struct tpm_cmd_t tpm_cmd; struct tpm_cmd_t tpm_cmd;
int rc; int rc;
...@@ -491,8 +501,8 @@ ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, ...@@ -491,8 +501,8 @@ ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = cpu_to_be32(subcap_id); tpm_cmd.params.getcap_in.subcap = cpu_to_be32(subcap_id);
} }
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
desc); min_cap_length, 0, desc);
if (!rc) if (!rc)
*cap = tpm_cmd.params.getcap_out.cap; *cap = tpm_cmd.params.getcap_out.cap;
return rc; return rc;
...@@ -516,7 +526,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) ...@@ -516,7 +526,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
start_cmd.params.startup_in.startup_type = startup_type; start_cmd.params.startup_in.startup_type = startup_type;
return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, 0, return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
"attempting to start the TPM"); 0, "attempting to start the TPM");
} }
int tpm_get_timeouts(struct tpm_chip *chip) int tpm_get_timeouts(struct tpm_chip *chip)
...@@ -545,7 +555,8 @@ int tpm_get_timeouts(struct tpm_chip *chip) ...@@ -545,7 +555,8 @@ int tpm_get_timeouts(struct tpm_chip *chip)
return 0; return 0;
} }
rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, NULL); rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, NULL,
sizeof(cap.timeout));
if (rc == TPM_ERR_INVALID_POSTINIT) { if (rc == TPM_ERR_INVALID_POSTINIT) {
/* The TPM is not started, we are the first to talk to it. /* The TPM is not started, we are the first to talk to it.
Execute a startup command. */ Execute a startup command. */
...@@ -554,8 +565,10 @@ int tpm_get_timeouts(struct tpm_chip *chip) ...@@ -554,8 +565,10 @@ int tpm_get_timeouts(struct tpm_chip *chip)
return rc; return rc;
rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
"attempting to determine the timeouts"); "attempting to determine the timeouts",
sizeof(cap.timeout));
} }
if (rc) { if (rc) {
dev_err(&chip->dev, dev_err(&chip->dev,
"A TPM error (%zd) occurred attempting to determine the timeouts\n", "A TPM error (%zd) occurred attempting to determine the timeouts\n",
...@@ -617,7 +630,8 @@ int tpm_get_timeouts(struct tpm_chip *chip) ...@@ -617,7 +630,8 @@ int tpm_get_timeouts(struct tpm_chip *chip)
chip->timeout_d = usecs_to_jiffies(timeout_eff[3]); chip->timeout_d = usecs_to_jiffies(timeout_eff[3]);
rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap, rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap,
"attempting to determine the durations"); "attempting to determine the durations",
sizeof(cap.duration));
if (rc) if (rc)
return rc; return rc;
...@@ -668,13 +682,14 @@ static int tpm_continue_selftest(struct tpm_chip *chip) ...@@ -668,13 +682,14 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
struct tpm_cmd_t cmd; struct tpm_cmd_t cmd;
cmd.header.in = continue_selftest_header; cmd.header.in = continue_selftest_header;
rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0, rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0, 0,
"continue selftest"); "continue selftest");
return rc; return rc;
} }
#define TPM_ORDINAL_PCRREAD cpu_to_be32(21) #define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
#define READ_PCR_RESULT_SIZE 30 #define READ_PCR_RESULT_SIZE 30
#define READ_PCR_RESULT_BODY_SIZE 20
static const struct tpm_input_header pcrread_header = { static const struct tpm_input_header pcrread_header = {
.tag = TPM_TAG_RQU_COMMAND, .tag = TPM_TAG_RQU_COMMAND,
.length = cpu_to_be32(14), .length = cpu_to_be32(14),
...@@ -688,7 +703,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) ...@@ -688,7 +703,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
cmd.header.in = pcrread_header; cmd.header.in = pcrread_header;
cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, 0, rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
READ_PCR_RESULT_BODY_SIZE, 0,
"attempting to read a pcr value"); "attempting to read a pcr value");
if (rc == 0) if (rc == 0)
...@@ -751,6 +767,7 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read); ...@@ -751,6 +767,7 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read);
#define TPM_ORD_PCR_EXTEND cpu_to_be32(20) #define TPM_ORD_PCR_EXTEND cpu_to_be32(20)
#define EXTEND_PCR_RESULT_SIZE 34 #define EXTEND_PCR_RESULT_SIZE 34
#define EXTEND_PCR_RESULT_BODY_SIZE 24
static const struct tpm_input_header pcrextend_header = { static const struct tpm_input_header pcrextend_header = {
.tag = TPM_TAG_RQU_COMMAND, .tag = TPM_TAG_RQU_COMMAND,
.length = cpu_to_be32(34), .length = cpu_to_be32(34),
...@@ -786,7 +803,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) ...@@ -786,7 +803,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
cmd.header.in = pcrextend_header; cmd.header.in = pcrextend_header;
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0, rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
EXTEND_PCR_RESULT_BODY_SIZE, 0,
"attempting extend a PCR value"); "attempting extend a PCR value");
tpm_put_ops(chip); tpm_put_ops(chip);
...@@ -890,7 +908,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen) ...@@ -890,7 +908,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
if (chip == NULL) if (chip == NULL)
return -ENODEV; return -ENODEV;
rc = tpm_transmit_cmd(chip, cmd, buflen, 0, "attempting tpm_cmd"); rc = tpm_transmit_cmd(chip, cmd, buflen, 0, 0, "attempting tpm_cmd");
tpm_put_ops(chip); tpm_put_ops(chip);
return rc; return rc;
...@@ -992,7 +1010,8 @@ int tpm_pm_suspend(struct device *dev) ...@@ -992,7 +1010,8 @@ int tpm_pm_suspend(struct device *dev)
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr); cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
memcpy(cmd.params.pcrextend_in.hash, dummy_hash, memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
TPM_DIGEST_SIZE); TPM_DIGEST_SIZE);
rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0, rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
EXTEND_PCR_RESULT_BODY_SIZE, 0,
"extending dummy pcr before suspend"); "extending dummy pcr before suspend");
} }
...@@ -1000,7 +1019,7 @@ int tpm_pm_suspend(struct device *dev) ...@@ -1000,7 +1019,7 @@ int tpm_pm_suspend(struct device *dev)
for (try = 0; try < TPM_RETRY; try++) { for (try = 0; try < TPM_RETRY; try++) {
cmd.header.in = savestate_header; cmd.header.in = savestate_header;
rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, 0, rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, 0,
NULL); 0, NULL);
/* /*
* If the TPM indicates that it is too busy to respond to * If the TPM indicates that it is too busy to respond to
...@@ -1062,7 +1081,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) ...@@ -1062,7 +1081,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
{ {
struct tpm_chip *chip; struct tpm_chip *chip;
struct tpm_cmd_t tpm_cmd; struct tpm_cmd_t tpm_cmd;
u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA); u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA), rlength;
int err, total = 0, retries = 5; int err, total = 0, retries = 5;
u8 *dest = out; u8 *dest = out;
...@@ -1085,11 +1104,20 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) ...@@ -1085,11 +1104,20 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
err = tpm_transmit_cmd(chip, &tpm_cmd, err = tpm_transmit_cmd(chip, &tpm_cmd,
TPM_GETRANDOM_RESULT_SIZE + num_bytes, TPM_GETRANDOM_RESULT_SIZE + num_bytes,
offsetof(struct tpm_getrandom_out,
rng_data),
0, "attempting get random"); 0, "attempting get random");
if (err) if (err)
break; break;
recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len);
rlength = be32_to_cpu(tpm_cmd.header.out.length);
if (rlength < offsetof(struct tpm_getrandom_out, rng_data) +
recd) {
total = -EFAULT;
break;
}
memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd); memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd);
dest += recd; dest += recd;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "tpm.h" #include "tpm.h"
#define READ_PUBEK_RESULT_SIZE 314 #define READ_PUBEK_RESULT_SIZE 314
#define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256)
#define TPM_ORD_READPUBEK cpu_to_be32(124) #define TPM_ORD_READPUBEK cpu_to_be32(124)
static const struct tpm_input_header tpm_readpubek_header = { static const struct tpm_input_header tpm_readpubek_header = {
.tag = TPM_TAG_RQU_COMMAND, .tag = TPM_TAG_RQU_COMMAND,
...@@ -39,7 +40,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, ...@@ -39,7 +40,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
struct tpm_chip *chip = to_tpm_chip(dev); struct tpm_chip *chip = to_tpm_chip(dev);
tpm_cmd.header.in = tpm_readpubek_header; tpm_cmd.header.in = tpm_readpubek_header;
err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, 0, err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
"attempting to read the PUBEK"); "attempting to read the PUBEK");
if (err) if (err)
goto out; goto out;
...@@ -95,7 +97,8 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr, ...@@ -95,7 +97,8 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr,
struct tpm_chip *chip = to_tpm_chip(dev); struct tpm_chip *chip = to_tpm_chip(dev);
rc = tpm_getcap(chip, TPM_CAP_PROP_PCR, &cap, rc = tpm_getcap(chip, TPM_CAP_PROP_PCR, &cap,
"attempting to determine the number of PCRS"); "attempting to determine the number of PCRS",
sizeof(cap.num_pcrs));
if (rc) if (rc)
return 0; return 0;
...@@ -120,7 +123,8 @@ static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, ...@@ -120,7 +123,8 @@ static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
ssize_t rc; ssize_t rc;
rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap, rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
"attempting to determine the permanent enabled state"); "attempting to determine the permanent enabled state",
sizeof(cap.perm_flags));
if (rc) if (rc)
return 0; return 0;
...@@ -136,7 +140,8 @@ static ssize_t active_show(struct device *dev, struct device_attribute *attr, ...@@ -136,7 +140,8 @@ static ssize_t active_show(struct device *dev, struct device_attribute *attr,
ssize_t rc; ssize_t rc;
rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap, rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
"attempting to determine the permanent active state"); "attempting to determine the permanent active state",
sizeof(cap.perm_flags));
if (rc) if (rc)
return 0; return 0;
...@@ -152,7 +157,8 @@ static ssize_t owned_show(struct device *dev, struct device_attribute *attr, ...@@ -152,7 +157,8 @@ static ssize_t owned_show(struct device *dev, struct device_attribute *attr,
ssize_t rc; ssize_t rc;
rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap, rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap,
"attempting to determine the owner state"); "attempting to determine the owner state",
sizeof(cap.owned));
if (rc) if (rc)
return 0; return 0;
...@@ -168,7 +174,8 @@ static ssize_t temp_deactivated_show(struct device *dev, ...@@ -168,7 +174,8 @@ static ssize_t temp_deactivated_show(struct device *dev,
ssize_t rc; ssize_t rc;
rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap, rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap,
"attempting to determine the temporary state"); "attempting to determine the temporary state",
sizeof(cap.stclear_flags));
if (rc) if (rc)
return 0; return 0;
...@@ -186,7 +193,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, ...@@ -186,7 +193,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
char *str = buf; char *str = buf;
rc = tpm_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap, rc = tpm_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap,
"attempting to determine the manufacturer"); "attempting to determine the manufacturer",
sizeof(cap.manufacturer_id));
if (rc) if (rc)
return 0; return 0;
str += sprintf(str, "Manufacturer: 0x%x\n", str += sprintf(str, "Manufacturer: 0x%x\n",
...@@ -194,7 +202,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, ...@@ -194,7 +202,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
/* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */ /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */
rc = tpm_getcap(chip, TPM_CAP_VERSION_1_2, &cap, rc = tpm_getcap(chip, TPM_CAP_VERSION_1_2, &cap,
"attempting to determine the 1.2 version"); "attempting to determine the 1.2 version",
sizeof(cap.tpm_version_1_2));
if (!rc) { if (!rc) {
str += sprintf(str, str += sprintf(str,
"TCG version: %d.%d\nFirmware version: %d.%d\n", "TCG version: %d.%d\nFirmware version: %d.%d\n",
...@@ -205,7 +214,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, ...@@ -205,7 +214,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
} else { } else {
/* Otherwise just use TPM_STRUCT_VER */ /* Otherwise just use TPM_STRUCT_VER */
rc = tpm_getcap(chip, TPM_CAP_VERSION_1_1, &cap, rc = tpm_getcap(chip, TPM_CAP_VERSION_1_1, &cap,
"attempting to determine the 1.1 version"); "attempting to determine the 1.1 version",
sizeof(cap.tpm_version));
if (rc) if (rc)
return 0; return 0;
str += sprintf(str, str += sprintf(str,
......
...@@ -493,10 +493,11 @@ enum tpm_transmit_flags { ...@@ -493,10 +493,11 @@ enum tpm_transmit_flags {
ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
unsigned int flags); unsigned int flags);
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len, ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf, size_t bufsiz,
unsigned int flags, const char *desc); size_t min_rsp_body_len, unsigned int flags,
ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc); const char *desc);
ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length);
int tpm_get_timeouts(struct tpm_chip *); int tpm_get_timeouts(struct tpm_chip *);
int tpm1_auto_startup(struct tpm_chip *chip); int tpm1_auto_startup(struct tpm_chip *chip);
int tpm_do_selftest(struct tpm_chip *chip); int tpm_do_selftest(struct tpm_chip *chip);
......
...@@ -248,6 +248,9 @@ static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = { ...@@ -248,6 +248,9 @@ static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = {
(sizeof(struct tpm_input_header) + \ (sizeof(struct tpm_input_header) + \
sizeof(struct tpm2_pcr_read_in)) sizeof(struct tpm2_pcr_read_in))
#define TPM2_PCR_READ_RESP_BODY_SIZE \
sizeof(struct tpm2_pcr_read_out)
static const struct tpm_input_header tpm2_pcrread_header = { static const struct tpm_input_header tpm2_pcrread_header = {
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
.length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE), .length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE),
...@@ -280,8 +283,9 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) ...@@ -280,8 +283,9 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
sizeof(cmd.params.pcrread_in.pcr_select)); sizeof(cmd.params.pcrread_in.pcr_select));
cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
"attempting to read a pcr value"); TPM2_PCR_READ_RESP_BODY_SIZE,
0, "attempting to read a pcr value");
if (rc == 0) { if (rc == 0) {
buf = cmd.params.pcrread_out.digest; buf = cmd.params.pcrread_out.digest;
memcpy(res_buf, buf, TPM_DIGEST_SIZE); memcpy(res_buf, buf, TPM_DIGEST_SIZE);
...@@ -327,7 +331,7 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) ...@@ -327,7 +331,7 @@ int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE); memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE);
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0,
"attempting extend a PCR value"); "attempting extend a PCR value");
return rc; return rc;
...@@ -356,7 +360,7 @@ static const struct tpm_input_header tpm2_getrandom_header = { ...@@ -356,7 +360,7 @@ static const struct tpm_input_header tpm2_getrandom_header = {
int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
{ {
struct tpm2_cmd cmd; struct tpm2_cmd cmd;
u32 recd; u32 recd, rlength;
u32 num_bytes; u32 num_bytes;
int err; int err;
int total = 0; int total = 0;
...@@ -373,13 +377,19 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) ...@@ -373,13 +377,19 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
cmd.header.in = tpm2_getrandom_header; cmd.header.in = tpm2_getrandom_header;
cmd.params.getrandom_in.size = cpu_to_be16(num_bytes); cmd.params.getrandom_in.size = cpu_to_be16(num_bytes);
err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
"attempting get random"); offsetof(struct tpm2_get_random_out,
buffer),
0, "attempting get random");
if (err) if (err)
break; break;
recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size), recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size),
num_bytes); num_bytes);
rlength = be32_to_cpu(cmd.header.out.length);
if (rlength < offsetof(struct tpm2_get_random_out, buffer) +
recd)
return -EFAULT;
memcpy(dest, cmd.params.getrandom_out.buffer, recd); memcpy(dest, cmd.params.getrandom_out.buffer, recd);
dest += recd; dest += recd;
...@@ -394,6 +404,9 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) ...@@ -394,6 +404,9 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
(sizeof(struct tpm_input_header) + \ (sizeof(struct tpm_input_header) + \
sizeof(struct tpm2_get_tpm_pt_in)) sizeof(struct tpm2_get_tpm_pt_in))
#define TPM2_GET_TPM_PT_OUT_BODY_SIZE \
sizeof(struct tpm2_get_tpm_pt_out)
static const struct tpm_input_header tpm2_get_tpm_pt_header = { static const struct tpm_input_header tpm2_get_tpm_pt_header = {
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
.length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE), .length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE),
...@@ -445,7 +458,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, ...@@ -445,7 +458,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
{ {
unsigned int blob_len; unsigned int blob_len;
struct tpm_buf buf; struct tpm_buf buf;
u32 hash; u32 hash, rlength;
int i; int i;
int rc; int rc;
...@@ -510,7 +523,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip, ...@@ -510,7 +523,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
goto out; goto out;
} }
rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, "sealing data"); rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 4, 0,
"sealing data");
if (rc) if (rc)
goto out; goto out;
...@@ -519,6 +533,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip, ...@@ -519,6 +533,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
rc = -E2BIG; rc = -E2BIG;
goto out; goto out;
} }
rlength = be32_to_cpu(((struct tpm2_cmd *)&buf)->header.out.length);
if (rlength < TPM_HEADER_SIZE + 4 + blob_len) {
rc = -EFAULT;
goto out;
}
memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len); memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len);
payload->blob_len = blob_len; payload->blob_len = blob_len;
...@@ -588,7 +607,8 @@ static int tpm2_load_cmd(struct tpm_chip *chip, ...@@ -588,7 +607,8 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
goto out; goto out;
} }
rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "loading blob"); rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 4, flags,
"loading blob");
if (!rc) if (!rc)
*blob_handle = be32_to_cpup( *blob_handle = be32_to_cpup(
(__be32 *) &buf.data[TPM_HEADER_SIZE]); (__be32 *) &buf.data[TPM_HEADER_SIZE]);
...@@ -626,7 +646,7 @@ static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, ...@@ -626,7 +646,7 @@ static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
tpm_buf_append_u32(&buf, handle); tpm_buf_append_u32(&buf, handle);
rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, flags,
"flushing context"); "flushing context");
if (rc) if (rc)
dev_warn(&chip->dev, "0x%08x was not flushed, rc=%d\n", handle, dev_warn(&chip->dev, "0x%08x was not flushed, rc=%d\n", handle,
...@@ -657,6 +677,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, ...@@ -657,6 +677,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
u16 data_len; u16 data_len;
u8 *data; u8 *data;
int rc; int rc;
u32 rlength;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL); rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
if (rc) if (rc)
...@@ -671,13 +692,21 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, ...@@ -671,13 +692,21 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
options->blobauth /* hmac */, options->blobauth /* hmac */,
TPM_DIGEST_SIZE); TPM_DIGEST_SIZE);
rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "unsealing"); rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 6, flags,
"unsealing");
if (rc > 0) if (rc > 0)
rc = -EPERM; rc = -EPERM;
if (!rc) { if (!rc) {
data_len = be16_to_cpup( data_len = be16_to_cpup(
(__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
rlength = be32_to_cpu(((struct tpm2_cmd *)&buf)
->header.out.length);
if (rlength < TPM_HEADER_SIZE + 6 + data_len) {
rc = -EFAULT;
goto out;
}
data = &buf.data[TPM_HEADER_SIZE + 6]; data = &buf.data[TPM_HEADER_SIZE + 6];
memcpy(payload->key, data, data_len - 1); memcpy(payload->key, data, data_len - 1);
...@@ -685,6 +714,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, ...@@ -685,6 +714,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
payload->migratable = data[data_len - 1]; payload->migratable = data[data_len - 1];
} }
out:
tpm_buf_destroy(&buf); tpm_buf_destroy(&buf);
return rc; return rc;
} }
...@@ -739,7 +769,8 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, ...@@ -739,7 +769,8 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id); cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id);
cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, desc); rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
TPM2_GET_TPM_PT_OUT_BODY_SIZE, 0, desc);
if (!rc) if (!rc)
*value = be32_to_cpu(cmd.params.get_tpm_pt_out.value); *value = be32_to_cpu(cmd.params.get_tpm_pt_out.value);
...@@ -773,7 +804,7 @@ static int tpm2_startup(struct tpm_chip *chip, u16 startup_type) ...@@ -773,7 +804,7 @@ static int tpm2_startup(struct tpm_chip *chip, u16 startup_type)
cmd.header.in = tpm2_startup_header; cmd.header.in = tpm2_startup_header;
cmd.params.startup_in.startup_type = cpu_to_be16(startup_type); cmd.params.startup_in.startup_type = cpu_to_be16(startup_type);
return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0,
"attempting to start the TPM"); "attempting to start the TPM");
} }
...@@ -802,7 +833,8 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) ...@@ -802,7 +833,8 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
cmd.header.in = tpm2_shutdown_header; cmd.header.in = tpm2_shutdown_header;
cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type); cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, "stopping the TPM"); rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0,
"stopping the TPM");
/* In places where shutdown command is sent there's no much we can do /* In places where shutdown command is sent there's no much we can do
* except print the error code on a system failure. * except print the error code on a system failure.
...@@ -865,7 +897,7 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full) ...@@ -865,7 +897,7 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full)
cmd.header.in = tpm2_selftest_header; cmd.header.in = tpm2_selftest_header;
cmd.params.selftest_in.full_test = full; cmd.params.selftest_in.full_test = full;
rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, 0,
"continue selftest"); "continue selftest");
/* At least some prototype chips seem to give RC_TESTING error /* At least some prototype chips seem to give RC_TESTING error
...@@ -916,7 +948,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip) ...@@ -916,7 +948,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
cmd.params.pcrread_in.pcr_select[1] = 0x00; cmd.params.pcrread_in.pcr_select[1] = 0x00;
cmd.params.pcrread_in.pcr_select[2] = 0x00; cmd.params.pcrread_in.pcr_select[2] = 0x00;
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, NULL); rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, NULL);
if (rc < 0) if (rc < 0)
break; break;
...@@ -949,7 +981,7 @@ int tpm2_probe(struct tpm_chip *chip) ...@@ -949,7 +981,7 @@ int tpm2_probe(struct tpm_chip *chip)
cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100); cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100);
cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, NULL); rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, NULL);
if (rc < 0) if (rc < 0)
return rc; return rc;
......
...@@ -552,7 +552,8 @@ static int tpm_tis_gen_interrupt(struct tpm_chip *chip) ...@@ -552,7 +552,8 @@ static int tpm_tis_gen_interrupt(struct tpm_chip *chip)
if (chip->flags & TPM_CHIP_FLAG_TPM2) if (chip->flags & TPM_CHIP_FLAG_TPM2)
return tpm2_get_tpm_pt(chip, 0x100, &cap2, desc); return tpm2_get_tpm_pt(chip, 0x100, &cap2, desc);
else else
return tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc); return tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc,
0);
} }
/* Register the IRQ and issue a command that will cause an interrupt. If an /* Register the IRQ and issue a command that will cause an interrupt. If an
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment