tpm2-software / tpm2-tss

OSS implementation of the TCG TPM2 Software Stack (TSS2)
https://tpm2-software.github.io
BSD 2-Clause "Simplified" License
730 stars 359 forks source link

Invalid MAX_NV_BUFFER_SIZE defined in stable 1.3.0 #667

Closed jiazhang0 closed 6 years ago

jiazhang0 commented 6 years ago

The testcase test_tpm2_nv.sh in the latest stable version of tpm2-tools 3.0.1 fails with the following failure:

/ERROR: Failed to read NVRAM area at index 0x1000000 (16777216). Error:0x80006
tpm2_nvread -Q -x $nv_test_index -a $nv_auth_handle > $large_file_read_name on line 167 failed: 1
test_tpm2_nv.sh ... FAILED

The root cause it due to invalid definition of MAX_NV_BUFFER_SIZE:

sapi/implementation.h:280:#define MAX_NV_BUFFER_SIZE              1024

This definition in the latest tpm2-tss has already corrected to 2048. I wonder whether we will have a new stable version of tpm2-tss with this fix.

Thanks.

flihp commented 6 years ago

Hi @jiazhang0. We had a chat about this on the tpm2@01.org mailing list a while back: https://lists.01.org/pipermail/tpm2/2017-November/000330.html but I'm only seeing the original message from @williamcroberts in the archive, not any of the replies.

The end result of the discussion is that this constant is used to define the maximum read size supported by the TSS. It's still possible to read NV areas larger than this, but it will require multiple read operations. The maximum NV read possible for a given TPM is vendor specific and that value can be queried using GetCapability with the capability field set to TPM_CAP_TPM_PROPERTIES and the property field set to TPM_PT_NV_BUFFER_MAX so it's quite possible that you may have a TPM that supports NV operations with buffers larger or smaller than the MAX_NV_BUFFER_SIZE supported by the TSS.

So this isn't an issue with the TSS, but instead it looks like the tpm2_nvread tool may need some attention. Hopefully @williamcroberts can help shed some light on this.

In the meantime can you provide some additional data? I know you're working to enable the test cases to be run against a hardware TPM so if you're using anything other than the simulator here it would help to know the make / model / firmware version etc from your TPM.

jiazhang0 commented 6 years ago

@flihp This is the fixed properties returned from my hw TPM NationZ Z32H320TC.

$tpm2_getcap -c properties-fixed
TPM_PT_FAMILY_INDICATOR:
  as UINT32:                0x08322e3000
  as string:                "2.0"
TPM_PT_LEVEL:               0
TPM_PT_REVISION:            1.16
TPM_PT_DAY_OF_YEAR:         0x0000012f
TPM_PT_YEAR:                0x000007de
TPM_PT_MANUFACTURER:        0x4e545a00
TPM_PT_VENDOR_STRING_1:
  as UINT32:                0x4e545a00
  as string:                "NTZ"
TPM_PT_VENDOR_STRING_2:
  as UINT32:                0x00000000
  as string:                ""
TPM_PT_VENDOR_STRING_3:
  as UINT32:                0x00000000
  as string:                ""
TPM_PT_VENDOR_STRING_4:
  as UINT32:                0x00000000
  as string:                ""
TPM_PT_VENDOR_TPM_TYPE:     0x00000011
TPM_PT_FIRMWARE_VERSION_1:  0x00040001
TPM_PT_FIRMWARE_VERSION_2:  0x15041509
TPM_PT_INPUT_BUFFER:        0x00000667
TPM_PT_HR_TRANSIENT_MIN:    0x00000004
TPM_PT_HR_PERSISTENT_MIN:   0x00000007
TPM_PT_HR_LOADED_MIN:       0x00000004
TPM_PT_ACTIVE_SESSIONS_MAX: 0x00000040
TPM_PT_PCR_COUNT:           0x00000018
TPM_PT_PCR_SELECT_MIN:      0x00000003
TPM_PT_CONTEXT_GAP_MAX:     0x0000ffff
TPM_PT_NV_COUNTERS_MAX:     0x00000000
TPM_PT_NV_INDEX_MAX:        0x00000667
TPM_PT_MEMORY:              0x00000004
TPM_PT_CLOCK_UPDATE:        0x003e8000
TPM_PT_CONTEXT_HASH:        0x0000000b
TPM_PT_CONTEXT_SYM:         0x00000006
TPM_PT_CONTEXT_SYM_SIZE:    0x00000080
TPM_PT_ORDERLY_COUNT:       0x000000ff
TPM_PT_MAX_COMMAND_SIZE:    0x000008ac
TPM_PT_MAX_RESPONSE_SIZE:   0x000008ac
TPM_PT_MAX_DIGEST:          0x00000020
TPM_PT_MAX_OBJECT_CONTEXT:  0x000003a0
TPM_PT_MAX_SESSION_CONTEXT: 0x000000f4
TPM_PT_PS_FAMILY_INDICATOR: 0x00000002
TPM_PT_PS_LEVEL:            0x00000000
TPM_PT_PS_REVISION:         0x00000100
TPM_PT_PS_DAY_OF_YEAR:      0x00000000
TPM_PT_PS_YEAR:             0x00000000
TPM_PT_SPLIT_MAX:           0x00000080
TPM_PT_TOTAL_COMMANDS:      0x00000065
TPM_PT_LIBRARY_COMMANDS:    0x00000063
TPM_PT_VENDOR_COMMANDS:     0x00000002
TPM_PT_NV_BUFFER_MAX:       0x00000667
williamcroberts commented 6 years ago

