Message ID | 20190926172324.3405-1-jarkko.sakkinen@linux.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | tpm: Detach page allocation from tpm_buf | expand |
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 <zohar@linux.ibm.com> > Cc: Jerry Snitselaar <jsnitsel@redhat.com> > Cc: James Bottomley <James.Bottomley@HansenPartnership.com> > Cc: Sumit Garg <sumit.garg@linaro.org> > Cc: Stefan Berger <stefanb@linux.vnet.ibm.com> > Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> > --- > 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 <zohar@linux.ibm.com> >Cc: Jerry Snitselaar <jsnitsel@redhat.com> >Cc: James Bottomley <James.Bottomley@HansenPartnership.com> >Cc: Sumit Garg <sumit.garg@linaro.org> >Cc: Stefan Berger <stefanb@linux.vnet.ibm.com> >Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> >--- >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
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; }
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 <zohar@linux.ibm.com> Cc: Jerry Snitselaar <jsnitsel@redhat.com> Cc: James Bottomley <James.Bottomley@HansenPartnership.com> Cc: Sumit Garg <sumit.garg@linaro.org> Cc: Stefan Berger <stefanb@linux.vnet.ibm.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> --- 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(-)