Commit abc5cda0 authored by Stefan Berger's avatar Stefan Berger
Browse files

tpm: tpm_passthrough: Read the buffer size from the host device



Rather than hard coding the buffer size in the tpm_passthrough
backend read the TPM I/O buffer size from the host device.

Signed-off-by: default avatarStefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: default avatarMarc-André Lureau <marcandre.lureau@redhat.com>
parent 56388eee
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -45,11 +45,20 @@ struct tpm_resp_hdr {

#define TPM_ORD_ContinueSelfTest  0x53
#define TPM_ORD_GetTicks          0xf1
#define TPM_ORD_GetCapability     0x65

#define TPM_CAP_PROPERTY          0x05

#define TPM_CAP_PROP_INPUT_BUFFER 0x124

/* TPM2 defines */
#define TPM2_ST_NO_SESSIONS       0x8001

#define TPM2_CC_ReadClock         0x00000181
#define TPM2_CC_GetCapability     0x0000017a

#define TPM2_CAP_TPM_PROPERTIES   0x6

#define TPM2_PT_MAX_COMMAND_SIZE  0x11e

#endif /* TPM_TPM_INT_H */
+10 −1
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ struct TPMPassthruState {
    int cancel_fd;

    TPMVersion tpm_version;
    size_t tpm_buffersize;
};

typedef struct TPMPassthruState TPMPassthruState;
@@ -201,7 +202,15 @@ static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)

static size_t tpm_passthrough_get_buffer_size(TPMBackend *tb)
{
    return 4096;
    TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
    int ret;

    ret = tpm_util_get_buffer_size(tpm_pt->tpm_fd, tpm_pt->tpm_version,
                                   &tpm_pt->tpm_buffersize);
    if (ret < 0) {
        tpm_pt->tpm_buffersize = 4096;
    }
    return tpm_pt->tpm_buffersize;
}

/*
+115 −0
Original line number Diff line number Diff line
@@ -20,10 +20,19 @@
 */

#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "tpm_util.h"
#include "tpm_int.h"
#include "exec/memory.h"

#define DEBUG_TPM 0

#define DPRINTF(fmt, ...) do { \
    if (DEBUG_TPM) { \
        fprintf(stderr, "tpm-util:"fmt"\n", ## __VA_ARGS__); \
    } \
} while (0)

/*
 * Write an error message in the given output buffer.
 */
@@ -173,3 +182,109 @@ int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version)

    return 1;
}

int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
                             size_t *buffersize)
{
    unsigned char buf[1024];
    int ret;

    switch (tpm_version) {
    case TPM_VERSION_1_2: {
        const struct tpm_req_get_buffer_size {
            struct tpm_req_hdr hdr;
            uint32_t capability;
            uint32_t len;
            uint32_t subcap;
        } QEMU_PACKED tpm_get_buffer_size = {
            .hdr = {
                .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
                .len = cpu_to_be32(sizeof(tpm_get_buffer_size)),
                .ordinal = cpu_to_be32(TPM_ORD_GetCapability),
            },
            .capability = cpu_to_be32(TPM_CAP_PROPERTY),
            .len = cpu_to_be32(sizeof(uint32_t)),
            .subcap = cpu_to_be32(TPM_CAP_PROP_INPUT_BUFFER),
        };
        struct tpm_resp_get_buffer_size {
            struct tpm_resp_hdr hdr;
            uint32_t len;
            uint32_t buffersize;
        } QEMU_PACKED *tpm_resp = (struct tpm_resp_get_buffer_size *)buf;

        ret = tpm_util_request(tpm_fd, (unsigned char *)&tpm_get_buffer_size,
                               sizeof(tpm_get_buffer_size), buf, sizeof(buf));
        if (ret < 0) {
            return ret;
        }

        if (be32_to_cpu(tpm_resp->hdr.len) != sizeof(*tpm_resp) ||
            be32_to_cpu(tpm_resp->len) != sizeof(uint32_t)) {
            DPRINTF("tpm_resp->hdr.len = %u, expected = %zu\n",
                    be32_to_cpu(tpm_resp->hdr.len), sizeof(*tpm_resp));
            DPRINTF("tpm_resp->len = %u, expected = %zu\n",
                    be32_to_cpu(tpm_resp->len), sizeof(uint32_t));
            error_report("tpm_util: Got unexpected response to "
                         "TPM_GetCapability; errcode: 0x%x",
                         be32_to_cpu(tpm_resp->hdr.errcode));
            return -EFAULT;
        }
        *buffersize = be32_to_cpu(tpm_resp->buffersize);
        break;
    }
    case TPM_VERSION_2_0: {
        const struct tpm2_req_get_buffer_size {
            struct tpm_req_hdr hdr;
            uint32_t capability;
            uint32_t property;
            uint32_t count;
        } QEMU_PACKED tpm2_get_buffer_size = {
            .hdr = {
                .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
                .len = cpu_to_be32(sizeof(tpm2_get_buffer_size)),
                .ordinal = cpu_to_be32(TPM2_CC_GetCapability),
            },
            .capability = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES),
            .property = cpu_to_be32(TPM2_PT_MAX_COMMAND_SIZE),
            .count = cpu_to_be32(2), /* also get TPM2_PT_MAX_RESPONSE_SIZE */
        };
        struct tpm2_resp_get_buffer_size {
            struct tpm_resp_hdr hdr;
            uint8_t more;
            uint32_t capability;
            uint32_t count;
            uint32_t property1;
            uint32_t value1;
            uint32_t property2;
            uint32_t value2;
        } QEMU_PACKED *tpm2_resp = (struct tpm2_resp_get_buffer_size *)buf;

        ret = tpm_util_request(tpm_fd, (unsigned char *)&tpm2_get_buffer_size,
                               sizeof(tpm2_get_buffer_size), buf, sizeof(buf));
        if (ret < 0) {
            return ret;
        }

        if (be32_to_cpu(tpm2_resp->hdr.len) != sizeof(*tpm2_resp) ||
            be32_to_cpu(tpm2_resp->count) != 2) {
            DPRINTF("tpm2_resp->hdr.len = %u, expected = %zu\n",
                    be32_to_cpu(tpm2_resp->hdr.len), sizeof(*tpm2_resp));
            DPRINTF("tpm2_resp->len = %u, expected = %u\n",
                    be32_to_cpu(tpm2_resp->count), 2);
            error_report("tpm_util: Got unexpected response to "
                         "TPM2_GetCapability; errcode: 0x%x",
                         be32_to_cpu(tpm2_resp->hdr.errcode));
            return -EFAULT;
        }
        *buffersize = MAX(be32_to_cpu(tpm2_resp->value1),
                          be32_to_cpu(tpm2_resp->value2));
        break;
    }
    case TPM_VERSION_UNSPEC:
        return -EFAULT;
    }

    DPRINTF("buffersize of device: %zu\n", *buffersize);

    return 0;
}
+3 −0
Original line number Diff line number Diff line
@@ -36,4 +36,7 @@ static inline uint32_t tpm_cmd_get_size(const void *b)
    return be32_to_cpu(*(const uint32_t *)(b + 2));
}

int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version,
                             size_t *buffersize);

#endif /* TPM_TPM_UTIL_H */