From 6b444ad3ff73c755eeee39d888cd09c834e194ae Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 12 Jul 2018 12:08:22 -0400 Subject: [PATCH] rev148: Rework how the TPM internal clock works Signed-off-by: Stefan Berger --- configure.ac | 3 + src/Makefile.am | 2 +- src/tpm2/Clock.c | 150 +++++++++++++++++++++++++++------------- src/tpm2/NVMarshal.c | 50 ++++++++++++-- src/tpm2/PlatformData.c | 23 +++--- src/tpm2/PlatformData.h | 44 ++++++------ src/tpm2/Platform_fp.h | 2 +- 7 files changed, 192 insertions(+), 82 deletions(-) diff --git a/configure.ac b/configure.ac index 14d1cac8..e1794642 100644 --- a/configure.ac +++ b/configure.ac @@ -176,6 +176,9 @@ AC_C_INLINE AC_TYPE_SIZE_T +AC_CHECK_LIB(c, clock_gettime, LIBRT_LIBS="", LIBRT_LIBS="-lrt") +AC_SUBST([LIBRT_LIBS]) + AC_ARG_ENABLE([hardening], AS_HELP_STRING([--disable-hardening], [Disable hardening flags])) diff --git a/src/Makefile.am b/src/Makefile.am index 0ada97ce..c6ba79e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -169,7 +169,7 @@ noinst_LTLIBRARIES += libtpms_tpm2.la libtpms_la_LIBADD += libtpms_tpm2.la -libtpms_tpm2_la_LIBADD = +libtpms_tpm2_la_LIBADD = $(LIBRT_LIBS) libtpms_tpm2_la_CFLAGS = $(common_CFLAGS) diff --git a/src/tpm2/Clock.c b/src/tpm2/Clock.c index 37f64533..0a4b98f1 100644 --- a/src/tpm2/Clock.c +++ b/src/tpm2/Clock.c @@ -3,7 +3,7 @@ /* Used by the simulator to mimic a hardware clock */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ -/* $Id: Clock.c 1047 2017-07-20 18:27:34Z kgoldman $ */ +/* $Id: Clock.c 1259 2018-07-10 19:11:09Z kgoldman $ */ /* */ /* Licenses and Notices */ /* */ @@ -55,7 +55,7 @@ /* arising in any way out of use or reliance upon this specification or any */ /* information herein. */ /* */ -/* (c) Copyright IBM Corp. and others, 2016, 2017 */ +/* (c) Copyright IBM Corp. and others, 2016 - 2018 */ /* */ /********************************************************************************/ @@ -98,14 +98,22 @@ ClockGetTime( /* ClockAdjustPostResume -- adjust time parameters post resume */ #include "Tpm.h" void -ClockAdjustPostResume(UINT64 backthen) +ClockAdjustPostResume(UINT64 backthen, BOOL timesAreRealtime) { UINT64 now = ClockGetTime(CLOCK_REALTIME); INT64 timediff = now - backthen; - g_time += timediff; - s_realTimePrevious += timediff; - s_tpmTime += timediff; + if (timesAreRealtime) { + /* g_time, s_realTimePrevious, s_tpmTime are all in real time */ + s_suspendedElapsedTime = now; + s_hostMonotonicAdjustTime = -ClockGetTime(CLOCK_MONOTONIC); + + /* s_lastSystemTime & s_lastReportTime need to be set as well */ + s_lastSystemTime = now; + s_lastReportedTime = now; + } else if (timediff >= 0) { + s_suspendedElapsedTime += timediff; + } } /* C.3.3. Simulator Functions */ @@ -121,11 +129,13 @@ _plat__TimerReset( void ) { - s_realTimePrevious = (clock_t) ClockGetTime(CLOCK_REALTIME); /* kgold, FIXME, something wrong here */ + s_lastSystemTime = 0; s_tpmTime = 0; s_adjustRate = CLOCK_NOMINAL; s_timerReset = TRUE; s_timerStopped = TRUE; + s_hostMonotonicAdjustTime = 0; /* libtpms */ + s_suspendedElapsedTime = 0; /* libtpms */ return; } /* C.3.3.3. _plat__TimerRestart() */ @@ -139,11 +149,55 @@ _plat__TimerRestart( s_timerStopped = TRUE; return; } + /* C.3.4. Functions Used by TPM */ /* C.3.4.1. Introduction */ /* These functions are called by the TPM code. They should be replaced by appropriated hardware functions. */ -/* C.3.4.2. _plat__TimerRead() */ + +clock_t debugTime; +/* C.3.4.2. _plat__Time() */ +/* This is another, probably futile, attempt to define a portable function that will return a 64-bit + clock value that has mSec resolution. */ +uint64_t +_plat__RealTime( + void + ) +{ + clock64_t time; + //#ifdef _MSC_VER kgold +#ifdef TPM_WINDOWS + #include + struct _timeb sysTime; + // + _ftime(&sysTime); /* kgold, mingw doesn't have _ftime_s */ + time = (clock64_t)(sysTime.time) * 1000 + sysTime.millitm; + // set the time back by one hour if daylight savings + if(sysTime.dstflag) + time -= 1000 * 60 * 60; // mSec/sec * sec/min * min/hour = ms/hour +#else + // hopefully, this will work with most UNIX systems + struct timespec systime; + // + clock_gettime(CLOCK_MONOTONIC, &systime); + time = (clock64_t)systime.tv_sec * 1000 + (systime.tv_nsec / 1000000); +#endif + /* We have to make sure that this function returns monotonically increasing time + also when a vTPM has been suspended and the host has been rebooted. + Example: + - The vTPM is suspended at systime '5' + - The vTPM is resumed at systime '1' after a host reboot + -> we now need to add '4' to the time + Besides this we want to account for the time a vTPM was suspended. + If it was suspended for 10 time units, we need to add '10' here. + */ + time += s_hostMonotonicAdjustTime + s_suspendedElapsedTime; + return time; +} + + + +/* C.3.4.3. _plat__TimerRead() */ /* This function provides access to the tick timer of the platform. The TPM code uses this value to drive the TPM Clock. */ /* The tick timer is supposed to run when power is applied to the device. This timer should not be @@ -153,7 +207,6 @@ _plat__TimerRestart( TPM as long as the time provided by the environment is not allowed to go backwards. If the time provided by the system can go backwards during a power discontinuity, then the _plat__Signal_PowerOn() should call _plat__TimerReset(). */ -/* The code in this function should be replaced by a read of a hardware tick timer. */ LIB_EXPORT uint64_t _plat__TimerRead( void @@ -163,49 +216,50 @@ _plat__TimerRead( #error "need a defintion for reading the hardware clock" return HARDWARE_CLOCK #else -#define BILLION 1000000000 -#define MILLION 1000000 -#define THOUSAND 1000 - clock_t timeDiff; - uint64_t adjusted; - // Save the value previously read from the system clock - timeDiff = s_realTimePrevious; - // update with the current value of the system clock - s_realTimePrevious = ClockGetTime(CLOCK_REALTIME); - // In the place below when we "put back" the unused part of the timeDiff - // it is possible that we can put back more than we take out. That is, we could - // take out 1000 mSec, rate adjust it and put back 1001 mS. This means that - // on a subsequent call, time may not have caught up. Rather than trying - // to rate adjust this, just stop time. This only occurs in a simulation so - // time for more than one command being the same should not be an issue. - if(timeDiff >= s_realTimePrevious) + clock64_t timeDiff; + clock64_t adjustedTimeDiff; + clock64_t timeNow; + clock64_t readjustedTimeDiff; + // This produces a timeNow that is basically locked to the system clock. + timeNow = _plat__RealTime(); + // if this hasn't been initialized, initialize it + if(s_lastSystemTime == 0) { - s_realTimePrevious = timeDiff; - return s_tpmTime; + s_lastSystemTime = timeNow; + debugTime = clock(); + s_lastReportedTime = 0; + s_realTimePrevious = 0; } - // Compute the amount of time since the last call to the system clock - timeDiff = s_realTimePrevious - timeDiff; + // The system time can bounce around and that's OK as long as we don't allow + // time to go backwards. When the time does appear to go backwards, set + // lastSystemTime to be the new value and then update the reported time. + if(timeNow < s_lastReportedTime) + s_lastSystemTime = timeNow; + s_lastReportedTime = s_lastReportedTime + timeNow - s_lastSystemTime; + s_lastSystemTime = timeNow; + timeNow = s_lastReportedTime; + // The code above produces a timeNow that is similar to the value returned + // by Clock(). The difference is that timeNow does not max out, and it is + // at a ms. rate rather than at a CLOCKS_PER_SEC rate. The code below + // uses that value and does the rate adjustment on the time value. + // If there is no difference in time, then skip all the computations + if(s_realTimePrevious >= timeNow) + return s_tpmTime; + // Compute the amount of time since the last update of the system clock + timeDiff = timeNow - s_realTimePrevious; // Do the time rate adjustment and conversion from CLOCKS_PER_SEC to mSec -#if 0 - adjusted = (((uint64_t)timeDiff * (THOUSAND * CLOCK_NOMINAL)) - / ((uint64_t)s_adjustRate * CLOCKS_PER_SEC)); -#endif - /* kgold */ - adjusted = (timeDiff * (uint64_t)(s_adjustRate)) / (uint64_t)CLOCK_NOMINAL; - s_tpmTime += (clock_t)adjusted; + adjustedTimeDiff = (timeDiff * CLOCK_NOMINAL) / ((uint64_t)s_adjustRate); + // update the TPM time with the adjusted timeDiff + s_tpmTime += (clock64_t)adjustedTimeDiff; // Might have some rounding error that would loose CLOCKS. See what is not // being used. As mentioned above, this could result in putting back more than - // is taken out -#if 0 - adjusted = (adjusted * ((uint64_t)s_adjustRate * CLOCKS_PER_SEC)) - / (THOUSAND * CLOCK_NOMINAL); -#endif - // If adjusted is not the same as timeDiff, then there is some rounding - // error that needs to be pushed back into the previous sample. - // NOTE: the following is so that the fact that everything is signed will not - // matter. - s_realTimePrevious = (clock_t)((int64_t)s_realTimePrevious - adjusted); - s_realTimePrevious += timeDiff; + // is taken out. Here, we are trying to recreate timeDiff. + readjustedTimeDiff = (adjustedTimeDiff * (uint64_t)s_adjustRate ) + / CLOCK_NOMINAL; + // adjusted is now converted back to being the amount we should advance the + // previous sampled time. It should always be less than or equal to timeDiff. + // That is, we could not have use more time than we started with. + s_realTimePrevious = s_realTimePrevious + readjustedTimeDiff; #ifdef DEBUGGING_TIME // Put this in so that TPM time will pass much faster than real time when // doing debug. @@ -216,6 +270,8 @@ _plat__TimerRead( return s_tpmTime; #endif } + + /* C.3.4.3. _plat__TimerWasReset() */ /* This function is used to interrogate the flag indicating if the tick timer has been reset. */ /* If the resetFlag parameter is SET, then the flag will be CLEAR before the function returns. */ diff --git a/src/tpm2/NVMarshal.c b/src/tpm2/NVMarshal.c index f077f2ba..1175515c 100644 --- a/src/tpm2/NVMarshal.c +++ b/src/tpm2/NVMarshal.c @@ -2627,7 +2627,7 @@ skip_future_versions: return rc; } -#define VOLATILE_STATE_VERSION 3 +#define VOLATILE_STATE_VERSION 4 #define VOLATILE_STATE_MAGIC 0x45637889 UINT16 @@ -2916,8 +2916,18 @@ VolatileState_Marshal(BYTE **buffer, INT32 *size) written += TPM2B_Marshal(&pd.PPSeed.b, buffer, size); written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size); /* v4 */ + + tmp_uint64 = ClockGetTime(CLOCK_MONOTONIC) + s_hostMonotonicAdjustTime; + written += UINT64_Marshal(&tmp_uint64, buffer, size); + + written += UINT64_Marshal(&s_suspendedElapsedTime, buffer, size); + written += UINT64_Marshal(&s_lastSystemTime, buffer, size); + written += UINT64_Marshal(&s_lastReportedTime, buffer, size); + + written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size); /* v5 */ /* future versions append below this line */ + BLOCK_SKIP_WRITE_POP(size); /* v5 */ BLOCK_SKIP_WRITE_POP(size); /* v4 */ BLOCK_SKIP_WRITE_POP(size); /* v3 */ @@ -2930,6 +2940,29 @@ VolatileState_Marshal(BYTE **buffer, INT32 *size) return written; } +TPM_RC +VolatileState_TailV4_Unmarshal(BYTE **buffer, INT32 *size) +{ + TPM_RC rc = TPM_RC_SUCCESS; + UINT64 tmp_uint64; + + if (rc == TPM_RC_SUCCESS) { + rc = UINT64_Unmarshal(&tmp_uint64, buffer, size); + s_hostMonotonicAdjustTime = tmp_uint64 - ClockGetTime(CLOCK_MONOTONIC); + } + if (rc == TPM_RC_SUCCESS) { + rc = UINT64_Unmarshal(&s_suspendedElapsedTime, buffer, size); + } + if (rc == TPM_RC_SUCCESS) { + rc = UINT64_Unmarshal(&s_lastSystemTime, buffer, size); + } + if (rc == TPM_RC_SUCCESS) { + rc = UINT64_Unmarshal(&s_lastReportedTime, buffer, size); + } + + return rc; +} + TPM_RC VolatileState_TailV3_Unmarshal(BYTE **buffer, INT32 *size) { @@ -3374,9 +3407,15 @@ skip_hardware_clock: "Volatile State", "version 3 or later"); rc = VolatileState_TailV3_Unmarshal(buffer, size); - BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size, + BLOCK_SKIP_READ(skip_future_versions, hdr.version >= 4, buffer, size, "Volatile State", "version 4 or later"); - /* future versions nest-append here */ + if (rc == TPM_RC_SUCCESS) { + rc = VolatileState_TailV4_Unmarshal(buffer, size); + } + + BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size, + "Volatile State", "version 5 or later"); + /* future versions append here */ } skip_future_versions: @@ -3395,7 +3434,10 @@ skip_future_versions: } if (rc == TPM_RC_SUCCESS) { - ClockAdjustPostResume(backthen); + BOOL timesAreRealtime = hdr.version <= 3; + /* Before Rev148 (header version <= 3), times were reported in + realtime; we need to account for this now */ + ClockAdjustPostResume(backthen, timesAreRealtime); } return rc; } diff --git a/src/tpm2/PlatformData.c b/src/tpm2/PlatformData.c index 010a1716..18dd4d94 100644 --- a/src/tpm2/PlatformData.c +++ b/src/tpm2/PlatformData.c @@ -1,9 +1,9 @@ /********************************************************************************/ /* */ -/* */ +/* TPM variables that are not stack allocated */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ -/* $Id: PlatformData.c 809 2016-11-16 18:31:54Z kgoldman $ */ +/* $Id: PlatformData.c 1259 2018-07-10 19:11:09Z kgoldman $ */ /* */ /* Licenses and Notices */ /* */ @@ -55,15 +55,15 @@ /* arising in any way out of use or reliance upon this specification or any */ /* information herein. */ /* */ -/* (c) Copyright IBM Corp. and others, 2016 */ +/* (c) Copyright IBM Corp. and others, 2016 - 2018 */ /* */ /********************************************************************************/ -/* C.9 PlatformData.c */ -/* C.9.1. Description */ +/* C.10 PlatformData.c */ +/* C.10.1. Description */ /* This file will instance the TPM variables that are not stack allocated. The descriptions for these variables are in Global.h for this project. */ -/* C.9.2. Includes */ +/* C.10.2. Includes */ #include "Implementation.h" #include "PlatformData.h" /* From Cancel.c */ @@ -73,9 +73,14 @@ unsigned int s_adjustRate; BOOL s_timerReset; BOOL s_timerStopped; #ifndef HARDWARE_CLOCK -#include -clock_t s_realTimePrevious; -clock_t s_tpmTime; +clock64_t s_realTimePrevious; +clock64_t s_tpmTime; +clock64_t s_lastSystemTime; +clock64_t s_lastReportedTime; + +/* libtpms added: */ +int64_t s_hostMonotonicAdjustTime; /* can be negative */ +uint64_t s_suspendedElapsedTime; #endif /* From LocalityPlat.c */ unsigned char s_locality; diff --git a/src/tpm2/PlatformData.h b/src/tpm2/PlatformData.h index 3a711db5..fb5ebaf4 100644 --- a/src/tpm2/PlatformData.h +++ b/src/tpm2/PlatformData.h @@ -3,7 +3,7 @@ /* Instance data for the Platform module. */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ -/* $Id: PlatformData.h 1047 2017-07-20 18:27:34Z kgoldman $ */ +/* $Id: PlatformData.h 1259 2018-07-10 19:11:09Z kgoldman $ */ /* */ /* Licenses and Notices */ /* */ @@ -55,13 +55,10 @@ /* arising in any way out of use or reliance upon this specification or any */ /* information herein. */ /* */ -/* (c) Copyright IBM Corp. and others, 2016, 2017. */ +/* (c) Copyright IBM Corp. and others, 2016 - 2018. */ /* */ /********************************************************************************/ -#ifndef PLATFORMDATA_H -#define PLATFORMDATA_H - /* A.1 PlatformData.h */ /* This file contains the instance data for the Platform module. It is collected in this file so that the state of the module is easier to manage. */ @@ -71,21 +68,31 @@ /* From Cancel.c Cancel flag. It is initialized as FALSE, which indicate the command is not being canceled */ extern int s_isCanceled; -#include -#ifndef __CYGWIN__ -typedef struct { - time_t tv_sec; // Seconds - >= 0 - long tv_nsec; // Nanoseconds - [0, 999999999] -} timespec_t; + +#ifdef _MSC_VER +#include +#include +#else +#include +#include #endif + #ifndef HARDWARE_CLOCK -/* This is the value returned the last time that the system clock was read. This is only relevant - for a simulator or virtual TPM. */ -extern clock_t s_realTimePrevious; -/* This is the rate adjusted value that is the equivalent of what would be read from a hardware - register that produced rate adjusted time. */ -extern clock_t s_tpmTime; +typedef uint64_t clock64_t; +// This is the value returned the last time that the system clock was read. This is only relevant +// for a simulator or virtual TPM. +extern clock64_t s_realTimePrevious; +// These values are uses to try to synthesize a long lived version of clock(). +extern clock64_t s_lastSystemTime; +extern clock64_t s_lastReportedTime; +// This is the rate adjusted value that is the equivalent of what would be read from a hardware +// register that produced rate adjusted time. +extern clock64_t s_tpmTime; +/* libtpms added: */ +extern int64_t s_hostMonotonicAdjustTime; +extern uint64_t s_suspendedElapsedTime; #endif // HARDWARE_CLOCK + /* This value indicates that the timer was reset */ extern BOOL s_timerReset; /* This value indicates that the timer was stopped. It causes a clock discontinuity. */ @@ -133,6 +140,3 @@ extern BOOL s_powerLost; /* From Entropy.c */ extern uint32_t lastEntropy; #endif // _PLATFORM_DATA_H_ - - -#endif diff --git a/src/tpm2/Platform_fp.h b/src/tpm2/Platform_fp.h index 19152f1f..37da127c 100644 --- a/src/tpm2/Platform_fp.h +++ b/src/tpm2/Platform_fp.h @@ -379,7 +379,7 @@ _plat__GetUnique( /* libtpms: */ #include -void ClockAdjustPostResume(UINT64 backthen); +void ClockAdjustPostResume(UINT64 backthen, BOOL timesAreRealtime); uint64_t ClockGetTime(clockid_t clk_id); #endif // _PLATFORM_FP_H_