As has been seen recently, binding the buffer allocation and tpm_buf
together is sometimes far from optimal. The buffer might come from the
caller namely when tpm_send() is used by another subsystem. In addition we
can stability in call sites w/o rollback (e.g. power events)>
Take allocation out of the tpm_buf framework and make it purely a wrapper
for the data buffer.
Link: https://patchwork.kernel.org/patch/11146585/
Cc: Mimi Zohar <[email protected]>
Cc: Jerry Snitselaar <[email protected]>
Cc: James Bottomley <[email protected]>
Cc: Sumit Garg <[email protected]>
Cc: Stefan Berger <[email protected]>
Signed-off-by: Jarkko Sakkinen <[email protected]>
---
v2:
* In tpm2_get_random(), TPM2_CC_GET_RANDOM was accidently switch to
TPM2_CC_PCR_EXTEND. Now it has been switched back.
drivers/char/tpm/tpm-sysfs.c | 19 ++-
drivers/char/tpm/tpm.h | 40 ++---
drivers/char/tpm/tpm1-cmd.c | 114 +++++++++----
drivers/char/tpm/tpm2-cmd.c | 265 +++++++++++++++++++-----------
drivers/char/tpm/tpm2-space.c | 64 +++++---
drivers/char/tpm/tpm_vtpm_proxy.c | 24 +--
6 files changed, 333 insertions(+), 193 deletions(-)
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index edfa89160010..eeb90c9225b9 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -32,21 +32,26 @@ struct tpm_readpubek_out {
static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct tpm_buf tpm_buf;
- struct tpm_readpubek_out *out;
- int i;
- char *str = buf;
struct tpm_chip *chip = to_tpm_chip(dev);
+ struct tpm_readpubek_out *out;
+ struct page *data_page;
+ struct tpm_buf tpm_buf;
char anti_replay[20];
+ char *str = buf;
+ int i;
memset(&anti_replay, 0, sizeof(anti_replay));
if (tpm_try_get_ops(chip))
return 0;
- if (tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK))
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
goto out_ops;
+ tpm_buf_reset(&tpm_buf, kmap(data_page), PAGE_SIZE, TPM_TAG_RQU_COMMAND,
+ TPM_ORD_READPUBEK);
+
tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay));
if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
@@ -83,7 +88,9 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
}
out_buf:
- tpm_buf_destroy(&tpm_buf);
+ kunmap(data_page);
+ __free_page(data_page);
+
out_ops:
tpm_put_ops(chip);
return str - buf;
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index a7fea3e0ca86..45316e5d2d36 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -284,36 +284,30 @@ enum tpm_buf_flags {
};
struct tpm_buf {
- struct page *data_page;
- unsigned int flags;
u8 *data;
+ unsigned int size;
+ unsigned int flags;
};
-static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
+static inline void tpm_buf_reset(struct tpm_buf *buf, u8 *data,
+ unsigned int size, u16 tag, u32 ordinal)
{
- struct tpm_header *head = (struct tpm_header *)buf->data;
+ struct tpm_header *head = (struct tpm_header *)data;
- head->tag = cpu_to_be16(tag);
- head->length = cpu_to_be32(sizeof(*head));
- head->ordinal = cpu_to_be32(ordinal);
-}
-
-static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
-{
- buf->data_page = alloc_page(GFP_HIGHUSER);
- if (!buf->data_page)
- return -ENOMEM;
+ /* sanity check */
+ if (size < TPM_HEADER_SIZE) {
+ WARN(1, "tpm_buf: overflow\n");
+ buf->flags |= TPM_BUF_OVERFLOW;
+ return;
+ }
+ buf->data = data;
+ buf->size = size;
buf->flags = 0;
- buf->data = kmap(buf->data_page);
- tpm_buf_reset(buf, tag, ordinal);
- return 0;
-}
-static inline void tpm_buf_destroy(struct tpm_buf *buf)
-{
- kunmap(buf->data_page);
- __free_page(buf->data_page);
+ head->tag = cpu_to_be16(tag);
+ head->length = cpu_to_be32(sizeof(*head));
+ head->ordinal = cpu_to_be32(ordinal);
}
static inline u32 tpm_buf_length(struct tpm_buf *buf)
@@ -341,7 +335,7 @@ static inline void tpm_buf_append(struct tpm_buf *buf,
if (buf->flags & TPM_BUF_OVERFLOW)
return;
- if ((len + new_len) > PAGE_SIZE) {
+ if ((len + new_len) > buf->size) {
WARN(1, "tpm_buf: overflow\n");
buf->flags |= TPM_BUF_OVERFLOW;
return;
diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c
index 149e953ca369..2753699454ab 100644
--- a/drivers/char/tpm/tpm1-cmd.c
+++ b/drivers/char/tpm/tpm1-cmd.c
@@ -323,19 +323,25 @@ unsigned long tpm1_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
*/
static int tpm1_startup(struct tpm_chip *chip)
{
+ struct page *data_page;
struct tpm_buf buf;
int rc;
dev_info(&chip->dev, "starting up the TPM manually\n");
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
- if (rc < 0)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM_TAG_RQU_COMMAND,
+ TPM_ORD_STARTUP);
tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
- tpm_buf_destroy(&buf);
+
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
@@ -448,18 +454,24 @@ int tpm1_get_timeouts(struct tpm_chip *chip)
int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
const char *log_msg)
{
+ struct page *data_page;
struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM_TAG_RQU_COMMAND,
+ TPM_ORD_PCR_EXTEND);
tpm_buf_append_u32(&buf, pcr_idx);
tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, log_msg);
- tpm_buf_destroy(&buf);
+
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
@@ -467,12 +479,16 @@ int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length)
{
+ struct page *data_page;
struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM_TAG_RQU_COMMAND,
+ TPM_ORD_GET_CAP);
if (subcap_id == TPM_CAP_VERSION_1_1 ||
subcap_id == TPM_CAP_VERSION_1_2) {
@@ -491,7 +507,9 @@ ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
rc = tpm_transmit_cmd(chip, &buf, min_cap_length, desc);
if (!rc)
*cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
- tpm_buf_destroy(&buf);
+
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
EXPORT_SYMBOL_GPL(tpm1_getcap);
@@ -514,19 +532,26 @@ struct tpm1_get_random_out {
*/
int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
- struct tpm1_get_random_out *out;
u32 num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
+ struct tpm1_get_random_out *out;
+ struct page *data_page;
struct tpm_buf buf;
- u32 total = 0;
int retries = 5;
+ void *data_ptr;
+ u32 total = 0;
u32 recd;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ data_ptr = kmap(data_page);
do {
+ tpm_buf_reset(&buf, data_ptr, PAGE_SIZE, TPM_TAG_RQU_COMMAND,
+ TPM_ORD_GET_RANDOM);
+
tpm_buf_append_u32(&buf, num_bytes);
rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
@@ -555,25 +580,29 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
dest += recd;
total += recd;
num_bytes -= recd;
-
- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
} while (retries-- && total < max);
rc = total ? (int)total : -EIO;
+
out:
- tpm_buf_destroy(&buf);
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
#define TPM_ORD_PCRREAD 21
int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
{
+ struct page *data_page;
struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM_TAG_RQU_COMMAND,
+ TPM_ORD_PCRREAD);
tpm_buf_append_u32(&buf, pcr_idx);
@@ -590,7 +619,8 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
memcpy(res_buf, &buf.data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
out:
- tpm_buf_destroy(&buf);
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
@@ -604,15 +634,21 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
*/
static int tpm1_continue_selftest(struct tpm_chip *chip)
{
+ struct page *data_page;
struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM_TAG_RQU_COMMAND,
+ TPM_ORD_CONTINUE_SELFTEST);
rc = tpm_transmit_cmd(chip, &buf, 0, "continue selftest");
- tpm_buf_destroy(&buf);
+
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
@@ -722,21 +758,28 @@ int tpm1_auto_startup(struct tpm_chip *chip)
int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
{
u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
+ struct page *data_page;
struct tpm_buf buf;
unsigned int try;
+ void *data_ptr;
int rc;
-
/* for buggy tpm, flush pcrs with extend to selected dummy */
if (tpm_suspend_pcr)
rc = tpm1_pcr_extend(chip, tpm_suspend_pcr, dummy_hash,
"extending dummy pcr before suspend");
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ data_ptr = kmap(data_page);
+
/* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) {
+ tpm_buf_reset(&buf, data_ptr, PAGE_SIZE,
+ TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
+
rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
/*
* If the TPM indicates that it is too busy to respond to
@@ -750,9 +793,8 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
*/
if (rc != TPM_WARN_RETRY)
break;
- tpm_msleep(TPM_TIMEOUT_RETRY);
- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
+ tpm_msleep(TPM_TIMEOUT_RETRY);
}
if (rc)
@@ -762,8 +804,8 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
dev_warn(&chip->dev, "TPM savestate took %dms\n",
try * TPM_TIMEOUT_RETRY);
- tpm_buf_destroy(&buf);
-
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index ba9acae83bff..50674710aed0 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -175,13 +175,14 @@ struct tpm2_pcr_read_out {
int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
struct tpm_digest *digest, u16 *digest_size_ptr)
{
- int i;
- int rc;
- struct tpm_buf buf;
- struct tpm2_pcr_read_out *out;
u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
- u16 digest_size;
+ struct tpm2_pcr_read_out *out;
u16 expected_digest_size = 0;
+ struct page *data_page;
+ struct tpm_buf buf;
+ u16 digest_size;
+ int rc;
+ int i;
if (pcr_idx >= TPM2_PLATFORM_PCR)
return -EINVAL;
@@ -197,9 +198,12 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
expected_digest_size = chip->allocated_banks[i].digest_size;
}
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
+ TPM2_CC_PCR_READ);
pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
@@ -225,8 +229,10 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
*digest_size_ptr = digest_size;
memcpy(digest->digest, out->digest, digest_size);
+
out:
- tpm_buf_destroy(&buf);
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
@@ -249,14 +255,18 @@ struct tpm2_null_auth_area {
int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
struct tpm_digest *digests)
{
- struct tpm_buf buf;
struct tpm2_null_auth_area auth_area;
+ struct page *data_page;
+ struct tpm_buf buf;
int rc;
int i;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_SESSIONS,
+ TPM2_CC_PCR_EXTEND);
tpm_buf_append_u32(&buf, pcr_idx);
@@ -278,8 +288,8 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
- tpm_buf_destroy(&buf);
-
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
@@ -302,23 +312,29 @@ struct tpm2_get_random_out {
int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
struct tpm2_get_random_out *out;
+ struct page *data_page;
+ u8 *dest_ptr = dest;
+ u32 num_bytes = max;
struct tpm_buf buf;
+ void *data_ptr;
+ int retries = 5;
+ int total = 0;
u32 recd;
- u32 num_bytes = max;
int err;
- int total = 0;
- int retries = 5;
- u8 *dest_ptr = dest;
if (!num_bytes || max > TPM_MAX_RNG_DATA)
return -EINVAL;
- err = tpm_buf_init(&buf, 0, 0);
- if (err)
- return err;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ data_ptr = kmap(data_page);
do {
- tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_RANDOM);
+ tpm_buf_reset(&buf, data_ptr, PAGE_SIZE,
+ TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_EXTEND);
+
tpm_buf_append_u16(&buf, num_bytes);
err = tpm_transmit_cmd(chip, &buf,
offsetof(struct tpm2_get_random_out,
@@ -347,10 +363,13 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
num_bytes -= recd;
} while (retries-- && total < max);
- tpm_buf_destroy(&buf);
+ kunmap(data_page);
+ __free_page(data_page);
return total ? total : -EIO;
+
out:
- tpm_buf_destroy(&buf);
+ kunmap(data_page);
+ __free_page(data_page);
return err;
}
@@ -361,20 +380,24 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
*/
void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
{
+ struct page *data_page;
struct tpm_buf buf;
- int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
- if (rc) {
- dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
- handle);
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page) {
+ WARN(1, "tpm: out of memory");
return;
}
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
+ TPM2_CC_FLUSH_CONTEXT);
+
tpm_buf_append_u32(&buf, handle);
tpm_transmit_cmd(chip, &buf, 0, "flushing context");
- tpm_buf_destroy(&buf);
+
+ kunmap(data_page);
+ __free_page(data_page);
}
/**
@@ -420,6 +443,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
+ struct page *data_page;
unsigned int blob_len;
struct tpm_buf buf;
u32 hash;
@@ -436,9 +460,12 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
if (i == ARRAY_SIZE(tpm2_hash_map))
return -EINVAL;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_SESSIONS,
+ TPM2_CC_CREATE);
tpm_buf_append_u32(&buf, options->keyhandle);
tpm2_buf_append_auth(&buf, TPM2_RS_PW,
@@ -505,7 +532,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
payload->blob_len = blob_len;
out:
- tpm_buf_destroy(&buf);
+ kunmap(data_page);
+ __free_page(data_page);
if (rc > 0) {
if (tpm2_rc_value(rc) == TPM2_RC_HASH)
@@ -535,10 +563,11 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
struct trusted_key_options *options,
u32 *blob_handle)
{
- struct tpm_buf buf;
unsigned int private_len;
unsigned int public_len;
+ struct page *data_page;
unsigned int blob_len;
+ struct tpm_buf buf;
int rc;
private_len = be16_to_cpup((__be16 *) &payload->blob[0]);
@@ -550,9 +579,12 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
if (blob_len > payload->blob_len)
return -E2BIG;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_SESSIONS,
+ TPM2_CC_LOAD);
tpm_buf_append_u32(&buf, options->keyhandle);
tpm2_buf_append_auth(&buf, TPM2_RS_PW,
@@ -574,7 +606,8 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
(__be32 *) &buf.data[TPM_HEADER_SIZE]);
out:
- tpm_buf_destroy(&buf);
+ kunmap(data_page);
+ __free_page(data_page);
if (rc > 0)
rc = -EPERM;
@@ -599,14 +632,18 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
struct trusted_key_options *options,
u32 blob_handle)
{
+ struct page *data_page;
struct tpm_buf buf;
u16 data_len;
u8 *data;
int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_SESSIONS,
+ TPM2_CC_UNSEAL);
tpm_buf_append_u32(&buf, blob_handle);
tpm2_buf_append_auth(&buf,
@@ -641,7 +678,8 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
}
out:
- tpm_buf_destroy(&buf);
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
@@ -693,12 +731,17 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
const char *desc)
{
struct tpm2_get_cap_out *out;
+ struct page *data_page;
struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
+ TPM2_CC_GET_CAPABILITY);
+
tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
tpm_buf_append_u32(&buf, property_id);
tpm_buf_append_u32(&buf, 1);
@@ -708,7 +751,9 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
&buf.data[TPM_HEADER_SIZE];
*value = be32_to_cpu(out->value);
}
- tpm_buf_destroy(&buf);
+
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
@@ -725,15 +770,23 @@ EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
*/
void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
{
+ struct page *data_page;
struct tpm_buf buf;
- int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
- if (rc)
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page) {
+ WARN(1, "tpm: out of memory");
return;
+ }
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
+ TPM2_CC_SHUTDOWN);
+
tpm_buf_append_u16(&buf, shutdown_type);
tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM");
- tpm_buf_destroy(&buf);
+
+ kunmap(data_page);
+ __free_page(data_page);
}
/**
@@ -751,26 +804,36 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
*/
static int tpm2_do_selftest(struct tpm_chip *chip)
{
+ struct page *data_page;
struct tpm_buf buf;
+ void *data_ptr;
int full;
int rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ data_ptr = kmap(data_page);
+
for (full = 0; full < 2; full++) {
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
- if (rc)
- return rc;
+ tpm_buf_reset(&buf, data_ptr, PAGE_SIZE, TPM2_ST_NO_SESSIONS,
+ TPM2_CC_SELF_TEST);
tpm_buf_append_u8(&buf, full);
+
rc = tpm_transmit_cmd(chip, &buf, 0,
"attempting the self test");
- tpm_buf_destroy(&buf);
if (rc == TPM2_RC_TESTING)
rc = TPM2_RC_SUCCESS;
+
if (rc == TPM2_RC_INITIALIZE || rc == TPM2_RC_SUCCESS)
- return rc;
+ break;
}
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
@@ -788,16 +851,22 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
*/
int tpm2_probe(struct tpm_chip *chip)
{
+ struct page *data_page;
struct tpm_header *out;
struct tpm_buf buf;
int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
+ TPM2_CC_GET_CAPABILITY);
+
tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS);
tpm_buf_append_u32(&buf, 1);
+
rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
/* We ignore TPM return codes on purpose. */
if (rc >= 0) {
@@ -805,7 +874,9 @@ int tpm2_probe(struct tpm_chip *chip)
if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS)
chip->flags |= TPM_CHIP_FLAG_TPM2;
}
- tpm_buf_destroy(&buf);
+
+ kunmap(data_page);
+ __free_page(data_page);
return 0;
}
EXPORT_SYMBOL_GPL(tpm2_probe);
@@ -843,21 +914,25 @@ struct tpm2_pcr_selection {
ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
{
struct tpm2_pcr_selection pcr_selection;
- struct tpm_buf buf;
- void *marker;
- void *end;
- void *pcr_select_offset;
u32 sizeof_pcr_selection;
- u32 nr_possible_banks;
+ void *pcr_select_offset;
u32 nr_alloc_banks = 0;
+ struct page *data_page;
+ u32 nr_possible_banks;
+ struct tpm_buf buf;
u16 hash_alg;
+ void *marker;
u32 rsp_len;
- int rc;
int i = 0;
+ void *end;
+ int rc;
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
+ TPM2_CC_GET_CAPABILITY);
tpm_buf_append_u32(&buf, TPM2_CAP_PCRS);
tpm_buf_append_u32(&buf, 0);
@@ -913,14 +988,16 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
}
chip->nr_allocated_banks = nr_alloc_banks;
-out:
- tpm_buf_destroy(&buf);
+out:
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
{
+ struct page *data_page;
struct tpm_buf buf;
u32 nr_commands;
__be32 *attrs;
@@ -930,35 +1007,32 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL);
if (rc)
- goto out;
+ return rc;
- if (nr_commands > 0xFFFFF) {
- rc = -EFAULT;
- goto out;
- }
+ if (nr_commands > 0xFFFFF)
+ return -EFAULT;
chip->cc_attrs_tbl = devm_kcalloc(&chip->dev, 4, nr_commands,
GFP_KERNEL);
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
- if (rc)
- goto out;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
+ TPM2_CC_GET_CAPABILITY);
tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS);
tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
tpm_buf_append_u32(&buf, nr_commands);
rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL);
- if (rc) {
- tpm_buf_destroy(&buf);
+ if (rc)
goto out;
- }
if (nr_commands !=
- be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
- tpm_buf_destroy(&buf);
+ be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5]))
goto out;
- }
chip->nr_commands = nr_commands;
@@ -974,11 +1048,13 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
}
}
- tpm_buf_destroy(&buf);
-
out:
+ kunmap(data_page);
+ __free_page(data_page);
+
if (rc > 0)
rc = -ENODEV;
+
return rc;
}
@@ -995,19 +1071,24 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
static int tpm2_startup(struct tpm_chip *chip)
{
+ struct page *data_page;
struct tpm_buf buf;
int rc;
dev_info(&chip->dev, "starting up the TPM manually\n");
- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
- if (rc < 0)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
+ TPM2_CC_STARTUP);
tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
- tpm_buf_destroy(&buf);
+ kunmap(data_page);
+ __free_page(data_page);
return rc;
}
diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
index 982d341d8837..1d3e47392f23 100644
--- a/drivers/char/tpm/tpm2-space.c
+++ b/drivers/char/tpm/tpm2-space.c
@@ -68,14 +68,18 @@ void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
unsigned int *offset, u32 *handle)
{
- struct tpm_buf tbuf;
struct tpm2_context *ctx;
+ struct page *data_page;
unsigned int body_size;
+ struct tpm_buf tbuf;
int rc;
- rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+
+ tpm_buf_reset(&tbuf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
+ TPM2_CC_CONTEXT_LOAD);
ctx = (struct tpm2_context *)&buf[*offset];
body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
@@ -85,8 +89,8 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
- return -EFAULT;
+ rc = -EFAULT;
+ goto out;
} else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
rc == TPM2_RC_REFERENCE_H0) {
/*
@@ -100,62 +104,70 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
* flushed outside the space
*/
*handle = 0;
- tpm_buf_destroy(&tbuf);
- return -ENOENT;
+ rc = -ENOENT;
+ goto out;
} else if (rc > 0) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
- return -EFAULT;
+ rc = -EFAULT;
+ goto out;
}
*handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
*offset += body_size;
- tpm_buf_destroy(&tbuf);
- return 0;
+out:
+ kunmap(data_page);
+ __free_page(data_page);
+ return rc;
}
static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
unsigned int buf_size, unsigned int *offset)
{
- struct tpm_buf tbuf;
unsigned int body_size;
+ struct page *data_page;
+ struct tpm_buf tbuf;
int rc;
- rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
- if (rc)
- return rc;
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
+ tpm_buf_reset(&tbuf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
+ TPM2_CC_CONTEXT_SAVE);
tpm_buf_append_u32(&tbuf, handle);
rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
- return -EFAULT;
+ rc = -EFAULT;
+ goto out;
} else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
- tpm_buf_destroy(&tbuf);
- return -ENOENT;
+ rc = -ENOENT;
+ goto out;
} else if (rc) {
dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
__func__, rc);
- tpm_buf_destroy(&tbuf);
- return -EFAULT;
+ rc = -EFAULT;
+ goto out;
}
body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
if ((*offset + body_size) > buf_size) {
dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
- tpm_buf_destroy(&tbuf);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto out;
}
memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
*offset += body_size;
- tpm_buf_destroy(&tbuf);
- return 0;
+
+out:
+ kunmap(data_page);
+ __free_page(data_page);
+ return rc;
}
void tpm2_flush_space(struct tpm_chip *chip)
diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c
index 2f6e087ec496..e6e89be0e149 100644
--- a/drivers/char/tpm/tpm_vtpm_proxy.c
+++ b/drivers/char/tpm/tpm_vtpm_proxy.c
@@ -394,19 +394,23 @@ static bool vtpm_proxy_tpm_req_canceled(struct tpm_chip *chip, u8 status)
static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
{
+ struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
+ const struct tpm_header *header;
+ struct page *data_page;
struct tpm_buf buf;
int rc;
- const struct tpm_header *header;
- struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
+
+ data_page = alloc_page(GFP_HIGHUSER);
+ if (!data_page)
+ return -ENOMEM;
if (chip->flags & TPM_CHIP_FLAG_TPM2)
- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS,
- TPM2_CC_SET_LOCALITY);
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE,
+ TPM2_ST_SESSIONS, TPM2_CC_SET_LOCALITY);
else
- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND,
- TPM_ORD_SET_LOCALITY);
- if (rc)
- return rc;
+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE,
+ TPM_TAG_RQU_COMMAND, TPM_ORD_SET_LOCALITY);
+
tpm_buf_append_u8(&buf, locality);
proxy_dev->state |= STATE_DRIVER_COMMAND;
@@ -426,8 +430,8 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
locality = -1;
out:
- tpm_buf_destroy(&buf);
-
+ kunmap(data_page);
+ __free_page(data_page);
return locality;
}
--
2.20.1
On Thu, Sep 26, 2019 at 08:23:24PM +0300, Jarkko Sakkinen wrote:
> As has been seen recently, binding the buffer allocation and tpm_buf
> together is sometimes far from optimal. The buffer might come from the
> caller namely when tpm_send() is used by another subsystem. In addition we
> can stability in call sites w/o rollback (e.g. power events)>
>
> Take allocation out of the tpm_buf framework and make it purely a wrapper
> for the data buffer.
>
> Link: https://patchwork.kernel.org/patch/11146585/
> Cc: Mimi Zohar <[email protected]>
> Cc: Jerry Snitselaar <[email protected]>
> Cc: James Bottomley <[email protected]>
> Cc: Sumit Garg <[email protected]>
> Cc: Stefan Berger <[email protected]>
> Signed-off-by: Jarkko Sakkinen <[email protected]>
> ---
> v2:
> * In tpm2_get_random(), TPM2_CC_GET_RANDOM was accidently switch to
> TPM2_CC_PCR_EXTEND. Now it has been switched back.
Forgot --subject-prefix="PATCH v2".
/Jarkko
On Thu Sep 26 19, Jarkko Sakkinen wrote:
>As has been seen recently, binding the buffer allocation and tpm_buf
>together is sometimes far from optimal. The buffer might come from the
>caller namely when tpm_send() is used by another subsystem. In addition we
>can stability in call sites w/o rollback (e.g. power events)>
>
>Take allocation out of the tpm_buf framework and make it purely a wrapper
>for the data buffer.
>
>Link: https://patchwork.kernel.org/patch/11146585/
>Cc: Mimi Zohar <[email protected]>
>Cc: Jerry Snitselaar <[email protected]>
>Cc: James Bottomley <[email protected]>
>Cc: Sumit Garg <[email protected]>
>Cc: Stefan Berger <[email protected]>
>Signed-off-by: Jarkko Sakkinen <[email protected]>
>---
>v2:
>* In tpm2_get_random(), TPM2_CC_GET_RANDOM was accidently switch to
> TPM2_CC_PCR_EXTEND. Now it has been switched back.
> drivers/char/tpm/tpm-sysfs.c | 19 ++-
> drivers/char/tpm/tpm.h | 40 ++---
> drivers/char/tpm/tpm1-cmd.c | 114 +++++++++----
> drivers/char/tpm/tpm2-cmd.c | 265 +++++++++++++++++++-----------
> drivers/char/tpm/tpm2-space.c | 64 +++++---
> drivers/char/tpm/tpm_vtpm_proxy.c | 24 +--
> 6 files changed, 333 insertions(+), 193 deletions(-)
>
>diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
>index edfa89160010..eeb90c9225b9 100644
>--- a/drivers/char/tpm/tpm-sysfs.c
>+++ b/drivers/char/tpm/tpm-sysfs.c
>@@ -32,21 +32,26 @@ struct tpm_readpubek_out {
> static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> {
>- struct tpm_buf tpm_buf;
>- struct tpm_readpubek_out *out;
>- int i;
>- char *str = buf;
> struct tpm_chip *chip = to_tpm_chip(dev);
>+ struct tpm_readpubek_out *out;
>+ struct page *data_page;
>+ struct tpm_buf tpm_buf;
> char anti_replay[20];
>+ char *str = buf;
>+ int i;
>
> memset(&anti_replay, 0, sizeof(anti_replay));
>
> if (tpm_try_get_ops(chip))
> return 0;
>
>- if (tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK))
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
> goto out_ops;
>
>+ tpm_buf_reset(&tpm_buf, kmap(data_page), PAGE_SIZE, TPM_TAG_RQU_COMMAND,
>+ TPM_ORD_READPUBEK);
>+
> tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay));
>
> if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE,
>@@ -83,7 +88,9 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
> }
>
> out_buf:
>- tpm_buf_destroy(&tpm_buf);
>+ kunmap(data_page);
>+ __free_page(data_page);
>+
> out_ops:
> tpm_put_ops(chip);
> return str - buf;
>diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
>index a7fea3e0ca86..45316e5d2d36 100644
>--- a/drivers/char/tpm/tpm.h
>+++ b/drivers/char/tpm/tpm.h
>@@ -284,36 +284,30 @@ enum tpm_buf_flags {
> };
>
> struct tpm_buf {
>- struct page *data_page;
>- unsigned int flags;
> u8 *data;
>+ unsigned int size;
>+ unsigned int flags;
> };
>
>-static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
>+static inline void tpm_buf_reset(struct tpm_buf *buf, u8 *data,
>+ unsigned int size, u16 tag, u32 ordinal)
> {
>- struct tpm_header *head = (struct tpm_header *)buf->data;
>+ struct tpm_header *head = (struct tpm_header *)data;
>
>- head->tag = cpu_to_be16(tag);
>- head->length = cpu_to_be32(sizeof(*head));
>- head->ordinal = cpu_to_be32(ordinal);
>-}
>-
>-static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
>-{
>- buf->data_page = alloc_page(GFP_HIGHUSER);
>- if (!buf->data_page)
>- return -ENOMEM;
>+ /* sanity check */
>+ if (size < TPM_HEADER_SIZE) {
>+ WARN(1, "tpm_buf: overflow\n");
>+ buf->flags |= TPM_BUF_OVERFLOW;
>+ return;
>+ }
>
>+ buf->data = data;
>+ buf->size = size;
> buf->flags = 0;
>- buf->data = kmap(buf->data_page);
>- tpm_buf_reset(buf, tag, ordinal);
>- return 0;
>-}
>
>-static inline void tpm_buf_destroy(struct tpm_buf *buf)
>-{
>- kunmap(buf->data_page);
>- __free_page(buf->data_page);
>+ head->tag = cpu_to_be16(tag);
>+ head->length = cpu_to_be32(sizeof(*head));
>+ head->ordinal = cpu_to_be32(ordinal);
> }
>
> static inline u32 tpm_buf_length(struct tpm_buf *buf)
>@@ -341,7 +335,7 @@ static inline void tpm_buf_append(struct tpm_buf *buf,
> if (buf->flags & TPM_BUF_OVERFLOW)
> return;
>
>- if ((len + new_len) > PAGE_SIZE) {
>+ if ((len + new_len) > buf->size) {
> WARN(1, "tpm_buf: overflow\n");
> buf->flags |= TPM_BUF_OVERFLOW;
> return;
>diff --git a/drivers/char/tpm/tpm1-cmd.c b/drivers/char/tpm/tpm1-cmd.c
>index 149e953ca369..2753699454ab 100644
>--- a/drivers/char/tpm/tpm1-cmd.c
>+++ b/drivers/char/tpm/tpm1-cmd.c
>@@ -323,19 +323,25 @@ unsigned long tpm1_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
> */
> static int tpm1_startup(struct tpm_chip *chip)
> {
>+ struct page *data_page;
> struct tpm_buf buf;
> int rc;
>
> dev_info(&chip->dev, "starting up the TPM manually\n");
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
>- if (rc < 0)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM_TAG_RQU_COMMAND,
>+ TPM_ORD_STARTUP);
>
> tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
>
> rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
>- tpm_buf_destroy(&buf);
>+
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
>
>@@ -448,18 +454,24 @@ int tpm1_get_timeouts(struct tpm_chip *chip)
> int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
> const char *log_msg)
> {
>+ struct page *data_page;
> struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM_TAG_RQU_COMMAND,
>+ TPM_ORD_PCR_EXTEND);
>
> tpm_buf_append_u32(&buf, pcr_idx);
> tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
>
> rc = tpm_transmit_cmd(chip, &buf, TPM_DIGEST_SIZE, log_msg);
>- tpm_buf_destroy(&buf);
>+
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
>
>@@ -467,12 +479,16 @@ int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash,
> ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
> const char *desc, size_t min_cap_length)
> {
>+ struct page *data_page;
> struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM_TAG_RQU_COMMAND,
>+ TPM_ORD_GET_CAP);
>
> if (subcap_id == TPM_CAP_VERSION_1_1 ||
> subcap_id == TPM_CAP_VERSION_1_2) {
>@@ -491,7 +507,9 @@ ssize_t tpm1_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
> rc = tpm_transmit_cmd(chip, &buf, min_cap_length, desc);
> if (!rc)
> *cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
>- tpm_buf_destroy(&buf);
>+
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
> EXPORT_SYMBOL_GPL(tpm1_getcap);
>@@ -514,19 +532,26 @@ struct tpm1_get_random_out {
> */
> int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> {
>- struct tpm1_get_random_out *out;
> u32 num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
>+ struct tpm1_get_random_out *out;
>+ struct page *data_page;
> struct tpm_buf buf;
>- u32 total = 0;
> int retries = 5;
>+ void *data_ptr;
>+ u32 total = 0;
> u32 recd;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ data_ptr = kmap(data_page);
>
> do {
>+ tpm_buf_reset(&buf, data_ptr, PAGE_SIZE, TPM_TAG_RQU_COMMAND,
>+ TPM_ORD_GET_RANDOM);
>+
> tpm_buf_append_u32(&buf, num_bytes);
>
> rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
>@@ -555,25 +580,29 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> dest += recd;
> total += recd;
> num_bytes -= recd;
>-
>- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_RANDOM);
> } while (retries-- && total < max);
>
> rc = total ? (int)total : -EIO;
>+
> out:
>- tpm_buf_destroy(&buf);
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
>
> #define TPM_ORD_PCRREAD 21
> int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
> {
>+ struct page *data_page;
> struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCRREAD);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM_TAG_RQU_COMMAND,
>+ TPM_ORD_PCRREAD);
>
> tpm_buf_append_u32(&buf, pcr_idx);
>
>@@ -590,7 +619,8 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
> memcpy(res_buf, &buf.data[TPM_HEADER_SIZE], TPM_DIGEST_SIZE);
>
> out:
>- tpm_buf_destroy(&buf);
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
>
>@@ -604,15 +634,21 @@ int tpm1_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf)
> */
> static int tpm1_continue_selftest(struct tpm_chip *chip)
> {
>+ struct page *data_page;
> struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_CONTINUE_SELFTEST);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM_TAG_RQU_COMMAND,
>+ TPM_ORD_CONTINUE_SELFTEST);
>
> rc = tpm_transmit_cmd(chip, &buf, 0, "continue selftest");
>- tpm_buf_destroy(&buf);
>+
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
>
>@@ -722,21 +758,28 @@ int tpm1_auto_startup(struct tpm_chip *chip)
> int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
> {
> u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
>+ struct page *data_page;
> struct tpm_buf buf;
> unsigned int try;
>+ void *data_ptr;
> int rc;
>
>-
> /* for buggy tpm, flush pcrs with extend to selected dummy */
> if (tpm_suspend_pcr)
> rc = tpm1_pcr_extend(chip, tpm_suspend_pcr, dummy_hash,
> "extending dummy pcr before suspend");
>
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ data_ptr = kmap(data_page);
>+
> /* now do the actual savestate */
> for (try = 0; try < TPM_RETRY; try++) {
>+ tpm_buf_reset(&buf, data_ptr, PAGE_SIZE,
>+ TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
>+
> rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
> /*
> * If the TPM indicates that it is too busy to respond to
>@@ -750,9 +793,8 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
> */
> if (rc != TPM_WARN_RETRY)
> break;
>- tpm_msleep(TPM_TIMEOUT_RETRY);
>
>- tpm_buf_reset(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_SAVESTATE);
>+ tpm_msleep(TPM_TIMEOUT_RETRY);
> }
>
> if (rc)
>@@ -762,8 +804,8 @@ int tpm1_pm_suspend(struct tpm_chip *chip, u32 tpm_suspend_pcr)
> dev_warn(&chip->dev, "TPM savestate took %dms\n",
> try * TPM_TIMEOUT_RETRY);
>
>- tpm_buf_destroy(&buf);
>-
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
>
>diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
>index ba9acae83bff..50674710aed0 100644
>--- a/drivers/char/tpm/tpm2-cmd.c
>+++ b/drivers/char/tpm/tpm2-cmd.c
>@@ -175,13 +175,14 @@ struct tpm2_pcr_read_out {
> int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
> struct tpm_digest *digest, u16 *digest_size_ptr)
> {
>- int i;
>- int rc;
>- struct tpm_buf buf;
>- struct tpm2_pcr_read_out *out;
> u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
>- u16 digest_size;
>+ struct tpm2_pcr_read_out *out;
> u16 expected_digest_size = 0;
>+ struct page *data_page;
>+ struct tpm_buf buf;
>+ u16 digest_size;
>+ int rc;
>+ int i;
>
> if (pcr_idx >= TPM2_PLATFORM_PCR)
> return -EINVAL;
>@@ -197,9 +198,12 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
> expected_digest_size = chip->allocated_banks[i].digest_size;
> }
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
>+ TPM2_CC_PCR_READ);
>
> pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
>
>@@ -225,8 +229,10 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
> *digest_size_ptr = digest_size;
>
> memcpy(digest->digest, out->digest, digest_size);
>+
> out:
>- tpm_buf_destroy(&buf);
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
>
>@@ -249,14 +255,18 @@ struct tpm2_null_auth_area {
> int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
> struct tpm_digest *digests)
> {
>- struct tpm_buf buf;
> struct tpm2_null_auth_area auth_area;
>+ struct page *data_page;
>+ struct tpm_buf buf;
> int rc;
> int i;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_SESSIONS,
>+ TPM2_CC_PCR_EXTEND);
>
> tpm_buf_append_u32(&buf, pcr_idx);
>
>@@ -278,8 +288,8 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
>
> rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
>
>- tpm_buf_destroy(&buf);
>-
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
>
>@@ -302,23 +312,29 @@ struct tpm2_get_random_out {
> int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> {
> struct tpm2_get_random_out *out;
>+ struct page *data_page;
>+ u8 *dest_ptr = dest;
>+ u32 num_bytes = max;
> struct tpm_buf buf;
>+ void *data_ptr;
>+ int retries = 5;
>+ int total = 0;
> u32 recd;
>- u32 num_bytes = max;
> int err;
>- int total = 0;
>- int retries = 5;
>- u8 *dest_ptr = dest;
>
> if (!num_bytes || max > TPM_MAX_RNG_DATA)
> return -EINVAL;
>
>- err = tpm_buf_init(&buf, 0, 0);
>- if (err)
>- return err;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ data_ptr = kmap(data_page);
>
> do {
>- tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_RANDOM);
>+ tpm_buf_reset(&buf, data_ptr, PAGE_SIZE,
>+ TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_EXTEND);
TPM2_CC_GET_RANDOM
>+
> tpm_buf_append_u16(&buf, num_bytes);
> err = tpm_transmit_cmd(chip, &buf,
> offsetof(struct tpm2_get_random_out,
>@@ -347,10 +363,13 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> num_bytes -= recd;
> } while (retries-- && total < max);
>
>- tpm_buf_destroy(&buf);
>+ kunmap(data_page);
>+ __free_page(data_page);
> return total ? total : -EIO;
>+
> out:
>- tpm_buf_destroy(&buf);
>+ kunmap(data_page);
>+ __free_page(data_page);
> return err;
> }
Would this work here?
err = total ? total : -EIO;
out:
kunmap(data_page);
__free_page(data_page);
return err;
>
>@@ -361,20 +380,24 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
> */
> void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
> {
>+ struct page *data_page;
> struct tpm_buf buf;
>- int rc;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
>- if (rc) {
>- dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n",
>- handle);
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page) {
>+ WARN(1, "tpm: out of memory");
> return;
> }
>
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
>+ TPM2_CC_FLUSH_CONTEXT);
>+
> tpm_buf_append_u32(&buf, handle);
>
> tpm_transmit_cmd(chip, &buf, 0, "flushing context");
>- tpm_buf_destroy(&buf);
>+
>+ kunmap(data_page);
>+ __free_page(data_page);
> }
>
> /**
>@@ -420,6 +443,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> struct trusted_key_payload *payload,
> struct trusted_key_options *options)
> {
>+ struct page *data_page;
> unsigned int blob_len;
> struct tpm_buf buf;
> u32 hash;
>@@ -436,9 +460,12 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> if (i == ARRAY_SIZE(tpm2_hash_map))
> return -EINVAL;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_SESSIONS,
>+ TPM2_CC_CREATE);
>
> tpm_buf_append_u32(&buf, options->keyhandle);
> tpm2_buf_append_auth(&buf, TPM2_RS_PW,
>@@ -505,7 +532,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
> payload->blob_len = blob_len;
>
> out:
>- tpm_buf_destroy(&buf);
>+ kunmap(data_page);
>+ __free_page(data_page);
>
> if (rc > 0) {
> if (tpm2_rc_value(rc) == TPM2_RC_HASH)
>@@ -535,10 +563,11 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> struct trusted_key_options *options,
> u32 *blob_handle)
> {
>- struct tpm_buf buf;
> unsigned int private_len;
> unsigned int public_len;
>+ struct page *data_page;
> unsigned int blob_len;
>+ struct tpm_buf buf;
> int rc;
>
> private_len = be16_to_cpup((__be16 *) &payload->blob[0]);
>@@ -550,9 +579,12 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> if (blob_len > payload->blob_len)
> return -E2BIG;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_SESSIONS,
>+ TPM2_CC_LOAD);
>
> tpm_buf_append_u32(&buf, options->keyhandle);
> tpm2_buf_append_auth(&buf, TPM2_RS_PW,
>@@ -574,7 +606,8 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
> (__be32 *) &buf.data[TPM_HEADER_SIZE]);
>
> out:
>- tpm_buf_destroy(&buf);
>+ kunmap(data_page);
>+ __free_page(data_page);
>
> if (rc > 0)
> rc = -EPERM;
>@@ -599,14 +632,18 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
> struct trusted_key_options *options,
> u32 blob_handle)
> {
>+ struct page *data_page;
> struct tpm_buf buf;
> u16 data_len;
> u8 *data;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_SESSIONS,
>+ TPM2_CC_UNSEAL);
>
> tpm_buf_append_u32(&buf, blob_handle);
> tpm2_buf_append_auth(&buf,
>@@ -641,7 +678,8 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
> }
>
> out:
>- tpm_buf_destroy(&buf);
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
>
>@@ -693,12 +731,17 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
> const char *desc)
> {
> struct tpm2_get_cap_out *out;
>+ struct page *data_page;
> struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
>+ TPM2_CC_GET_CAPABILITY);
>+
> tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
> tpm_buf_append_u32(&buf, property_id);
> tpm_buf_append_u32(&buf, 1);
>@@ -708,7 +751,9 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
> &buf.data[TPM_HEADER_SIZE];
> *value = be32_to_cpu(out->value);
> }
>- tpm_buf_destroy(&buf);
>+
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
> EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
>@@ -725,15 +770,23 @@ EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
> */
> void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
> {
>+ struct page *data_page;
> struct tpm_buf buf;
>- int rc;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN);
>- if (rc)
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page) {
>+ WARN(1, "tpm: out of memory");
> return;
>+ }
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
>+ TPM2_CC_SHUTDOWN);
>+
> tpm_buf_append_u16(&buf, shutdown_type);
> tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM");
>- tpm_buf_destroy(&buf);
>+
>+ kunmap(data_page);
>+ __free_page(data_page);
> }
>
> /**
>@@ -751,26 +804,36 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
> */
> static int tpm2_do_selftest(struct tpm_chip *chip)
> {
>+ struct page *data_page;
> struct tpm_buf buf;
>+ void *data_ptr;
> int full;
> int rc;
>
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ data_ptr = kmap(data_page);
>+
> for (full = 0; full < 2; full++) {
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
>- if (rc)
>- return rc;
>+ tpm_buf_reset(&buf, data_ptr, PAGE_SIZE, TPM2_ST_NO_SESSIONS,
>+ TPM2_CC_SELF_TEST);
>
> tpm_buf_append_u8(&buf, full);
>+
> rc = tpm_transmit_cmd(chip, &buf, 0,
> "attempting the self test");
>- tpm_buf_destroy(&buf);
>
> if (rc == TPM2_RC_TESTING)
> rc = TPM2_RC_SUCCESS;
>+
> if (rc == TPM2_RC_INITIALIZE || rc == TPM2_RC_SUCCESS)
>- return rc;
>+ break;
> }
>
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
>
>@@ -788,16 +851,22 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
> */
> int tpm2_probe(struct tpm_chip *chip)
> {
>+ struct page *data_page;
> struct tpm_header *out;
> struct tpm_buf buf;
> int rc;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
>+ TPM2_CC_GET_CAPABILITY);
>+
> tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES);
> tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS);
> tpm_buf_append_u32(&buf, 1);
>+
> rc = tpm_transmit_cmd(chip, &buf, 0, NULL);
> /* We ignore TPM return codes on purpose. */
> if (rc >= 0) {
>@@ -805,7 +874,9 @@ int tpm2_probe(struct tpm_chip *chip)
> if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS)
> chip->flags |= TPM_CHIP_FLAG_TPM2;
> }
>- tpm_buf_destroy(&buf);
>+
>+ kunmap(data_page);
>+ __free_page(data_page);
> return 0;
> }
> EXPORT_SYMBOL_GPL(tpm2_probe);
>@@ -843,21 +914,25 @@ struct tpm2_pcr_selection {
> ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
> {
> struct tpm2_pcr_selection pcr_selection;
>- struct tpm_buf buf;
>- void *marker;
>- void *end;
>- void *pcr_select_offset;
> u32 sizeof_pcr_selection;
>- u32 nr_possible_banks;
>+ void *pcr_select_offset;
> u32 nr_alloc_banks = 0;
>+ struct page *data_page;
>+ u32 nr_possible_banks;
>+ struct tpm_buf buf;
> u16 hash_alg;
>+ void *marker;
> u32 rsp_len;
>- int rc;
> int i = 0;
>+ void *end;
>+ int rc;
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
>+ TPM2_CC_GET_CAPABILITY);
>
> tpm_buf_append_u32(&buf, TPM2_CAP_PCRS);
> tpm_buf_append_u32(&buf, 0);
>@@ -913,14 +988,16 @@ ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
> }
>
> chip->nr_allocated_banks = nr_alloc_banks;
>-out:
>- tpm_buf_destroy(&buf);
>
>+out:
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
>
> static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
> {
>+ struct page *data_page;
> struct tpm_buf buf;
> u32 nr_commands;
> __be32 *attrs;
>@@ -930,35 +1007,32 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
>
> rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL);
> if (rc)
>- goto out;
>+ return rc;
>
>- if (nr_commands > 0xFFFFF) {
>- rc = -EFAULT;
>- goto out;
>- }
>+ if (nr_commands > 0xFFFFF)
>+ return -EFAULT;
>
> chip->cc_attrs_tbl = devm_kcalloc(&chip->dev, 4, nr_commands,
> GFP_KERNEL);
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
>- if (rc)
>- goto out;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
>+ TPM2_CC_GET_CAPABILITY);
>
> tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS);
> tpm_buf_append_u32(&buf, TPM2_CC_FIRST);
> tpm_buf_append_u32(&buf, nr_commands);
>
> rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL);
>- if (rc) {
>- tpm_buf_destroy(&buf);
>+ if (rc)
> goto out;
>- }
>
> if (nr_commands !=
>- be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) {
>- tpm_buf_destroy(&buf);
>+ be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5]))
> goto out;
>- }
>
> chip->nr_commands = nr_commands;
>
>@@ -974,11 +1048,13 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
> }
> }
>
>- tpm_buf_destroy(&buf);
>-
> out:
>+ kunmap(data_page);
>+ __free_page(data_page);
>+
> if (rc > 0)
> rc = -ENODEV;
>+
> return rc;
> }
>
>@@ -995,19 +1071,24 @@ static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
>
> static int tpm2_startup(struct tpm_chip *chip)
> {
>+ struct page *data_page;
> struct tpm_buf buf;
> int rc;
>
> dev_info(&chip->dev, "starting up the TPM manually\n");
>
>- rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
>- if (rc < 0)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
>+ TPM2_CC_STARTUP);
>
> tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
> rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM");
>- tpm_buf_destroy(&buf);
>
>+ kunmap(data_page);
>+ __free_page(data_page);
> return rc;
> }
>
>diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c
>index 982d341d8837..1d3e47392f23 100644
>--- a/drivers/char/tpm/tpm2-space.c
>+++ b/drivers/char/tpm/tpm2-space.c
>@@ -68,14 +68,18 @@ void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space)
> static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
> unsigned int *offset, u32 *handle)
> {
>- struct tpm_buf tbuf;
> struct tpm2_context *ctx;
>+ struct page *data_page;
> unsigned int body_size;
>+ struct tpm_buf tbuf;
> int rc;
>
>- rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_LOAD);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>+
>+ tpm_buf_reset(&tbuf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
>+ TPM2_CC_CONTEXT_LOAD);
>
> ctx = (struct tpm2_context *)&buf[*offset];
> body_size = sizeof(*ctx) + be16_to_cpu(ctx->blob_size);
>@@ -85,8 +89,8 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
> if (rc < 0) {
> dev_warn(&chip->dev, "%s: failed with a system error %d\n",
> __func__, rc);
>- tpm_buf_destroy(&tbuf);
>- return -EFAULT;
>+ rc = -EFAULT;
>+ goto out;
> } else if (tpm2_rc_value(rc) == TPM2_RC_HANDLE ||
> rc == TPM2_RC_REFERENCE_H0) {
> /*
>@@ -100,62 +104,70 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
> * flushed outside the space
> */
> *handle = 0;
>- tpm_buf_destroy(&tbuf);
>- return -ENOENT;
>+ rc = -ENOENT;
>+ goto out;
> } else if (rc > 0) {
> dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
> __func__, rc);
>- tpm_buf_destroy(&tbuf);
>- return -EFAULT;
>+ rc = -EFAULT;
>+ goto out;
> }
>
> *handle = be32_to_cpup((__be32 *)&tbuf.data[TPM_HEADER_SIZE]);
> *offset += body_size;
>
>- tpm_buf_destroy(&tbuf);
>- return 0;
>+out:
>+ kunmap(data_page);
>+ __free_page(data_page);
>+ return rc;
> }
>
> static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
> unsigned int buf_size, unsigned int *offset)
> {
>- struct tpm_buf tbuf;
> unsigned int body_size;
>+ struct page *data_page;
>+ struct tpm_buf tbuf;
> int rc;
>
>- rc = tpm_buf_init(&tbuf, TPM2_ST_NO_SESSIONS, TPM2_CC_CONTEXT_SAVE);
>- if (rc)
>- return rc;
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>
>+ tpm_buf_reset(&tbuf, kmap(data_page), PAGE_SIZE, TPM2_ST_NO_SESSIONS,
>+ TPM2_CC_CONTEXT_SAVE);
> tpm_buf_append_u32(&tbuf, handle);
>
> rc = tpm_transmit_cmd(chip, &tbuf, 0, NULL);
> if (rc < 0) {
> dev_warn(&chip->dev, "%s: failed with a system error %d\n",
> __func__, rc);
>- tpm_buf_destroy(&tbuf);
>- return -EFAULT;
>+ rc = -EFAULT;
>+ goto out;
> } else if (tpm2_rc_value(rc) == TPM2_RC_REFERENCE_H0) {
>- tpm_buf_destroy(&tbuf);
>- return -ENOENT;
>+ rc = -ENOENT;
>+ goto out;
> } else if (rc) {
> dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
> __func__, rc);
>- tpm_buf_destroy(&tbuf);
>- return -EFAULT;
>+ rc = -EFAULT;
>+ goto out;
> }
>
> body_size = tpm_buf_length(&tbuf) - TPM_HEADER_SIZE;
> if ((*offset + body_size) > buf_size) {
> dev_warn(&chip->dev, "%s: out of backing storage\n", __func__);
>- tpm_buf_destroy(&tbuf);
>- return -ENOMEM;
>+ rc = -ENOMEM;
>+ goto out;
> }
>
> memcpy(&buf[*offset], &tbuf.data[TPM_HEADER_SIZE], body_size);
> *offset += body_size;
>- tpm_buf_destroy(&tbuf);
>- return 0;
>+
>+out:
>+ kunmap(data_page);
>+ __free_page(data_page);
>+ return rc;
> }
>
> void tpm2_flush_space(struct tpm_chip *chip)
>diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c
>index 2f6e087ec496..e6e89be0e149 100644
>--- a/drivers/char/tpm/tpm_vtpm_proxy.c
>+++ b/drivers/char/tpm/tpm_vtpm_proxy.c
>@@ -394,19 +394,23 @@ static bool vtpm_proxy_tpm_req_canceled(struct tpm_chip *chip, u8 status)
>
> static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
> {
>+ struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
>+ const struct tpm_header *header;
>+ struct page *data_page;
> struct tpm_buf buf;
> int rc;
>- const struct tpm_header *header;
>- struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
>+
>+ data_page = alloc_page(GFP_HIGHUSER);
>+ if (!data_page)
>+ return -ENOMEM;
>
> if (chip->flags & TPM_CHIP_FLAG_TPM2)
>- rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS,
>- TPM2_CC_SET_LOCALITY);
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE,
>+ TPM2_ST_SESSIONS, TPM2_CC_SET_LOCALITY);
> else
>- rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND,
>- TPM_ORD_SET_LOCALITY);
>- if (rc)
>- return rc;
>+ tpm_buf_reset(&buf, kmap(data_page), PAGE_SIZE,
>+ TPM_TAG_RQU_COMMAND, TPM_ORD_SET_LOCALITY);
>+
> tpm_buf_append_u8(&buf, locality);
>
> proxy_dev->state |= STATE_DRIVER_COMMAND;
>@@ -426,8 +430,8 @@ static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
> locality = -1;
>
> out:
>- tpm_buf_destroy(&buf);
>-
>+ kunmap(data_page);
>+ __free_page(data_page);
> return locality;
> }
>
>--
>2.20.1
>
On Sat, Sep 28, 2019 at 12:58:13AM -0700, Jerry Snitselaar wrote:
> TPM2_CC_GET_RANDOM
Ugh, I somehow sent v1 2nd time also in terms of contents (was fixed in
v2).
I think it would be a great idea to add call to tpm_get_random() to the
chip startup as an additional test.
> Would this work here?
>
> err = total ? total : -EIO;
> out:
> kunmap(data_page);
> __free_page(data_page);
> return err;
I'd guess but I want to keep this commit as dumbed down and mechanical
as possible given the amount of changes.
/Jarkko