Skip to content

Commit

Permalink
tpm: Check size of response before accessing data
Browse files Browse the repository at this point in the history
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: Stefan Berger <[email protected]>
Reviewed-by: Jarkko Sakkinen <[email protected]>
Tested-by: Jarkko Sakkinen <[email protected]>
Signed-off-by: Jarkko Sakkinen <[email protected]>
  • Loading branch information
stefanberger authored and Jarkko Sakkinen committed Jan 23, 2017
1 parent 1d70fe9 commit c659af7
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 51 deletions.
70 changes: 49 additions & 21 deletions drivers/char/tpm/tpm-interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
* @chip: TPM chip to use
* @cmd: TPM command buffer
* @len: length of the TPM command
* @buf: TPM command buffer
* @bufsiz: length of the buffer
* @min_rsp_body_length: minimum expected length of response body
* @flags: tpm transmit flags - bitmap
* @desc: command description used in the error message
*
Expand All @@ -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 positive number for a TPM error.
*/
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd,
int len, unsigned int flags, const char *desc)
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf,
size_t bufsiz, size_t min_rsp_body_length,
unsigned int flags, const char *desc)
{
const struct tpm_output_header *header;
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)
return len;
else if (len < TPM_HEADER_SIZE)
return -EFAULT;

header = cmd;
header = buf;
if (len != be32_to_cpu(header->length))
return -EFAULT;

err = be32_to_cpu(header->return_code);
if (err != 0 && desc)
dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err,
desc);
if (err)
return err;

if (len < min_rsp_body_length + TPM_HEADER_SIZE)
return -EFAULT;

return err;
return 0;
}

#define TPM_DIGEST_SIZE 20
Expand All @@ -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,
const char *desc)
const char *desc, size_t min_cap_length)
{
struct tpm_cmd_t tpm_cmd;
int rc;
Expand All @@ -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 = cpu_to_be32(subcap_id);
}
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
desc);
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
min_cap_length, 0, desc);
if (!rc)
*cap = tpm_cmd.params.getcap_out.cap;
return rc;
Expand All @@ -516,7 +526,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)

start_cmd.params.startup_in.startup_type = startup_type;
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)
Expand Down Expand Up @@ -545,7 +555,8 @@ int tpm_get_timeouts(struct tpm_chip *chip)
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) {
/* The TPM is not started, we are the first to talk to it.
Execute a startup command. */
Expand All @@ -554,8 +565,10 @@ int tpm_get_timeouts(struct tpm_chip *chip)
return rc;

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) {
dev_err(&chip->dev,
"A TPM error (%zd) occurred attempting to determine the timeouts\n",
Expand Down Expand Up @@ -617,7 +630,8 @@ int tpm_get_timeouts(struct tpm_chip *chip)
chip->timeout_d = usecs_to_jiffies(timeout_eff[3]);

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)
return rc;

Expand Down Expand Up @@ -668,13 +682,14 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
struct tpm_cmd_t cmd;

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");
return rc;
}

#define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
#define READ_PCR_RESULT_SIZE 30
#define READ_PCR_RESULT_BODY_SIZE 20
static const struct tpm_input_header pcrread_header = {
.tag = TPM_TAG_RQU_COMMAND,
.length = cpu_to_be32(14),
Expand All @@ -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.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");

if (rc == 0)
Expand Down Expand Up @@ -751,6 +767,7 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read);

#define TPM_ORD_PCR_EXTEND cpu_to_be32(20)
#define EXTEND_PCR_RESULT_SIZE 34
#define EXTEND_PCR_RESULT_BODY_SIZE 24
static const struct tpm_input_header pcrextend_header = {
.tag = TPM_TAG_RQU_COMMAND,
.length = cpu_to_be32(34),
Expand Down Expand Up @@ -786,7 +803,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
cmd.header.in = pcrextend_header;
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
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");

tpm_put_ops(chip);
Expand Down Expand Up @@ -890,7 +908,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
if (chip == NULL)
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);
return rc;
Expand Down Expand Up @@ -992,15 +1010,16 @@ int tpm_pm_suspend(struct device *dev)
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
memcpy(cmd.params.pcrextend_in.hash, dummy_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,
"extending dummy pcr before suspend");
}

/* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) {
cmd.header.in = savestate_header;
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
Expand Down Expand Up @@ -1062,7 +1081,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
{
struct tpm_chip *chip;
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;
u8 *dest = out;

Expand All @@ -1085,11 +1104,20 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)

err = tpm_transmit_cmd(chip, &tpm_cmd,
TPM_GETRANDOM_RESULT_SIZE + num_bytes,
offsetof(struct tpm_getrandom_out,
rng_data),
0, "attempting get random");
if (err)
break;

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);

dest += recd;
Expand Down
28 changes: 19 additions & 9 deletions drivers/char/tpm/tpm-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "tpm.h"

#define READ_PUBEK_RESULT_SIZE 314
#define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256)
#define TPM_ORD_READPUBEK cpu_to_be32(124)
static const struct tpm_input_header tpm_readpubek_header = {
.tag = TPM_TAG_RQU_COMMAND,
Expand All @@ -39,7 +40,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
struct tpm_chip *chip = to_tpm_chip(dev);

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");
if (err)
goto out;
Expand Down Expand Up @@ -95,7 +97,8 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr,
struct tpm_chip *chip = to_tpm_chip(dev);

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)
return 0;

Expand All @@ -120,7 +123,8 @@ static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
ssize_t rc;

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)
return 0;

Expand All @@ -136,7 +140,8 @@ static ssize_t active_show(struct device *dev, struct device_attribute *attr,
ssize_t rc;

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)
return 0;

Expand All @@ -152,7 +157,8 @@ static ssize_t owned_show(struct device *dev, struct device_attribute *attr,
ssize_t rc;

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)
return 0;

Expand All @@ -168,7 +174,8 @@ static ssize_t temp_deactivated_show(struct device *dev,
ssize_t rc;

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)
return 0;

Expand All @@ -186,15 +193,17 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
char *str = buf;

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)
return 0;
str += sprintf(str, "Manufacturer: 0x%x\n",
be32_to_cpu(cap.manufacturer_id));

/* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */
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) {
str += sprintf(str,
"TCG version: %d.%d\nFirmware version: %d.%d\n",
Expand All @@ -205,7 +214,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
} else {
/* Otherwise just use TPM_STRUCT_VER */
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)
return 0;
str += sprintf(str,
Expand Down
7 changes: 4 additions & 3 deletions drivers/char/tpm/tpm.h
Original file line number Diff line number Diff line change
Expand Up @@ -493,10 +493,11 @@ enum tpm_transmit_flags {

ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
unsigned int flags);
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len,
unsigned int flags, const char *desc);
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf, size_t bufsiz,
size_t min_rsp_body_len, unsigned int flags,
const char *desc);
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);
int tpm_get_timeouts(struct tpm_chip *);
int tpm1_auto_startup(struct tpm_chip *chip);
int tpm_do_selftest(struct tpm_chip *chip);
Expand Down
Loading

0 comments on commit c659af7

Please sign in to comment.