[SLOF] [PATCH 05/16] Extend internal firmware API
Stefan Berger
stefanb at linux.vnet.ibm.com
Tue Nov 10 05:23:46 AEDT 2015
On 11/09/2015 03:56 AM, Nikunj A Dadhania wrote:
> Stefan Berger <stefanb at linux.vnet.ibm.com> writes:
>
>> Extend the internal API of the TPM firmware support with additional
>> functions for hashing data, extending the TPM's platform configuration
>> registers with a hash, and appending to the log that is recording
>> what was hashed.
>>
>> Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
>> ---
>> lib/libtpm/tcgbios.c | 276 +++++++++++++++++++++++++++++++++++++++++++++++
>> lib/libtpm/tcgbios_int.h | 1 +
>> 2 files changed, 277 insertions(+)
>>
>> diff --git a/lib/libtpm/tcgbios.c b/lib/libtpm/tcgbios.c
>> index afbaede..072ed4d 100644
>> --- a/lib/libtpm/tcgbios.c
>> +++ b/lib/libtpm/tcgbios.c
>> @@ -24,6 +24,9 @@
>> #include "tcgbios.h"
>> #include "tcgbios_int.h"
>> #include "stdio.h"
>> +#include "sha1.h"
>> +#include "stddef.h"
>> +#include "helpers.h"
>>
>> #define DEBUG 0
>> #define dprintf(_x ...) do { \
>> @@ -79,6 +82,8 @@ extern struct tpm_driver tpm_drivers[];
>>
>> static void *log_base;
>> static uint32_t log_area_size;
>> +/* next log entry goes here */
>> +static void *log_area_address_next;
>>
>> /********************************************************
>> Extensions for TCG-enabled BIOS
>> @@ -89,6 +94,7 @@ void tpm_set_log_parameters(void *addr, unsigned int size)
>> dprintf("Log is at 0x%llx; size is %u bytes\n",
>> (uint64_t)addr, size);
>> log_base = addr;
>> + log_area_address_next = addr;
>> log_area_size = size;
>> }
>>
>> @@ -399,3 +405,273 @@ err_exit:
>> return rc;
>> return TCGBIOS_COMMAND_ERROR;
>> }
>> +
>> +static void set_log_area_address_next(void *next)
>> +{
>> + log_area_address_next = next;
>> +}
> Where do you verify that next address is not more than log-area-size ?
This is verified when the blob is appended to the log. If it doesn't
fit, this function will not be called.
>
>> +
>> +static void *get_log_area_address_next(void)
>> +{
>> + return log_area_address_next;
>> +}
>> +
>> +static uint32_t tpm_sha1_calc(const uint8_t *data, uint32_t length,
>> + uint8_t *hash)
>> +{
>> + uint32_t rc;
>> + uint32_t returnCode;
>> + struct tpm_res_sha1start start;
>> + struct tpm_res_sha1complete complete;
>> + uint32_t blocks = length / 64;
>> + uint32_t rest = length & 0x3f;
> Better like this:
>
> #define BLK_SIZE 64
>
> uint32_t blocks = length / BLK_SIZE;
> uint32_t rest = length & (BLK_SIZE - 1);
>
>
>> + uint32_t numbytes, numbytes_no;
> Bit confusing names :-)
_no stands for network (byte) order. Do you have a better suggestion for
the name ?
>> + return tpm_sha1_calc(data, length, hash);
>> +
>> + return sha1(data, length, hash);
>> +}
>> +
>> +/*
>> + * Extend the ACPI log with the given entry by copying the
>> + * entry data into the log.
>> + *
>> + * @pcpes: Pointer to the structure to be copied into the log
>> + * @event: The event to be appended to 'pcpes'
>> + * @event_length: The length of the event
>> + *
>> + * Output:
>> + * lower 16 bits of return code contain entry number
>> + * if entry number is '0', then upper 16 bits contain error code.
>> + */
>> +static uint32_t tpm_extend_ofdt_log(struct pcpes *pcpes,
>> + const char *event, uint32_t event_length)
>> +{
>> + uint32_t size;
>> + uint32_t log_area_size = get_log_area_size();
>> + uint8_t *log_area_start_address = get_log_base_ptr();
>> + uint8_t *log_area_address_next = get_log_area_address_next();
>> +
>> + dprintf("LASA_BASE = %p, LASA_NEXT = %p\n",
>> + log_area_start_address, log_area_address_next);
>> +
>> + if (!log_area_address_next || log_area_size == 0)
>> + return TCGBIOS_LOGOVERFLOW;
>> +
>> + size = offset_of(struct pcpes, event) + event_length;
>> +
>> + if ((log_area_address_next + size - log_area_start_address) >
>> + log_area_size) {
>> + dprintf("LOG OVERFLOW: size = %d\n", size);
>> + return TCGBIOS_LOGOVERFLOW;
>> + }
>> +
>> + pcpes->eventdatasize = event_length;
>> +
>> + memcpy(log_area_address_next, pcpes, offset_of(struct pcpes, event));
>> + memcpy(log_area_address_next + offset_of(struct pcpes, event),
>> + event, event_length);
>> +
>> + set_log_area_address_next(log_area_address_next + size);
>> +
>> + return 0;
>> +}
>> +
>> +static uint32_t is_preboot_if_shutdown(void)
> Confusing function name. how about: is_interface_down(). Or just get rid
> of this helper, only being used at two places.
>
>> +{
>> + return tpm_state.if_shutdown;
>> +}
>> +
>> +static uint32_t shutdown_preboot_interface(void)
>> +{
>> + uint32_t rc = 0;
>> +
>> + if (!is_preboot_if_shutdown()) {
>> + tpm_state.if_shutdown = 1;
>> + } else {
>> + rc = TCGBIOS_INTERFACE_SHUTDOWN;
>> + }
>> +
>> + return rc;
>> +}
>> +
>> +static void tpm_shutdown(void)
>> +{
>> + reset_ofdt_log();
>> + shutdown_preboot_interface();
>> +}
>> +
>> +/*
>> + * Pass a TPM command through to the TPM
>> + *
>> + * @req: request buffer to send
>> + * @reqlen: request buffer length
>> + * @to_t: timeout type
>> + * @rsp: response buffer
>> + * @rsplen: size of response buffer in input
>> + * on output the number of bytes used in the buffer
>> + *
>> + * Returns an error code or 0 for successful sending of command
>> + * and reception of response.
>> + */
>> +static bool pass_through_to_tpm(unsigned char *req,
> how about send_tpm_req() ?
The name of this function directly relates to the name of a API call of
the firmware, which will later on invoke it. I would rather like to keep
it....
>
>> + uint32_t reqlen,
>> + enum tpmDurationType to_t,
>> + unsigned char *rsp,
>> + uint32_t *rsplen)
>> +{
>> + uint8_t locty = 0;
>> + struct iovec iovec[2] = {{ 0 }};
>> +
>> + if (!has_working_tpm())
>> + return TCGBIOS_FATAL_COM_ERROR;
>> +
>> + iovec[0].data = req;
>> + iovec[0].length = reqlen;
>> +
>> + return transmit(locty, iovec, rsp, rsplen, to_t);
>> +}
>> +
>> +/*
>> + * Extend a PCR of the TPM with the given hash
>> + *
>> + * @hash: sha1 hash (20 bytes) to extend PCR with
>> + * @pcrindex: the PCR to extend [ 0..23 ]
>> + */
>> +static uint32_t tpm_extend(uint8_t *hash, uint32_t pcrindex)
>> +{
>> + struct tpm_req_extend req = {
>> + .tag = cpu_to_be16(TPM_TAG_RQU_CMD),
>> + .totlen = cpu_to_be32(sizeof(req)),
>> + .ordinal = cpu_to_be32(TPM_ORD_Extend),
>> + .pcrindex = cpu_to_be32(pcrindex),
>> + };
>> + struct tpm_rsp_extend rsp;
>> + uint32_t rsplen = sizeof(rsp);
>> + uint32_t rc;
>> +
>> + memcpy(req.digest, hash, sizeof(req.digest));
>> +
>> + rc = pass_through_to_tpm((unsigned char *)&req, sizeof(req),
>> + TPM_DURATION_TYPE_SHORT,
>> + (unsigned char *)&rsp, &rsplen);
>> + if (!rc) {
>> + if (rsplen != sizeof(rsp)) {
>> + dprintf("TPM_Extend response has unexpected size: %u\n",
>> + rsplen);
>> + rc = TCGBIOS_FATAL_COM_ERROR;
>> + }
>> + }
>> +
>> + if (rc)
>> + tpm_shutdown();
>> +
>> + return rc;
>> +}
>> +
>> +/*
>> + * Hash then given input data and append the hash to the log
> the
>
>> + *
>> + * @hashdata: the data to hash
>> + * @hashdatalen: the size of the data to hash
>> + * @pcpes: the 'pcpes' to append to the log; the hash will be written into this
>> + * structure
>> + * @event: the event to append to the pcpes
>> + * @event_length: the lenth of the event array
>> + */
>> +static uint32_t hash_log_event(const void *hashdata,
>> + uint32_t hashdatalen,
>> + struct pcpes *pcpes,
>> + const char *event, uint32_t event_length)
>> +{
>> + uint32_t rc;
>> +
>> + if (is_preboot_if_shutdown())
>> + return TCGBIOS_INTERFACE_SHUTDOWN;
>> +
>> + if (pcpes->pcrindex >= 24)
> What does 24 mean? Comments?
The TPM has a maximum of 24 PCRs.
Stefan
More information about the SLOF
mailing list