Weird, 3.X releases should include the fix: https://github.com/intel/tpm2-tools/blob/3.0.1/tools/tpm2_nvread.c#L118

The code queries the TPM to get the max buffer transmission size via: TPM_PT_NV_BUFFER_MAX

The test queries for TPM_PT_NV_INDEX_MAX and uses that to define the size of the index to use in nvdefine.

Then tpm2_nvwrite writes TPM_PT_NV_BUFFER_MAX chunks until it's written the data that is TPM_PT_NV_BUFFER_MAX bytes big.

Did I miss something here?

jiazhang0 commented 6 years ago

@williamcroberts @flihp The issue only happens if the requesting buffer size is larger than MAX_NV_BUFFER_SIZE supported by TSS.

This is the reference code and I add the comments for the test results.

    UINT32 max_data_size;
    rval = tpm2_util_nv_max_buffer_size(sapi_context, &max_data_size);
    if (rval != TPM_RC_SUCCESS) {
        return false;
    }

    UINT8 *data_buffer = malloc(data_size);
    if (!data_buffer) {
        LOG_ERR("oom");
        return false;
    }

    UINT16 data_offset = 0;
    while (ctx.size_to_read) {

        UINT16 bytes_to_read = ctx.size_to_read > max_data_size ?
                max_data_size : ctx.size_to_read;

        TPM2B_MAX_NV_BUFFER nv_data = TPM2B_TYPE_INIT(TPM2B_MAX_NV_BUFFER, buffer);

        //                           bytes_to_read         max_data_size    nv_data.t.size
        // success case:  13                            1639                    1024
        // failure case:      1639                       1639                    1024
        // success case:   1639                       1639                    2048
        rval = TSS2_RETRY_EXP(Tss2_Sys_NV_Read(sapi_context, ctx.auth_handle, ctx.nv_index,
                &sessions_data, bytes_to_read, ctx.offset, &nv_data, &sessions_data_out));
        if (rval != TPM2_RC_SUCCESS) {
            LOG_ERR("Failed to read NVRAM area at index 0x%x (%d). Error:0x%x",
                    ctx.nv_index, ctx.nv_index, rval);
            goto out;
        }

MAX_NV_BUFFER_SIZE is just a configuration value supported by TSS. If a hw tpm has a max_data_size (TPM_PT_NV_BUFFER_MAX) smaller than MAX_NV_BUFFER_SIZE, there would be no any problem.

Therefore, If the fixup should locate in tpm2-tss, just simply enlarge MAX_NV_BUFFER_SIZE; If the fix fixup should locate in tpm2-tools, such a pseudo code will fix this issue as well.

    UINT32 max_data_size;
    rval = tpm2_util_nv_max_buffer_size(sapi_context, &max_data_size);
    max_data_size = MIN(max_data_size, MAX_NV_BUFFER_SIZE);
martinezjavier commented 6 years ago

@jiazhang0 I prefer your proposed fix for the tools, since enlarging MAX_NV_BUFFER_SIZE will only fix the issue in some TPM, there could always be a TPM that has a TPM_PT_NV_BUFFER_MAX bigger than whatever MAX_NV_BUFFER_SIZE constant we defined in tpm2-tss.

jiazhang0 commented 6 years ago

@martinezjavier I see this PR can fix this issue https://github.com/intel/tpm2-tools/pull/725/commits/d89a9813cd4566fc1f2a34008ee5f9ae69967f82

martinezjavier commented 6 years ago

@jiazhang0 yes, already fixed by Jerry.