[PATCH 1/6] tpm: implement TPM2 function to get update counter
Tushar Sugandhi
tusharsu at linux.microsoft.com
Tue Aug 1 14:01:12 PDT 2023
Thanks for the response Jarkko.
On 8/1/23 12:02, Jarkko Sakkinen wrote:
> The short summary is cryptic to say the least.
Do you mean the patch subject line, or the description below?
> "update counter" does not map it to have anything to do with PCRs.
Agreed. I noticed that when I was testing the patches.
The update counter is same for all PCRs. It was also the same for
the two hash algo's I tested it for (SHA1 and SHA256). But the spec
description and Kernel implementation requires to pass the
pcr_idx and hash algo to PCR_Read command to get the update counter.
> Why not "tpm: Read pcrUpdateCounter field from TPM2_PCR_Read"?
As I said in the patch description below, update counter is only
needed for IMA measurements. None of the other code that calls
tpm2_pcr_read() use the update counter.
I was not sure if you were okay changing the function signature and
implementation of tpm2_pcr_read(). It felt disruptive.
But I can update tpm2_pcr_read() if you are ok with it.
Please let me know.
I also have a few more thoughts on this in the comment below.
> On Tue Aug 1, 2023 at 9:19 PM EEST, Tushar Sugandhi wrote:
>> The TPM2_PCR_Read command returns TPM2_PCR_Read Response struct[1]. It
>> contains pcrUpdateCounter member which contains the current value of TPM
>> PCR update counter. The update counter provides the number of times the
>> PCRs are updated, which is essential for tracking changes and verifying
>> system integrity. Thus, subsystems (like IMA) should measure
>> pcrUpdateCounter value. Although tpm2_pcr_read_out struct is returned
>> by tpm2_pcr_read(), it is not used by it's caller function tpm_pcr_read().
>> Further, TPM2_PCR_Read Response struct and pcrUpdateCounter is not
>> available in tpm1_pcr_read().
>>
>> PcrUpdateCounter is only needed in a specific case (IMA for measurements).
>> Changing tpm_pcr_read() and tpm2_pcr_read() function signature to return
>> tpm2_pcr_read_out struct would be a more disruptive change, since these
>> functions are used elsewhere too. Creating separate functions to get
>> pcrUpdateCounter when needed would be a cleaner approach.
>>
>> Add a function, 'tpm2_pcr_get_update_counter()' to retrieve
>> the update counter for a given PCR index and algorithm ID on a TPM2 chip.
>>
>> This function complements existing TPM functionalities such as reading
>> and extending PCRs, and enhances the ability to monitor PCR status
>> in the Linux Kernel.
>>
>> [1] https://trustedcomputinggroup.org/wp-content/uploads/TCG_TPM2_r1p59_Part3_Commands_pub.pdf
>> Section 22.4.2, Page 206.
>>
>> Signed-off-by: Tushar Sugandhi <tusharsu at linux.microsoft.com>
>> ---
>> drivers/char/tpm/tpm.h | 3 +++
>> drivers/char/tpm/tpm2-cmd.c | 48 +++++++++++++++++++++++++++++++++++++
>> 2 files changed, 51 insertions(+)
>>
>> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
>> index 830014a26609..60489f21d3bd 100644
>> --- a/drivers/char/tpm/tpm.h
>> +++ b/drivers/char/tpm/tpm.h
>> @@ -288,6 +288,9 @@ static inline void tpm_add_ppi(struct tpm_chip *chip)
>> int tpm2_get_timeouts(struct tpm_chip *chip);
>> int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
>> struct tpm_digest *digest, u16 *digest_size_ptr);
>> +int tpm2_pcr_get_update_counter(struct tpm_chip *chip,
>> + u32 pcr_idx, u16 alg_id,
>> + u32 *update_counter);
> tpm_pcr_read_update_cnt()
I can rename 'get' -> 'read'
About 'tpm2' -> 'tpm':
I already have tpm_pcr_get_update_counter() defined in patch 2.
I was following the existing pattern here in patch 1 and 2 i. e.
- Implementing the tpm1/tpm2 specific functionality in
drivers/char/tpm/tpm.h, drivers/char/tpm/tpm2-cmd.c,
drivers/char/tpm/tpm1-cmd.c.
- And combining that functionality in drivers/char/tpm/tpm-interface.c
and exposing it to other subsystems (like IMA) through
include/linux/tpm.h
(patch 2 of this series)
BTW, if I understand correctly, the update counter is not available in
TPM 1.2.
Please let me know if you want me to expose the functionality directly
from drivers/char/tpm/tpm2-cmd.c and getting rid of patch #2 of this series.
~Tushar
>> int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
>> struct tpm_digest *digests);
>> int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max);
>> diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
>> index 93545be190a5..55f4e102289a 100644
>> --- a/drivers/char/tpm/tpm2-cmd.c
>> +++ b/drivers/char/tpm/tpm2-cmd.c
>> @@ -216,6 +216,54 @@ int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx,
>> return rc;
>> }
>>
>> +/**
>> + * tpm2_pcr_get_update_counter() - gets an update counter value for a PCR bank
>> + * @chip: TPM chip to use
>> + * @pcr_idx: PCR index used to retrieve the update counter
>> + * @alg_id: alg id used to retrieve the update counter
>> + * @update_counter: output update counter value
>> + *
>> + * Return: Same as with tpm_transmit_cmd.
>> + */
>> +int tpm2_pcr_get_update_counter(struct tpm_chip *chip,
>> + u32 pcr_idx, u16 alg_id, u32 *update_counter)
>> +{
>> + int rc;
>> + struct tpm_buf buf;
>> + struct tpm2_pcr_read_out *read_out;
>> + u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
>> +
>> + if (pcr_idx >= TPM2_PLATFORM_PCR)
>> + return -EINVAL;
>> +
>> + if (!update_counter)
>> + return -EINVAL;
>> +
>> + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
>> + if (rc)
>> + return rc;
>> +
>> + pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
>> +
>> + tpm_buf_append_u32(&buf, 1);
>> + tpm_buf_append_u16(&buf, alg_id);
>> + tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN);
>> + tpm_buf_append(&buf, (const unsigned char *)pcr_select,
>> + sizeof(pcr_select));
>> +
>> + rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value");
>> + if (rc)
>> + goto out;
>> +
>> + read_out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
>> +
>> + *update_counter = be32_to_cpu(read_out->update_cnt);
>> +
>> +out:
>> + tpm_buf_destroy(&buf);
>> + return rc;
>> +}
>> +
>> struct tpm2_null_auth_area {
>> __be32 handle;
>> __be16 nonce_size;
>> --
>> 2.25.1
> BR, Jarkko
More information about the kexec
mailing list